Mailing List Archive

[PATCH] GSS-API Authentication support
Here is a patch that I'm working on. It's not complete, but it works.

What works:
- authentication against "host" principals.
- built w/o openssl
What hasn't been tested
- built w/ openssl
Still to do:
- Switch to using "console" principals.
- I'm using a sleep in conserver to wait for the token from console. I
think I should add a new I/O mode and switch to that.
- the user logged in turns to "user@REALM@peername" which may have some
side effects.

Give it a shot in a test environment and let me know if you run into any
problems.

Nate Straz
Re: [PATCH] GSS-API Authentication support [ In reply to ]
On Feb 7 14:36, Nathan Straz wrote:
> Here is a patch that I'm working on. It's not complete, but it works.

I'm a little closer to complete now. Here is v2 of the patch.

> What works:
> - authentication against "host" principals.
> - built w/o openssl
> What hasn't been tested
> - built w/ openssl

I did build and test with openssl. It Just Works(tm).

> Still to do:
> - Switch to using "console" principals.

I haven't done this yet.

> - I'm using a sleep in conserver to wait for the token from console. I
> think I should add a new I/O mode and switch to that.

I finished this and it was a lot easier than when I first looked at it.
The trick was to just switch to the new ioState instead of trying to
accept the GSS-API token first.

> - the user logged in turns to "user@REALM@peername" which may have some
> side effects.

I did some investigation on the side effects with this. When specifying
admin users, I needed to specify user@REALM instead of just user. I
don't know if anyone deploys conserver in a multi-realm environment, but
I don't think it would be a good idea to strip off @REALM just in case
someone wants to.

> Give it a shot in a test environment and let me know if you run into any
> problems.

Please do,

Nate Straz
Re: [PATCH] GSS-API Authentication support [ In reply to ]
On Feb 21 15:11, Nathan Straz wrote:
> On Feb 7 14:36, Nathan Straz wrote:
> > Here is a patch that I'm working on. It's not complete, but it works.
>
> I'm a little closer to complete now. Here is v2 of the patch.

Here is the latest version of the patch. I am now using this version in
production.

> > Still to do:
> > - Switch to using "console" principals.

I decided not to do this yet. It will be an easy change if anyone wants
to use something other than "host" service principal names.

Nate

diff --git a/config.h.in b/config.h.in
index 1c3095c..a698b6b 100644
--- a/config.h.in
+++ b/config.h.in
@@ -75,6 +75,9 @@
/* Define to 1 if you have the `grantpt' function. */
#undef HAVE_GRANTPT

+/* have gss-api support */
+#undef HAVE_GSSAPI
+
/* Define to 1 if you have the <hpsecurity.h> header file. */
#undef HAVE_HPSECURITY_H

diff --git a/configure b/configure
index 8f58bda..fb2bf67 100755
--- a/configure
+++ b/configure
@@ -868,6 +868,8 @@ Optional Packages:
Compile in libwrap (tcp_wrappers) support
--with-openssl[=PATH]
Compile in OpenSSL support
+ --with-gssapi[=PATH]
+ Compile in GSS-API support
--with-dmalloc[=PATH]
Compile in dmalloc support
--with-pam Enable PAM support
@@ -6092,6 +6094,242 @@ fi

fi;

+cons_with_gssapi="NO"
+
+# Check whether --with-gssapi or --without-gssapi was given.
+if test "${with_gssapi+set}" = set; then
+ withval="$with_gssapi"
+ if test "$withval" != "no"; then
+ if test "$withval" != "yes"; then
+ GSSAPICPPFLAGS="-I$withval/include"
+ if test "$use_dash_r" != "yes"; then
+ GSSAPILDFLAGS="-L$withval/lib"
+ else
+ GSSAPILDFLAGS="-L$withval/lib -R$withval/lib"
+ fi
+ else
+ GSSAPICPPFLAGS=""
+ GSSAPILDFLAGS=""
+ fi
+
+ oCPPFLAGS="$CPPFLAGS"
+ oLDFLAGS="$LDFLAGS"
+ oLIBS="$LIBS"
+ have_gssapi=no
+
+ CPPFLAGS="$CPPFLAGS $GSSAPICPPFLAGS"
+ LDFLAGS="$LDFLAGS $GSSAPILDFLAGS"
+
+ 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 the AC_PACKAGE_NAME lists. ##
+## ------------------------------------------ ##
+_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
+ LIBS="$LIBS -lgssapi"
+ echo "$as_me:$LINENO: checking for gssapi library -lgssapi" >&5
+echo $ECHO_N "checking for gssapi library -lgssapi... $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>
+
+int
+main ()
+{
+gss_create_empty_oid_set(NULL, NULL)
+ ;
+ 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
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ cons_with_gssapi="YES"
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_GSSAPI 1
+_ACEOF
+
+ have_gssapi=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+
+
+
+ if test $have_gssapi = no; then
+ LIBS="$oLIBS"
+ CPPFLAGS="$oCPPFLAGS"
+ LDFLAGS="$oLDFLAGS"
+ fi
+ fi
+
+fi;
+
+
cons_with_dmalloc="NO"

# Check whether --with-dmalloc or --without-dmalloc was given.
@@ -8844,6 +9082,7 @@ echo ""
echo " Unix domain sockets (--with-uds) : $cons_with_uds"
echo " TCP wrappers (--with-libwrap): $cons_with_libwrap"
echo " OpenSSL (--with-openssl): $cons_with_openssl"
+echo " GSS-API (--with-gssapi) : $cons_with_gssapi"
echo " dmalloc (--with-dmalloc): $cons_with_dmalloc"
echo " PAM support (--with-pam) : $cons_with_pam"
echo ""
diff --git a/configure.in b/configure.in
index 8bd2620..c845c7e 100644
--- a/configure.in
+++ b/configure.in
@@ -14,6 +14,7 @@ AH_TEMPLATE([USE_LIBWRAP], [use tcp_wrappers libwrap])
dnl AH_TEMPLATE([HAVE_POSIX_REGCOMP], [have POSIX regcomp])
AH_TEMPLATE([HAVE_PAM], [have PAM support])
AH_TEMPLATE([HAVE_OPENSSL], [have openssl support])
+AH_TEMPLATE([HAVE_GSSAPI], [have gss-api support])
AH_TEMPLATE([HAVE_DMALLOC], [have dmalloc support])
AH_TEMPLATE([HAVE_SA_LEN],[Defined if sa_len member exists in struct sockaddr])
AH_TEMPLATE([TRUST_REVERSE_DNS],[Defined if we trust reverse DNS])
@@ -499,6 +500,51 @@ AC_ARG_WITH(openssl,
fi]
)

+cons_with_gssapi="NO"
+AC_ARG_WITH(gssapi,
+ AS_HELP_STRING([--with-gssapi@<:@=PATH@:>@],
+ [Compile in GSS-API support]),
+ [.if test "$withval" != "no"; then
+ if test "$withval" != "yes"; then
+ GSSAPICPPFLAGS="-I$withval/include"
+ if test "$use_dash_r" != "yes"; then
+ GSSAPILDFLAGS="-L$withval/lib"
+ else
+ GSSAPILDFLAGS="-L$withval/lib -R$withval/lib"
+ fi
+ else
+ GSSAPICPPFLAGS=""
+ GSSAPILDFLAGS=""
+ fi
+
+ oCPPFLAGS="$CPPFLAGS"
+ oLDFLAGS="$LDFLAGS"
+ oLIBS="$LIBS"
+ have_gssapi=no
+
+ CPPFLAGS="$CPPFLAGS $GSSAPICPPFLAGS"
+ LDFLAGS="$LDFLAGS $GSSAPILDFLAGS"
+
+ AC_CHECK_HEADER([gssapi/gssapi.h],
+ [.LIBS="$LIBS -lgssapi"
+ AC_MSG_CHECKING(for gssapi library -lgssapi)
+ AC_TRY_LINK([#include <gssapi/gssapi.h>
+ ],[gss_create_empty_oid_set(NULL, NULL)],
+ [AC_MSG_RESULT(yes)
+ cons_with_gssapi="YES"
+ AC_DEFINE(HAVE_GSSAPI)
+ have_gssapi=yes],
+ [AC_MSG_RESULT(no)])],)
+
+ if test $have_gssapi = no; then
+ LIBS="$oLIBS"
+ CPPFLAGS="$oCPPFLAGS"
+ LDFLAGS="$oLDFLAGS"
+ fi
+ fi]
+)
+
+
cons_with_dmalloc="NO"
AC_ARG_WITH(dmalloc,
AS_HELP_STRING([--with-dmalloc@<:@=PATH@:>@],
@@ -657,6 +703,7 @@ echo ""
echo " Unix domain sockets (--with-uds) : $cons_with_uds"
echo " TCP wrappers (--with-libwrap): $cons_with_libwrap"
echo " OpenSSL (--with-openssl): $cons_with_openssl"
+echo " GSS-API (--with-gssapi) : $cons_with_gssapi"
echo " dmalloc (--with-dmalloc): $cons_with_dmalloc"
echo " PAM support (--with-pam) : $cons_with_pam"
echo ""
diff --git a/conserver/cutil.h b/conserver/cutil.h
index a9b579a..da1a5ae 100644
--- a/conserver/cutil.h
+++ b/conserver/cutil.h
@@ -15,6 +15,9 @@
#include <openssl/ssl.h>
#include <openssl/err.h>
#endif
+#if HAVE_GSSAPI
+#include <gssapi/gssapi.h>
+#endif

/* communication constants
*/
@@ -46,6 +49,9 @@ typedef enum IOState {
INSSLACCEPT,
INSSLSHUTDOWN,
#endif
+#if HAVE_GSSAPI
+ INGSSACCEPT,
+#endif
ISFLUSHING
} IOSTATE;

diff --git a/conserver/group.c b/conserver/group.c
index ea6bd76..9f28135 100644
--- a/conserver/group.c
+++ b/conserver/group.c
@@ -1869,6 +1869,63 @@ AttemptSSL(pCL)
}
#endif

+#if HAVE_GSSAPI
+int
+#if PROTOTYPES
+AttemptGSSAPI(CONSCLIENT *pCL)
+#else
+AttemptGSSAPI(pCL)
+ CONSCLIENT *pCL;
+#endif
+{
+ int nr, ret = 0;
+ char buf[1024];
+ gss_buffer_desc sendtok, recvtok, dbuf;
+ gss_ctx_id_t gssctx = GSS_C_NO_CONTEXT;
+ OM_uint32 stmaj, stmin, mctx, dmin;
+ gss_name_t user = 0;
+
+ if ((nr = FileRead(pCL->fd, buf, sizeof(buf))) <= 0) {
+ return nr;
+ }
+ recvtok.value = buf;
+ recvtok.length = nr;
+
+ stmaj = gss_accept_sec_context(&stmin, &gssctx, gss_mycreds,
+ &recvtok, NULL, &user, NULL, &sendtok, NULL, NULL, NULL);
+ switch (stmaj) {
+ case GSS_S_COMPLETE:
+ FileSetQuoteIAC(pCL->fd, FLAGFALSE);
+ FileWrite(pCL->fd, FLAGFALSE, sendtok.value, sendtok.length);
+ FileSetQuoteIAC(pCL->fd, FLAGTRUE);
+ pCL->iState = S_NORMAL;
+ gss_release_buffer(NULL, &sendtok);
+ BuildString((char *)0, pCL->username);
+ BuildString((char *)0, pCL->acid);
+ stmaj = gss_display_name(&stmin, user, &dbuf, NULL);
+
+ BuildStringN(dbuf.value, dbuf.length, pCL->username);
+ BuildStringN(dbuf.value, dbuf.length, pCL->acid);
+ BuildStringChar('@', pCL->acid);
+ BuildString(pCL->peername->string,
+ pCL->acid);
+ gss_release_name(&stmin, &user);
+ gss_release_buffer(NULL, &dbuf);
+ ret = 1;
+ break;
+ case GSS_S_CREDENTIALS_EXPIRED:
+ /* reacquire creds and try again */
+ Error("Credentials expired");
+ break;
+ default:
+ gss_display_status(&dmin, stmaj, GSS_C_GSS_CODE, GSS_C_NULL_OID, &mctx, &dbuf);
+ Error("GSSAPI didn't work, %*s", dbuf.length, dbuf.value);
+ ret = -1;
+ }
+ return ret;
+}
+#endif
+
CONSENT *
#if PROTOTYPES
HuntForConsole(GRPENT *pGE, char *name)
@@ -2945,6 +3002,7 @@ DoClientRead(pGE, pCLServing)
static char *pcArgs;
static char *pcCmd;

+ CONDDEBUG((1, "state = %d", pCLServing->iState));
if ('\n' != acIn[i]) {
BuildStringChar(acIn[i], pCLServing->accmd);
continue;
@@ -2993,6 +3051,9 @@ DoClientRead(pGE, pCLServing)
#if HAVE_OPENSSL
"ssl start ssl session\r\n",
#endif
+#if HAVE_GSSAPI
+ "gssapi log in with gssapi\r\n",
+#endif
(char *)0
};
static char *apcHelp2[] = {
@@ -3033,6 +3094,14 @@ DoClientRead(pGE, pCLServing)
return;
}
#endif
+#if HAVE_GSSAPI
+ } else if (pCLServing->iState == S_IDENT &&
+ strcmp(pcCmd, "gssapi") == 0) {
+ FileWrite(pCLServing->fd, FLAGFALSE, "ok\r\n", -1);
+ /* Change the I/O mode right away, we'll do the read
+ * and accept when the select gets back to us */
+ pCLServing->ioState = INGSSACCEPT;
+#endif
} else if (pCLServing->iState == S_IDENT &&
strcmp(pcCmd, "login") == 0) {
#if HAVE_OPENSSL
@@ -3267,6 +3336,7 @@ DoClientRead(pGE, pCLServing)
} else {
FileWrite(pCLServing->fd, FLAGFALSE,
"unknown command\r\n", -1);
+ CONDDEBUG((1, "command %s state %d", pcCmd, pCLServing->iState));
}
BuildString((char *)0, pCLServing->accmd);
} else
@@ -4651,6 +4721,16 @@ Kiddie(pGE, sfd)
}
break;
#endif
+#if HAVE_GSSAPI
+ case INGSSACCEPT:
+ { int r;
+ if ((r = AttemptGSSAPI(pCLServing)) < 0)
+ DropMasterClient(pCLServing, FLAGFALSE);
+ else if (r == 1)
+ pCLServing->ioState = ISNORMAL;
+ }
+ break;
+#endif
case ISNORMAL:
if (FileCanRead(pCLServing->fd, &rmask, &wmask))
DoClientRead(pGE, pCLServing);
diff --git a/conserver/main.c b/conserver/main.c
index 38b66dd..24fbcbe 100644
--- a/conserver/main.c
+++ b/conserver/main.c
@@ -44,6 +44,9 @@
#if HAVE_OPENSSL
# include <openssl/opensslv.h>
#endif
+#if HAVE_GSSAPI
+# include <gssapi/gssapi.h>
+#endif


int fAll = 0, fNoinit = 0, fVersion = 0, fStrip = 0, fReopen =
@@ -378,6 +381,40 @@ SetupSSL()
}
#endif

+#if HAVE_GSSAPI
+gss_name_t gss_myname = GSS_C_NO_NAME;
+gss_cred_id_t gss_mycreds = GSS_C_NO_CREDENTIAL;
+
+void
+#if PROTOTYPES
+SetupGSSAPI(void)
+#else
+SetupGSSAPI()
+#endif
+{
+ OM_uint32 stmaj, stmin;
+ char namestr[128];
+ gss_buffer_desc namebuf;
+
+ snprintf(namestr, 128, "host@%s", myHostname);
+ namebuf.value = namestr;
+ namebuf.length = strlen(namestr) + 1;
+ stmaj = gss_import_name(&stmin, &namebuf, GSS_C_NT_HOSTBASED_SERVICE,
+ &gss_myname);
+ /* XXX: handle error */
+ if (stmaj != GSS_S_COMPLETE) {
+ Error("gss_import_name failed");
+ }
+ /* Get some initial credentials */
+ stmaj = gss_acquire_cred(&stmin, gss_myname, 0, GSS_C_NULL_OID_SET,
+ GSS_C_ACCEPT, &gss_mycreds, NULL, NULL);
+ if (stmaj != GSS_S_COMPLETE) {
+ Error("Could not acquire GSS-API credentials");
+ }
+
+}
+#endif
+
void
#if PROTOTYPES
ReopenLogfile(void)
@@ -1563,6 +1600,9 @@ main(argc, argv)
/* Prep the SSL layer */
SetupSSL();
#endif
+#if HAVE_GSSAPI
+ SetupGSSAPI();
+#endif

if (config->daemonmode == FLAGTRUE)
Daemonize();
diff --git a/conserver/main.h b/conserver/main.h
index 1b59a5a..aae8a10 100644
--- a/conserver/main.h
+++ b/conserver/main.h
@@ -54,6 +54,10 @@ extern char *interface;
#if HAVE_OPENSSL
extern SSL_CTX *ctx;
#endif
+#if HAVE_GSSAPI
+extern gss_name_t gss_myname;
+extern gss_cred_id_t gss_mycreds;
+#endif
extern void ReopenLogfile PARAMS((void));
extern void ReopenUnifiedlog PARAMS((void));
extern void DumpDataStructures PARAMS((void));
diff --git a/conserver/master.c b/conserver/master.c
index 36622cc..d406b19 100644
--- a/conserver/master.c
+++ b/conserver/master.c
@@ -494,6 +494,9 @@ DoNormalRead(pCLServing)
#if HAVE_OPENSSL
"ssl start ssl session\r\n",
#endif
+#if HAVE_GSSAPI
+ "gssapi log in with gssapi\r\n",
+#endif
(char *)0
};
static char *apcHelp2[] = {
@@ -532,6 +535,14 @@ DoNormalRead(pCLServing)
return;
}
#endif
+#if HAVE_GSSAPI
+ } else if (pCLServing->iState == S_IDENT &&
+ strcmp(pcCmd, "gssapi") == 0) {
+ FileWrite(pCLServing->fd, FLAGFALSE, "ok\r\n", -1);
+ /* Change the I/O mode right away, we'll do the read
+ * and accept when the select gets back to us */
+ pCLServing->ioState = INGSSACCEPT;
+#endif
} else if (pCLServing->iState == S_IDENT &&
strcmp(pcCmd, "login") == 0) {
#if HAVE_OPENSSL
@@ -921,6 +932,16 @@ Master()
}
break;
#endif
+#if HAVE_GSSAPI
+ case INGSSACCEPT:
+ { int r;
+ if ((r = AttemptGSSAPI(pCLServing)) < 0)
+ DropMasterClient(pCLServing, FLAGFALSE);
+ else if (r == 1)
+ pCLServing->ioState = ISNORMAL;
+ }
+ break;
+#endif
case ISNORMAL:
if (FileCanRead(pCLServing->fd, &rmask, &wmask))
DoNormalRead(pCLServing);
diff --git a/console/console.c b/console/console.c
index 4ec949b..fa0f00c 100644
--- a/console/console.c
+++ b/console/console.c
@@ -40,6 +40,9 @@
#include <openssl/err.h>
#include <openssl/opensslv.h>
#endif
+#if HAVE_GSSAPI
+#include <gssapi/gssapi.h>
+#endif


int fReplay = 0, fVersion = 0;
@@ -152,6 +155,80 @@ AttemptSSL(pcf)
}
#endif

+#if HAVE_GSSAPI
+gss_name_t gss_server_name = GSS_C_NO_NAME;
+gss_ctx_id_t secctx = GSS_C_NO_CONTEXT;
+gss_buffer_desc mytok = GSS_C_EMPTY_BUFFER;
+
+int
+#if PROTOTYPES
+CanGetGSSContext(const char *servername)
+#else
+CanGetGSSContext(servername)
+ const char *servername;
+#endif
+{
+ char namestr[128];
+ gss_buffer_desc namebuf, dbuf;
+ OM_uint32 stmaj, stmin, mctx, dmin;
+
+ snprintf(namestr, 128, "host@%s", servername);
+ namebuf.value = namestr;
+ namebuf.length = strlen(namestr) + 1;
+ stmaj = gss_import_name(&stmin, &namebuf, GSS_C_NT_HOSTBASED_SERVICE,
+ &gss_server_name);
+ /* XXX: handle error */
+ if (stmaj != GSS_S_COMPLETE) {
+ Error("gss_import_name failed");
+ return 0;
+ }
+ secctx = GSS_C_NO_CONTEXT;
+ mytok.length = 0; mytok.value = NULL;
+
+ stmaj = gss_init_sec_context(&stmin, GSS_C_NO_CREDENTIAL, &secctx,
+ gss_server_name, GSS_C_NULL_OID, GSS_C_MUTUAL_FLAG, 0,
+ GSS_C_NO_CHANNEL_BINDINGS, NULL, NULL,
+ &mytok, NULL, NULL);
+
+ if (stmaj != GSS_S_COMPLETE && stmaj != GSS_S_CONTINUE_NEEDED) {
+ gss_release_name(&stmin, &gss_server_name);
+ return 0;
+ }
+}
+
+int
+#if PROTOTYPES
+AttemptGSSAPI(CONSFILE *pcf)
+#else
+AttemptGSSAPI(pcf)
+ CONSFILE *pcf;
+#endif
+{
+ OM_uint32 stmaj, stmin;
+ gss_buffer_desc servertok;
+ char buf[1024];
+ int nr;
+ int ret;
+
+ FileSetQuoteIAC(pcf, FLAGFALSE);
+ FileWrite(pcf, FLAGFALSE, mytok.value, mytok.length);
+ FileSetQuoteIAC(pcf, FLAGTRUE);
+ nr = FileRead(pcf, buf, sizeof(buf));
+ servertok.length = nr;
+ servertok.value = buf;
+
+ stmaj = gss_init_sec_context(&stmin, GSS_C_NO_CREDENTIAL, &secctx,
+ gss_server_name, GSS_C_NULL_OID, GSS_C_MUTUAL_FLAG, 0,
+ GSS_C_NO_CHANNEL_BINDINGS, &servertok,
+ NULL, &mytok, NULL, NULL);
+ gss_release_buffer(NULL, &mytok);
+
+ ret = (stmaj == GSS_S_COMPLETE);
+ gss_release_name(&stmin, &gss_server_name);
+ return ret;
+}
+#endif
+
/* output a control (or plain) character as a UNIX user would expect it (ksb)
*/
static void
@@ -271,6 +348,9 @@ Version()
#if HAVE_OPENSSL
"openssl",
#endif
+#if HAVE_GSSAPI
+ "gssapi",
+#endif
#if HAVE_PAM
"pam",
#endif
@@ -1522,6 +1602,9 @@ DoCmds(master, pports, cmdi)
char *ports;
char *pcopy;
char *serverName;
+#if HAVE_GSSAPI
+ int toksize;
+#endif

if ((pcopy = ports = StrDup(pports)) == (char *)0)
OutOfMem();
@@ -1599,6 +1682,17 @@ DoCmds(master, pports, cmdi)
}
}
#endif
+#if HAVE_GSSAPI
+ if ((toksize = CanGetGSSContext(server)) > 0) {
+ FilePrint(pcf, FLAGFALSE, "gssapi %d\r\n", toksize);
+ t = ReadReply(pcf, FLAGFALSE);
+ if (strcmp(t, "ok\r\n") == 0) {
+ if (AttemptGSSAPI(pcf)) {
+ goto gssapi_logged_me_in;
+ }
+ }
+ }
+#endif

FilePrint(pcf, FLAGFALSE, "login %s\r\n", config->username);

@@ -1651,6 +1745,9 @@ DoCmds(master, pports, cmdi)
FilePrint(cfstdout, FLAGFALSE, "%s: %s", serverName, t);
continue;
}
+#if HAVE_GSSAPI
+gssapi_logged_me_in:
+#endif

/* now that we're logged in, we can do something */
/* if we're on the last cmd or the command is 'call' and we
_______________________________________________
users mailing list
users@conserver.com
https://www.conserver.com/mailman/listinfo/users