From 38ec987005c92d3f6106238fddc915b27d1639e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20R.=20Sede=C3=B1o?= Date: Sat, 6 Feb 2010 17:22:19 -0500 Subject: [PATCH 04/13] Move the unix GSSAPI implementation into common core Modifications to the unix build: * Remove compile-time linking to kerberos and gssapi * Add compile-time linking to libdl for dynamic library linking --- Recipe | 1 + mkfiles.pl | 13 --- ssh.c | 1 + sshgssc.c | 194 ++++++++++++++++++++++++++++++++++++++++++++++++ sshgssc.h | 13 +++ unix/configure.ac | 20 +++-- unix/unix.h | 12 +-- unix/uxgss.c | 214 ++++++---------------------------------------------- 8 files changed, 250 insertions(+), 218 deletions(-) create mode 100644 sshgssc.c create mode 100644 sshgssc.h diff --git a/Recipe b/Recipe index 81ac122..4c9b117 100644 --- a/Recipe +++ b/Recipe @@ -261,6 +261,7 @@ NONSSH = telnet raw rlogin ldisc pinger SSH = ssh sshcrc sshdes sshmd5 sshrsa sshrand sshsha sshblowf + sshdh sshcrcda sshpubk sshzlib sshdss x11fwd portfwd + sshaes sshsh256 sshsh512 sshbn wildcard pinger ssharcf + + sshgssc pgssapi WINSSH = SSH winnoise winpgntc wingss UXSSH = SSH uxnoise uxagentc uxgss MACSSH = SSH macnoise diff --git a/mkfiles.pl b/mkfiles.pl index 9466ffe..f249558 100755 --- a/mkfiles.pl +++ b/mkfiles.pl @@ -924,8 +924,6 @@ if (defined $makefiles{'gtk'}) { "# You can define this path to point at your tools if you need to\n". "# TOOLPATH = /opt/gcc/bin\n". "CC = \$(TOOLPATH)cc\n". - "# If necessary set the path to krb5-config here\n". - "KRB5CONFIG=krb5-config\n". "# You can manually set this to `gtk-config' or `pkg-config gtk+-1.2'\n". "# (depending on what works on your system) if you want to enforce\n". "# building with GTK 1.2, or you can set it to `pkg-config gtk+-2.0'\n". @@ -943,11 +941,6 @@ if (defined $makefiles{'gtk'}) { " -D _FILE_OFFSET_BITS=64\n". "XLDFLAGS = \$(LDFLAGS) \$(shell \$(GTK_CONFIG) --libs)\n". "ULDFLAGS = \$(LDFLAGS)\n". - "ifeq (,\$(findstring NO_GSSAPI,\$(COMPAT)))\n". - "CFLAGS+= \$(shell \$(KRB5CONFIG) --cflags gssapi)\n". - "XLDFLAGS+= \$(shell \$(KRB5CONFIG) --libs gssapi)\n". - "ULDFLAGS = \$(shell \$(KRB5CONFIG) --libs gssapi)\n". - "endif\n". "INSTALL=install\n". "INSTALL_PROGRAM=\$(INSTALL)\n". "INSTALL_DATA=\$(INSTALL)\n". @@ -1006,8 +999,6 @@ if (defined $makefiles{'unix'}) { "# You can define this path to point at your tools if you need to\n". "# TOOLPATH = /opt/gcc/bin\n". "CC = \$(TOOLPATH)cc\n". - "# If necessary set the path to krb5-config here\n". - "KRB5CONFIG=krb5-config\n". "\n". "-include Makefile.local\n". "\n". @@ -1017,10 +1008,6 @@ if (defined $makefiles{'unix'}) { (join " ", map {"-I$dirpfx$_"} @srcdirs)). " -D _FILE_OFFSET_BITS=64\n". "ULDFLAGS = \$(LDFLAGS)\n". - "ifeq (,\$(findstring NO_GSSAPI,\$(COMPAT)))\n". - "CFLAGS+= \$(shell \$(KRB5CONFIG) --cflags gssapi)\n". - "ULDFLAGS = \$(shell \$(KRB5CONFIG) --libs gssapi)\n". - "endif\n". "INSTALL=install\n". "INSTALL_PROGRAM=\$(INSTALL)\n". "INSTALL_DATA=\$(INSTALL)\n". diff --git a/ssh.c b/ssh.c index 068db3c..cc11978 100644 --- a/ssh.c +++ b/ssh.c @@ -13,6 +13,7 @@ #include "tree234.h" #include "ssh.h" #ifndef NO_GSSAPI +#include "sshgssc.h" #include "sshgss.h" #endif diff --git a/sshgssc.c b/sshgssc.c new file mode 100644 index 0000000..b64e8d8 --- /dev/null +++ b/sshgssc.c @@ -0,0 +1,194 @@ +#include "putty.h" + +#ifndef NO_GSSAPI + +#include +#include "sshgssc.h" +#include "sshgss.h" +#include "misc.h" + +typedef struct gssapi_ssh_gss_ctx { + OM_uint32 maj_stat; + OM_uint32 min_stat; + gss_ctx_id_t ctx; +} gssapi_ssh_gss_ctx; + +#if 0 +int ssh_gss_init(void) +{ + /* Dynamically load gssapi lib here. */ + /* Bind function pointers here. */ + return 0; +} +#endif + +Ssh_gss_stat ssh_gss_indicate_mech(Ssh_gss_buf *mech) +{ + /* Copy constant into mech */ + mech->length = putty_gss_mech_krb5->length; + mech->value = putty_gss_mech_krb5->elements; + + return SSH_GSS_OK; +} + +Ssh_gss_stat ssh_gss_import_name(char *host, + Ssh_gss_name *srv_name) +{ + OM_uint32 min_stat,maj_stat; + gss_buffer_desc host_buf; + char *pStr; + + pStr = dupcat("host@", host, NULL); + + host_buf.value = pStr; + host_buf.length = strlen(pStr); + + maj_stat = gss_import_name(&min_stat, &host_buf, + GSS_C_NT_HOSTBASED_SERVICE, srv_name); + /* Release buffer */ + sfree(pStr); + if (maj_stat == GSS_S_COMPLETE) return SSH_GSS_OK; + return SSH_GSS_FAILURE; +} + +Ssh_gss_stat ssh_gss_acquire_cred(Ssh_gss_ctx *ctx) +{ + gssapi_ssh_gss_ctx *gssctx = snew(gssapi_ssh_gss_ctx); + + gssctx->maj_stat = gssctx->min_stat = GSS_S_COMPLETE; + gssctx->ctx = GSS_C_NO_CONTEXT; + *ctx = (Ssh_gss_ctx) gssctx; + + return SSH_GSS_OK; +} + +Ssh_gss_stat ssh_gss_init_sec_context(Ssh_gss_ctx *ctx, + Ssh_gss_name srv_name, + int to_deleg, + Ssh_gss_buf *recv_tok, + Ssh_gss_buf *send_tok) +{ + gssapi_ssh_gss_ctx *gssctx = (gssapi_ssh_gss_ctx*) *ctx; + OM_uint32 ret_flags; + + if (to_deleg) to_deleg = GSS_C_DELEG_FLAG; + gssctx->maj_stat = gss_init_sec_context(&gssctx->min_stat, + GSS_C_NO_CREDENTIAL, + &gssctx->ctx, + srv_name, + (gss_OID) putty_gss_mech_krb5, + GSS_C_MUTUAL_FLAG | + GSS_C_INTEG_FLAG | to_deleg, + 0, + GSS_C_NO_CHANNEL_BINDINGS, + recv_tok, + NULL, /* ignore mech type */ + send_tok, + &ret_flags, + NULL); /* ignore time_rec */ + + if (gssctx->maj_stat == GSS_S_COMPLETE) return SSH_GSS_S_COMPLETE; + if (gssctx->maj_stat == GSS_S_CONTINUE_NEEDED) return SSH_GSS_S_CONTINUE_NEEDED; + return SSH_GSS_FAILURE; +} + +Ssh_gss_stat ssh_gss_display_status(Ssh_gss_ctx ctx, Ssh_gss_buf *buf) +{ + gssapi_ssh_gss_ctx *gssctx = (gssapi_ssh_gss_ctx *) ctx; + OM_uint32 lmin,lmax; + OM_uint32 ccc; + gss_buffer_desc msg_maj=GSS_C_EMPTY_BUFFER; + gss_buffer_desc msg_min=GSS_C_EMPTY_BUFFER; + + /* Return empty buffer in case of failure */ + SSH_GSS_CLEAR_BUF(buf); + + /* get first mesg from GSS */ + ccc=0; + lmax=gss_display_status(&lmin,gssctx->maj_stat,GSS_C_GSS_CODE,(gss_OID) putty_gss_mech_krb5,&ccc,&msg_maj); + + if (lmax != GSS_S_COMPLETE) return SSH_GSS_FAILURE; + + /* get first mesg from Kerberos */ + ccc=0; + lmax=gss_display_status(&lmin,gssctx->min_stat,GSS_C_MECH_CODE,(gss_OID) putty_gss_mech_krb5,&ccc,&msg_min); + + if (lmax != GSS_S_COMPLETE) { + gss_release_buffer(&lmin, &msg_maj); + return SSH_GSS_FAILURE; + } + + /* copy data into buffer */ + buf->length = msg_maj.length + msg_min.length + 1; + buf->value = snewn(buf->length + 1, char); + + /* copy mem */ + memcpy((char *)buf->value, msg_maj.value, msg_maj.length); + ((char *)buf->value)[msg_maj.length] = ' '; + memcpy((char *)buf->value + msg_maj.length + 1, msg_min.value, msg_min.length); + ((char *)buf->value)[buf->length] = 0; + /* free mem & exit */ + gss_release_buffer(&lmin, &msg_maj); + gss_release_buffer(&lmin, &msg_min); + return SSH_GSS_OK; +} + +Ssh_gss_stat ssh_gss_free_tok(Ssh_gss_buf *send_tok) +{ + OM_uint32 min_stat,maj_stat; + maj_stat = gss_release_buffer(&min_stat, send_tok); + + if (maj_stat == GSS_S_COMPLETE) return SSH_GSS_OK; + return SSH_GSS_FAILURE; +} + +Ssh_gss_stat ssh_gss_release_cred(Ssh_gss_ctx *ctx) +{ + gssapi_ssh_gss_ctx *gssctx = (gssapi_ssh_gss_ctx *) *ctx; + OM_uint32 min_stat; + OM_uint32 maj_stat=GSS_S_COMPLETE; + + if (gssctx == NULL) return SSH_GSS_FAILURE; + if (gssctx->ctx != GSS_C_NO_CONTEXT) + maj_stat = gss_delete_sec_context(&min_stat,&gssctx->ctx,GSS_C_NO_BUFFER); + sfree(gssctx); + + if (maj_stat == GSS_S_COMPLETE) return SSH_GSS_OK; + return SSH_GSS_FAILURE; +} + + +Ssh_gss_stat ssh_gss_release_name(Ssh_gss_name *srv_name) +{ + OM_uint32 min_stat,maj_stat; + maj_stat = gss_release_name(&min_stat, srv_name); + + if (maj_stat == GSS_S_COMPLETE) return SSH_GSS_OK; + return SSH_GSS_FAILURE; +} + +Ssh_gss_stat ssh_gss_get_mic(Ssh_gss_ctx ctx, Ssh_gss_buf *buf, + Ssh_gss_buf *hash) +{ + gssapi_ssh_gss_ctx *gssctx = (gssapi_ssh_gss_ctx *) ctx; + if (gssctx == NULL) return SSH_GSS_FAILURE; + return gss_get_mic(&(gssctx->min_stat), gssctx->ctx, 0, buf, hash); +} + +Ssh_gss_stat ssh_gss_free_mic(Ssh_gss_buf *hash) +{ + /* On Unix this is the same freeing process as ssh_gss_free_tok. */ + return ssh_gss_free_tok(hash); +} + +#else + +/* Dummy function so this source file defines something if NO_GSSAPI + is defined. */ + +int ssh_gss_init(void) +{ + return 1; +} + +#endif diff --git a/sshgssc.h b/sshgssc.h new file mode 100644 index 0000000..659d149 --- /dev/null +++ b/sshgssc.h @@ -0,0 +1,13 @@ +#ifndef PUTTY_SSHGSSC_H +#define PUTTY_SSHGSSC_H + +#ifndef NO_GSSAPI + +#include "pgssapi.h" + +typedef gss_buffer_desc Ssh_gss_buf; +typedef gss_name_t Ssh_gss_name; + +#endif /*NO_GSSAPI*/ + +#endif /*PUTTY_SSHGSSC_H*/ diff --git a/unix/configure.ac b/unix/configure.ac index 482b70c..108b09f 100644 --- a/unix/configure.ac +++ b/unix/configure.ac @@ -17,15 +17,19 @@ else fi AC_SUBST(PUTTYCFLAGS) -AC_ARG_WITH(gssapi, -[ --without-gssapi disable GSS-API support]) +AC_ARG_WITH([gssapi], + [AS_HELP_STRING([--without-gssapi], + [disable GSSAPI support])], + [], + [with_gssapi=yes]) + +WITH_GSSAPI= +AS_IF([test "x$with_gssapi" != xno], + [AC_DEFINE([WITH_GSSAPI], [1], [Define if building with GSSAPI support.])]) AC_CHECK_HEADERS([utmpx.h sys/select.h],,,[ #include #include ]) -if test "$with_gssapi" != "no"; then - AC_CHECK_HEADERS([gssapi/gssapi.h]) -fi # Look for both GTK 1 and GTK 2. # AM_PATH_GTK([1.2.0], [gtk=1], [gtk=none]) @@ -47,9 +51,7 @@ fi AC_SUBST([all_targets]) AC_SEARCH_LIBS([socket], [xnet]) -if test "$with_gssapi" != "no"; then - AC_SEARCH_LIBS([gss_init_sec_context], [gssapi gssapi_krb5 gss]) -fi +AC_SEARCH_LIBS([dlopen], [dl]) AC_CHECK_FUNCS([getaddrinfo ptsname setresuid strsignal updwtmpx]) @@ -82,7 +84,7 @@ AH_BOTTOM([ #ifndef HAVE_PANGO_FONT_MAP_LIST_FAMILIES # define PANGO_PRE_1POINT6 #endif -#ifndef HAVE_GSSAPI_GSSAPI_H +#ifndef WITH_GSSAPI # define NO_GSSAPI #endif ]) diff --git a/unix/unix.h b/unix/unix.h index f635747..d265b57 100644 --- a/unix/unix.h +++ b/unix/unix.h @@ -7,6 +7,7 @@ #include /* for FILENAME_MAX */ #include /* C99 int types */ +#include /* Dynamic library loading */ #include "charset.h" struct Filename { @@ -64,15 +65,12 @@ extern long tickcount_offset; #define WCHAR wchar_t #define BYTE unsigned char -#ifndef NO_GSSAPI /* - * GSS-API stuff + * GSSAPI Dynamic function binding. */ -#include -typedef gss_buffer_desc Ssh_gss_buf; -#define SSH_GSS_EMPTY_BUF GSS_C_EMPTY_BUFFER -typedef gss_name_t Ssh_gss_name; -#endif + +#define BIND_GSS_FN(handle, name) \ + name = handle ? (t_##name) dlsym(handle, #name) : NULL /* * Unix-specific global flag diff --git a/unix/uxgss.c b/unix/uxgss.c index 7bc6dca..57ef37c 100644 --- a/unix/uxgss.c +++ b/unix/uxgss.c @@ -1,197 +1,33 @@ -#include "putty.h" - #ifndef NO_GSSAPI +#include "putty.h" +#include "pgssapi.h" -#include -#include -#include "sshgss.h" -#include "misc.h" - -static gss_OID_desc putty_gss_mech_krb5_desc = - { 9, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02" }; -static gss_OID const putty_gss_mech_krb5 = &putty_gss_mech_krb5_desc; - -typedef struct uxSsh_gss_ctx { - OM_uint32 maj_stat; - OM_uint32 min_stat; - gss_ctx_id_t ctx; -} uxSsh_gss_ctx; +/* Unix specific GSSAPI code */ +/* Library loading */ +static void *gsslib = NULL; int ssh_gss_init(void) { - /* On Windows this tries to load the SSPI library functions. On - Unix we assume we have GSSAPI at runtime if we were linked with - it at compile time */ - return 1; -} - -Ssh_gss_stat ssh_gss_indicate_mech(Ssh_gss_buf *mech) -{ - /* Copy constant into mech */ - mech->length = putty_gss_mech_krb5->length; - mech->value = putty_gss_mech_krb5->elements; - - return SSH_GSS_OK; -} - -Ssh_gss_stat ssh_gss_import_name(char *host, - Ssh_gss_name *srv_name) -{ - OM_uint32 min_stat,maj_stat; - gss_buffer_desc host_buf; - char *pStr; - - pStr = dupcat("host@", host, NULL); - - host_buf.value = pStr; - host_buf.length = strlen(pStr); - - maj_stat = gss_import_name(&min_stat, &host_buf, - GSS_C_NT_HOSTBASED_SERVICE, srv_name); - /* Release buffer */ - sfree(pStr); - if (maj_stat == GSS_S_COMPLETE) return SSH_GSS_OK; - return SSH_GSS_FAILURE; -} - -Ssh_gss_stat ssh_gss_acquire_cred(Ssh_gss_ctx *ctx) -{ - uxSsh_gss_ctx *uxctx = snew(uxSsh_gss_ctx); - - uxctx->maj_stat = uxctx->min_stat = GSS_S_COMPLETE; - uxctx->ctx = GSS_C_NO_CONTEXT; - *ctx = (Ssh_gss_ctx) uxctx; - - return SSH_GSS_OK; -} - -Ssh_gss_stat ssh_gss_init_sec_context(Ssh_gss_ctx *ctx, - Ssh_gss_name srv_name, - int to_deleg, - Ssh_gss_buf *recv_tok, - Ssh_gss_buf *send_tok) -{ - uxSsh_gss_ctx *uxctx = (uxSsh_gss_ctx*) *ctx; - OM_uint32 ret_flags; - - if (to_deleg) to_deleg = GSS_C_DELEG_FLAG; - uxctx->maj_stat = gss_init_sec_context(&uxctx->min_stat, - GSS_C_NO_CREDENTIAL, - &uxctx->ctx, - srv_name, - (gss_OID) putty_gss_mech_krb5, - GSS_C_MUTUAL_FLAG | - GSS_C_INTEG_FLAG | to_deleg, - 0, - GSS_C_NO_CHANNEL_BINDINGS, - recv_tok, - NULL, /* ignore mech type */ - send_tok, - &ret_flags, - NULL); /* ignore time_rec */ - - if (uxctx->maj_stat == GSS_S_COMPLETE) return SSH_GSS_S_COMPLETE; - if (uxctx->maj_stat == GSS_S_CONTINUE_NEEDED) return SSH_GSS_S_CONTINUE_NEEDED; - return SSH_GSS_FAILURE; -} - -Ssh_gss_stat ssh_gss_display_status(Ssh_gss_ctx ctx, Ssh_gss_buf *buf) -{ - uxSsh_gss_ctx *uxctx = (uxSsh_gss_ctx *) ctx; - OM_uint32 lmin,lmax; - OM_uint32 ccc; - gss_buffer_desc msg_maj=GSS_C_EMPTY_BUFFER; - gss_buffer_desc msg_min=GSS_C_EMPTY_BUFFER; - - /* Return empty buffer in case of failure */ - SSH_GSS_CLEAR_BUF(buf); - - /* get first mesg from GSS */ - ccc=0; - lmax=gss_display_status(&lmin,uxctx->maj_stat,GSS_C_GSS_CODE,(gss_OID) putty_gss_mech_krb5,&ccc,&msg_maj); - - if (lmax != GSS_S_COMPLETE) return SSH_GSS_FAILURE; - - /* get first mesg from Kerberos */ - ccc=0; - lmax=gss_display_status(&lmin,uxctx->min_stat,GSS_C_MECH_CODE,(gss_OID) putty_gss_mech_krb5,&ccc,&msg_min); - - if (lmax != GSS_S_COMPLETE) { - gss_release_buffer(&lmin, &msg_maj); - return SSH_GSS_FAILURE; + /* Dynamically load gssapi lib here. */ + /* 1) MIT Kerberos's GSSAPI Library */ + gsslib = dlopen("libgssapi_krb5.so.2", RTLD_LAZY); + /* 2) Heimdal's GSSAPI Library */ + if (!gsslib) + gsslib = dlopen("libgssapi.so.2", RTLD_LAZY); + + /* Bind function pointers here. */ + if (gsslib) { + BIND_GSS_FN(gsslib, gss_delete_sec_context); + BIND_GSS_FN(gsslib, gss_display_status); + BIND_GSS_FN(gsslib, gss_get_mic); + BIND_GSS_FN(gsslib, gss_import_name); + BIND_GSS_FN(gsslib, gss_init_sec_context); + BIND_GSS_FN(gsslib, gss_release_buffer); + BIND_GSS_FN(gsslib, gss_release_cred); + BIND_GSS_FN(gsslib, gss_release_name); + return 1; } - - /* copy data into buffer */ - buf->length = msg_maj.length + msg_min.length + 1; - buf->value = snewn(buf->length + 1, char); - - /* copy mem */ - memcpy((char *)buf->value, msg_maj.value, msg_maj.length); - ((char *)buf->value)[msg_maj.length] = ' '; - memcpy((char *)buf->value + msg_maj.length + 1, msg_min.value, msg_min.length); - ((char *)buf->value)[buf->length] = 0; - /* free mem & exit */ - gss_release_buffer(&lmin, &msg_maj); - gss_release_buffer(&lmin, &msg_min); - return SSH_GSS_OK; -} - -Ssh_gss_stat ssh_gss_free_tok(Ssh_gss_buf *send_tok) -{ - OM_uint32 min_stat,maj_stat; - maj_stat = gss_release_buffer(&min_stat, send_tok); - - if (maj_stat == GSS_S_COMPLETE) return SSH_GSS_OK; - return SSH_GSS_FAILURE; -} - -Ssh_gss_stat ssh_gss_release_cred(Ssh_gss_ctx *ctx) -{ - uxSsh_gss_ctx *uxctx = (uxSsh_gss_ctx *) *ctx; - OM_uint32 min_stat; - OM_uint32 maj_stat=GSS_S_COMPLETE; - - if (uxctx == NULL) return SSH_GSS_FAILURE; - if (uxctx->ctx != GSS_C_NO_CONTEXT) - maj_stat = gss_delete_sec_context(&min_stat,&uxctx->ctx,GSS_C_NO_BUFFER); - sfree(uxctx); - - if (maj_stat == GSS_S_COMPLETE) return SSH_GSS_OK; - return SSH_GSS_FAILURE; -} - - -Ssh_gss_stat ssh_gss_release_name(Ssh_gss_name *srv_name) -{ - OM_uint32 min_stat,maj_stat; - maj_stat = gss_release_name(&min_stat, srv_name); - - if (maj_stat == GSS_S_COMPLETE) return SSH_GSS_OK; - return SSH_GSS_FAILURE; -} - -Ssh_gss_stat ssh_gss_get_mic(Ssh_gss_ctx ctx, Ssh_gss_buf *buf, - Ssh_gss_buf *hash) -{ - uxSsh_gss_ctx *uxctx = (uxSsh_gss_ctx *) ctx; - if (uxctx == NULL) return SSH_GSS_FAILURE; - return gss_get_mic(&(uxctx->min_stat), uxctx->ctx, 0, buf, hash); -} - -Ssh_gss_stat ssh_gss_free_mic(Ssh_gss_buf *hash) -{ - /* On Unix this is the same freeing process as ssh_gss_free_tok. */ - return ssh_gss_free_tok(hash); -} - -#else - -/* Dummy function so this source file defines something if NO_GSSAPI - is defined. */ - -int ssh_gss_init(void) -{ - return 1; + return 0; } -#endif +#endif /* NO_GSSAPI */ -- 1.6.6