#include "putty.h"
#include "tree234.h"
#include "ssh.h"
+#ifndef NO_GSSAPI
+#include "sshgss.h"
+#endif
#ifndef FALSE
#define FALSE 0
#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
SSH2_PKTCTX_NOAUTH,
SSH2_PKTCTX_PUBLICKEY,
SSH2_PKTCTX_PASSWORD,
+ SSH2_PKTCTX_GSSAPI,
SSH2_PKTCTX_KBDINTER
} Pkt_ACtx;
}
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);
*
* - OUR_V2_BIGWIN is the window size we advertise for the only
* channel in a simple connection. It must be <= INT_MAX.
+ *
+ * - OUR_V2_MAXPKT is the official "maximum packet size" we send
+ * to the remote side. This actually has nothing to do with the
+ * size of the _packet_, but is instead a limit on the amount
+ * of data we're willing to receive in a single SSH2 channel
+ * data message.
+ *
+ * - OUR_V2_PACKETLIMIT is actually the maximum size of SSH
+ * _packet_ we're prepared to cope with. It must be a multiple
+ * of the cipher block size, and must be at least 35000.
*/
#define SSH1_BUFFER_LIMIT 32768
#define OUR_V2_WINSIZE 16384
#define OUR_V2_BIGWIN 0x7fffffff
#define OUR_V2_MAXPKT 0x4000UL
+#define OUR_V2_PACKETLIMIT 0x9000UL
/* Maximum length of passwords/passphrases (arbitrary) */
#define SSH_MAX_PASSWORD_LEN 100
Pkt_KCtx pkt_kctx;
Pkt_ACtx pkt_actx;
- void *x11auth;
+ struct X11Display *x11disp;
int version;
int conn_throttle_count;
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)
PKT_INCOMING, st->pktin->type,
ssh1_pkt_type(st->pktin->type),
st->pktin->body, st->pktin->length,
- nblanks, &blank);
+ nblanks, &blank, NULL);
}
crFinish(st->pktin);
st->cipherblk = 8;
if (st->cipherblk < 8)
st->cipherblk = 8;
+ st->maclen = ssh->scmac ? ssh->scmac->len : 0;
- st->pktin->data = snewn(st->cipherblk + APIEXTRA, unsigned char);
+ if (ssh->sccipher && (ssh->sccipher->flags & SSH_CIPHER_IS_CBC) &&
+ ssh->scmac) {
+ /*
+ * When dealing with a CBC-mode cipher, we want to avoid the
+ * possibility of an attacker's tweaking the ciphertext stream
+ * so as to cause us to feed the same block to the block
+ * cipher more than once and thus leak information
+ * (VU#958563). The way we do this is not to take any
+ * decisions on the basis of anything we've decrypted until
+ * we've verified it with a MAC. That includes the packet
+ * length, so we just read data and check the MAC repeatedly,
+ * and when the MAC passes, see if the length we've got is
+ * plausible.
+ */
- /*
- * Acquire and decrypt the first block of the packet. This will
- * contain the length and padding details.
- */
- for (st->i = st->len = 0; st->i < st->cipherblk; st->i++) {
- while ((*datalen) == 0)
- crReturn(NULL);
- st->pktin->data[st->i] = *(*data)++;
- (*datalen)--;
- }
+ /* May as well allocate the whole lot now. */
+ st->pktin->data = snewn(OUR_V2_PACKETLIMIT + st->maclen + APIEXTRA,
+ unsigned char);
- if (ssh->sccipher)
- ssh->sccipher->decrypt(ssh->sc_cipher_ctx,
- st->pktin->data, st->cipherblk);
+ /* Read an amount corresponding to the MAC. */
+ for (st->i = 0; st->i < st->maclen; st->i++) {
+ while ((*datalen) == 0)
+ crReturn(NULL);
+ st->pktin->data[st->i] = *(*data)++;
+ (*datalen)--;
+ }
- /*
- * Now get the length and padding figures.
- */
- st->len = GET_32BIT(st->pktin->data);
- st->pad = st->pktin->data[4];
+ st->packetlen = 0;
+ {
+ unsigned char seq[4];
+ ssh->scmac->start(ssh->sc_mac_ctx);
+ PUT_32BIT(seq, st->incoming_sequence);
+ ssh->scmac->bytes(ssh->sc_mac_ctx, seq, 4);
+ }
- /*
- * _Completely_ silly lengths should be stomped on before they
- * do us any more damage.
- */
- if (st->len < 0 || st->len > 35000 || st->pad < 4 ||
- st->len - st->pad < 1 || (st->len + 4) % st->cipherblk != 0) {
- bombout(("Incoming packet was garbled on decryption"));
- ssh_free_packet(st->pktin);
- crStop(NULL);
- }
+ for (;;) { /* Once around this loop per cipher block. */
+ /* Read another cipher-block's worth, and tack it onto the end. */
+ for (st->i = 0; st->i < st->cipherblk; st->i++) {
+ while ((*datalen) == 0)
+ crReturn(NULL);
+ st->pktin->data[st->packetlen+st->maclen+st->i] = *(*data)++;
+ (*datalen)--;
+ }
+ /* Decrypt one more block (a little further back in the stream). */
+ ssh->sccipher->decrypt(ssh->sc_cipher_ctx,
+ st->pktin->data + st->packetlen,
+ st->cipherblk);
+ /* Feed that block to the MAC. */
+ ssh->scmac->bytes(ssh->sc_mac_ctx,
+ st->pktin->data + st->packetlen, st->cipherblk);
+ st->packetlen += st->cipherblk;
+ /* See if that gives us a valid packet. */
+ if (ssh->scmac->verresult(ssh->sc_mac_ctx,
+ st->pktin->data + st->packetlen) &&
+ (st->len = GET_32BIT(st->pktin->data)) + 4 == st->packetlen)
+ break;
+ if (st->packetlen >= OUR_V2_PACKETLIMIT) {
+ bombout(("No valid incoming packet found"));
+ ssh_free_packet(st->pktin);
+ crStop(NULL);
+ }
+ }
+ st->pktin->maxlen = st->packetlen + st->maclen;
+ st->pktin->data = sresize(st->pktin->data,
+ st->pktin->maxlen + APIEXTRA,
+ unsigned char);
+ } else {
+ st->pktin->data = snewn(st->cipherblk + APIEXTRA, unsigned char);
- /*
- * This enables us to deduce the payload length.
- */
- st->payload = st->len - st->pad - 1;
+ /*
+ * Acquire and decrypt the first block of the packet. This will
+ * contain the length and padding details.
+ */
+ for (st->i = st->len = 0; st->i < st->cipherblk; st->i++) {
+ while ((*datalen) == 0)
+ crReturn(NULL);
+ st->pktin->data[st->i] = *(*data)++;
+ (*datalen)--;
+ }
- st->pktin->length = st->payload + 5;
+ if (ssh->sccipher)
+ ssh->sccipher->decrypt(ssh->sc_cipher_ctx,
+ st->pktin->data, st->cipherblk);
- /*
- * So now we can work out the total packet length.
- */
- st->packetlen = st->len + 4;
- st->maclen = ssh->scmac ? ssh->scmac->len : 0;
+ /*
+ * Now get the length figure.
+ */
+ st->len = GET_32BIT(st->pktin->data);
- /*
- * Allocate memory for the rest of the packet.
- */
- st->pktin->maxlen = st->packetlen + st->maclen;
- st->pktin->data = sresize(st->pktin->data,
- st->pktin->maxlen + APIEXTRA,
- unsigned char);
+ /*
+ * _Completely_ silly lengths should be stomped on before they
+ * do us any more damage.
+ */
+ if (st->len < 0 || st->len > OUR_V2_PACKETLIMIT ||
+ (st->len + 4) % st->cipherblk != 0) {
+ bombout(("Incoming packet was garbled on decryption"));
+ ssh_free_packet(st->pktin);
+ crStop(NULL);
+ }
- /*
- * Read and decrypt the remainder of the packet.
- */
- for (st->i = st->cipherblk; st->i < st->packetlen + st->maclen;
- st->i++) {
- while ((*datalen) == 0)
- crReturn(NULL);
- st->pktin->data[st->i] = *(*data)++;
- (*datalen)--;
- }
- /* Decrypt everything _except_ the MAC. */
- if (ssh->sccipher)
- ssh->sccipher->decrypt(ssh->sc_cipher_ctx,
- st->pktin->data + st->cipherblk,
- st->packetlen - st->cipherblk);
+ /*
+ * So now we can work out the total packet length.
+ */
+ st->packetlen = st->len + 4;
- st->pktin->encrypted_len = st->packetlen;
+ /*
+ * Allocate memory for the rest of the packet.
+ */
+ st->pktin->maxlen = st->packetlen + st->maclen;
+ st->pktin->data = sresize(st->pktin->data,
+ st->pktin->maxlen + APIEXTRA,
+ unsigned char);
- /*
- * Check the MAC.
- */
- if (ssh->scmac
- && !ssh->scmac->verify(ssh->sc_mac_ctx, st->pktin->data, st->len + 4,
- st->incoming_sequence)) {
- bombout(("Incorrect MAC received on packet"));
+ /*
+ * Read and decrypt the remainder of the packet.
+ */
+ for (st->i = st->cipherblk; st->i < st->packetlen + st->maclen;
+ st->i++) {
+ while ((*datalen) == 0)
+ crReturn(NULL);
+ st->pktin->data[st->i] = *(*data)++;
+ (*datalen)--;
+ }
+ /* Decrypt everything _except_ the MAC. */
+ if (ssh->sccipher)
+ ssh->sccipher->decrypt(ssh->sc_cipher_ctx,
+ st->pktin->data + st->cipherblk,
+ st->packetlen - st->cipherblk);
+
+ /*
+ * Check the MAC.
+ */
+ if (ssh->scmac
+ && !ssh->scmac->verify(ssh->sc_mac_ctx, st->pktin->data,
+ st->len + 4, st->incoming_sequence)) {
+ bombout(("Incorrect MAC received on packet"));
+ ssh_free_packet(st->pktin);
+ crStop(NULL);
+ }
+ }
+ /* Get and sanity-check the amount of random padding. */
+ st->pad = st->pktin->data[4];
+ if (st->pad < 4 || st->len - st->pad < 1) {
+ bombout(("Invalid padding length on received packet"));
ssh_free_packet(st->pktin);
crStop(NULL);
}
+ /*
+ * This enables us to deduce the payload length.
+ */
+ st->payload = st->len - st->pad - 1;
+
+ st->pktin->length = st->payload + 5;
+ st->pktin->encrypted_len = st->packetlen;
st->pktin->sequence = st->incoming_sequence++;
ssh2_pkt_type(ssh->pkt_kctx, ssh->pkt_actx,
st->pktin->type),
st->pktin->data+6, st->pktin->length-6,
- nblanks, &blank);
+ nblanks, &blank, &st->pktin->sequence);
}
crFinish(st->pktin);
log_packet(ssh->logctx, PKT_OUTGOING, pkt->data[12],
ssh1_pkt_type(pkt->data[12]),
pkt->body, pkt->length - (pkt->body - pkt->data),
- pkt->nblanks, pkt->blanks);
+ pkt->nblanks, pkt->blanks, NULL);
sfree(pkt->blanks); pkt->blanks = NULL;
pkt->nblanks = 0;
static int s_write(Ssh ssh, void *data, int len)
{
if (ssh->logctx)
- log_packet(ssh->logctx, PKT_OUTGOING, -1, NULL, data, len, 0, NULL);
+ log_packet(ssh->logctx, PKT_OUTGOING, -1, NULL, data, len,
+ 0, NULL, NULL);
return sk_write(ssh->s, (char *)data, len);
}
log_packet(ssh->logctx, PKT_OUTGOING, pkt->data[5],
ssh2_pkt_type(ssh->pkt_kctx, ssh->pkt_actx, pkt->data[5]),
pkt->body, pkt->length - (pkt->body - pkt->data),
- pkt->nblanks, pkt->blanks);
+ pkt->nblanks, pkt->blanks, &ssh->v2_outgoing_sequence);
sfree(pkt->blanks); pkt->blanks = NULL;
pkt->nblanks = 0;
if (ssh->cfg.sshbug_maxpkt2 == FORCE_ON ||
(ssh->cfg.sshbug_maxpkt2 == AUTO &&
- (wc_match("1.36_sshlib GlobalSCAPE", imp)))) {
+ (wc_match("1.36_sshlib GlobalSCAPE", imp) ||
+ wc_match("1.36 sshlib: GlobalScape", imp)))) {
/*
* This version ignores our makpkt and needs to be throttled.
*/
/* Log raw data, if we're in that mode. */
if (ssh->logctx)
log_packet(ssh->logctx, PKT_INCOMING, -1, NULL, data, datalen,
- 0, NULL);
+ 0, NULL, NULL);
crBegin(ssh->ssh_gotdata_crstate);
sk_addr_free(addr);
return err;
}
+ ssh->fullhostname = dupstr(*realhost); /* save in case of GSSAPI */
/*
* Open socket.
fflush(stdout); /* FIXME eh? */
{
- if (!*ssh->cfg.username) {
+ if (!get_remote_username(&ssh->cfg, s->username,
+ sizeof(s->username))) {
int ret; /* need not be kept over crReturn */
s->cur_prompt = new_prompts(ssh->frontend);
s->cur_prompt->to_server = TRUE;
memcpy(s->username, s->cur_prompt->prompts[0]->result,
lenof(s->username));
free_prompts(s->cur_prompt);
- } else {
- strncpy(s->username, ssh->cfg.username, sizeof(s->username));
- s->username[sizeof(s->username)-1] = '\0';
}
send_packet(ssh, SSH1_CMSG_USER, PKT_STR, s->username, PKT_END);
c = snew(struct ssh_channel);
c->ssh = ssh;
- if (x11_init(&c->u.x11.s, ssh->cfg.x11_display, c,
- ssh->x11auth, NULL, -1, &ssh->cfg) != NULL) {
+ if (x11_init(&c->u.x11.s, ssh->x11disp, c,
+ NULL, -1, &ssh->cfg) != NULL) {
logevent("Opening X11 forward connection failed");
sfree(c);
send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_FAILURE,
}
}
- if (ssh->cfg.x11_forward) {
- char proto[20], data[64];
+ if (ssh->cfg.x11_forward &&
+ (ssh->x11disp = x11_setup_display(ssh->cfg.x11_display,
+ ssh->cfg.x11_auth, &ssh->cfg))) {
logevent("Requesting X11 forwarding");
- ssh->x11auth = x11_invent_auth(proto, sizeof(proto),
- data, sizeof(data), ssh->cfg.x11_auth);
- x11_get_real_auth(ssh->x11auth, ssh->cfg.x11_display);
/*
* Note that while we blank the X authentication data here, we don't
* take any special action to blank the start of an X11 channel,
*/
if (ssh->v1_local_protoflags & SSH1_PROTOFLAG_SCREEN_NUMBER) {
send_packet(ssh, SSH1_CMSG_X11_REQUEST_FORWARDING,
- PKT_STR, proto,
- PKTT_PASSWORD, PKT_STR, data, PKTT_OTHER,
- PKT_INT, x11_get_screen_number(ssh->cfg.x11_display),
+ PKT_STR, ssh->x11disp->remoteauthprotoname,
+ PKTT_PASSWORD,
+ PKT_STR, ssh->x11disp->remoteauthdatastring,
+ PKTT_OTHER,
+ PKT_INT, ssh->x11disp->screennum,
PKT_END);
} else {
send_packet(ssh, SSH1_CMSG_X11_REQUEST_FORWARDING,
- PKT_STR, proto,
- PKTT_PASSWORD, PKT_STR, data, PKTT_OTHER, PKT_END);
+ PKT_STR, ssh->x11disp->remoteauthprotoname,
+ PKTT_PASSWORD,
+ PKT_STR, ssh->x11disp->remoteauthdatastring,
+ PKTT_OTHER,
+ PKT_END);
}
do {
crReturnV;
if (typelen == 3 && !memcmp(type, "x11", 3)) {
char *addrstr;
+ const char *x11err;
ssh_pkt_getstring(pktin, &peeraddr, &peeraddrlen);
addrstr = snewn(peeraddrlen+1, char);
if (!ssh->X11_fwd_enabled)
error = "X11 forwarding is not enabled";
- else if (x11_init(&c->u.x11.s, ssh->cfg.x11_display, c,
- ssh->x11auth, addrstr, peerport,
- &ssh->cfg) != NULL) {
+ else if ((x11err = x11_init(&c->u.x11.s, ssh->x11disp, c,
+ addrstr, peerport, &ssh->cfg)) != NULL) {
+ logeventf(ssh, "Local X11 connection failed: %s", x11err);
error = "Unable to open an X11 connection";
} else {
logevent("Opening X11 forward connection succeeded");
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;
+#ifndef NO_GSSAPI
+ int can_gssapi;
+ int tried_gssapi;
+#endif
int kbd_inter_refused;
int we_are_in;
prompts_t *cur_prompt;
int try_send;
int num_env, env_left, env_ok;
struct Packet *pktout;
+#ifndef NO_GSSAPI
+ 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;
+#endif
};
crState(do_ssh2_authconn_state);
s->done_service_req = FALSE;
s->we_are_in = FALSE;
+#ifndef NO_GSSAPI
+ s->tried_gssapi = FALSE;
+#endif
+
if (!ssh->cfg.ssh_no_userauth) {
/*
* Request userauth protocol, and await a response to it.
* with change_username turned off we don't try to get
* it again.
*/
- } else if (!*ssh->cfg.username) {
+ } else if (!get_remote_username(&ssh->cfg, s->username,
+ sizeof(s->username))) {
int ret; /* need not be kept over crReturn */
s->cur_prompt = new_prompts(ssh->frontend);
s->cur_prompt->to_server = TRUE;
free_prompts(s->cur_prompt);
} else {
char *stuff;
- strncpy(s->username, ssh->cfg.username, sizeof(s->username));
- s->username[sizeof(s->username)-1] = '\0';
if ((flags & FLAG_VERBOSE) || (flags & FLAG_INTERACTIVE)) {
stuff = dupprintf("Using username \"%s\".\r\n", s->username);
c_write_str(ssh, stuff);
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;
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;
key->alg->freekey(key->data);
}
+#ifndef NO_GSSAPI
+ } else if (s->can_gssapi && !s->tried_gssapi) {
+
+ /* GSSAPI Authentication */
+
+ int micoffset, len;
+ char *data;
+ 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.length + 2);
+ ssh2_pkt_addbyte(s->pktout, SSH2_GSS_OIDTYPE);
+
+ /* length of OID */
+ ssh2_pkt_addbyte(s->pktout, (unsigned char) s->gss_buf.length);
+
+ ssh_pkt_adddata(s->pktout, s->gss_buf.value,
+ s->gss_buf.length);
+ 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, &data, &len);
+ s->gss_rcvtok.value = data;
+ s->gss_rcvtok.length = len;
+ if (s->gss_rcvtok.length != s->gss_buf.length + 2 ||
+ ((char *)s->gss_rcvtok.value)[0] != SSH2_GSS_OIDTYPE ||
+ ((char *)s->gss_rcvtok.value)[1] != s->gss_buf.length ||
+ memcmp((char *)s->gss_rcvtok.value + 2,
+ s->gss_buf.value,s->gss_buf.length) ) {
+ 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 */
+ SSH_GSS_CLEAR_BUF(&s->gss_rcvtok);
+ SSH_GSS_CLEAR_BUF(&s->gss_sndtok);
+
+ /* 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.value);
+ sfree(s->gss_buf.value);
+ }
+
+ break;
+ }
+ logevent("GSSAPI authentication initialised");
+
+ /* Client and server now exchange tokens until GSSAPI
+ * no longer says CONTINUE_NEEDED */
+
+ if (s->gss_sndtok.length != 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.value,s->gss_sndtok.length);
+ 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, &data, &len);
+ s->gss_rcvtok.value = data;
+ s->gss_rcvtok.length = 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.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->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->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) {
/*
ssh_pkt_getstring(pktin, &lang, &lang_len);
s->cur_prompt = new_prompts(ssh->frontend);
s->cur_prompt->to_server = TRUE;
- if (name_len) {
- /* FIXME: better prefix to distinguish from
- * local prompts? */
- s->cur_prompt->name =
- dupprintf("SSH server: %.*s", name_len, name);
- s->cur_prompt->name_reqd = TRUE;
- } else {
- s->cur_prompt->name =
- dupstr("SSH server authentication");
- s->cur_prompt->name_reqd = FALSE;
- }
- /* FIXME: ugly to print "Using..." in prompt _every_
- * time round. Can this be done more subtly? */
- s->cur_prompt->instruction =
- dupprintf("Using keyboard-interactive authentication.%s%.*s",
- inst_len ? "\n" : "", inst_len, inst);
- s->cur_prompt->instr_reqd = TRUE;
/*
- * Get the prompts from the packet.
+ * Get any prompt(s) from the packet.
*/
s->num_prompts = ssh_pkt_getuint32(pktin);
for (i = 0; i < s->num_prompts; i++) {
echo, SSH_MAX_PASSWORD_LEN);
}
+ if (name_len) {
+ /* FIXME: better prefix to distinguish from
+ * local prompts? */
+ s->cur_prompt->name =
+ dupprintf("SSH server: %.*s", name_len, name);
+ s->cur_prompt->name_reqd = TRUE;
+ } else {
+ s->cur_prompt->name =
+ dupstr("SSH server authentication");
+ s->cur_prompt->name_reqd = FALSE;
+ }
+ /* We add a prefix to try to make it clear that a prompt
+ * has come from the server.
+ * FIXME: ugly to print "Using..." in prompt _every_
+ * time round. Can this be done more subtly? */
+ /* Special case: for reasons best known to themselves,
+ * some servers send k-i requests with no prompts and
+ * nothing to display. Keep quiet in this case. */
+ if (s->num_prompts || name_len || inst_len) {
+ s->cur_prompt->instruction =
+ dupprintf("Using keyboard-interactive authentication.%s%.*s",
+ inst_len ? "\n" : "", inst_len, inst);
+ s->cur_prompt->instr_reqd = TRUE;
+ } else {
+ s->cur_prompt->instr_reqd = FALSE;
+ }
+
/*
- * Get the user's responses.
+ * Display any instructions, and get the user's
+ * response(s).
*/
- if (s->num_prompts) {
+ {
int ret; /* not live over crReturn */
ret = get_userpass_input(s->cur_prompt, NULL, 0);
while (ret < 0) {
}
/*
- * Send the responses to the server.
+ * Send the response(s) to the server.
*/
s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_INFO_RESPONSE);
ssh2_pkt_adduint32(s->pktout, s->num_prompts);
/*
* Potentially enable X11 forwarding.
*/
- if (ssh->mainchan && !ssh->ncmode && ssh->cfg.x11_forward) {
- char proto[20], data[64];
+ if (ssh->mainchan && !ssh->ncmode && ssh->cfg.x11_forward &&
+ (ssh->x11disp = x11_setup_display(ssh->cfg.x11_display,
+ ssh->cfg.x11_auth, &ssh->cfg))) {
logevent("Requesting X11 forwarding");
- ssh->x11auth = x11_invent_auth(proto, sizeof(proto),
- data, sizeof(data), ssh->cfg.x11_auth);
- x11_get_real_auth(ssh->x11auth, ssh->cfg.x11_display);
s->pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST);
ssh2_pkt_adduint32(s->pktout, ssh->mainchan->remoteid);
ssh2_pkt_addstring(s->pktout, "x11-req");
ssh2_pkt_addbool(s->pktout, 1); /* want reply */
ssh2_pkt_addbool(s->pktout, 0); /* many connections */
- ssh2_pkt_addstring(s->pktout, proto);
+ ssh2_pkt_addstring(s->pktout, ssh->x11disp->remoteauthprotoname);
/*
* Note that while we blank the X authentication data here, we don't
* take any special action to blank the start of an X11 channel,
* cookie into the log.
*/
dont_log_password(ssh, s->pktout, PKTLOG_BLANK);
- ssh2_pkt_addstring(s->pktout, data);
+ ssh2_pkt_addstring(s->pktout, ssh->x11disp->remoteauthdatastring);
end_log_omission(ssh, s->pktout);
- ssh2_pkt_adduint32(s->pktout, x11_get_screen_number(ssh->cfg.x11_display));
+ ssh2_pkt_adduint32(s->pktout, ssh->x11disp->screennum);
ssh2_pkt_send(ssh, s->pktout);
crWaitUntilV(pktin);
ssh->fallback_cmd = 0;
ssh->pkt_kctx = SSH2_PKTCTX_NOKEX;
ssh->pkt_actx = SSH2_PKTCTX_NOAUTH;
- ssh->x11auth = NULL;
+ ssh->x11disp = NULL;
ssh->v1_compressing = FALSE;
ssh->v2_outgoing_sequence = 0;
ssh->ssh1_rdpkt_crstate = 0;
ssh->rportfwds = NULL;
}
sfree(ssh->deferred_send_data);
- if (ssh->x11auth)
- x11_free_auth(ssh->x11auth);
+ if (ssh->x11disp)
+ x11_free_display(ssh->x11disp);
sfree(ssh->do_ssh_init_state);
sfree(ssh->do_ssh1_login_state);
sfree(ssh->do_ssh2_transport_state);
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;