# Disables PuTTY's ability to use GSSAPI functions for
# authentication and key exchange.
#
+# - COMPAT=/DSTATIC_GSSAPI
+# Causes PuTTY to try to link statically against the GSSAPI
+# library instead of the default of doing it at run time.
+#
# - COMPAT=/DMSVC4 (Windows only)
# - RCFL=/DMSVC4
# Makes a couple of minor changes so that PuTTY compiles using
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
+MACSSH = SSH macnoise sshnogss
# SFTP implementation (pscp, psftp).
SFTP = sftp int64 logging
# X/GTK Unix app, [U] for command-line Unix app, [M] for Macintosh app.
putty : [G] GUITERM NONSSH WINSSH W_BE_ALL WINMISC winx11 putty.res LIBS
-puttytel : [G] GUITERM NONSSH W_BE_NOSSH WINMISC puttytel.res LIBS
+puttytel : [G] GUITERM NONSSH W_BE_NOSSH WINMISC puttytel.res nogss LIBS
plink : [C] winplink wincons NONSSH WINSSH W_BE_ALL logging WINMISC
+ winx11 plink.res LIBS
pscp : [C] pscp winsftp wincons WINSSH BE_SSH SFTP wildcard WINMISC
pterm : [X] GTKTERM uxmisc misc ldisc settings uxpty uxsel BE_NONE uxstore
+ uxsignal CHARSET cmdline uxpterm version time xpmpterm xpmptcfg
+ + nogss
putty : [X] GTKTERM uxmisc misc ldisc settings uxsel U_BE_ALL uxstore
+ uxsignal CHARSET uxputty NONSSH UXSSH UXMISC ux_x11 xpmputty
+ xpmpucfg
puttytel : [X] GTKTERM uxmisc misc ldisc settings uxsel U_BE_NOSSH
+ uxstore uxsignal CHARSET uxputty NONSSH UXMISC xpmputty xpmpucfg
+ + nogss
plink : [U] uxplink uxcons NONSSH UXSSH U_BE_ALL logging UXMISC uxsignal
+ ux_x11
+ stricmp vsnprint dialog config macctrls minibidi
PuTTYtel : [M] terminal wcwidth ldiscucs logging BE_NOSSH mac macdlg
+ macevlog macterm macucs mac_res.rsrc testback NONSSH MACMISC
- + CHARSET stricmp vsnprint dialog config macctrls minibidi
+ + CHARSET stricmp vsnprint dialog config macctrls minibidi nogss
PuTTYgen : [M] macpgen sshrsag sshdssg sshprime sshdes sshbn sshmd5 version
+ sshrand macnoise sshsha macstore misc sshrsa sshdss macmisc sshpubk
+ sshaes sshsh256 sshsh512 import macpgen.rsrc macpgkey macabout
}
}
+#ifndef NO_GSSAPI
+static void gsslist_handler(union control *ctrl, void *dlg,
+ void *data, int event)
+{
+ Config *cfg = (Config *)data;
+ if (event == EVENT_REFRESH) {
+ int i;
+
+ dlg_update_start(ctrl, dlg);
+ dlg_listbox_clear(ctrl, dlg);
+ for (i = 0; i < ngsslibs; i++) {
+ int id = cfg->ssh_gsslist[i];
+ assert(id >= 0 && id < ngsslibs);
+ dlg_listbox_addwithid(ctrl, dlg, gsslibnames[id], id);
+ }
+ dlg_update_done(ctrl, dlg);
+
+ } else if (event == EVENT_VALCHANGE) {
+ int i;
+
+ /* Update array to match the list box. */
+ for (i=0; i < ngsslibs; i++)
+ cfg->ssh_gsslist[i] = dlg_listbox_getid(ctrl, dlg, i);
+ }
+}
+#endif
+
static void kexlist_handler(union control *ctrl, void *dlg,
void *data, int event)
{
ctrl_checkbox(s, "Allow agent forwarding", 'f',
HELPCTX(ssh_auth_agentfwd),
dlg_stdcheckbox_handler, I(offsetof(Config,agentfwd)));
- ctrl_checkbox(s, "Allow attempted changes of username in SSH-2", 'u',
+ ctrl_checkbox(s, "Allow attempted changes of username in SSH-2", NO_SHORTCUT,
HELPCTX(ssh_auth_changeuser),
dlg_stdcheckbox_handler,
I(offsetof(Config,change_username)));
FILTER_KEY_FILES, FALSE, "Select private key file",
HELPCTX(ssh_auth_privkey),
dlg_stdfilesel_handler, I(offsetof(Config, keyfile)));
+
+#ifndef NO_GSSAPI
+ /*
+ * GSSAPI library selection.
+ */
+ if (ngsslibs > 1) {
+ c = ctrl_draglist(s, "Preference order for GSSAPI libraries:", NO_SHORTCUT,
+ HELPCTX(no_help),
+ gsslist_handler, P(NULL));
+ c->listbox.height = ngsslibs;
+ }
+#endif
}
if (!midsession) {
#define BYTE UInt8
#define DWORD UInt32
+typedef UInt32 uint32;
+#define PUTTY_UINT32_DEFINED
+
#define OPTIMISE_SCROLL
/*
"XLDFLAGS = \$(LDFLAGS) \$(shell \$(GTK_CONFIG) --libs)\n".
"ULDFLAGS = \$(LDFLAGS)\n".
"ifeq (,\$(findstring NO_GSSAPI,\$(COMPAT)))\n".
- "CFLAGS+= \$(shell \$(KRB5CONFIG) --cflags gssapi)\n".
+ "ifeq (,\$(findstring STATIC_GSSAPI,\$(COMPAT)))\n".
+ "XLDFLAGS+= -ldl\n".
+ "ULDFLAGS+= -ldl\n".
+ "else\n".
+ "CFLAGS+= -DNO_LIBDL \$(shell \$(KRB5CONFIG) --cflags gssapi)\n".
"XLDFLAGS+= \$(shell \$(KRB5CONFIG) --libs gssapi)\n".
- "ULDFLAGS = \$(shell \$(KRB5CONFIG) --libs gssapi)\n".
+ "ULDFLAGS+= \$(shell \$(KRB5CONFIG) --libs gssapi)\n".
+ "endif\n".
"endif\n".
"INSTALL=install\n".
"INSTALL_PROGRAM=\$(INSTALL)\n".
"# 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".
(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".
--- /dev/null
+/*
+ * Stub definitions of the GSSAPI library list, for Unix pterm and
+ * any other application that needs the symbols defined but has no
+ * use for them.
+ */
+
+const int ngsslibs = 0;
+const char *const gsslibnames[1] = { "dummy" };
+const char *const gsslibkeywords[1] = { "dummy" };
+
--- /dev/null
+/* This file actually defines the GSSAPI function pointers for
+ * functions we plan to import from a GSSAPI library.
+ */
+#include "putty.h"
+
+#ifndef NO_GSSAPI
+
+#include "pgssapi.h"
+
+#ifndef NO_LIBDL
+
+/* Reserved static storage for GSS_oids. Comments are quotes from RFC 2744. */
+static const gss_OID_desc oids[] = {
+ /* The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value */
+ {10, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x01"},
+ /* corresponding to an object-identifier value of
+ * {iso(1) member-body(2) United States(840) mit(113554)
+ * infosys(1) gssapi(2) generic(1) user_name(1)}. The constant
+ * GSS_C_NT_USER_NAME should be initialized to point
+ * to that gss_OID_desc.
+
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value */
+ {10, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x02"},
+ /* corresponding to an object-identifier value of
+ * {iso(1) member-body(2) United States(840) mit(113554)
+ * infosys(1) gssapi(2) generic(1) machine_uid_name(2)}.
+ * The constant GSS_C_NT_MACHINE_UID_NAME should be
+ * initialized to point to that gss_OID_desc.
+
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value */
+ {10, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x03"},
+ /* corresponding to an object-identifier value of
+ * {iso(1) member-body(2) United States(840) mit(113554)
+ * infosys(1) gssapi(2) generic(1) string_uid_name(3)}.
+ * The constant GSS_C_NT_STRING_UID_NAME should be
+ * initialized to point to that gss_OID_desc.
+ *
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value */
+ {6, (void *)"\x2b\x06\x01\x05\x06\x02"},
+ /* corresponding to an object-identifier value of
+ * {iso(1) org(3) dod(6) internet(1) security(5)
+ * nametypes(6) gss-host-based-services(2)). The constant
+ * GSS_C_NT_HOSTBASED_SERVICE_X should be initialized to point
+ * to that gss_OID_desc. This is a deprecated OID value, and
+ * implementations wishing to support hostbased-service names
+ * should instead use the GSS_C_NT_HOSTBASED_SERVICE OID,
+ * defined below, to identify such names;
+ * GSS_C_NT_HOSTBASED_SERVICE_X should be accepted a synonym
+ * for GSS_C_NT_HOSTBASED_SERVICE when presented as an input
+ * parameter, but should not be emitted by GSS-API
+ * implementations
+ *
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value */
+ {10, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x04"},
+ /* corresponding to an object-identifier value of {iso(1)
+ * member-body(2) Unites States(840) mit(113554) infosys(1)
+ * gssapi(2) generic(1) service_name(4)}. The constant
+ * GSS_C_NT_HOSTBASED_SERVICE should be initialized
+ * to point to that gss_OID_desc.
+ *
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value */
+ {6, (void *)"\x2b\x06\01\x05\x06\x03"},
+ /* corresponding to an object identifier value of
+ * {1(iso), 3(org), 6(dod), 1(internet), 5(security),
+ * 6(nametypes), 3(gss-anonymous-name)}. The constant
+ * and GSS_C_NT_ANONYMOUS should be initialized to point
+ * to that gss_OID_desc.
+ *
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value */
+ {6, (void *)"\x2b\x06\x01\x05\x06\x04"},
+ /* corresponding to an object-identifier value of
+ * {1(iso), 3(org), 6(dod), 1(internet), 5(security),
+ * 6(nametypes), 4(gss-api-exported-name)}. The constant
+ * GSS_C_NT_EXPORT_NAME should be initialized to point
+ * to that gss_OID_desc.
+ */
+};
+
+/* Here are the constants which point to the static structure above.
+ *
+ * Constants of the form GSS_C_NT_* are specified by rfc 2744.
+ */
+const_gss_OID GSS_C_NT_USER_NAME = oids+0;
+const_gss_OID GSS_C_NT_MACHINE_UID_NAME = oids+1;
+const_gss_OID GSS_C_NT_STRING_UID_NAME = oids+2;
+const_gss_OID GSS_C_NT_HOSTBASED_SERVICE_X = oids+3;
+const_gss_OID GSS_C_NT_HOSTBASED_SERVICE = oids+4;
+const_gss_OID GSS_C_NT_ANONYMOUS = oids+5;
+const_gss_OID GSS_C_NT_EXPORT_NAME = oids+6;
+
+#endif /* NO_LIBDL */
+
+static gss_OID_desc gss_mech_krb5_desc =
+{ 9, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02" };
+/* iso(1) member-body(2) United States(840) mit(113554) infosys(1) gssapi(2) krb5(2)*/
+const gss_OID GSS_MECH_KRB5 = &gss_mech_krb5_desc;
+
+#endif /* NO_GSSAPI */
--- /dev/null
+#ifndef PUTTY_PGSSAPI_H
+#define PUTTY_PGSSAPI_H
+
+#include "putty.h"
+
+#ifndef NO_GSSAPI
+
+/*
+ * On Unix, if we're statically linking against GSSAPI, we leave the
+ * declaration of all this lot to the official header. If we're
+ * dynamically linking, we declare it ourselves, because that avoids
+ * us needing the official header at compile time.
+ *
+ * However, we still need the function pointer types, because even
+ * with statically linked GSSAPI we use the ssh_gss_library wrapper.
+ */
+#ifdef STATIC_GSSAPI
+#include <gssapi/gssapi.h>
+typedef gss_OID const_gss_OID; /* for our prototypes below */
+#else /* STATIC_GSSAPI */
+
+/*******************************************************************************
+ * GSSAPI Definitions, taken from RFC 2744
+ ******************************************************************************/
+
+/* GSSAPI Type Definitions */
+typedef uint32 OM_uint32;
+
+typedef struct gss_OID_desc_struct {
+ OM_uint32 length;
+ void *elements;
+} gss_OID_desc;
+typedef const gss_OID_desc *const_gss_OID;
+typedef gss_OID_desc *gss_OID;
+
+typedef struct gss_OID_set_desc_struct {
+ size_t count;
+ gss_OID elements;
+} gss_OID_set_desc;
+typedef const gss_OID_set_desc *const_gss_OID_set;
+typedef gss_OID_set_desc *gss_OID_set;
+
+typedef struct gss_buffer_desc_struct {
+ size_t length;
+ void *value;
+} gss_buffer_desc, *gss_buffer_t;
+
+typedef struct gss_channel_bindings_struct {
+ OM_uint32 initiator_addrtype;
+ gss_buffer_desc initiator_address;
+ OM_uint32 acceptor_addrtype;
+ gss_buffer_desc acceptor_address;
+ gss_buffer_desc application_data;
+} *gss_channel_bindings_t;
+
+typedef void * gss_ctx_id_t;
+typedef void * gss_name_t;
+typedef void * gss_cred_id_t;
+
+typedef OM_uint32 gss_qop_t;
+
+/* Flag bits for context-level services. */
+
+#define GSS_C_DELEG_FLAG 1
+#define GSS_C_MUTUAL_FLAG 2
+#define GSS_C_REPLAY_FLAG 4
+#define GSS_C_SEQUENCE_FLAG 8
+#define GSS_C_CONF_FLAG 16
+#define GSS_C_INTEG_FLAG 32
+#define GSS_C_ANON_FLAG 64
+#define GSS_C_PROT_READY_FLAG 128
+#define GSS_C_TRANS_FLAG 256
+
+/* Credential usage options */
+#define GSS_C_BOTH 0
+#define GSS_C_INITIATE 1
+#define GSS_C_ACCEPT 2
+
+/* Status code types for gss_display_status */
+#define GSS_C_GSS_CODE 1
+#define GSS_C_MECH_CODE 2
+
+/* The constant definitions for channel-bindings address families */
+#define GSS_C_AF_UNSPEC 0
+#define GSS_C_AF_LOCAL 1
+#define GSS_C_AF_INET 2
+#define GSS_C_AF_IMPLINK 3
+#define GSS_C_AF_PUP 4
+#define GSS_C_AF_CHAOS 5
+#define GSS_C_AF_NS 6
+#define GSS_C_AF_NBS 7
+#define GSS_C_AF_ECMA 8
+#define GSS_C_AF_DATAKIT 9
+#define GSS_C_AF_CCITT 10
+#define GSS_C_AF_SNA 11
+#define GSS_C_AF_DECnet 12
+#define GSS_C_AF_DLI 13
+#define GSS_C_AF_LAT 14
+#define GSS_C_AF_HYLINK 15
+#define GSS_C_AF_APPLETALK 16
+#define GSS_C_AF_BSC 17
+#define GSS_C_AF_DSS 18
+#define GSS_C_AF_OSI 19
+#define GSS_C_AF_X25 21
+
+#define GSS_C_AF_NULLADDR 255
+
+/* Various Null values */
+#define GSS_C_NO_NAME ((gss_name_t) 0)
+#define GSS_C_NO_BUFFER ((gss_buffer_t) 0)
+#define GSS_C_NO_OID ((gss_OID) 0)
+#define GSS_C_NO_OID_SET ((gss_OID_set) 0)
+#define GSS_C_NO_CONTEXT ((gss_ctx_id_t) 0)
+#define GSS_C_NO_CREDENTIAL ((gss_cred_id_t) 0)
+#define GSS_C_NO_CHANNEL_BINDINGS ((gss_channel_bindings_t) 0)
+#define GSS_C_EMPTY_BUFFER {0, NULL}
+
+/* Major status codes */
+#define GSS_S_COMPLETE 0
+
+/* Some "helper" definitions to make the status code macros obvious. */
+#define GSS_C_CALLING_ERROR_OFFSET 24
+#define GSS_C_ROUTINE_ERROR_OFFSET 16
+
+#define GSS_C_SUPPLEMENTARY_OFFSET 0
+#define GSS_C_CALLING_ERROR_MASK 0377ul
+#define GSS_C_ROUTINE_ERROR_MASK 0377ul
+#define GSS_C_SUPPLEMENTARY_MASK 0177777ul
+
+/*
+ * The macros that test status codes for error conditions.
+ * Note that the GSS_ERROR() macro has changed slightly from
+ * the V1 GSS-API so that it now evaluates its argument
+ * only once.
+ */
+#define GSS_CALLING_ERROR(x) \
+ (x & (GSS_C_CALLING_ERROR_MASK << GSS_C_CALLING_ERROR_OFFSET))
+#define GSS_ROUTINE_ERROR(x) \
+ (x & (GSS_C_ROUTINE_ERROR_MASK << GSS_C_ROUTINE_ERROR_OFFSET))
+#define GSS_SUPPLEMENTARY_INFO(x) \
+ (x & (GSS_C_SUPPLEMENTARY_MASK << GSS_C_SUPPLEMENTARY_OFFSET))
+#define GSS_ERROR(x) \
+ (x & ((GSS_C_CALLING_ERROR_MASK << GSS_C_CALLING_ERROR_OFFSET) | \
+ (GSS_C_ROUTINE_ERROR_MASK << GSS_C_ROUTINE_ERROR_OFFSET)))
+
+/* Now the actual status code definitions */
+
+/* Calling errors: */
+#define GSS_S_CALL_INACCESSIBLE_READ \
+ (1ul << GSS_C_CALLING_ERROR_OFFSET)
+#define GSS_S_CALL_INACCESSIBLE_WRITE \
+ (2ul << GSS_C_CALLING_ERROR_OFFSET)
+#define GSS_S_CALL_BAD_STRUCTURE \
+ (3ul << GSS_C_CALLING_ERROR_OFFSET)
+
+/* Routine errors: */
+#define GSS_S_BAD_MECH (1ul << \
+ GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_BAD_NAME (2ul << \
+ GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_BAD_NAMETYPE (3ul << \
+ GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_BAD_BINDINGS (4ul << \
+ GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_BAD_STATUS (5ul << \
+ GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_BAD_SIG (6ul << \
+ GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_BAD_MIC GSS_S_BAD_SIG
+#define GSS_S_NO_CRED (7ul << \
+ GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_NO_CONTEXT (8ul << \
+ GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_DEFECTIVE_TOKEN (9ul << \
+ GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_DEFECTIVE_CREDENTIAL (10ul << \
+ GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_CREDENTIALS_EXPIRED (11ul << \
+ GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_CONTEXT_EXPIRED (12ul << \
+ GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_FAILURE (13ul << \
+ GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_BAD_QOP (14ul << \
+ GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_UNAUTHORIZED (15ul << \
+ GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_UNAVAILABLE (16ul << \
+ GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_DUPLICATE_ELEMENT (17ul << \
+ GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_NAME_NOT_MN (18ul << \
+ GSS_C_ROUTINE_ERROR_OFFSET)
+
+/* Supplementary info bits: */
+#define GSS_S_CONTINUE_NEEDED \
+ (1ul << (GSS_C_SUPPLEMENTARY_OFFSET + 0))
+#define GSS_S_DUPLICATE_TOKEN \
+ (1ul << (GSS_C_SUPPLEMENTARY_OFFSET + 1))
+#define GSS_S_OLD_TOKEN \
+ (1ul << (GSS_C_SUPPLEMENTARY_OFFSET + 2))
+#define GSS_S_UNSEQ_TOKEN \
+ (1ul << (GSS_C_SUPPLEMENTARY_OFFSET + 3))
+#define GSS_S_GAP_TOKEN \
+ (1ul << (GSS_C_SUPPLEMENTARY_OFFSET + 4))
+
+extern const_gss_OID GSS_C_NT_USER_NAME;
+extern const_gss_OID GSS_C_NT_MACHINE_UID_NAME;
+extern const_gss_OID GSS_C_NT_STRING_UID_NAME;
+extern const_gss_OID GSS_C_NT_HOSTBASED_SERVICE_X;
+extern const_gss_OID GSS_C_NT_HOSTBASED_SERVICE;
+extern const_gss_OID GSS_C_NT_ANONYMOUS;
+extern const_gss_OID GSS_C_NT_EXPORT_NAME;
+
+#endif /* STATIC_GSSAPI */
+
+extern const gss_OID GSS_MECH_KRB5;
+
+/* GSSAPI functions we use.
+ * TODO: Replace with all GSSAPI functions from RFC?
+ */
+
+/* Calling convention, just in case we need one. */
+#ifndef GSS_CC
+#define GSS_CC
+#endif /*GSS_CC*/
+
+typedef OM_uint32 (GSS_CC *t_gss_release_cred)
+ (OM_uint32 * /*minor_status*/,
+ gss_cred_id_t * /*cred_handle*/);
+
+typedef OM_uint32 (GSS_CC *t_gss_init_sec_context)
+ (OM_uint32 * /*minor_status*/,
+ const gss_cred_id_t /*initiator_cred_handle*/,
+ gss_ctx_id_t * /*context_handle*/,
+ const gss_name_t /*target_name*/,
+ const gss_OID /*mech_type*/,
+ OM_uint32 /*req_flags*/,
+ OM_uint32 /*time_req*/,
+ const gss_channel_bindings_t /*input_chan_bindings*/,
+ const gss_buffer_t /*input_token*/,
+ gss_OID * /*actual_mech_type*/,
+ gss_buffer_t /*output_token*/,
+ OM_uint32 * /*ret_flags*/,
+ OM_uint32 * /*time_rec*/);
+
+typedef OM_uint32 (GSS_CC *t_gss_delete_sec_context)
+ (OM_uint32 * /*minor_status*/,
+ gss_ctx_id_t * /*context_handle*/,
+ gss_buffer_t /*output_token*/);
+
+typedef OM_uint32 (GSS_CC *t_gss_get_mic)
+ (OM_uint32 * /*minor_status*/,
+ const gss_ctx_id_t /*context_handle*/,
+ gss_qop_t /*qop_req*/,
+ const gss_buffer_t /*message_buffer*/,
+ gss_buffer_t /*msg_token*/);
+
+typedef OM_uint32 (GSS_CC *t_gss_display_status)
+ (OM_uint32 * /*minor_status*/,
+ OM_uint32 /*status_value*/,
+ int /*status_type*/,
+ const gss_OID /*mech_type*/,
+ OM_uint32 * /*message_context*/,
+ gss_buffer_t /*status_string*/);
+
+
+typedef OM_uint32 (GSS_CC *t_gss_import_name)
+ (OM_uint32 * /*minor_status*/,
+ const gss_buffer_t /*input_name_buffer*/,
+ const_gss_OID /*input_name_type*/,
+ gss_name_t * /*output_name*/);
+
+
+typedef OM_uint32 (GSS_CC *t_gss_release_name)
+ (OM_uint32 * /*minor_status*/,
+ gss_name_t * /*name*/);
+
+typedef OM_uint32 (GSS_CC *t_gss_release_buffer)
+ (OM_uint32 * /*minor_status*/,
+ gss_buffer_t /*buffer*/);
+
+struct gssapi_functions {
+ t_gss_delete_sec_context delete_sec_context;
+ t_gss_display_status display_status;
+ t_gss_get_mic get_mic;
+ t_gss_import_name import_name;
+ t_gss_init_sec_context init_sec_context;
+ t_gss_release_buffer release_buffer;
+ t_gss_release_cred release_cred;
+ t_gss_release_name release_name;
+};
+
+#endif /* NO_GSSAPI */
+
+#endif /* PUTTY_PGSSAPI_H */
SER_FLOW_NONE, SER_FLOW_XONXOFF, SER_FLOW_RTSCTS, SER_FLOW_DSRDTR
};
+/*
+ * Tables of string <-> enum value mappings used in settings.c.
+ * Defined here so that backends can export their GSS library tables
+ * to the cross-platform settings code.
+ */
+struct keyval { char *s; int v; };
+
+#ifndef NO_GSSAPI
+extern const int ngsslibs;
+extern const char *const gsslibnames[];/* for displaying in configuration */
+extern const struct keyval gsslibkeywords[]; /* for storing by settings.c */
+#endif
+
extern const char *const ttymodes[];
enum {
int try_ki_auth;
int try_gssapi_auth; /* attempt gssapi auth */
int gssapifwd; /* forward tgt via gss */
+ int ssh_gsslist[4]; /* preference order for local GSS libs */
int ssh_subsys; /* run a subsystem rather than a command */
int ssh_subsys2; /* fallback to go with remote_cmd_ptr2 */
int ssh_no_shell; /* avoid running a shell */
#include "putty.h"
#include "storage.h"
-/*
- * Tables of string <-> enum value mappings
- */
-struct keyval { char *s; int v; };
-
/* The cipher order given here is the default order. */
static const struct keyval ciphernames[] = {
{ "aes", CIPHER_AES },
write_setting_i(sesskey, "AuthTIS", cfg->try_tis_auth);
write_setting_i(sesskey, "AuthKI", cfg->try_ki_auth);
write_setting_i(sesskey, "AuthGSSAPI", cfg->try_gssapi_auth);
+ wprefs(sesskey, "GSSLibs", gsslibkeywords, ngsslibs,
+ cfg->ssh_gsslist);
write_setting_i(sesskey, "SshNoShell", cfg->ssh_no_shell);
write_setting_i(sesskey, "SshProt", cfg->sshprot);
write_setting_s(sesskey, "LogHost", cfg->loghost);
gppi(sesskey, "AuthTIS", 0, &cfg->try_tis_auth);
gppi(sesskey, "AuthKI", 1, &cfg->try_ki_auth);
gppi(sesskey, "AuthGSSAPI", 1, &cfg->try_gssapi_auth);
+ gprefs(sesskey, "GSSList", "\0",
+ gsslibkeywords, ngsslibs, cfg->ssh_gsslist);
gppi(sesskey, "SshNoShell", 0, &cfg->ssh_no_shell);
gppfile(sesskey, "PublicKeyFile", &cfg->keyfile);
gpps(sesskey, "RemoteCommand", "", cfg->remote_cmd,
#include "tree234.h"
#include "ssh.h"
#ifndef NO_GSSAPI
+#include "sshgssc.h"
#include "sshgss.h"
#endif
int num_env, env_left, env_ok;
struct Packet *pktout;
#ifndef NO_GSSAPI
+ struct ssh_gss_library *gsslib;
Ssh_gss_ctx gss_ctx;
Ssh_gss_buf gss_buf;
Ssh_gss_buf gss_rcvtok, gss_sndtok;
s->can_keyb_inter = ssh->cfg.try_ki_auth &&
in_commasep_string("keyboard-interactive", methods, methlen);
#ifndef NO_GSSAPI
+ ssh_gss_init();
s->can_gssapi = ssh->cfg.try_gssapi_auth &&
- in_commasep_string("gssapi-with-mic", methods, methlen) &&
- ssh_gss_init();
+ in_commasep_string("gssapi-with-mic", methods, methlen) &&
+ n_ssh_gss_libraries > 0;
#endif
}
s->gotit = TRUE;
ssh->pkt_actx = SSH2_PKTCTX_GSSAPI;
+ /*
+ * Pick the highest GSS library on the preference
+ * list.
+ */
+ {
+ int i, j;
+ s->gsslib = NULL;
+ for (i = 0; i < ngsslibs; i++) {
+ int want_id = ssh->cfg.ssh_gsslist[i];
+ for (j = 0; j < n_ssh_gss_libraries; j++)
+ if (ssh_gss_libraries[j].id == want_id) {
+ s->gsslib = &ssh_gss_libraries[j];
+ goto got_gsslib; /* double break */
+ }
+ }
+ got_gsslib:
+ /*
+ * We always expect to have found something in
+ * the above loop: we only came here if there
+ * was at least one viable GSS library, and the
+ * preference list should always mention
+ * everything and only change the order.
+ */
+ assert(s->gsslib);
+ }
+
+ if (s->gsslib->gsslogmsg)
+ logevent(s->gsslib->gsslogmsg);
+
/* Sending USERAUTH_REQUEST with "gssapi-with-mic" method */
s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);
ssh2_pkt_addstring(s->pktout, s->username);
ssh2_pkt_addstring(s->pktout, "gssapi-with-mic");
/* add mechanism info */
- ssh_gss_indicate_mech(&s->gss_buf);
+ s->gsslib->indicate_mech(s->gsslib, &s->gss_buf);
/* number of GSSAPI mechanisms */
ssh2_pkt_adduint32(s->pktout,1);
}
/* now start running */
- s->gss_stat = ssh_gss_import_name(ssh->fullhostname,
- &s->gss_srv_name);
+ s->gss_stat = s->gsslib->import_name(s->gsslib,
+ ssh->fullhostname,
+ &s->gss_srv_name);
if (s->gss_stat != SSH_GSS_OK) {
if (s->gss_stat == SSH_GSS_BAD_HOST_NAME)
logevent("GSSAPI import name failed - Bad service name");
}
/* fetch TGT into GSS engine */
- s->gss_stat = ssh_gss_acquire_cred(&s->gss_ctx);
+ s->gss_stat = s->gsslib->acquire_cred(s->gsslib, &s->gss_ctx);
if (s->gss_stat != SSH_GSS_OK) {
logevent("GSSAPI authentication failed to get credentials");
- ssh_gss_release_name(&s->gss_srv_name);
+ s->gsslib->release_name(s->gsslib, &s->gss_srv_name);
continue;
}
/* now enter the loop */
do {
- s->gss_stat = ssh_gss_init_sec_context(&s->gss_ctx,
- s->gss_srv_name,
- ssh->cfg.gssapifwd,
- &s->gss_rcvtok,
- &s->gss_sndtok);
+ s->gss_stat = s->gsslib->init_sec_context
+ (s->gsslib,
+ &s->gss_ctx,
+ s->gss_srv_name,
+ ssh->cfg.gssapifwd,
+ &s->gss_rcvtok,
+ &s->gss_sndtok);
if (s->gss_stat!=SSH_GSS_S_COMPLETE &&
s->gss_stat!=SSH_GSS_S_CONTINUE_NEEDED) {
logevent("GSSAPI authentication initialisation failed");
- if (ssh_gss_display_status(s->gss_ctx,&s->gss_buf) == SSH_GSS_OK) {
+ if (s->gsslib->display_status(s->gsslib, s->gss_ctx,
+ &s->gss_buf) == SSH_GSS_OK) {
logevent(s->gss_buf.value);
sfree(s->gss_buf.value);
}
ssh_pkt_addstring_start(s->pktout);
ssh_pkt_addstring_data(s->pktout,s->gss_sndtok.value,s->gss_sndtok.length);
ssh2_pkt_send(ssh, s->pktout);
- ssh_gss_free_tok(&s->gss_sndtok);
+ s->gsslib->free_tok(s->gsslib, &s->gss_sndtok);
}
if (s->gss_stat == SSH_GSS_S_CONTINUE_NEEDED) {
} while (s-> gss_stat == SSH_GSS_S_CONTINUE_NEEDED);
if (s->gss_stat != SSH_GSS_OK) {
- ssh_gss_release_name(&s->gss_srv_name);
- ssh_gss_release_cred(&s->gss_ctx);
+ s->gsslib->release_name(s->gsslib, &s->gss_srv_name);
+ s->gsslib->release_cred(s->gsslib, &s->gss_ctx);
continue;
}
logevent("GSSAPI authentication loop finished OK");
s->gss_buf.value = (char *)s->pktout->data + micoffset;
s->gss_buf.length = s->pktout->length - micoffset;
- ssh_gss_get_mic(s->gss_ctx, &s->gss_buf, &mic);
+ s->gsslib->get_mic(s->gsslib, s->gss_ctx, &s->gss_buf, &mic);
s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_GSSAPI_MIC);
ssh_pkt_addstring_start(s->pktout);
ssh_pkt_addstring_data(s->pktout, mic.value, mic.length);
ssh2_pkt_send(ssh, s->pktout);
- ssh_gss_free_mic(&mic);
+ s->gsslib->free_mic(s->gsslib, &mic);
s->gotit = FALSE;
- ssh_gss_release_name(&s->gss_srv_name);
- ssh_gss_release_cred(&s->gss_ctx);
+ s->gsslib->release_name(s->gsslib, &s->gss_srv_name);
+ s->gsslib->release_cred(s->gsslib, &s->gss_ctx);
continue;
#endif
} else if (s->can_keyb_inter && !s->kbd_inter_refused) {
int rsa_public_blob_len(void *data, int maxlen);
void freersakey(struct RSAKey *key);
-typedef unsigned int word32;
+#ifndef PUTTY_UINT32_DEFINED
+/* This makes assumptions about the int type. */
typedef unsigned int uint32;
+#define PUTTY_UINT32_DEFINED
+#endif
+typedef uint32 word32;
unsigned long crc32_compute(const void *s, size_t len);
unsigned long crc32_update(unsigned long crc_input, const void *s, size_t len);
-#include "puttyps.h"
+#ifndef PUTTY_SSHGSS_H
+#define PUTTY_SSHGSS_H
+#include "putty.h"
+#include "pgssapi.h"
+
+#ifndef NO_GSSAPI
#define SSH2_GSS_OIDTYPE 0x06
typedef void *Ssh_gss_ctx;
(*buf).value = NULL; \
} while (0)
-/* Functions, provided by either wingss.c or uxgss.c */
+typedef gss_buffer_desc Ssh_gss_buf;
+typedef gss_name_t Ssh_gss_name;
+
+/* Functions, provided by either wingss.c or sshgssc.c */
+
+struct ssh_gss_library;
/*
- * Do startup-time initialisation for using GSSAPI. (On Windows,
- * for instance, this dynamically loads the GSSAPI DLL and
- * retrieves some function pointers.)
- *
- * Return value is 1 on success, or 0 if initialisation failed.
+ * Do startup-time initialisation for using GSSAPI. This should
+ * correctly initialise the array of struct ssh_gss_library declared
+ * below.
*
- * May be called multiple times (since the most convenient place
- * to call it _from_ is the ssh.c setup code), and will harmlessly
+ * Must be callable multiple times (since the most convenient place
+ * to call it _from_ is the ssh.c setup code), and should harmlessly
* return success if already initialised.
*/
-int ssh_gss_init(void);
+void ssh_gss_init(void);
/*
* Fills in buf with a string describing the GSSAPI mechanism in
* use. buf->data is not dynamically allocated.
*/
-Ssh_gss_stat ssh_gss_indicate_mech(Ssh_gss_buf *buf);
+typedef Ssh_gss_stat (*t_ssh_gss_indicate_mech)(struct ssh_gss_library *lib,
+ Ssh_gss_buf *buf);
/*
* Converts a name such as a hostname into a GSSAPI internal form,
* which is placed in "out". The result should be freed by
* ssh_gss_release_name().
*/
-Ssh_gss_stat ssh_gss_import_name(char *in, Ssh_gss_name *out);
+typedef Ssh_gss_stat (*t_ssh_gss_import_name)(struct ssh_gss_library *lib,
+ char *in, Ssh_gss_name *out);
/*
* Frees the contents of an Ssh_gss_name structure filled in by
* ssh_gss_import_name().
*/
-Ssh_gss_stat ssh_gss_release_name(Ssh_gss_name *name);
+typedef Ssh_gss_stat (*t_ssh_gss_release_name)(struct ssh_gss_library *lib,
+ Ssh_gss_name *name);
/*
* The main GSSAPI security context setup function. The "out"
* parameter will need to be freed by ssh_gss_free_tok.
*/
-Ssh_gss_stat ssh_gss_init_sec_context(Ssh_gss_ctx *ctx, Ssh_gss_name name, int delegate,
- Ssh_gss_buf *in, Ssh_gss_buf *out);
+typedef Ssh_gss_stat (*t_ssh_gss_init_sec_context)
+ (struct ssh_gss_library *lib,
+ Ssh_gss_ctx *ctx, Ssh_gss_name name, int delegate,
+ Ssh_gss_buf *in, Ssh_gss_buf *out);
/*
* Frees the contents of an Ssh_gss_buf filled in by
* different free function) or something filled in by any other
* way.
*/
-Ssh_gss_stat ssh_gss_free_tok(Ssh_gss_buf *);
+typedef Ssh_gss_stat (*t_ssh_gss_free_tok)(struct ssh_gss_library *lib,
+ Ssh_gss_buf *);
/*
* Acquires the credentials to perform authentication in the first
* place. Needs to be freed by ssh_gss_release_cred().
*/
-Ssh_gss_stat ssh_gss_acquire_cred(Ssh_gss_ctx *);
+typedef Ssh_gss_stat (*t_ssh_gss_acquire_cred)(struct ssh_gss_library *lib,
+ Ssh_gss_ctx *);
/*
* Frees the contents of an Ssh_gss_ctx filled in by
* ssh_gss_acquire_cred().
*/
-Ssh_gss_stat ssh_gss_release_cred(Ssh_gss_ctx *);
+typedef Ssh_gss_stat (*t_ssh_gss_release_cred)(struct ssh_gss_library *lib,
+ Ssh_gss_ctx *);
/*
* Gets a MIC for some input data. "out" needs to be freed by
* ssh_gss_free_mic().
*/
-Ssh_gss_stat ssh_gss_get_mic(Ssh_gss_ctx ctx, Ssh_gss_buf *in,
- Ssh_gss_buf *out);
+typedef Ssh_gss_stat (*t_ssh_gss_get_mic)(struct ssh_gss_library *lib,
+ Ssh_gss_ctx ctx, Ssh_gss_buf *in,
+ Ssh_gss_buf *out);
/*
* Frees the contents of an Ssh_gss_buf filled in by
* different free function) or something filled in by any other
* way.
*/
-Ssh_gss_stat ssh_gss_free_mic(Ssh_gss_buf *);
+typedef Ssh_gss_stat (*t_ssh_gss_free_mic)(struct ssh_gss_library *lib,
+ Ssh_gss_buf *);
/*
* Return an error message after authentication failed. The
* containing one more character which is a trailing NUL.
* buf->data should be manually freed by the caller.
*/
-Ssh_gss_stat ssh_gss_display_status(Ssh_gss_ctx, Ssh_gss_buf *buf);
+typedef Ssh_gss_stat (*t_ssh_gss_display_status)(struct ssh_gss_library *lib,
+ Ssh_gss_ctx, Ssh_gss_buf *buf);
+
+struct ssh_gss_library {
+ /*
+ * Identifying number in the enumeration used by the
+ * configuration code to specify a preference order.
+ */
+ int id;
+
+ /*
+ * Filled in at initialisation time, if there's anything
+ * interesting to say about how GSSAPI was initialised (e.g.
+ * which of a number of alternative libraries was used).
+ */
+ const char *gsslogmsg;
+
+ /*
+ * Function pointers implementing the SSH wrapper layer on top
+ * of GSSAPI. (Defined in sshgssc, typically, though Windows
+ * provides an alternative layer to sit on top of the annoyingly
+ * different SSPI.)
+ */
+ t_ssh_gss_indicate_mech indicate_mech;
+ t_ssh_gss_import_name import_name;
+ t_ssh_gss_release_name release_name;
+ t_ssh_gss_init_sec_context init_sec_context;
+ t_ssh_gss_free_tok free_tok;
+ t_ssh_gss_acquire_cred acquire_cred;
+ t_ssh_gss_release_cred release_cred;
+ t_ssh_gss_get_mic get_mic;
+ t_ssh_gss_free_mic free_mic;
+ t_ssh_gss_display_status display_status;
+
+ /*
+ * Additional data for the wrapper layers.
+ */
+ union {
+ struct gssapi_functions gssapi;
+ /*
+ * The SSPI wrappers don't need to store their Windows API
+ * function pointers in this structure, because there can't
+ * be more than one set of them available.
+ */
+ } u;
+};
+
+extern struct ssh_gss_library ssh_gss_libraries[];
+extern int n_ssh_gss_libraries;
+
+#endif /* NO_GSSAPI */
+
+#endif /*PUTTY_SSHGSS_H*/
--- /dev/null
+#include "putty.h"
+
+#include <string.h>
+#include "sshgssc.h"
+#include "misc.h"
+
+#ifndef NO_GSSAPI
+
+static Ssh_gss_stat ssh_gssapi_indicate_mech(struct ssh_gss_library *lib,
+ Ssh_gss_buf *mech)
+{
+ /* Copy constant into mech */
+ mech->length = GSS_MECH_KRB5->length;
+ mech->value = GSS_MECH_KRB5->elements;
+ return SSH_GSS_OK;
+}
+
+static Ssh_gss_stat ssh_gssapi_import_name(struct ssh_gss_library *lib,
+ char *host,
+ Ssh_gss_name *srv_name)
+{
+ struct gssapi_functions *gss = &lib->u.gssapi;
+ 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;
+}
+
+static Ssh_gss_stat ssh_gssapi_acquire_cred(struct ssh_gss_library *lib,
+ 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;
+}
+
+static Ssh_gss_stat ssh_gssapi_init_sec_context(struct ssh_gss_library *lib,
+ Ssh_gss_ctx *ctx,
+ Ssh_gss_name srv_name,
+ int to_deleg,
+ Ssh_gss_buf *recv_tok,
+ Ssh_gss_buf *send_tok)
+{
+ struct gssapi_functions *gss = &lib->u.gssapi;
+ 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) 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;
+}
+
+static Ssh_gss_stat ssh_gssapi_display_status(struct ssh_gss_library *lib,
+ Ssh_gss_ctx ctx,
+ Ssh_gss_buf *buf)
+{
+ struct gssapi_functions *gss = &lib->u.gssapi;
+ 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) 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) 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;
+}
+
+static Ssh_gss_stat ssh_gssapi_free_tok(struct ssh_gss_library *lib,
+ Ssh_gss_buf *send_tok)
+{
+ struct gssapi_functions *gss = &lib->u.gssapi;
+ 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;
+}
+
+static Ssh_gss_stat ssh_gssapi_release_cred(struct ssh_gss_library *lib,
+ Ssh_gss_ctx *ctx)
+{
+ struct gssapi_functions *gss = &lib->u.gssapi;
+ 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;
+}
+
+
+static Ssh_gss_stat ssh_gssapi_release_name(struct ssh_gss_library *lib,
+ Ssh_gss_name *srv_name)
+{
+ struct gssapi_functions *gss = &lib->u.gssapi;
+ 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;
+}
+
+static Ssh_gss_stat ssh_gssapi_get_mic(struct ssh_gss_library *lib,
+ Ssh_gss_ctx ctx, Ssh_gss_buf *buf,
+ Ssh_gss_buf *hash)
+{
+ struct gssapi_functions *gss = &lib->u.gssapi;
+ 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);
+}
+
+static Ssh_gss_stat ssh_gssapi_free_mic(struct ssh_gss_library *lib,
+ Ssh_gss_buf *hash)
+{
+ /* On Unix this is the same freeing process as ssh_gssapi_free_tok. */
+ return ssh_gssapi_free_tok(lib, hash);
+}
+
+void ssh_gssapi_bind_fns(struct ssh_gss_library *lib)
+{
+ lib->indicate_mech = ssh_gssapi_indicate_mech;
+ lib->import_name = ssh_gssapi_import_name;
+ lib->release_name = ssh_gssapi_release_name;
+ lib->init_sec_context = ssh_gssapi_init_sec_context;
+ lib->free_tok = ssh_gssapi_free_tok;
+ lib->acquire_cred = ssh_gssapi_acquire_cred;
+ lib->release_cred = ssh_gssapi_release_cred;
+ lib->get_mic = ssh_gssapi_get_mic;
+ lib->free_mic = ssh_gssapi_free_mic;
+ lib->display_status = ssh_gssapi_display_status;
+}
+
+#else
+
+/* Dummy function so this source file defines something if NO_GSSAPI
+ is defined. */
+
+int ssh_gssapi_init(void)
+{
+ return 0;
+}
+
+#endif
--- /dev/null
+#ifndef PUTTY_SSHGSSC_H
+#define PUTTY_SSHGSSC_H
+#include "putty.h"
+#ifndef NO_GSSAPI
+
+#include "pgssapi.h"
+#include "sshgss.h"
+
+typedef struct gssapi_ssh_gss_ctx {
+ OM_uint32 maj_stat;
+ OM_uint32 min_stat;
+ gss_ctx_id_t ctx;
+} gssapi_ssh_gss_ctx;
+
+void ssh_gssapi_bind_fns(struct ssh_gss_library *lib);
+
+#else
+
+int ssh_gssapi_init(void);
+
+#endif /*NO_GSSAPI*/
+
+#endif /*PUTTY_SSHGSSC_H*/
--- /dev/null
+#include "putty.h"
+#ifndef NO_GSSAPI
+
+/* For platforms not supporting GSSAPI */
+
+void ssh_gss_init(void)
+{
+}
+
+#endif /* NO_GSSAPI */
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 <sys/types.h>
#include <utmp.h>])
-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])
+# AM_PATH_GTK([1.2.0], [gtk=1], [gtk=none])
AM_PATH_GTK_2_0([2.0.0], [gtk=2], [])
if test "$gtk" = "none"; then
all_targets="all-cli"
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
+
+AS_IF([test "x$with_gssapi" != xno],
+ [AC_SEARCH_LIBS(
+ [dlopen],[dl],
+ [],
+ [AC_DEFINE([NO_LIBDL], [1], [Define if we could not find libdl.])
+ AC_CHECK_HEADERS([gssapi/gssapi.h])
+ AC_SEARCH_LIBS(
+ [gss_init_sec_context],[gssapi gssapi_krb5 gss],
+ [],
+ [AC_DEFINE([NO_GSSAPI_LIB], [1], [Define if we could not find a gssapi library])])])])
AC_CHECK_LIB(X11, XOpenDisplay)
#ifndef HAVE_PANGO_FONT_MAP_LIST_FAMILIES
# define PANGO_PRE_1POINT6
#endif
-#ifndef HAVE_GSSAPI_GSSAPI_H
+#if !defined(WITH_GSSAPI)
# define NO_GSSAPI
#endif
+#if !defined(NO_GSSAPI) && defined(NO_LIBDL)
+# if !defined(HAVE_GSSAPI_GSSAPI_H) || defined(NO_GSSAPI_LIB)
+# define NO_GSSAPI
+# endif
+#endif
])
#endif
#include <stdio.h> /* for FILENAME_MAX */
+#include <stdint.h> /* C99 int types */
+#ifndef NO_LIBDL
+#include <dlfcn.h> /* Dynamic library loading */
+#endif /* NO_LIBDL */
#include "charset.h"
struct Filename {
extern Backend pty_backend;
+typedef uint32_t uint32; /* C99: uint32_t defined in stdint.h */
+#define PUTTY_UINT32_DEFINED
+
/*
* Under GTK, we send MA_CLICK _and_ MA_2CLK, or MA_CLICK _and_
* MA_3CLK, when a button is pressed for the second or third time.
#define WCHAR wchar_t
#define BYTE unsigned char
-#ifndef NO_GSSAPI
-/*
- * GSS-API stuff
- */
-#include <gssapi/gssapi.h>
-typedef gss_buffer_desc Ssh_gss_buf;
-#define SSH_GSS_EMPTY_BUF GSS_C_EMPTY_BUFFER
-typedef gss_name_t Ssh_gss_name;
-#endif
-
/*
* Unix-specific global flag
*
#include "putty.h"
-
#ifndef NO_GSSAPI
-
-#include <string.h>
-#include <gssapi/gssapi.h>
+#include "pgssapi.h"
#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;
-
-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)
+#include "sshgssc.h"
+
+/* Unix code to set up the GSSAPI library list. */
+
+struct ssh_gss_library ssh_gss_libraries[3];
+int n_ssh_gss_libraries = 0;
+static int initialised = FALSE;
+
+const int ngsslibs = 3;
+const char *const gsslibnames[3] = {
+ "libgssapi (Heimdal)",
+ "libgssapi_krb5 (MIT Kerberos)",
+ "libgss (Sun)",
+};
+const struct keyval gsslibkeywords[] = {
+ { "libgssapi", 0 },
+ { "libgssapi_krb5", 1 },
+ { "libgss", 2 },
+};
+
+#ifndef NO_LIBDL
+
+/*
+ * Run-time binding against a choice of GSSAPI implementations. We
+ * try loading several libraries, and produce an entry in
+ * ssh_gss_libraries[] for each one.
+ */
+
+static void gss_init(struct ssh_gss_library *lib, void *dlhandle,
+ int id, const char *msg)
{
- /* Copy constant into mech */
- mech->length = putty_gss_mech_krb5->length;
- mech->value = putty_gss_mech_krb5->elements;
+ lib->id = id;
+ lib->gsslogmsg = msg;
- return SSH_GSS_OK;
-}
+#define BIND_GSS_FN(name) \
+ lib->u.gssapi.name = (t_gss_##name) dlsym(dlhandle, "gss_" #name)
-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;
+ BIND_GSS_FN(delete_sec_context);
+ BIND_GSS_FN(display_status);
+ BIND_GSS_FN(get_mic);
+ BIND_GSS_FN(import_name);
+ BIND_GSS_FN(init_sec_context);
+ BIND_GSS_FN(release_buffer);
+ BIND_GSS_FN(release_cred);
+ BIND_GSS_FN(release_name);
- pStr = dupcat("host@", host, NULL);
+#undef BIND_GSS_FN
- 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_gssapi_bind_fns(lib);
}
-Ssh_gss_stat ssh_gss_acquire_cred(Ssh_gss_ctx *ctx)
+/* Dynamically load gssapi libs. */
+void ssh_gss_init(void)
{
- uxSsh_gss_ctx *uxctx = snew(uxSsh_gss_ctx);
+ void *gsslib;
- uxctx->maj_stat = uxctx->min_stat = GSS_S_COMPLETE;
- uxctx->ctx = GSS_C_NO_CONTEXT;
- *ctx = (Ssh_gss_ctx) uxctx;
+ if (initialised) return;
+ initialised = TRUE;
- return SSH_GSS_OK;
-}
+ /* Heimdal's GSSAPI Library */
+ if ((gsslib = dlopen("libgssapi.so.2", RTLD_LAZY)) != NULL)
+ gss_init(&ssh_gss_libraries[n_ssh_gss_libraries++], gsslib,
+ 0, "Using GSSAPI from libgssapi.so.2");
-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;
-}
+ /* MIT Kerberos's GSSAPI Library */
+ if ((gsslib = dlopen("libgssapi_krb5.so.2", RTLD_LAZY)) != NULL)
+ gss_init(&ssh_gss_libraries[n_ssh_gss_libraries++], gsslib,
+ 1, "Using GSSAPI from libgssapi_krb5.so.2");
-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;
- }
-
- /* 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;
+ /* Sun's GSSAPI Library */
+ if ((gsslib = dlopen("libgss.so.1", RTLD_LAZY)) != NULL)
+ gss_init(&ssh_gss_libraries[n_ssh_gss_libraries++], gsslib,
+ 2, "Using GSSAPI from libgss.so.1");
}
-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;
-}
+#else /* NO_LIBDL */
-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;
-}
+/*
+ * Link-time binding against GSSAPI. Here we just construct a single
+ * library structure containing pointers to the functions we linked
+ * against.
+ */
+#include <gssapi/gssapi.h>
-Ssh_gss_stat ssh_gss_release_name(Ssh_gss_name *srv_name)
+/* Dynamically load gssapi libs. */
+void ssh_gss_init(void)
{
- 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;
-}
+ if (initialised) return;
+ initialised = TRUE;
-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);
-}
+ n_ssh_gss_libraries = 1;
+ ssh_gss_libraries[0].gsslogmsg = "Using statically linked GSSAPI";
-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);
-}
+#define BIND_GSS_FN(name) \
+ ssh_gss_libraries[0].u.gssapi.name = (t_gss_##name) gss_##name
-#else
+ BIND_GSS_FN(delete_sec_context);
+ BIND_GSS_FN(display_status);
+ BIND_GSS_FN(get_mic);
+ BIND_GSS_FN(import_name);
+ BIND_GSS_FN(init_sec_context);
+ BIND_GSS_FN(release_buffer);
+ BIND_GSS_FN(release_cred);
+ BIND_GSS_FN(release_name);
-/* Dummy function so this source file defines something if NO_GSSAPI
- is defined. */
+#undef BIND_GSS_FN
-int ssh_gss_init(void)
-{
- return 1;
+ ssh_gssapi_bind_fns(&ssh_gss_libraries[0]);
}
-#endif
+#endif /* NO_LIBDL */
+
+#endif /* NO_GSSAPI */
* FIXME: the above comment is a bit out of date. Did it happen?
*/
-struct keyval {
+struct skeyval {
const char *key;
const char *value;
};
int keycmp(void *av, void *bv)
{
- struct keyval *a = (struct keyval *)av;
- struct keyval *b = (struct keyval *)bv;
+ struct skeyval *a = (struct skeyval *)av;
+ struct skeyval *b = (struct skeyval *)bv;
return strcmp(a->key, b->key);
}
void provide_xrm_string(char *string)
{
char *p, *q, *key;
- struct keyval *xrms, *ret;
+ struct skeyval *xrms, *ret;
p = q = strchr(string, ':');
if (!q) {
q++;
while (p > string && p[-1] != '.' && p[-1] != '*')
p--;
- xrms = snew(struct keyval);
+ xrms = snew(struct skeyval);
key = snewn(q-p, char);
memcpy(key, p, q-p);
key[q-p-1] = '\0';
const char *get_setting(const char *key)
{
- struct keyval tmp, *ret;
+ struct skeyval tmp, *ret;
tmp.key = key;
if (xrmtree) {
ret = find234(xrmtree, &tmp, NULL);
while ( (line = fgetline(fp)) ) {
char *value = strchr(line, '=');
- struct keyval *kv;
+ struct skeyval *kv;
if (!value)
continue;
*value++ = '\0';
value[strcspn(value, "\r\n")] = '\0'; /* trim trailing NL */
- kv = snew(struct keyval);
+ kv = snew(struct skeyval);
kv->key = dupstr(line);
kv->value = dupstr(value);
add234(ret, kv);
{
tree234 *tree = (tree234 *)handle;
const char *val;
- struct keyval tmp, *kv;
+ struct skeyval tmp, *kv;
tmp.key = key;
if (tree != NULL &&
{
tree234 *tree = (tree234 *)handle;
const char *val;
- struct keyval tmp, *kv;
+ struct skeyval tmp, *kv;
tmp.key = key;
if (tree != NULL &&
void close_settings_r(void *handle)
{
tree234 *tree = (tree234 *)handle;
- struct keyval *kv;
+ struct skeyval *kv;
if (!tree)
return;
#include <security.h>
+#include "pgssapi.h"
#include "sshgss.h"
+#include "sshgssc.h"
+
#include "misc.h"
+/* Windows code to set up the GSSAPI library list. */
+
+struct ssh_gss_library ssh_gss_libraries[2];
+int n_ssh_gss_libraries = 0;
+static int initialised = FALSE;
+
+const int ngsslibs = 2;
+const char *const gsslibnames[2] = {
+ "GSSAPI32.DLL (MIT Kerberos)",
+ "SSPI.DLL (Microsoft SSPI)",
+};
+const struct keyval gsslibkeywords[] = {
+ { "gssapi32", 0 },
+ { "sspi", 1 },
+};
+
DECL_WINDOWS_FUNCTION(static, SECURITY_STATUS,
AcquireCredentialsHandleA,
(SEC_CHAR *, SEC_CHAR *, ULONG, PLUID,
MakeSignature,
(PCtxtHandle, ULONG, PSecBufferDesc, ULONG));
-static HMODULE security_module = NULL;
-
typedef struct winSsh_gss_ctx {
unsigned long maj_stat;
unsigned long min_stat;
const Ssh_gss_buf gss_mech_krb5={9,"\x2A\x86\x48\x86\xF7\x12\x01\x02\x02"};
-int ssh_gss_init(void)
+const char *gsslogmsg = NULL;
+
+static void ssh_sspi_bind_fns(struct ssh_gss_library *lib);
+
+void ssh_gss_init(void)
{
- if (security_module)
- return 1; /* already initialised */
-
- security_module = LoadLibrary("secur32.dll");
- if (security_module) {
- GET_WINDOWS_FUNCTION(security_module, AcquireCredentialsHandleA);
- GET_WINDOWS_FUNCTION(security_module, InitializeSecurityContextA);
- GET_WINDOWS_FUNCTION(security_module, FreeContextBuffer);
- GET_WINDOWS_FUNCTION(security_module, FreeCredentialsHandle);
- GET_WINDOWS_FUNCTION(security_module, DeleteSecurityContext);
- GET_WINDOWS_FUNCTION(security_module, QueryContextAttributesA);
- GET_WINDOWS_FUNCTION(security_module, MakeSignature);
- return 1;
+ HMODULE module;
+
+ if (initialised) return;
+ initialised = TRUE;
+
+ /* MIT Kerberos GSSAPI implementation */
+ /* TODO: For 64-bit builds, check for gssapi64.dll */
+ module = LoadLibrary("gssapi32.dll");
+ if (module) {
+ struct ssh_gss_library *lib =
+ &ssh_gss_libraries[n_ssh_gss_libraries++];
+
+ lib->id = 0;
+ lib->gsslogmsg = "Using GSSAPI from GSSAPI32.DLL";
+
+#define BIND_GSS_FN(name) \
+ lib->u.gssapi.name = (t_gss_##name) GetProcAddress(module, "gss_" #name)
+
+ BIND_GSS_FN(delete_sec_context);
+ BIND_GSS_FN(display_status);
+ BIND_GSS_FN(get_mic);
+ BIND_GSS_FN(import_name);
+ BIND_GSS_FN(init_sec_context);
+ BIND_GSS_FN(release_buffer);
+ BIND_GSS_FN(release_cred);
+ BIND_GSS_FN(release_name);
+
+#undef BIND_GSS_FN
+
+ ssh_gssapi_bind_fns(lib);
+ }
+
+ /* Microsoft SSPI Implementation */
+ module = LoadLibrary("secur32.dll");
+ if (module) {
+ struct ssh_gss_library *lib =
+ &ssh_gss_libraries[n_ssh_gss_libraries++];
+
+ lib->id = 1;
+ lib->gsslogmsg = "Using SSPI from SECUR32.DLL";
+
+ GET_WINDOWS_FUNCTION(module, AcquireCredentialsHandleA);
+ GET_WINDOWS_FUNCTION(module, InitializeSecurityContextA);
+ GET_WINDOWS_FUNCTION(module, FreeContextBuffer);
+ GET_WINDOWS_FUNCTION(module, FreeCredentialsHandle);
+ GET_WINDOWS_FUNCTION(module, DeleteSecurityContext);
+ GET_WINDOWS_FUNCTION(module, QueryContextAttributesA);
+ GET_WINDOWS_FUNCTION(module, MakeSignature);
+
+ ssh_sspi_bind_fns(lib);
}
- return 0;
}
-Ssh_gss_stat ssh_gss_indicate_mech(Ssh_gss_buf *mech)
+static Ssh_gss_stat ssh_sspi_indicate_mech(struct ssh_gss_library *lib,
+ Ssh_gss_buf *mech)
{
*mech = gss_mech_krb5;
return SSH_GSS_OK;
}
-Ssh_gss_stat ssh_gss_import_name(char *host, Ssh_gss_name *srv_name)
+static Ssh_gss_stat ssh_sspi_import_name(struct ssh_gss_library *lib,
+ char *host, Ssh_gss_name *srv_name)
{
char *pStr;
return SSH_GSS_OK;
}
-Ssh_gss_stat ssh_gss_acquire_cred(Ssh_gss_ctx *ctx)
+static Ssh_gss_stat ssh_sspi_acquire_cred(struct ssh_gss_library *lib,
+ Ssh_gss_ctx *ctx)
{
winSsh_gss_ctx *winctx = snew(winSsh_gss_ctx);
memset(winctx, 0, sizeof(winSsh_gss_ctx));
}
-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)
+static Ssh_gss_stat ssh_sspi_init_sec_context(struct ssh_gss_library *lib,
+ Ssh_gss_ctx *ctx,
+ Ssh_gss_name srv_name,
+ int to_deleg,
+ Ssh_gss_buf *recv_tok,
+ Ssh_gss_buf *send_tok)
{
winSsh_gss_ctx *winctx = (winSsh_gss_ctx *) *ctx;
SecBuffer wsend_tok = {send_tok->length,SECBUFFER_TOKEN,send_tok->value};
return SSH_GSS_FAILURE;
}
-Ssh_gss_stat ssh_gss_free_tok(Ssh_gss_buf *send_tok)
+static Ssh_gss_stat ssh_sspi_free_tok(struct ssh_gss_library *lib,
+ Ssh_gss_buf *send_tok)
{
/* check input */
if (send_tok == NULL) return SSH_GSS_FAILURE;
return SSH_GSS_OK;
}
-Ssh_gss_stat ssh_gss_release_cred(Ssh_gss_ctx *ctx)
+static Ssh_gss_stat ssh_sspi_release_cred(struct ssh_gss_library *lib,
+ Ssh_gss_ctx *ctx)
{
winSsh_gss_ctx *winctx= (winSsh_gss_ctx *) *ctx;
}
-Ssh_gss_stat ssh_gss_release_name(Ssh_gss_name *srv_name)
+static Ssh_gss_stat ssh_sspi_release_name(struct ssh_gss_library *lib,
+ Ssh_gss_name *srv_name)
{
char *pStr= (char *) *srv_name;
return SSH_GSS_OK;
}
-Ssh_gss_stat ssh_gss_display_status(Ssh_gss_ctx ctx, Ssh_gss_buf *buf)
+static Ssh_gss_stat ssh_sspi_display_status(struct ssh_gss_library *lib,
+ Ssh_gss_ctx ctx, Ssh_gss_buf *buf)
{
winSsh_gss_ctx *winctx = (winSsh_gss_ctx *) ctx;
char *msg;
return SSH_GSS_OK;
}
-Ssh_gss_stat ssh_gss_get_mic(Ssh_gss_ctx ctx, Ssh_gss_buf *buf,
- Ssh_gss_buf *hash)
+static Ssh_gss_stat ssh_sspi_get_mic(struct ssh_gss_library *lib,
+ Ssh_gss_ctx ctx, Ssh_gss_buf *buf,
+ Ssh_gss_buf *hash)
{
winSsh_gss_ctx *winctx= (winSsh_gss_ctx *) ctx;
SecPkgContext_Sizes ContextSizes;
return winctx->maj_stat;
}
-Ssh_gss_stat ssh_gss_free_mic(Ssh_gss_buf *hash)
+static Ssh_gss_stat ssh_sspi_free_mic(struct ssh_gss_library *lib,
+ Ssh_gss_buf *hash)
{
sfree(hash->value);
return SSH_GSS_OK;
}
+static void ssh_sspi_bind_fns(struct ssh_gss_library *lib)
+{
+ lib->indicate_mech = ssh_sspi_indicate_mech;
+ lib->import_name = ssh_sspi_import_name;
+ lib->release_name = ssh_sspi_release_name;
+ lib->init_sec_context = ssh_sspi_init_sec_context;
+ lib->free_tok = ssh_sspi_free_tok;
+ lib->acquire_cred = ssh_sspi_acquire_cred;
+ lib->release_cred = ssh_sspi_release_cred;
+ lib->get_mic = ssh_sspi_get_mic;
+ lib->free_mic = ssh_sspi_free_mic;
+ lib->display_status = ssh_sspi_display_status;
+}
+
#else
/* Dummy function so this source file defines something if NO_GSSAPI
is defined. */
-int ssh_gss_init(void)
+void ssh_gss_init(void)
{
- return 0;
}
#endif
typedef HDC Context;
+typedef unsigned int uint32; /* int is 32-bits on Win32 and Win64. */
+#define PUTTY_UINT32_DEFINED
+
#ifndef NO_GSSAPI
/*
* GSS-API stuff
*/
+#define GSS_CC CALLBACK
+/*
typedef struct Ssh_gss_buf {
- int length;
+ size_t length;
char *value;
} Ssh_gss_buf;
#define SSH_GSS_EMPTY_BUF (Ssh_gss_buf) {0,NULL}
typedef void *Ssh_gss_name;
+*/
#endif
/*