mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-09 17:38:00 +00:00
Initial commit of GSSAPI Kerberos support.
[originally from svn r8138]
This commit is contained in:
parent
0677c73c1a
commit
de5dd9d65c
9
Recipe
9
Recipe
@ -95,6 +95,10 @@
|
||||
# it to compile under development environments which do not
|
||||
# support IPv6 in their header files.
|
||||
#
|
||||
# - COMPAT=/DNO_GSSAPI
|
||||
# Disables PuTTY's ability to use GSSAPI functions for
|
||||
# authentication and key exchange.
|
||||
#
|
||||
# - COMPAT=/DMSVC4 (Windows only)
|
||||
# - RCFL=/DMSVC4
|
||||
# Makes a couple of minor changes so that PuTTY compiles using
|
||||
@ -166,6 +170,7 @@ version.o: FORCE
|
||||
# Add VER to Windows resource targets, and force them to be rebuilt every
|
||||
# time, on the assumption that they will contain version information.
|
||||
!begin vc vars
|
||||
CFLAGS = $(CFLAGS) /DHAS_GSSAPI
|
||||
RCFLAGS = $(RCFLAGS) $(VER)
|
||||
!end
|
||||
!begin cygwin vars
|
||||
@ -255,8 +260,8 @@ 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
|
||||
WINSSH = SSH winnoise winpgntc
|
||||
UXSSH = SSH uxnoise uxagentc
|
||||
WINSSH = SSH winnoise winpgntc wingss
|
||||
UXSSH = SSH uxnoise uxagentc uxgss
|
||||
MACSSH = SSH macnoise
|
||||
|
||||
# SFTP implementation (pscp, psftp).
|
||||
|
13
config.c
13
config.c
@ -2051,6 +2051,13 @@ void setup_config_box(struct controlbox *b, int midsession,
|
||||
dlg_stdcheckbox_handler,
|
||||
I(offsetof(Config,try_ki_auth)));
|
||||
|
||||
#ifndef NO_GSSAPI
|
||||
ctrl_checkbox(s, "Attempt GSSAPI auth (SSH-2)",
|
||||
NO_SHORTCUT, HELPCTX(no_help),
|
||||
dlg_stdcheckbox_handler,
|
||||
I(offsetof(Config,try_gssapi_auth)));
|
||||
#endif
|
||||
|
||||
s = ctrl_getset(b, "Connection/SSH/Auth", "params",
|
||||
"Authentication parameters");
|
||||
ctrl_checkbox(s, "Allow agent forwarding", 'f',
|
||||
@ -2060,6 +2067,12 @@ void setup_config_box(struct controlbox *b, int midsession,
|
||||
HELPCTX(ssh_auth_changeuser),
|
||||
dlg_stdcheckbox_handler,
|
||||
I(offsetof(Config,change_username)));
|
||||
#ifndef NO_GSSAPI
|
||||
ctrl_checkbox(s, "Allow GSSAPI credential delegation in SSH-2", NO_SHORTCUT,
|
||||
HELPCTX(no_help),
|
||||
dlg_stdcheckbox_handler,
|
||||
I(offsetof(Config,gssapifwd)));
|
||||
#endif
|
||||
ctrl_filesel(s, "Private key file for authentication:", 'k',
|
||||
FILTER_KEY_FILES, FALSE, "Select private key file",
|
||||
HELPCTX(ssh_auth_privkey),
|
||||
|
@ -924,6 +924,8 @@ 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".
|
||||
@ -939,6 +941,11 @@ if (defined $makefiles{'gtk'}) {
|
||||
" -D _FILE_OFFSET_BITS=64\n".
|
||||
"XLDFLAGS = \$(LDFLAGS) `\$(GTK_CONFIG) --libs`\n".
|
||||
"ULDFLAGS = \$(LDFLAGS)\n".
|
||||
"ifeq (,\$(findstring NO_GSSAPI,\$(COMPAT)))\n".
|
||||
"CFLAGS+= `\$(KRB5CONFIG) --cflags gssapi`\n".
|
||||
"XLDFLAGS+= `\$(KRB5CONFIG) --libs gssapi`\n".
|
||||
"ULDFLAGS = `\$(KRB5CONFIG) --libs gssapi`\n".
|
||||
"endif\n";
|
||||
"INSTALL=install\n",
|
||||
"INSTALL_PROGRAM=\$(INSTALL)\n",
|
||||
"INSTALL_DATA=\$(INSTALL)\n",
|
||||
|
2
putty.h
2
putty.h
@ -459,6 +459,8 @@ struct config_tag {
|
||||
int ssh_no_userauth; /* bypass "ssh-userauth" (SSH-2 only) */
|
||||
int try_tis_auth;
|
||||
int try_ki_auth;
|
||||
int try_gssapi_auth; /* attempt gssapi auth */
|
||||
int gssapifwd; /* forward tgt via gss */
|
||||
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 */
|
||||
|
@ -321,6 +321,7 @@ void save_open_settings(void *sesskey, Config *cfg)
|
||||
write_setting_i(sesskey, "Compression", cfg->compression);
|
||||
write_setting_i(sesskey, "TryAgent", cfg->tryagent);
|
||||
write_setting_i(sesskey, "AgentFwd", cfg->agentfwd);
|
||||
write_setting_i(sesskey, "GssapiFwd", cfg->gssapifwd);
|
||||
write_setting_i(sesskey, "ChangeUsername", cfg->change_username);
|
||||
wprefs(sesskey, "Cipher", ciphernames, CIPHER_MAX,
|
||||
cfg->ssh_cipherlist);
|
||||
@ -330,6 +331,7 @@ void save_open_settings(void *sesskey, Config *cfg)
|
||||
write_setting_i(sesskey, "SshNoAuth", cfg->ssh_no_userauth);
|
||||
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);
|
||||
write_setting_i(sesskey, "SshNoShell", cfg->ssh_no_shell);
|
||||
write_setting_i(sesskey, "SshProt", cfg->sshprot);
|
||||
write_setting_s(sesskey, "LogHost", cfg->loghost);
|
||||
@ -581,7 +583,7 @@ void load_open_settings(void *sesskey, Config *cfg)
|
||||
gpps(sesskey, "ProxyTelnetCommand", "connect %host %port\\n",
|
||||
cfg->proxy_telnet_command, sizeof(cfg->proxy_telnet_command));
|
||||
gppmap(sesskey, "Environment", "", cfg->environmt, lenof(cfg->environmt));
|
||||
gpps(sesskey, "UserName", "", cfg->username, sizeof(cfg->username));
|
||||
gpps(sesskey, "UserName", get_username(), cfg->username, sizeof(cfg->username));
|
||||
gpps(sesskey, "LocalUserName", "", cfg->localusername,
|
||||
sizeof(cfg->localusername));
|
||||
gppi(sesskey, "NoPTY", 0, &cfg->nopty);
|
||||
@ -589,6 +591,7 @@ void load_open_settings(void *sesskey, Config *cfg)
|
||||
gppi(sesskey, "TryAgent", 1, &cfg->tryagent);
|
||||
gppi(sesskey, "AgentFwd", 0, &cfg->agentfwd);
|
||||
gppi(sesskey, "ChangeUsername", 0, &cfg->change_username);
|
||||
gppi(sesskey, "GssapiFwd", 0, &cfg->gssapifwd);
|
||||
gprefs(sesskey, "Cipher", "\0",
|
||||
ciphernames, CIPHER_MAX, cfg->ssh_cipherlist);
|
||||
{
|
||||
@ -614,6 +617,7 @@ void load_open_settings(void *sesskey, Config *cfg)
|
||||
gppi(sesskey, "SshNoAuth", 0, &cfg->ssh_no_userauth);
|
||||
gppi(sesskey, "AuthTIS", 0, &cfg->try_tis_auth);
|
||||
gppi(sesskey, "AuthKI", 1, &cfg->try_ki_auth);
|
||||
gppi(sesskey, "AuthGSSAPI", 1, &cfg->try_gssapi_auth);
|
||||
gppi(sesskey, "SshNoShell", 0, &cfg->ssh_no_shell);
|
||||
gppfile(sesskey, "PublicKeyFile", &cfg->keyfile);
|
||||
gpps(sesskey, "RemoteCommand", "", cfg->remote_cmd,
|
||||
|
189
ssh.c
189
ssh.c
@ -12,6 +12,7 @@
|
||||
#include "putty.h"
|
||||
#include "tree234.h"
|
||||
#include "ssh.h"
|
||||
#include "sshgss.h"
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
@ -112,6 +113,12 @@
|
||||
#define SSH2_MSG_CHANNEL_REQUEST 98 /* 0x62 */
|
||||
#define SSH2_MSG_CHANNEL_SUCCESS 99 /* 0x63 */
|
||||
#define SSH2_MSG_CHANNEL_FAILURE 100 /* 0x64 */
|
||||
#define SSH2_MSG_USERAUTH_GSSAPI_RESPONSE 60
|
||||
#define SSH2_MSG_USERAUTH_GSSAPI_TOKEN 61
|
||||
#define SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE 63
|
||||
#define SSH2_MSG_USERAUTH_GSSAPI_ERROR 64
|
||||
#define SSH2_MSG_USERAUTH_GSSAPI_ERRTOK 65
|
||||
#define SSH2_MSG_USERAUTH_GSSAPI_MIC 66
|
||||
|
||||
/*
|
||||
* Packet type contexts, so that ssh2_pkt_type can correctly decode
|
||||
@ -127,6 +134,7 @@ typedef enum {
|
||||
SSH2_PKTCTX_NOAUTH,
|
||||
SSH2_PKTCTX_PUBLICKEY,
|
||||
SSH2_PKTCTX_PASSWORD,
|
||||
SSH2_PKTCTX_GSSAPI,
|
||||
SSH2_PKTCTX_KBDINTER
|
||||
} Pkt_ACtx;
|
||||
|
||||
@ -339,6 +347,12 @@ static char *ssh1_pkt_type(int type)
|
||||
}
|
||||
static char *ssh2_pkt_type(Pkt_KCtx pkt_kctx, Pkt_ACtx pkt_actx, int type)
|
||||
{
|
||||
translatea(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE,SSH2_PKTCTX_GSSAPI);
|
||||
translatea(SSH2_MSG_USERAUTH_GSSAPI_TOKEN,SSH2_PKTCTX_GSSAPI);
|
||||
translatea(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE,SSH2_PKTCTX_GSSAPI);
|
||||
translatea(SSH2_MSG_USERAUTH_GSSAPI_ERROR,SSH2_PKTCTX_GSSAPI);
|
||||
translatea(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK,SSH2_PKTCTX_GSSAPI);
|
||||
translatea(SSH2_MSG_USERAUTH_GSSAPI_MIC, SSH2_PKTCTX_GSSAPI);
|
||||
translate(SSH2_MSG_DISCONNECT);
|
||||
translate(SSH2_MSG_IGNORE);
|
||||
translate(SSH2_MSG_UNIMPLEMENTED);
|
||||
@ -896,6 +910,11 @@ struct ssh_tag {
|
||||
int kex_in_progress;
|
||||
long next_rekey, last_rekey;
|
||||
char *deferred_rekey_reason; /* points to STATIC string; don't free */
|
||||
|
||||
/*
|
||||
* Fully qualified host name, which we need if doing GSSAPI.
|
||||
*/
|
||||
char *fullhostname;
|
||||
};
|
||||
|
||||
#define logevent(s) logevent(ssh->frontend, s)
|
||||
@ -2875,6 +2894,7 @@ static const char *connect_to_host(Ssh ssh, char *host, int port,
|
||||
sk_addr_free(addr);
|
||||
return err;
|
||||
}
|
||||
ssh->fullhostname = dupstr(*realhost); /* save in case of GSSAPI */
|
||||
|
||||
/*
|
||||
* Open socket.
|
||||
@ -7043,12 +7063,15 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,
|
||||
AUTH_TYPE_PUBLICKEY_OFFER_LOUD,
|
||||
AUTH_TYPE_PUBLICKEY_OFFER_QUIET,
|
||||
AUTH_TYPE_PASSWORD,
|
||||
AUTH_TYPE_GSSAPI,
|
||||
AUTH_TYPE_KEYBOARD_INTERACTIVE,
|
||||
AUTH_TYPE_KEYBOARD_INTERACTIVE_QUIET
|
||||
} type;
|
||||
int done_service_req;
|
||||
int gotit, need_pw, can_pubkey, can_passwd, can_keyb_inter;
|
||||
int tried_pubkey_config, done_agent;
|
||||
int can_gssapi;
|
||||
int tried_gssapi;
|
||||
int kbd_inter_refused;
|
||||
int we_are_in;
|
||||
prompts_t *cur_prompt;
|
||||
@ -7072,6 +7095,11 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,
|
||||
int try_send;
|
||||
int num_env, env_left, env_ok;
|
||||
struct Packet *pktout;
|
||||
Ssh_gss_ctx gss_ctx;
|
||||
Ssh_gss_buf gss_buf;
|
||||
Ssh_gss_buf gss_rcvtok, gss_sndtok;
|
||||
Ssh_gss_name gss_srv_name;
|
||||
Ssh_gss_stat gss_stat;
|
||||
};
|
||||
crState(do_ssh2_authconn_state);
|
||||
|
||||
@ -7079,6 +7107,8 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,
|
||||
|
||||
s->done_service_req = FALSE;
|
||||
s->we_are_in = FALSE;
|
||||
s->tried_gssapi = FALSE;
|
||||
|
||||
if (!ssh->cfg.ssh_no_userauth) {
|
||||
/*
|
||||
* Request userauth protocol, and await a response to it.
|
||||
@ -7366,7 +7396,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,
|
||||
break;
|
||||
}
|
||||
|
||||
if (pktin->type != SSH2_MSG_USERAUTH_FAILURE) {
|
||||
if (pktin->type != SSH2_MSG_USERAUTH_FAILURE && s->type != AUTH_TYPE_GSSAPI) {
|
||||
bombout(("Strange packet received during authentication: "
|
||||
"type %d", pktin->type));
|
||||
crStopV;
|
||||
@ -7437,6 +7467,11 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,
|
||||
in_commasep_string("password", methods, methlen);
|
||||
s->can_keyb_inter = ssh->cfg.try_ki_auth &&
|
||||
in_commasep_string("keyboard-interactive", methods, methlen);
|
||||
#ifndef NO_GSSAPI
|
||||
s->can_gssapi = ssh->cfg.try_gssapi_auth &&
|
||||
in_commasep_string("gssapi-with-mic", methods, methlen) &&
|
||||
ssh_gss_init();
|
||||
#endif
|
||||
}
|
||||
|
||||
ssh->pkt_actx = SSH2_PKTCTX_NOAUTH;
|
||||
@ -7765,6 +7800,157 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,
|
||||
key->alg->freekey(key->data);
|
||||
}
|
||||
|
||||
#ifndef NO_GSSAPI
|
||||
} else if (s->can_gssapi && !s->tried_gssapi) {
|
||||
|
||||
/* GSSAPI Authentication */
|
||||
|
||||
int micoffset;
|
||||
Ssh_gss_buf mic;
|
||||
s->type = AUTH_TYPE_GSSAPI;
|
||||
s->tried_gssapi = TRUE;
|
||||
s->gotit = TRUE;
|
||||
ssh->pkt_actx = SSH2_PKTCTX_GSSAPI;
|
||||
|
||||
/* 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, "ssh-connection");
|
||||
ssh2_pkt_addstring(s->pktout, "gssapi-with-mic");
|
||||
|
||||
/* add mechanism info */
|
||||
ssh_gss_indicate_mech(&s->gss_buf);
|
||||
|
||||
/* number of GSSAPI mechanisms */
|
||||
ssh2_pkt_adduint32(s->pktout,1);
|
||||
|
||||
/* length of OID + 2 */
|
||||
ssh2_pkt_adduint32(s->pktout, s->gss_buf.len + 2);
|
||||
ssh2_pkt_addbyte(s->pktout, SSH2_GSS_OIDTYPE);
|
||||
|
||||
/* length of OID */
|
||||
ssh2_pkt_addbyte(s->pktout, (unsigned char) s->gss_buf.len);
|
||||
|
||||
ssh_pkt_adddata(s->pktout, s->gss_buf.data, s->gss_buf.len);
|
||||
ssh2_pkt_send(ssh, s->pktout);
|
||||
crWaitUntilV(pktin);
|
||||
if (pktin->type != SSH2_MSG_USERAUTH_GSSAPI_RESPONSE) {
|
||||
logevent("GSSAPI authentication request refused");
|
||||
continue;
|
||||
}
|
||||
|
||||
/* check returned packet ... */
|
||||
|
||||
ssh_pkt_getstring(pktin,&s->gss_rcvtok.data,&s->gss_rcvtok.len);
|
||||
if (s->gss_rcvtok.len != s->gss_buf.len + 2 ||
|
||||
s->gss_rcvtok.data[0] != SSH2_GSS_OIDTYPE ||
|
||||
s->gss_rcvtok.data[1] != s->gss_buf.len ||
|
||||
memcmp(s->gss_rcvtok.data+2,s->gss_buf.data,s->gss_buf.len) ) {
|
||||
logevent("GSSAPI authentication - wrong response from server");
|
||||
continue;
|
||||
}
|
||||
|
||||
/* now start running */
|
||||
s->gss_stat = ssh_gss_import_name(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");
|
||||
else
|
||||
logevent("GSSAPI import name failed");
|
||||
continue;
|
||||
}
|
||||
|
||||
/* fetch TGT into GSS engine */
|
||||
s->gss_stat = ssh_gss_acquire_cred(&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);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* initial tokens are empty */
|
||||
s->gss_rcvtok.len = s->gss_sndtok.len = 0;
|
||||
s->gss_rcvtok.data = s->gss_sndtok.data = NULL;
|
||||
|
||||
/* 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);
|
||||
|
||||
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) {
|
||||
logevent(s->gss_buf.data);
|
||||
sfree(s->gss_buf.data);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
logevent("GSSAPI authentication initialised");
|
||||
|
||||
/* Client and server now exchange tokens until GSSAPI
|
||||
* no longer says CONTINUE_NEEDED */
|
||||
|
||||
if (s->gss_sndtok.len != 0) {
|
||||
s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_GSSAPI_TOKEN);
|
||||
ssh_pkt_addstring_start(s->pktout);
|
||||
ssh_pkt_addstring_data(s->pktout,s->gss_sndtok.data,s->gss_sndtok.len);
|
||||
ssh2_pkt_send(ssh, s->pktout);
|
||||
ssh_gss_free_tok(&s->gss_sndtok);
|
||||
}
|
||||
|
||||
if (s->gss_stat == SSH_GSS_S_CONTINUE_NEEDED) {
|
||||
crWaitUntilV(pktin);
|
||||
if (pktin->type != SSH2_MSG_USERAUTH_GSSAPI_TOKEN) {
|
||||
logevent("GSSAPI authentication - bad server response");
|
||||
s->gss_stat = SSH_GSS_FAILURE;
|
||||
break;
|
||||
}
|
||||
ssh_pkt_getstring(pktin,&s->gss_rcvtok.data,&s->gss_rcvtok.len);
|
||||
}
|
||||
} 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);
|
||||
continue;
|
||||
}
|
||||
logevent("GSSAPI authentication loop finished OK");
|
||||
|
||||
/* Now send the MIC */
|
||||
|
||||
s->pktout = ssh2_pkt_init(0);
|
||||
micoffset = s->pktout->length;
|
||||
ssh_pkt_addstring_start(s->pktout);
|
||||
ssh_pkt_addstring_data(s->pktout, (char *)ssh->v2_session_id, ssh->v2_session_id_len);
|
||||
ssh_pkt_addbyte(s->pktout, SSH2_MSG_USERAUTH_REQUEST);
|
||||
ssh_pkt_addstring(s->pktout, s->username);
|
||||
ssh_pkt_addstring(s->pktout, "ssh-connection");
|
||||
ssh_pkt_addstring(s->pktout, "gssapi-with-mic");
|
||||
|
||||
s->gss_buf.data = (char *)s->pktout->data + micoffset;
|
||||
s->gss_buf.len = s->pktout->length - micoffset;
|
||||
|
||||
ssh_gss_get_mic(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.data, mic.len);
|
||||
ssh2_pkt_send(ssh, s->pktout);
|
||||
ssh_gss_free_mic(&mic);
|
||||
|
||||
s->gotit = FALSE;
|
||||
|
||||
ssh_gss_release_name(&s->gss_srv_name);
|
||||
ssh_gss_release_cred(&s->gss_ctx);
|
||||
continue;
|
||||
#endif
|
||||
} else if (s->can_keyb_inter && !s->kbd_inter_refused) {
|
||||
|
||||
/*
|
||||
@ -8949,6 +9135,7 @@ static void ssh_free(void *handle)
|
||||
sfree(ssh->do_ssh2_authconn_state);
|
||||
sfree(ssh->v_c);
|
||||
sfree(ssh->v_s);
|
||||
sfree(ssh->fullhostname);
|
||||
if (ssh->crcda_ctx) {
|
||||
crcda_free_context(ssh->crcda_ctx);
|
||||
ssh->crcda_ctx = NULL;
|
||||
|
112
sshgss.h
Normal file
112
sshgss.h
Normal file
@ -0,0 +1,112 @@
|
||||
#define SSH2_GSS_OIDTYPE 0x06
|
||||
typedef void *Ssh_gss_ctx;
|
||||
typedef void *Ssh_gss_name;
|
||||
|
||||
typedef enum Ssh_gss_stat {
|
||||
SSH_GSS_OK = 0,
|
||||
SSH_GSS_S_CONTINUE_NEEDED,
|
||||
SSH_GSS_NO_MEM,
|
||||
SSH_GSS_BAD_HOST_NAME,
|
||||
SSH_GSS_FAILURE
|
||||
} Ssh_gss_stat;
|
||||
|
||||
#define SSH_GSS_S_COMPLETE SSH_GSS_OK
|
||||
|
||||
typedef struct Ssh_gss_buf {
|
||||
int len;
|
||||
char *data;
|
||||
} Ssh_gss_buf;
|
||||
|
||||
#define SSH_GSS_EMPTY_BUF (Ssh_gss_buf) {0,NULL}
|
||||
|
||||
#define SSH_GSS_CLEAR_BUF(buf) do { \
|
||||
(*buf).len = 0; \
|
||||
(*buf).data = NULL; \
|
||||
} while (0)
|
||||
|
||||
/* Functions, provided by either wingss.c or uxgss.c */
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* May be called multiple times (since the most convenient place
|
||||
* to call it _from_ is the ssh.c setup code), and will harmlessly
|
||||
* return success if already initialised.
|
||||
*/
|
||||
int 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);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
/*
|
||||
* Frees the contents of an Ssh_gss_buf filled in by
|
||||
* ssh_gss_init_sec_context(). Do not accidentally call this on
|
||||
* something filled in by ssh_gss_get_mic() (which requires a
|
||||
* different free function) or something filled in by any other
|
||||
* way.
|
||||
*/
|
||||
Ssh_gss_stat ssh_gss_free_tok(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 *);
|
||||
|
||||
/*
|
||||
* 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 *);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
/*
|
||||
* Frees the contents of an Ssh_gss_buf filled in by
|
||||
* ssh_gss_get_mic(). Do not accidentally call this on something
|
||||
* filled in by ssh_gss_init_sec_context() (which requires a
|
||||
* different free function) or something filled in by any other
|
||||
* way.
|
||||
*/
|
||||
Ssh_gss_stat ssh_gss_free_mic(Ssh_gss_buf *);
|
||||
|
||||
/*
|
||||
* Return an error message after authentication failed. The
|
||||
* message string is returned in "buf", with buf->len giving the
|
||||
* number of characters of printable message text and buf->data
|
||||
* 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);
|
196
unix/uxgss.c
Normal file
196
unix/uxgss.c
Normal file
@ -0,0 +1,196 @@
|
||||
#ifndef NO_GSSAPI
|
||||
|
||||
#include <string.h>
|
||||
#include <gssapi/gssapi_krb5.h>
|
||||
#include "sshgss.h"
|
||||
#include "misc.h"
|
||||
|
||||
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)
|
||||
{
|
||||
/* Copy constant into mech */
|
||||
mech->len = gss_mech_krb5->length;
|
||||
mech->data = 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,
|
||||
(gss_name_t *)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,
|
||||
(gss_name_t) srv_name,
|
||||
(gss_OID) gss_mech_krb5,
|
||||
GSS_C_MUTUAL_FLAG |
|
||||
GSS_C_INTEG_FLAG | to_deleg,
|
||||
0,
|
||||
NULL, /* no channel bindings */
|
||||
(gss_buffer_desc *)recv_tok,
|
||||
NULL, /* ignore mech type */
|
||||
(gss_buffer_desc *)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) 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) 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->len = msg_maj.length + msg_min.length + 1;
|
||||
buf->data = snewn(buf->len + 1, char);
|
||||
|
||||
/* copy mem */
|
||||
memcpy(buf->data, msg_maj.value, msg_maj.length);
|
||||
buf->data[msg_maj.length] = ' ';
|
||||
memcpy(buf->data + msg_maj.length + 1, msg_min.value, msg_min.length);
|
||||
buf->data[buf->len] = 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, (gss_buffer_desc *)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, (gss_name_t) 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,
|
||||
(gss_buffer_desc *)buf,
|
||||
(gss_buffer_desc *)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
|
@ -107,8 +107,8 @@ char *platform_default_s(const char *name)
|
||||
{
|
||||
if (!strcmp(name, "TermType"))
|
||||
return dupstr(getenv("TERM"));
|
||||
if (!strcmp(name, "UserName"))
|
||||
return get_username();
|
||||
if (!strcmp(name, "UserName"))
|
||||
return get_username();
|
||||
if (!strcmp(name, "SerialLine"))
|
||||
return dupstr("/dev/ttyS0");
|
||||
return NULL;
|
||||
|
319
windows/wingss.c
Normal file
319
windows/wingss.c
Normal file
@ -0,0 +1,319 @@
|
||||
#ifndef NO_GSSAPI
|
||||
|
||||
#include <windows.h>
|
||||
#define SECURITY_WIN32
|
||||
#include <security.h>
|
||||
#include "sshgss.h"
|
||||
#include "misc.h"
|
||||
|
||||
#define NOTHING
|
||||
#define DECL_SSPI_FUNCTION(linkage, rettype, name, params) \
|
||||
typedef rettype (WINAPI *t_##name) params; \
|
||||
linkage t_##name p_##name
|
||||
#define GET_SSPI_FUNCTION(module, name) \
|
||||
p_##name = module ? (t_##name) GetProcAddress(module, #name) : NULL
|
||||
|
||||
DECL_SSPI_FUNCTION(static, SECURITY_STATUS,
|
||||
AcquireCredentialsHandleA,
|
||||
(SEC_CHAR *, SEC_CHAR *, ULONG, PLUID,
|
||||
PVOID, SEC_GET_KEY_FN, PVOID, PCredHandle, PTimeStamp));
|
||||
DECL_SSPI_FUNCTION(static, SECURITY_STATUS,
|
||||
InitializeSecurityContextA,
|
||||
(PCredHandle, PCtxtHandle, SEC_CHAR *, ULONG, ULONG,
|
||||
ULONG, PSecBufferDesc, ULONG, PCtxtHandle,
|
||||
PSecBufferDesc, PULONG, PTimeStamp));
|
||||
DECL_SSPI_FUNCTION(static, SECURITY_STATUS,
|
||||
FreeContextBuffer,
|
||||
(PVOID));
|
||||
DECL_SSPI_FUNCTION(static, SECURITY_STATUS,
|
||||
FreeCredentialsHandle,
|
||||
(PCredHandle));
|
||||
DECL_SSPI_FUNCTION(static, SECURITY_STATUS,
|
||||
DeleteSecurityContext,
|
||||
(PCtxtHandle));
|
||||
DECL_SSPI_FUNCTION(static, SECURITY_STATUS,
|
||||
QueryContextAttributesA,
|
||||
(PCtxtHandle, ULONG, PVOID));
|
||||
DECL_SSPI_FUNCTION(static, SECURITY_STATUS,
|
||||
MakeSignature,
|
||||
(PCtxtHandle, ULONG, PSecBufferDesc, ULONG));
|
||||
|
||||
static HMODULE security_module = NULL;
|
||||
|
||||
typedef struct winSsh_gss_ctx {
|
||||
unsigned long maj_stat;
|
||||
unsigned long min_stat;
|
||||
CredHandle cred_handle;
|
||||
CtxtHandle context;
|
||||
PCtxtHandle context_handle;
|
||||
TimeStamp expiry;
|
||||
} winSsh_gss_ctx;
|
||||
|
||||
|
||||
const Ssh_gss_buf gss_mech_krb5={9,"\x2A\x86\x48\x86\xF7\x12\x01\x02\x02"};
|
||||
|
||||
int ssh_gss_init(void)
|
||||
{
|
||||
if (security_module)
|
||||
return 1; /* already initialised */
|
||||
|
||||
security_module = LoadLibrary("secur32.dll");
|
||||
if (security_module) {
|
||||
GET_SSPI_FUNCTION(security_module, AcquireCredentialsHandleA);
|
||||
GET_SSPI_FUNCTION(security_module, InitializeSecurityContextA);
|
||||
GET_SSPI_FUNCTION(security_module, FreeContextBuffer);
|
||||
GET_SSPI_FUNCTION(security_module, FreeCredentialsHandle);
|
||||
GET_SSPI_FUNCTION(security_module, DeleteSecurityContext);
|
||||
GET_SSPI_FUNCTION(security_module, QueryContextAttributesA);
|
||||
GET_SSPI_FUNCTION(security_module, MakeSignature);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
Ssh_gss_stat ssh_gss_indicate_mech(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)
|
||||
{
|
||||
char *pStr;
|
||||
|
||||
/* Check hostname */
|
||||
if (host == NULL) return SSH_GSS_FAILURE;
|
||||
|
||||
/* copy it into form host/FQDN */
|
||||
pStr = dupcat("host/", host, NULL);
|
||||
|
||||
*srv_name = (Ssh_gss_name) pStr;
|
||||
|
||||
return SSH_GSS_OK;
|
||||
}
|
||||
|
||||
Ssh_gss_stat ssh_gss_acquire_cred(Ssh_gss_ctx *ctx)
|
||||
{
|
||||
winSsh_gss_ctx *winctx = snew(winSsh_gss_ctx);
|
||||
|
||||
/* prepare our "wrapper" structure */
|
||||
winctx->maj_stat = winctx->min_stat = SEC_E_OK;
|
||||
winctx->context_handle = NULL;
|
||||
|
||||
/* Specifying no principal name here means use the credentials of
|
||||
the current logged-in user */
|
||||
|
||||
winctx->maj_stat = p_AcquireCredentialsHandleA(NULL,
|
||||
"Kerberos",
|
||||
SECPKG_CRED_OUTBOUND,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
&winctx->cred_handle,
|
||||
&winctx->expiry);
|
||||
|
||||
if (winctx->maj_stat != SEC_E_OK) return SSH_GSS_FAILURE;
|
||||
|
||||
*ctx = (Ssh_gss_ctx) winctx;
|
||||
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)
|
||||
{
|
||||
winSsh_gss_ctx *winctx = (winSsh_gss_ctx *) *ctx;
|
||||
SecBuffer wsend_tok = {send_tok->len,SECBUFFER_TOKEN,send_tok->data};
|
||||
SecBuffer wrecv_tok = {recv_tok->len,SECBUFFER_TOKEN,recv_tok->data};
|
||||
SecBufferDesc output_desc={SECBUFFER_VERSION,1,&wsend_tok};
|
||||
SecBufferDesc input_desc ={SECBUFFER_VERSION,1,&wrecv_tok};
|
||||
unsigned long flags=ISC_REQ_MUTUAL_AUTH|ISC_REQ_REPLAY_DETECT|
|
||||
ISC_REQ_CONFIDENTIALITY|ISC_REQ_ALLOCATE_MEMORY;
|
||||
unsigned long ret_flags=0;
|
||||
|
||||
/* check if we have to delegate ... */
|
||||
if (to_deleg) flags |= ISC_REQ_DELEGATE;
|
||||
winctx->maj_stat = p_InitializeSecurityContextA(&winctx->cred_handle,
|
||||
winctx->context_handle,
|
||||
(char*) srv_name,
|
||||
flags,
|
||||
0, /* reserved */
|
||||
SECURITY_NATIVE_DREP,
|
||||
&input_desc,
|
||||
0, /* reserved */
|
||||
&winctx->context,
|
||||
&output_desc,
|
||||
&ret_flags,
|
||||
&winctx->expiry);
|
||||
|
||||
/* prepare for the next round */
|
||||
winctx->context_handle = &winctx->context;
|
||||
send_tok->data = (char*) wsend_tok.pvBuffer;
|
||||
send_tok->len = wsend_tok.cbBuffer;
|
||||
|
||||
/* check & return our status */
|
||||
if (winctx->maj_stat==SEC_E_OK) return SSH_GSS_S_COMPLETE;
|
||||
if (winctx->maj_stat==SEC_I_CONTINUE_NEEDED) return SSH_GSS_S_CONTINUE_NEEDED;
|
||||
|
||||
return SSH_GSS_FAILURE;
|
||||
}
|
||||
|
||||
Ssh_gss_stat ssh_gss_free_tok(Ssh_gss_buf *send_tok)
|
||||
{
|
||||
/* check input */
|
||||
if (send_tok == NULL) return SSH_GSS_FAILURE;
|
||||
|
||||
/* free Windows buffer */
|
||||
p_FreeContextBuffer(send_tok->data);
|
||||
send_tok->len = 0; send_tok->data = NULL;
|
||||
|
||||
return SSH_GSS_OK;
|
||||
}
|
||||
|
||||
Ssh_gss_stat ssh_gss_release_cred(Ssh_gss_ctx *ctx)
|
||||
{
|
||||
winSsh_gss_ctx *winctx= (winSsh_gss_ctx *) *ctx;
|
||||
|
||||
/* check input */
|
||||
if (winctx == NULL) return SSH_GSS_FAILURE;
|
||||
|
||||
/* free Windows data */
|
||||
p_FreeCredentialsHandle(&winctx->cred_handle);
|
||||
p_DeleteSecurityContext(&winctx->context);
|
||||
|
||||
/* delete our "wrapper" structure */
|
||||
sfree(winctx);
|
||||
*ctx = (Ssh_gss_ctx) NULL;
|
||||
|
||||
return SSH_GSS_OK;
|
||||
}
|
||||
|
||||
|
||||
Ssh_gss_stat ssh_gss_release_name(Ssh_gss_name *srv_name)
|
||||
{
|
||||
char *pStr= (char *) *srv_name;
|
||||
|
||||
if (pStr == NULL) return SSH_GSS_FAILURE;
|
||||
sfree(pStr);
|
||||
*srv_name = (Ssh_gss_name) NULL;
|
||||
|
||||
return SSH_GSS_OK;
|
||||
}
|
||||
|
||||
Ssh_gss_stat ssh_gss_display_status(Ssh_gss_ctx ctx, Ssh_gss_buf *buf)
|
||||
{
|
||||
winSsh_gss_ctx *winctx = (winSsh_gss_ctx *) ctx;
|
||||
char *msg;
|
||||
|
||||
if (winctx == NULL) return SSH_GSS_FAILURE;
|
||||
|
||||
/* decode the error code */
|
||||
switch (winctx->maj_stat) {
|
||||
case SEC_E_OK: msg="SSPI status OK"; break;
|
||||
case SEC_E_INVALID_HANDLE: msg="The handle passed to the function"
|
||||
" is invalid.";
|
||||
break;
|
||||
case SEC_E_TARGET_UNKNOWN: msg="The target was not recognized."; break;
|
||||
case SEC_E_LOGON_DENIED: msg="The logon failed."; break;
|
||||
case SEC_E_INTERNAL_ERROR: msg="The Local Security Authority cannot"
|
||||
" be contacted.";
|
||||
break;
|
||||
case SEC_E_NO_CREDENTIALS: msg="No credentials are available in the"
|
||||
" security package.";
|
||||
break;
|
||||
case SEC_E_NO_AUTHENTICATING_AUTHORITY:
|
||||
msg="No authority could be contacted for authentication."
|
||||
"The domain name of the authenticating party could be wrong,"
|
||||
" the domain could be unreachable, or there might have been"
|
||||
" a trust relationship failure.";
|
||||
break;
|
||||
case SEC_E_INSUFFICIENT_MEMORY:
|
||||
msg="One or more of the SecBufferDesc structures passed as"
|
||||
" an OUT parameter has a buffer that is too small.";
|
||||
break;
|
||||
case SEC_E_INVALID_TOKEN:
|
||||
msg="The error is due to a malformed input token, such as a"
|
||||
" token corrupted in transit, a token"
|
||||
" of incorrect size, or a token passed into the wrong"
|
||||
" security package. Passing a token to"
|
||||
" the wrong package can happen if client and server did not"
|
||||
" negotiate the proper security package.";
|
||||
break;
|
||||
default:
|
||||
msg = "Internal SSPI error";
|
||||
break;
|
||||
}
|
||||
|
||||
buf->data = dupstr(msg);
|
||||
buf->len = strlen(buf->data);
|
||||
|
||||
return SSH_GSS_OK;
|
||||
}
|
||||
|
||||
Ssh_gss_stat ssh_gss_get_mic(Ssh_gss_ctx ctx, Ssh_gss_buf *buf,
|
||||
Ssh_gss_buf *hash)
|
||||
{
|
||||
winSsh_gss_ctx *winctx= (winSsh_gss_ctx *) ctx;
|
||||
SecPkgContext_Sizes ContextSizes;
|
||||
SecBufferDesc InputBufferDescriptor;
|
||||
SecBuffer InputSecurityToken[2];
|
||||
|
||||
if (winctx == NULL) return SSH_GSS_FAILURE;
|
||||
|
||||
winctx->maj_stat = 0;
|
||||
|
||||
memset(&ContextSizes, 0, sizeof(ContextSizes));
|
||||
|
||||
winctx->maj_stat = p_QueryContextAttributesA(&winctx->context,
|
||||
SECPKG_ATTR_SIZES,
|
||||
&ContextSizes);
|
||||
|
||||
if (winctx->maj_stat != SEC_E_OK ||
|
||||
ContextSizes.cbMaxSignature == 0)
|
||||
return winctx->maj_stat;
|
||||
|
||||
InputBufferDescriptor.cBuffers = 2;
|
||||
InputBufferDescriptor.pBuffers = InputSecurityToken;
|
||||
InputBufferDescriptor.ulVersion = SECBUFFER_VERSION;
|
||||
InputSecurityToken[0].BufferType = SECBUFFER_DATA;
|
||||
InputSecurityToken[0].cbBuffer = buf->len;
|
||||
InputSecurityToken[0].pvBuffer = buf->data;
|
||||
InputSecurityToken[1].BufferType = SECBUFFER_TOKEN;
|
||||
InputSecurityToken[1].cbBuffer = ContextSizes.cbMaxSignature;
|
||||
InputSecurityToken[1].pvBuffer = snewn(ContextSizes.cbMaxSignature, char);
|
||||
|
||||
winctx->maj_stat = p_MakeSignature(&winctx->context,
|
||||
0,
|
||||
&InputBufferDescriptor,
|
||||
0);
|
||||
|
||||
if (winctx->maj_stat == SEC_E_OK) {
|
||||
hash->len = InputSecurityToken[1].cbBuffer;
|
||||
hash->data = InputSecurityToken[1].pvBuffer;
|
||||
}
|
||||
|
||||
return winctx->maj_stat;
|
||||
}
|
||||
|
||||
Ssh_gss_stat ssh_gss_free_mic(Ssh_gss_buf *hash)
|
||||
{
|
||||
sfree(hash->data);
|
||||
return SSH_GSS_OK;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* Dummy function so this source file defines something if NO_GSSAPI
|
||||
is defined. */
|
||||
|
||||
int ssh_gss_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user