[Date Prev] [Date Index] [Date Next] [Thread Prev] [Thread Index] [Thread Next]
Nathan Straz nstraz@redhat.com
Thu, 21 Feb 2008 12:11:32 -0800 (PST)
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
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..b8c3c06 100644 --- a/conserver/group.c +++ b/conserver/group.c @@ -1869,6 +1869,65 @@ 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 0; + } + 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: + do { + 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); + } while (mctx && dbuf.length); + ret = -1; + } + return ret; +} +#endif + CONSENT * #if PROTOTYPES HuntForConsole(GRPENT *pGE, char *name) @@ -2945,6 +3004,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 +3053,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 +3096,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 +3338,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 +4723,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..d9be01f 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,83 @@ 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) { + do { + gss_display_status(&dmin, stmaj, GSS_C_GSS_CODE, GSS_C_NULL_OID, &mctx, &dbuf); + Error("init sec context failed: %*s", dbuf.length, dbuf.value); + } while (mctx && dbuf.length); + 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 +351,9 @@ Version() #if HAVE_OPENSSL "openssl", #endif +#if HAVE_GSSAPI + "gssapi", +#endif #if HAVE_PAM "pam", #endif @@ -1522,6 +1605,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 +1685,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 +1748,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