Commit 6160106c authored by Magnus Hagander's avatar Magnus Hagander

Add support for GSSAPI authentication.

Documentation still being written, will be committed later.

Henry B. Hotz and Magnus Hagander
parent ff481ca0
......@@ -314,7 +314,7 @@ ac_includes_default="\
# include <unistd.h>
#endif"
ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS configure_args build build_cpu build_vendor build_os host host_cpu host_vendor host_os PORTNAME docdir enable_nls WANTED_LANGUAGES default_port enable_shared enable_rpath enable_debug enable_profiling DTRACE DTRACEFLAGS enable_dtrace CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT CPP GCC TAS autodepend INCLUDES enable_thread_safety with_tcl with_perl with_python with_krb5 krb_srvtab with_pam with_ldap with_bonjour with_openssl with_ossp_uuid XML2_CONFIG with_libxml with_libxslt with_zlib EGREP ELF_SYS LDFLAGS_SL AWK FLEX FLEXFLAGS LN_S LD with_gnu_ld ld_R_works RANLIB ac_ct_RANLIB TAR STRIP ac_ct_STRIP STRIP_STATIC_LIB STRIP_SHARED_LIB YACC YFLAGS PERL perl_archlibexp perl_privlibexp perl_useshrplib perl_embed_ldflags PYTHON python_version python_configdir python_includespec python_libdir python_libspec python_additional_libs HAVE_IPV6 LIBOBJS acx_pthread_config PTHREAD_CC PTHREAD_LIBS PTHREAD_CFLAGS LDAP_LIBS_FE LDAP_LIBS_BE HAVE_POSIX_SIGNALS MSGFMT MSGMERGE XGETTEXT localedir TCLSH TCL_CONFIG_SH TCL_INCLUDE_SPEC TCL_LIB_FILE TCL_LIBS TCL_LIB_SPEC TCL_SHARED_BUILD TCL_SHLIB_LD_LIBS NSGMLS JADE have_docbook DOCBOOKSTYLE COLLATEINDEX SGMLSPL vpath_build LTLIBOBJS'
ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS configure_args build build_cpu build_vendor build_os host host_cpu host_vendor host_os PORTNAME docdir enable_nls WANTED_LANGUAGES default_port enable_shared enable_rpath enable_debug enable_profiling DTRACE DTRACEFLAGS enable_dtrace CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT CPP GCC TAS autodepend INCLUDES enable_thread_safety with_tcl with_perl with_python with_gssapi with_krb5 krb_srvtab with_pam with_ldap with_bonjour with_openssl with_ossp_uuid XML2_CONFIG with_libxml with_libxslt with_zlib EGREP ELF_SYS LDFLAGS_SL AWK FLEX FLEXFLAGS LN_S LD with_gnu_ld ld_R_works RANLIB ac_ct_RANLIB TAR STRIP ac_ct_STRIP STRIP_STATIC_LIB STRIP_SHARED_LIB YACC YFLAGS PERL perl_archlibexp perl_privlibexp perl_useshrplib perl_embed_ldflags PYTHON python_version python_configdir python_includespec python_libdir python_libspec python_additional_libs HAVE_IPV6 LIBOBJS acx_pthread_config PTHREAD_CC PTHREAD_LIBS PTHREAD_CFLAGS LDAP_LIBS_FE LDAP_LIBS_BE HAVE_POSIX_SIGNALS MSGFMT MSGMERGE XGETTEXT localedir TCLSH TCL_CONFIG_SH TCL_INCLUDE_SPEC TCL_LIB_FILE TCL_LIBS TCL_LIB_SPEC TCL_SHARED_BUILD TCL_SHLIB_LD_LIBS NSGMLS JADE have_docbook DOCBOOKSTYLE COLLATEINDEX SGMLSPL vpath_build LTLIBOBJS'
ac_subst_files=''
# Initialize some variables set by options.
......@@ -887,6 +887,7 @@ Optional Packages:
--with-tclconfig=DIR tclConfig.sh is in DIR
--with-perl build Perl modules (PL/Perl)
--with-python build Python modules (PL/Python)
--with-gssapi build with GSSAPI support
--with-krb5 build with Kerberos 5 support
--with-krb-srvnam=NAME default service principal name in Kerberos [postgres]
--with-pam build with PAM support
......@@ -3919,6 +3920,50 @@ echo "$as_me:$LINENO: result: $with_python" >&5
echo "${ECHO_T}$with_python" >&6
#
# GSSAPI
#
echo "$as_me:$LINENO: checking wether to build with GSSAPI support" >&5
echo $ECHO_N "checking wether to build with GSSAPI support... $ECHO_C" >&6
pgac_args="$pgac_args with_gssapi"
# Check whether --with-gssapi or --without-gssapi was given.
if test "${with_gssapi+set}" = set; then
withval="$with_gssapi"
case $withval in
yes)
cat >>confdefs.h <<\_ACEOF
#define ENABLE_GSS 1
_ACEOF
krb_srvtab="FILE:\$(sysconfdir)/krb5.keytab"
;;
no)
:
;;
*)
{ { echo "$as_me:$LINENO: error: no argument expected for --with-gssapi option" >&5
echo "$as_me: error: no argument expected for --with-gssapi option" >&2;}
{ (exit 1); exit 1; }; }
;;
esac
else
with_gssapi=no
fi;
echo "$as_me:$LINENO: result: $with_gssapi" >&5
echo "${ECHO_T}$with_gssapi" >&6
#
# Kerberos 5
#
......@@ -6718,6 +6763,143 @@ echo "$as_me: WARNING:
*** Not using spinlocks will cause poor performance." >&2;}
fi
if test "$with_gssapi" = yes ; then
if test "$PORTNAME" != "win32"; then
echo "$as_me:$LINENO: checking for library containing gss_init_sec_context" >&5
echo $ECHO_N "checking for library containing gss_init_sec_context... $ECHO_C" >&6
if test "${ac_cv_search_gss_init_sec_context+set}" = set; then
echo $ECHO_N "(cached) $ECHO_C" >&6
else
ac_func_search_save_LIBS=$LIBS
ac_cv_search_gss_init_sec_context=no
cat >conftest.$ac_ext <<_ACEOF
/* confdefs.h. */
_ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
/* Override any gcc2 internal prototype to avoid an error. */
#ifdef __cplusplus
extern "C"
#endif
/* We use char because int might match the return type of a gcc2
builtin and then its argument prototype would still apply. */
char gss_init_sec_context ();
int
main ()
{
gss_init_sec_context ();
;
return 0;
}
_ACEOF
rm -f conftest.$ac_objext conftest$ac_exeext
if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
(eval $ac_link) 2>conftest.er1
ac_status=$?
grep -v '^ *+' conftest.er1 >conftest.err
rm -f conftest.er1
cat conftest.err >&5
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); } &&
{ ac_try='test -z "$ac_c_werror_flag"
|| test ! -s conftest.err'
{ (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
(eval $ac_try) 2>&5
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); }; } &&
{ ac_try='test -s conftest$ac_exeext'
{ (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
(eval $ac_try) 2>&5
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); }; }; then
ac_cv_search_gss_init_sec_context="none required"
else
echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
fi
rm -f conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
if test "$ac_cv_search_gss_init_sec_context" = no; then
for ac_lib in gssapi_krb5; do
LIBS="-l$ac_lib $ac_func_search_save_LIBS"
cat >conftest.$ac_ext <<_ACEOF
/* confdefs.h. */
_ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
/* Override any gcc2 internal prototype to avoid an error. */
#ifdef __cplusplus
extern "C"
#endif
/* We use char because int might match the return type of a gcc2
builtin and then its argument prototype would still apply. */
char gss_init_sec_context ();
int
main ()
{
gss_init_sec_context ();
;
return 0;
}
_ACEOF
rm -f conftest.$ac_objext conftest$ac_exeext
if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
(eval $ac_link) 2>conftest.er1
ac_status=$?
grep -v '^ *+' conftest.er1 >conftest.err
rm -f conftest.er1
cat conftest.err >&5
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); } &&
{ ac_try='test -z "$ac_c_werror_flag"
|| test ! -s conftest.err'
{ (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
(eval $ac_try) 2>&5
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); }; } &&
{ ac_try='test -s conftest$ac_exeext'
{ (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
(eval $ac_try) 2>&5
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); }; }; then
ac_cv_search_gss_init_sec_context="-l$ac_lib"
break
else
echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
fi
rm -f conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
done
fi
LIBS=$ac_func_search_save_LIBS
fi
echo "$as_me:$LINENO: result: $ac_cv_search_gss_init_sec_context" >&5
echo "${ECHO_T}$ac_cv_search_gss_init_sec_context" >&6
if test "$ac_cv_search_gss_init_sec_context" != no; then
test "$ac_cv_search_gss_init_sec_context" = "none required" || LIBS="$ac_cv_search_gss_init_sec_context $LIBS"
else
{ { echo "$as_me:$LINENO: error: could not find function 'gss_init_sec_context' required for GSSAPI" >&5
echo "$as_me: error: could not find function 'gss_init_sec_context' required for GSSAPI" >&2;}
{ (exit 1); exit 1; }; }
fi
else
LIBS="$LIBS -lgssapi32"
fi
fi
if test "$with_krb5" = yes ; then
if test "$PORTNAME" != "win32"; then
echo "$as_me:$LINENO: checking for library containing com_err" >&5
......@@ -10014,6 +10196,155 @@ Use --without-zlib to disable zlib support." >&2;}
fi
fi
if test "$with_gssapi" = yes ; then
if test "${ac_cv_header_gssapi_gssapi_h+set}" = set; then
echo "$as_me:$LINENO: checking for gssapi/gssapi.h" >&5
echo $ECHO_N "checking for gssapi/gssapi.h... $ECHO_C" >&6
if test "${ac_cv_header_gssapi_gssapi_h+set}" = set; then
echo $ECHO_N "(cached) $ECHO_C" >&6
fi
echo "$as_me:$LINENO: result: $ac_cv_header_gssapi_gssapi_h" >&5
echo "${ECHO_T}$ac_cv_header_gssapi_gssapi_h" >&6
else
# Is the header compilable?
echo "$as_me:$LINENO: checking gssapi/gssapi.h usability" >&5
echo $ECHO_N "checking gssapi/gssapi.h usability... $ECHO_C" >&6
cat >conftest.$ac_ext <<_ACEOF
/* confdefs.h. */
_ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
$ac_includes_default
#include <gssapi/gssapi.h>
_ACEOF
rm -f conftest.$ac_objext
if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
(eval $ac_compile) 2>conftest.er1
ac_status=$?
grep -v '^ *+' conftest.er1 >conftest.err
rm -f conftest.er1
cat conftest.err >&5
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); } &&
{ ac_try='test -z "$ac_c_werror_flag"
|| test ! -s conftest.err'
{ (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
(eval $ac_try) 2>&5
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); }; } &&
{ ac_try='test -s conftest.$ac_objext'
{ (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
(eval $ac_try) 2>&5
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); }; }; then
ac_header_compiler=yes
else
echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
ac_header_compiler=no
fi
rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
echo "${ECHO_T}$ac_header_compiler" >&6
# Is the header present?
echo "$as_me:$LINENO: checking gssapi/gssapi.h presence" >&5
echo $ECHO_N "checking gssapi/gssapi.h presence... $ECHO_C" >&6
cat >conftest.$ac_ext <<_ACEOF
/* confdefs.h. */
_ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
#include <gssapi/gssapi.h>
_ACEOF
if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
(eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
ac_status=$?
grep -v '^ *+' conftest.er1 >conftest.err
rm -f conftest.er1
cat conftest.err >&5
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); } >/dev/null; then
if test -s conftest.err; then
ac_cpp_err=$ac_c_preproc_warn_flag
ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
else
ac_cpp_err=
fi
else
ac_cpp_err=yes
fi
if test -z "$ac_cpp_err"; then
ac_header_preproc=yes
else
echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
ac_header_preproc=no
fi
rm -f conftest.err conftest.$ac_ext
echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
echo "${ECHO_T}$ac_header_preproc" >&6
# So? What about this header?
case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
yes:no: )
{ echo "$as_me:$LINENO: WARNING: gssapi/gssapi.h: accepted by the compiler, rejected by the preprocessor!" >&5
echo "$as_me: WARNING: gssapi/gssapi.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
{ echo "$as_me:$LINENO: WARNING: gssapi/gssapi.h: proceeding with the compiler's result" >&5
echo "$as_me: WARNING: gssapi/gssapi.h: proceeding with the compiler's result" >&2;}
ac_header_preproc=yes
;;
no:yes:* )
{ echo "$as_me:$LINENO: WARNING: gssapi/gssapi.h: present but cannot be compiled" >&5
echo "$as_me: WARNING: gssapi/gssapi.h: present but cannot be compiled" >&2;}
{ echo "$as_me:$LINENO: WARNING: gssapi/gssapi.h: check for missing prerequisite headers?" >&5
echo "$as_me: WARNING: gssapi/gssapi.h: check for missing prerequisite headers?" >&2;}
{ echo "$as_me:$LINENO: WARNING: gssapi/gssapi.h: see the Autoconf documentation" >&5
echo "$as_me: WARNING: gssapi/gssapi.h: see the Autoconf documentation" >&2;}
{ echo "$as_me:$LINENO: WARNING: gssapi/gssapi.h: section \"Present But Cannot Be Compiled\"" >&5
echo "$as_me: WARNING: gssapi/gssapi.h: section \"Present But Cannot Be Compiled\"" >&2;}
{ echo "$as_me:$LINENO: WARNING: gssapi/gssapi.h: proceeding with the preprocessor's result" >&5
echo "$as_me: WARNING: gssapi/gssapi.h: proceeding with the preprocessor's result" >&2;}
{ echo "$as_me:$LINENO: WARNING: gssapi/gssapi.h: in the future, the compiler will take precedence" >&5
echo "$as_me: WARNING: gssapi/gssapi.h: in the future, the compiler will take precedence" >&2;}
(
cat <<\_ASBOX
## ---------------------------------------- ##
## Report this to pgsql-bugs@postgresql.org ##
## ---------------------------------------- ##
_ASBOX
) |
sed "s/^/$as_me: WARNING: /" >&2
;;
esac
echo "$as_me:$LINENO: checking for gssapi/gssapi.h" >&5
echo $ECHO_N "checking for gssapi/gssapi.h... $ECHO_C" >&6
if test "${ac_cv_header_gssapi_gssapi_h+set}" = set; then
echo $ECHO_N "(cached) $ECHO_C" >&6
else
ac_cv_header_gssapi_gssapi_h=$ac_header_preproc
fi
echo "$as_me:$LINENO: result: $ac_cv_header_gssapi_gssapi_h" >&5
echo "${ECHO_T}$ac_cv_header_gssapi_gssapi_h" >&6
fi
if test $ac_cv_header_gssapi_gssapi_h = yes; then
:
else
{ { echo "$as_me:$LINENO: error: header file <gssapi/gssapi.h> is required for GSSAPI" >&5
echo "$as_me: error: header file <gssapi/gssapi.h> is required for GSSAPI" >&2;}
{ (exit 1); exit 1; }; }
fi
fi
if test "$with_krb5" = yes ; then
......@@ -24618,6 +24949,7 @@ s,@enable_thread_safety@,$enable_thread_safety,;t t
s,@with_tcl@,$with_tcl,;t t
s,@with_perl@,$with_perl,;t t
s,@with_python@,$with_python,;t t
s,@with_gssapi@,$with_gssapi,;t t
s,@with_krb5@,$with_krb5,;t t
s,@krb_srvtab@,$krb_srvtab,;t t
s,@with_pam@,$with_pam,;t t
......
dnl Process this file with autoconf to produce a configure script.
dnl $PostgreSQL: pgsql/configure.in,v 1.516 2007/06/29 16:18:43 tgl Exp $
dnl $PostgreSQL: pgsql/configure.in,v 1.517 2007/07/10 13:14:20 mha Exp $
dnl
dnl Developers, please strive to achieve this order:
dnl
......@@ -462,6 +462,19 @@ PGAC_ARG_BOOL(with, python, no, [ --with-python build Python modules
AC_MSG_RESULT([$with_python])
AC_SUBST(with_python)
#
# GSSAPI
#
AC_MSG_CHECKING([wether to build with GSSAPI support])
PGAC_ARG_BOOL(with, gssapi, no, [ --with-gssapi build with GSSAPI support],
[
AC_DEFINE(ENABLE_GSS, 1, [Define to build with GSSAPI support. (--with-gssapi)])
krb_srvtab="FILE:\$(sysconfdir)/krb5.keytab"
])
AC_MSG_RESULT([$with_gssapi])
AC_SUBST(with_gssapi)
#
# Kerberos 5
#
......@@ -753,6 +766,15 @@ else
*** Not using spinlocks will cause poor performance.])
fi
if test "$with_gssapi" = yes ; then
if test "$PORTNAME" != "win32"; then
AC_SEARCH_LIBS(gss_init_sec_context, [gssapi_krb5], [],
[AC_MSG_ERROR([could not find function 'gss_init_sec_context' required for GSSAPI])])
else
LIBS="$LIBS -lgssapi32"
fi
fi
if test "$with_krb5" = yes ; then
if test "$PORTNAME" != "win32"; then
AC_SEARCH_LIBS(com_err, [krb5 'krb5 -lcrypto -ldes -lasn1 -lroken' com_err], [],
......@@ -848,6 +870,10 @@ failure. It is possible the compiler isn't looking in the proper directory.
Use --without-zlib to disable zlib support.])])
fi
if test "$with_gssapi" = yes ; then
AC_CHECK_HEADER(gssapi/gssapi.h, [], [AC_MSG_ERROR([header file <gssapi/gssapi.h> is required for GSSAPI])])
fi
if test "$with_krb5" = yes ; then
AC_CHECK_HEADER(krb5.h, [], [AC_MSG_ERROR([header file <krb5.h> is required for Kerberos 5])])
fi
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/libpq/auth.c,v 1.148 2007/02/08 04:52:18 momjian Exp $
* $PostgreSQL: pgsql/src/backend/libpq/auth.c,v 1.149 2007/07/10 13:14:20 mha Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -23,6 +23,7 @@
#endif
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include "libpq/auth.h"
#include "libpq/crypt.h"
......@@ -295,6 +296,250 @@ pg_krb5_recvauth(Port *port)
}
#endif /* KRB5 */
#ifdef ENABLE_GSS
/*----------------------------------------------------------------
* GSSAPI authentication system
*----------------------------------------------------------------
*/
#include <gssapi/gssapi.h>
#ifdef WIN32
/*
* MIT Kerberos GSSAPI DLL doesn't properly export the symbols
* 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_USER_NAME_desc =
{10, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x02"};
static GSS_DLLIMP gss_OID GSS_C_NT_USER_NAME = &GSS_C_NT_USER_NAME_desc;
#endif
static void
pg_GSS_error(int severity, char *text, OM_uint32 maj_stat, OM_uint32 min_stat)
{
gss_buffer_desc gmsg;
OM_uint32 lmaj_s, lmin_s, msg_ctx;
char localmsg1[128],
localmsg2[128];
/* Fetch major status message */
msg_ctx = 0;
lmaj_s = gss_display_status(&lmin_s, maj_stat, GSS_C_GSS_CODE,
GSS_C_NO_OID, &msg_ctx, &gmsg);
strlcpy(localmsg1, gmsg.value, sizeof(localmsg1));
gss_release_buffer(&lmin_s, &gmsg);
if (msg_ctx)
/* More than one message available.
* XXX: Should we loop and read all messages?
* (same below)
*/
ereport(WARNING,
(errmsg_internal("incomplete GSS error report")));
/* Fetch mechanism minor status message */
msg_ctx = 0;
lmaj_s = gss_display_status(&lmin_s, min_stat, GSS_C_MECH_CODE,
GSS_C_NO_OID, &msg_ctx, &gmsg);
strlcpy(localmsg2, gmsg.value, sizeof(localmsg2));
gss_release_buffer(&lmin_s, &gmsg);
if (msg_ctx)
ereport(WARNING,
(errmsg_internal("incomplete GSS minor error report")));
/* errmsg_internal, since translation of the first part must be
* done before calling this function anyway. */
ereport(severity,
(errmsg_internal("%s:%s\n%s", text, localmsg1, localmsg2)));
}
static int
pg_GSS_recvauth(Port *port)
{
OM_uint32 maj_stat, min_stat, lmin_s, gflags;
char *kt_path;
int mtype;
int ret;
StringInfoData buf;
gss_buffer_desc gbuf;
if (pg_krb_server_keyfile && strlen(pg_krb_server_keyfile) > 0)
{
/*
* Set default Kerberos keytab file for the Krb5 mechanism.
*
* setenv("KRB5_KTNAME", pg_krb_server_keyfile, 0);
* except setenv() not always available.
*/
if (!getenv("KRB5_KTNAME"))
{
kt_path = palloc(PATH_MAX + 13);
snprintf(kt_path, PATH_MAX + 13,
"KRB5_KTNAME=%s", pg_krb_server_keyfile);
putenv(kt_path);
}
}
/*
* We accept any service principal that's present in our
* keytab. This increases interoperability between kerberos
* implementations that see for example case sensitivity
* differently, while not really opening up any vector
* of attack.
*/
port->gss->cred = GSS_C_NO_CREDENTIAL;
/*
* Initialize sequence with an empty context
*/
port->gss->ctx = GSS_C_NO_CONTEXT;
/*
* Loop through GSSAPI message exchange. This exchange can consist
* of multiple messags sent in both directions. First message is always
* from the client. All messages from client to server are password
* packets (type 'p').
*/
do
{
mtype = pq_getbyte();
if (mtype != 'p')
{
/* Only log error if client didn't disconnect. */
if (mtype != EOF)
ereport(COMMERROR,
(errcode(ERRCODE_PROTOCOL_VIOLATION),
errmsg("expected GSS response, got message type %d",
mtype)));
return STATUS_ERROR;
}
/* Get the actual GSS token */
initStringInfo(&buf);
if (pq_getmessage(&buf, 2000))
{
/* EOF - pq_getmessage already logged error */
pfree(buf.data);
return STATUS_ERROR;
}
/* Map to GSSAPI style buffer */
gbuf.length = buf.len;
gbuf.value = buf.data;
ereport(DEBUG4,
(errmsg_internal("Processing received GSS token of length: %u",
gbuf.length)));
maj_stat = gss_accept_sec_context(
&min_stat,
&port->gss->ctx,
port->gss->cred,
&gbuf,
GSS_C_NO_CHANNEL_BINDINGS,
&port->gss->name,
NULL,
&port->gss->outbuf,
&gflags,
NULL,
NULL);
/* gbuf no longer used */
pfree(buf.data);
ereport(DEBUG5,
(errmsg_internal("gss_accept_sec_context major: %i, "
"minor: %i, outlen: %u, outflags: %x",
maj_stat, min_stat,
port->gss->outbuf.length, gflags)));
if (port->gss->outbuf.length != 0)
{
/*
* Negotiation generated data to be sent to the client.
*/
ereport(DEBUG4,
(errmsg_internal("sending GSS response token of length %u",
port->gss->outbuf.length)));
sendAuthRequest(port, AUTH_REQ_GSS_CONT);
}
if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED)
{
OM_uint32 lmin_s;
gss_delete_sec_context(&lmin_s, &port->gss->ctx, GSS_C_NO_BUFFER);
pg_GSS_error(ERROR,
gettext_noop("accepting GSS security context failed"),
maj_stat, min_stat);
}
if (maj_stat == GSS_S_CONTINUE_NEEDED)
ereport(DEBUG4,
(errmsg_internal("GSS continue needed")));
} while (maj_stat == GSS_S_CONTINUE_NEEDED);
if (port->gss->cred != GSS_C_NO_CREDENTIAL)
{
/*
* Release service principal credentials
*/
gss_release_cred(&min_stat, port->gss->cred);
}
/*
* GSS_S_COMPLETE indicates that authentication is now complete.
*
* Get the name of the user that authenticated, and compare it to the
* pg username that was specified for the connection.
*/
maj_stat = gss_display_name(&min_stat, port->gss->name, &gbuf, NULL);
ereport(DEBUG1,
(errmsg("GSSAPI authenticated name: %s", (char *)gbuf.value)));
/*
* Compare the part of the username that comes before the @
* sign only (ignore realm). The GSSAPI libraries won't have
* authenticated the user if he's from an invalid realm.
*/
if (strchr(gbuf.value, '@'))
{
char *cp = strchr(gbuf.value, '@');
*cp = '\0';
}
if (pg_krb_caseins_users)
ret = pg_strcasecmp(port->user_name, gbuf.value);
else
ret = strcmp(port->user_name, gbuf.value);
if (ret)
/* GSS name and PGUSER are not equivalent */
ereport(ERROR,
(errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
errmsg("provided username and GSSAPI username don't match"),
errdetail("provided: %s, GSSAPI: %s",
port->user_name, (char *)gbuf.value)));
gss_release_buffer(&lmin_s, &gbuf);
return STATUS_OK;
}
#else /* no ENABLE_GSS */
static int
pg_GSS_recvauth(Port *port)
{
ereport(LOG,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("GSSAPI not implemented on this server.")));
return STATUS_ERROR;
}
#endif /* ENABLE_GSS */
/*
* Tell the user the authentication failed, but not (much about) why.
......@@ -334,6 +579,9 @@ auth_failed(Port *port, int status)
case uaKrb5:
errstr = gettext_noop("Kerberos 5 authentication failed for user \"%s\"");
break;
case uaGSS:
errstr = gettext_noop("GSSAPI authentication failed for user \"%s\"");
break;
case uaTrust:
errstr = gettext_noop("\"trust\" authentication failed for user \"%s\"");
break;
......@@ -429,6 +677,11 @@ ClientAuthentication(Port *port)
status = pg_krb5_recvauth(port);
break;
case uaGSS:
sendAuthRequest(port, AUTH_REQ_GSS);
status = pg_GSS_recvauth(port);
break;
case uaIdent:
/*
......@@ -518,6 +771,24 @@ sendAuthRequest(Port *port, AuthRequest areq)
else if (areq == AUTH_REQ_CRYPT)
pq_sendbytes(&buf, port->cryptSalt, 2);
#ifdef ENABLE_GSS
/* Add the authentication data for the next step of
* the GSSAPI negotiation. */
else if (areq == AUTH_REQ_GSS_CONT)
{
if (port->gss->outbuf.length > 0)
{
OM_uint32 lmin_s;
ereport(DEBUG4,
(errmsg_internal("sending GSS token of length %u",
port->gss->outbuf.length)));
pq_sendbytes(&buf, port->gss->outbuf.value, port->gss->outbuf.length);
gss_release_buffer(&lmin_s, &port->gss->outbuf);
}
}
#endif
pq_endmessage(&buf);
/*
......
......@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/libpq/hba.c,v 1.160 2007/02/10 14:58:54 petere Exp $
* $PostgreSQL: pgsql/src/backend/libpq/hba.c,v 1.161 2007/07/10 13:14:20 mha Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -602,6 +602,8 @@ parse_hba_auth(ListCell **line_item, UserAuth *userauth_p,
*userauth_p = uaPassword;
else if (strcmp(token, "krb5") == 0)
*userauth_p = uaKrb5;
else if (strcmp(token, "gss") == 0)
*userauth_p = uaGSS;
else if (strcmp(token, "reject") == 0)
*userauth_p = uaReject;
else if (strcmp(token, "md5") == 0)
......
......@@ -34,7 +34,7 @@
# the number of significant bits in the mask. Alternatively, you can write
# an IP address and netmask in separate columns to specify the set of hosts.
#
# METHOD can be "trust", "reject", "md5", "crypt", "password",
# METHOD can be "trust", "reject", "md5", "crypt", "password", "gss",
# "krb5", "ident", "pam" or "ldap". Note that "password" sends passwords
# in clear text; "md5" is preferred since it sends encrypted passwords.
#
......
......@@ -30,7 +30,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/backend/libpq/pqcomm.c,v 1.192 2007/06/04 11:59:20 mha Exp $
* $PostgreSQL: pgsql/src/backend/libpq/pqcomm.c,v 1.193 2007/07/10 13:14:20 mha Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -173,6 +173,16 @@ pq_close(int code, Datum arg)
{
if (MyProcPort != NULL)
{
#ifdef ENABLE_GSS
OM_uint32 min_s;
/* Shutdown GSSAPI layer */
if (MyProcPort->gss->ctx)
gss_delete_sec_context(&min_s, MyProcPort->gss->ctx, NULL);
if (MyProcPort->gss->cred)
gss_release_cred(&min_s, MyProcPort->gss->cred);
#endif
/* Cleanly shut down SSL layer */
secure_close(MyProcPort);
......
......@@ -37,7 +37,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.530 2007/07/01 18:28:41 tgl Exp $
* $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.531 2007/07/10 13:14:21 mha Exp $
*
* NOTES
*
......@@ -1727,6 +1727,13 @@ ConnCreate(int serverFd)
RandomSalt(port->cryptSalt, port->md5Salt);
}
/*
* Allocate GSSAPI specific state struct
*/
#ifdef ENABLE_GSS
port->gss = (pg_gssinfo *)calloc(1, sizeof(pg_gssinfo));
#endif
return port;
}
......@@ -1740,6 +1747,8 @@ ConnFree(Port *conn)
#ifdef USE_SSL
secure_close(conn);
#endif
if (conn->gss)
free(conn->gss);
free(conn);
}
......
......@@ -10,7 +10,7 @@
* Written by Peter Eisentraut <peter_e@gmx.net>.
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.404 2007/06/30 19:12:02 tgl Exp $
* $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.405 2007/07/10 13:14:21 mha Exp $
*
*--------------------------------------------------------------------
*/
......@@ -1040,7 +1040,7 @@ static struct config_bool ConfigureNamesBool[] =
{
{"krb_caseins_users", PGC_POSTMASTER, CONN_AUTH_SECURITY,
gettext_noop("Sets whether Kerberos user names should be treated as case-insensitive."),
gettext_noop("Sets whether Kerberos and GSSAPI user names should be treated as case-insensitive."),
NULL
},
&pg_krb_caseins_users,
......
......@@ -79,11 +79,11 @@
#password_encryption = on
#db_user_namespace = off
# Kerberos
# Kerberos and GSSAPI
#krb_server_keyfile = '' # (change requires restart)
#krb_srvname = 'postgres' # (change requires restart)
#krb_srvname = 'postgres' # (change requires restart, kerberos only)
#krb_server_hostname = '' # empty string matches any keytab entry
# (change requires restart)
# (change requires restart, kerberos only)
#krb_caseins_users = off # (change requires restart)
# - TCP Keepalives -
......
......@@ -4,7 +4,7 @@
* Interface to hba.c
*
*
* $PostgreSQL: pgsql/src/include/libpq/hba.h,v 1.45 2006/11/05 22:42:10 tgl Exp $
* $PostgreSQL: pgsql/src/include/libpq/hba.h,v 1.46 2007/07/10 13:14:21 mha Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -22,7 +22,8 @@ typedef enum UserAuth
uaIdent,
uaPassword,
uaCrypt,
uaMD5
uaMD5,
uaGSS
#ifdef USE_PAM
,uaPAM
#endif /* USE_PAM */
......
......@@ -11,7 +11,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/libpq/libpq-be.h,v 1.58 2007/01/05 22:19:55 momjian Exp $
* $PostgreSQL: pgsql/src/include/libpq/libpq-be.h,v 1.59 2007/07/10 13:14:21 mha Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -29,6 +29,10 @@
#include <netinet/tcp.h>
#endif
#ifdef ENABLE_GSS
#include <gssapi/gssapi.h>
#endif
#include "libpq/hba.h"
#include "libpq/pqcomm.h"
#include "utils/timestamp.h"
......@@ -39,6 +43,20 @@ typedef enum CAC_state
CAC_OK, CAC_STARTUP, CAC_SHUTDOWN, CAC_RECOVERY, CAC_TOOMANY
} CAC_state;
/*
* GSSAPI specific state information
*/
#ifdef ENABLE_GSS
typedef struct
{
gss_cred_id_t cred; /* GSSAPI connection cred's */
gss_ctx_id_t ctx; /* GSSAPI connection context */
gss_name_t name; /* GSSAPI client name */
gss_buffer_desc outbuf; /* GSSAPI output token buffer */
} pg_gssinfo;
#endif
/*
* This is used by the postmaster in its communication with frontends. It
* contains all state information needed during this communication before the
......@@ -98,6 +116,17 @@ typedef struct Port
int keepalives_interval;
int keepalives_count;
#ifdef ENABLE_GSS
/*
* If GSSAPI is supported, store GSSAPI information.
* Oterwise, store a NULL pointer to make sure offsets
* in the struct remain the same.
*/
pg_gssinfo *gss;
#else
void *gss;
#endif
/*
* SSL structures (keep these last so that USE_SSL doesn't affect
* locations of other fields)
......
......@@ -9,7 +9,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/libpq/pqcomm.h,v 1.104 2007/07/08 18:28:55 tgl Exp $
* $PostgreSQL: pgsql/src/include/libpq/pqcomm.h,v 1.105 2007/07/10 13:14:21 mha Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -156,6 +156,8 @@ extern bool Db_user_namespace;
#define AUTH_REQ_CRYPT 4 /* crypt password */
#define AUTH_REQ_MD5 5 /* md5 password */
#define AUTH_REQ_SCM_CREDS 6 /* transfer SCM credentials */
#define AUTH_REQ_GSS 7 /* GSSAPI without wrap() */
#define AUTH_REQ_GSS_CONT 8 /* Continue GSS exchanges */
typedef uint32 AuthRequest;
......
......@@ -568,6 +568,9 @@
/* Define to the appropriate snprintf format for 64-bit ints, if any. */
#undef INT64_FORMAT
/* Define to build with GSSAPI support. (--with-gssapi) */
#undef ENABLE_GSS
/* Define to build with Kerberos 5 support. (--with-krb5) */
#undef KRB5
......
......@@ -5,7 +5,7 @@
# Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
# Portions Copyright (c) 1994, Regents of the University of California
#
# $PostgreSQL: pgsql/src/interfaces/libpq/Makefile,v 1.154 2007/01/07 08:49:31 petere Exp $
# $PostgreSQL: pgsql/src/interfaces/libpq/Makefile,v 1.155 2007/07/10 13:14:21 mha Exp $
#
#-------------------------------------------------------------------------
......@@ -57,9 +57,9 @@ endif
# shared library link. (The order in which you list them here doesn't
# matter.)
ifneq ($(PORTNAME), win32)
SHLIB_LINK += $(filter -lcrypt -ldes -lcom_err -lcrypto -lk5crypto -lkrb5 -lssl -lsocket -lnsl -lresolv -lintl, $(LIBS)) $(LDAP_LIBS_FE) $(PTHREAD_LIBS)
SHLIB_LINK += $(filter -lcrypt -ldes -lcom_err -lcrypto -lk5crypto -lkrb5 -lgssapi_krb5 -lssl -lsocket -lnsl -lresolv -lintl, $(LIBS)) $(LDAP_LIBS_FE) $(PTHREAD_LIBS)
else
SHLIB_LINK += $(filter -lcrypt -ldes -lcom_err -lcrypto -lk5crypto -lkrb5 -lssl -lsocket -lnsl -lresolv -lintl $(PTHREAD_LIBS), $(LIBS)) $(LDAP_LIBS_FE)
SHLIB_LINK += $(filter -lcrypt -ldes -lcom_err -lcrypto -lk5crypto -lkrb5 -lgssapi32 -lssl -lsocket -lnsl -lresolv -lintl $(PTHREAD_LIBS), $(LIBS)) $(LDAP_LIBS_FE)
endif
ifeq ($(PORTNAME), win32)
SHLIB_LINK += -lshfolder -lwsock32 -lws2_32 $(filter -leay32 -lssleay32 -lcomerr32 -lkrb5_32, $(LIBS))
......
......@@ -10,7 +10,7 @@
* exceed INITIAL_EXPBUFFER_SIZE (currently 256 bytes).
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-auth.c,v 1.123 2007/02/10 14:58:55 petere Exp $
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-auth.c,v 1.124 2007/07/10 13:14:21 mha Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -313,6 +313,182 @@ pg_krb5_sendauth(char *PQerrormsg, int sock, const char *hostname, const char *s
}
#endif /* KRB5 */
#ifdef ENABLE_GSS
/*
* GSSAPI authentication system.
*/
#include <gssapi/gssapi.h>
#ifdef WIN32
/*
* MIT Kerberos GSSAPI DLL doesn't properly export the symbols
* 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 that fit into a buffer
* and append them.
*/
static void
pg_GSS_error_int(char *mprefix, char *msg, int msglen,
OM_uint32 stat, int type)
{
int curlen = 0;
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);
if (curlen < msglen)
{
snprintf(msg + curlen, msglen - curlen, "%s: %s\n",
mprefix, (char *)lmsg.value);
curlen += lmsg.length;
}
gss_release_buffer(&lmin_s, &lmsg);
} while (msg_ctx);
}
/*
* GSSAPI errors contains two parts. Put as much as possible of
* both parts into the string.
*/
void
pg_GSS_error(char *mprefix, char *msg, int msglen,
OM_uint32 maj_stat, OM_uint32 min_stat)
{
int mlen;
/* Fetch major error codes */
pg_GSS_error_int(mprefix, msg, msglen, maj_stat, GSS_C_GSS_CODE);
mlen = strlen(msg);
/* If there is room left, try to add the minor codes as well */
if (mlen < msglen-1)
pg_GSS_error_int(mprefix, msg + mlen, msglen - mlen,
min_stat, GSS_C_MECH_CODE);
}
/*
* Continue GSS authentication with next token as needed.
*/
static int
pg_GSS_continue(char *PQerrormsg, PGconn *conn)
{
OM_uint32 maj_stat, min_stat, lmin_s;
maj_stat = gss_init_sec_context(&min_stat,
GSS_C_NO_CREDENTIAL,
&conn->gctx,
conn->gtarg_nam,
GSS_C_NO_OID,
conn->gflags,
0,
GSS_C_NO_CHANNEL_BINDINGS,
(conn->gctx==GSS_C_NO_CONTEXT)?GSS_C_NO_BUFFER:&conn->ginbuf,
NULL,
&conn->goutbuf,
NULL,
NULL);
if (conn->gctx != GSS_C_NO_CONTEXT)
{
free(conn->ginbuf.value);
conn->ginbuf.value = NULL;
conn->ginbuf.length = 0;
}
if (conn->goutbuf.length != 0)
{
/*
* 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.
*/
if (pqPacketSend(conn, 'p',
conn->goutbuf.value, conn->goutbuf.length)
!= STATUS_OK)
{
gss_release_buffer(&lmin_s, &conn->goutbuf);
return STATUS_ERROR;
}
}
gss_release_buffer(&lmin_s, &conn->goutbuf);
if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED)
{
pg_GSS_error(libpq_gettext("GSSAPI continuation error"),
PQerrormsg, PQERRORMSG_LENGTH,
maj_stat, min_stat);
gss_release_name(&lmin_s, &conn->gtarg_nam);
if (conn->gctx)
gss_delete_sec_context(&lmin_s, &conn->gctx, GSS_C_NO_BUFFER);
return STATUS_ERROR;
}
if (maj_stat == GSS_S_COMPLETE)
gss_release_name(&lmin_s, &conn->gtarg_nam);
return STATUS_OK;
}
/*
* Send initial GSS authentication token
*/
static int
pg_GSS_startup(char *PQerrormsg, PGconn *conn)
{
OM_uint32 maj_stat, min_stat;
int maxlen;
gss_buffer_desc temp_gbuf;
if (conn->gctx)
{
snprintf(PQerrormsg, PQERRORMSG_LENGTH,
libpq_gettext("duplicate GSS auth request\n"));
return STATUS_ERROR;
}
/*
* Import service principal name so the proper ticket can be
* acquired by the GSSAPI system.
*/
maxlen = NI_MAXHOST + strlen(conn->krbsrvname) + 2;
temp_gbuf.value = (char*)malloc(maxlen);
snprintf(temp_gbuf.value, maxlen, "%s@%s",
conn->krbsrvname, conn->pghost);
temp_gbuf.length = strlen(temp_gbuf.value);
maj_stat = gss_import_name(&min_stat, &temp_gbuf,
GSS_C_NT_HOSTBASED_SERVICE, &conn->gtarg_nam);
free(temp_gbuf.value);
if (maj_stat != GSS_S_COMPLETE)
{
pg_GSS_error(libpq_gettext("GSSAPI name import error"),
PQerrormsg, PQERRORMSG_LENGTH,
maj_stat, min_stat);
return STATUS_ERROR;
}
/*
* Initial packet is the same as a continuation packet with
* no initial context.
*/
conn->gctx = GSS_C_NO_CONTEXT;
return pg_GSS_continue(PQerrormsg, conn);
}
#endif
/*
* Respond to AUTH_REQ_SCM_CREDS challenge.
......@@ -479,6 +655,37 @@ pg_fe_sendauth(AuthRequest areq, PGconn *conn, const char *hostname,
return STATUS_ERROR;
#endif
#ifdef ENABLE_GSS
case AUTH_REQ_GSS:
pglock_thread();
if (pg_GSS_startup(PQerrormsg, conn) != STATUS_OK)
{
/* PQerrormsg already filled in. */
pgunlock_thread();
return STATUS_ERROR;
}
pgunlock_thread();
break;
case AUTH_REQ_GSS_CONT:
pglock_thread();
if (pg_GSS_continue(PQerrormsg, conn) != STATUS_OK)
{
/* PQerrormsg already filled in. */
pgunlock_thread();
return STATUS_ERROR;
}
pgunlock_thread();
break;
#else
case AUTH_REQ_GSS:
case AUTH_REQ_GSS_CONT:
snprintf(PQerrormsg, PQERRORMSG_LENGTH,
libpq_gettext("GSSAPI authentication not supported\n"));
return STATUS_ERROR;
#endif
case AUTH_REQ_MD5:
case AUTH_REQ_CRYPT:
case AUTH_REQ_PASSWORD:
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-connect.c,v 1.347 2007/07/08 18:28:55 tgl Exp $
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-connect.c,v 1.348 2007/07/10 13:14:21 mha Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -181,8 +181,8 @@ static const PQconninfoOption PQconninfoOptions[] = {
{"sslmode", "PGSSLMODE", DefaultSSLMode, NULL,
"SSL-Mode", "", 8}, /* sizeof("disable") == 8 */
#ifdef KRB5
/* Kerberos authentication supports specifying the service name */
#if defined(KRB5) || defined(ENABLE_GSS)
/* Kerberos and GSSAPI authentication support specifying the service name */
{"krbsrvname", "PGKRBSRVNAME", PG_KRB_SRVNAM, NULL,
"Kerberos-service-name", "", 20},
#endif
......@@ -412,7 +412,7 @@ connectOptions1(PGconn *conn, const char *conninfo)
conn->sslmode = strdup("require");
}
#endif
#ifdef KRB5
#if defined(KRB5) || defined(ENABLE_GSS)
tmp = conninfo_getval(connOptions, "krbsrvname");
conn->krbsrvname = tmp ? strdup(tmp) : NULL;
#endif
......@@ -1496,12 +1496,13 @@ keep_going: /* We will come back to here until there is
/*
* Try to validate message length before using it.
* Authentication requests can't be very large. Errors can be
* Authentication requests can't be very large, although GSS
* auth requests may not be that small. Errors can be
* a little larger, but not huge. If we see a large apparent
* length in an error, it means we're really talking to a
* pre-3.0-protocol server; cope.
*/
if (beresp == 'R' && (msgLength < 8 || msgLength > 100))
if (beresp == 'R' && (msgLength < 8 || msgLength > 2000))
{
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext(
......@@ -1660,6 +1661,43 @@ keep_going: /* We will come back to here until there is
return PGRES_POLLING_READING;
}
}
#ifdef ENABLE_GSS
/*
* AUTH_REQ_GSS provides no input data
* Just set the request flags
*/
if (areq == AUTH_REQ_GSS)
conn->gflags = GSS_C_MUTUAL_FLAG;
/*
* Read GSSAPI data packets
*/
if (areq == AUTH_REQ_GSS_CONT)
{
/* Continue GSSAPI authentication */
int llen = msgLength - 4;
/*
* We can be called repeatedly for the same buffer.
* Avoid re-allocating the buffer in this case -
* just re-use the old buffer.
*/
if (llen != conn->ginbuf.length)
{
if (conn->ginbuf.value)
free(conn->ginbuf.value);
conn->ginbuf.length = llen;
conn->ginbuf.value = malloc(llen);
}
if (pqGetnchar(conn->ginbuf.value, llen, conn))
{
/* We'll come back when there is more data. */
return PGRES_POLLING_READING;
}
}
#endif
/*
* OK, we successfully read the message; mark data consumed
......@@ -1957,7 +1995,7 @@ freePGconn(PGconn *conn)
free(conn->pgpass);
if (conn->sslmode)
free(conn->sslmode);
#ifdef KRB5
#if defined(KRB5) || defined(ENABLE_GSS)
if (conn->krbsrvname)
free(conn->krbsrvname);
#endif
......@@ -1973,6 +2011,19 @@ freePGconn(PGconn *conn)
notify = notify->next;
free(prev);
}
#ifdef ENABLE_GSS
{
OM_uint32 min_s;
if (conn->gctx)
gss_delete_sec_context(&min_s, &conn->gctx, GSS_C_NO_BUFFER);
if (conn->gtarg_nam)
gss_release_name(&min_s, &conn->gtarg_nam);
if (conn->ginbuf.length)
gss_release_buffer(&min_s, &conn->ginbuf);
if (conn->goutbuf.length)
gss_release_buffer(&min_s, &conn->goutbuf);
}
#endif
pstatus = conn->pstatus;
while (pstatus != NULL)
{
......
......@@ -12,7 +12,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/interfaces/libpq/libpq-int.h,v 1.121 2007/07/08 18:28:56 tgl Exp $
* $PostgreSQL: pgsql/src/interfaces/libpq/libpq-int.h,v 1.122 2007/07/10 13:14:22 mha Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -44,6 +44,10 @@
/* include stuff found in fe only */
#include "pqexpbuffer.h"
#ifdef ENABLE_GSS
#include <gssapi/gssapi.h>
#endif
#ifdef USE_SSL
#include <openssl/ssl.h>
#include <openssl/err.h>
......@@ -268,7 +272,7 @@ struct pg_conn
char *pguser; /* Postgres username and password, if any */
char *pgpass;
char *sslmode; /* SSL mode (require,prefer,allow,disable) */
#ifdef KRB5
#if defined(KRB5) || defined(ENABLE_GSS)
char *krbsrvname; /* Kerberos service name */
#endif
......@@ -350,6 +354,14 @@ struct pg_conn
char peer_cn[SM_USER + 1]; /* peer common name */
#endif
#ifdef ENABLE_GSS
gss_ctx_id_t gctx; /* GSS context */
gss_name_t gtarg_nam; /* GSS target name */
OM_uint32 gflags; /* GSS service request flags */
gss_buffer_desc ginbuf; /* GSS input token */
gss_buffer_desc goutbuf; /* GSS output token */
#endif
/* Buffer for current error message */
PQExpBufferData errorMessage; /* expansible string */
......@@ -399,6 +411,11 @@ extern pgthreadlock_t pg_g_threadlock;
#define pgunlock_thread() ((void) 0)
#endif
/* === in fe-auth.c === */
#ifdef ENABLE_GSS
extern void pg_GSS_error(char *mprefix, char *msg, int msglen,
OM_uint32 maj_stat, OM_uint32 min_stat);
#endif
/* === in fe-exec.c === */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment