/*
- * Copyright (c) 2001,2002 Simon Wilkinson. All rights reserved.
+ * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
#include "ssh2.h"
#include "ssh-gss.h"
#include "monitor_wrap.h"
-#include "canohost.h"
+
+static void kex_gss_send_error(Gssctxt *ctxt);
void
kexgss_server(Kex *kex)
{
-
OM_uint32 maj_status, min_status;
/* Some GSSAPI implementations use the input value of ret_flags (an
- * output variable) as a means of triggering mechanism specific
- * features. Initializing it to zero avoids inadvertently
- * activating this non-standard behaviour.*/
+ * output variable) as a means of triggering mechanism specific
+ * features. Initializing it to zero avoids inadvertently
+ * activating this non-standard behaviour.*/
OM_uint32 ret_flags = 0;
gss_buffer_desc gssbuf,send_tok,recv_tok,msg_tok;
BIGNUM *shared_secret = NULL;
BIGNUM *dh_client_pub = NULL;
int type =0;
- gss_OID oid;
u_int slen;
+ gss_OID oid;
/* Initialise GSSAPI */
debug2("%s: Acquiring credentials",__func__);
- if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt,oid))))
- packet_disconnect("Unable to acquire credentials for the server");
-
+ if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt,oid)))) {
+ kex_gss_send_error(ctxt);
+ packet_disconnect("Unable to acquire credentials for the server");
+ }
+
do {
debug("Wait SSH2_MSG_GSSAPI_INIT");
type = packet_read();
dh_client_pub = BN_new();
if (dh_client_pub == NULL)
- fatal("dh_client_pub == NULL");
+ packet_disconnect("dh_client_pub == NULL");
packet_get_bignum2(dh_client_pub);
/* Send SSH_MSG_KEXGSS_HOSTKEY here, if we want */
}
maj_status=PRIVSEP(ssh_gssapi_accept_ctx(ctxt,&recv_tok,
- &send_tok, &ret_flags));
+ &send_tok, &ret_flags));
gss_release_buffer(&min_status,&recv_tok);
-
+
#ifdef GSS_C_GLOBUS_LIMITED_PROXY_FLAG
if (ret_flags & GSS_C_GLOBUS_LIMITED_PROXY_FLAG) {
packet_disconnect("Limited proxy is not allowed in gssapi key exchange.");
}
#endif
-
- if (maj_status & GSS_S_CONTINUE_NEEDED) {
+
+ if ((maj_status & GSS_S_CONTINUE_NEEDED) ||
+ (GSS_ERROR(maj_status) && send_tok.length>0)) {
debug("Sending GSSAPI_CONTINUE");
packet_start(SSH2_MSG_KEXGSS_CONTINUE);
packet_put_string(send_tok.value,send_tok.length);
} while (maj_status & GSS_S_CONTINUE_NEEDED);
if (GSS_ERROR(maj_status)) {
- ssh_gssapi_send_error(oid,maj_status,min_status);
+ kex_gss_send_error(ctxt);
packet_disconnect("gssapi key exchange handshake failed");
}
-
+
debug("gss_complete");
- if (!(ret_flags & GSS_C_MUTUAL_FLAG)) {
- ssh_gssapi_send_error(oid,maj_status,min_status);
- packet_disconnect("gssapi mutual authentication failed");
- }
+ if (!(ret_flags & GSS_C_MUTUAL_FLAG))
+ packet_disconnect("gssapi_mutual authentication failed");
- if (!(ret_flags & GSS_C_INTEG_FLAG)) {
- ssh_gssapi_send_error(oid,maj_status,min_status);
+ if (!(ret_flags & GSS_C_INTEG_FLAG))
packet_disconnect("gssapi channel integrity not established");
- }
-
+
dh = dh_new_group1();
dh_gen_key(dh, kex->we_need * 8);
memset(kbuf, 0, klen);
xfree(kbuf);
- hash = kex_gssapi_hash(
+ /* The GSSAPI hash is identical to the Diffie Helman one */
+ hash = kex_dh_hash(
kex->client_version_string,
kex->server_version_string,
buffer_ptr(&kex->peer), buffer_len(&kex->peer),
gssbuf.length = 20; /* Hashlen appears to always be 20 */
if (GSS_ERROR(PRIVSEP(ssh_gssapi_sign(ctxt,&gssbuf,&msg_tok)))) {
- if (ctxt) { /* may be NULL under privsep */
- ssh_gssapi_send_error(ctxt->oid,maj_status,min_status);
- } else {
- ssh_gssapi_send_error(GSS_C_NO_OID,maj_status,min_status);
- }
- packet_disconnect("Couldn't get MIC");
+ kex_gss_send_error(ctxt);
+ fatal("Couldn't get MIC");
}
packet_start(SSH2_MSG_KEXGSS_COMPLETE);
gss_release_buffer(&min_status, &send_tok);
/* If we've got a context, delete it. It may be NULL if we've been
- * using privsep */
+ * using privsep */
ssh_gssapi_delete_ctx(&ctxt);
DH_free(dh);
kex_finish(kex);
}
+static void
+kex_gss_send_error(Gssctxt *ctxt) {
+ char *errstr;
+ OM_uint32 maj,min;
+
+ errstr=PRIVSEP(ssh_gssapi_last_error(ctxt,&maj,&min));
+ if (errstr) {
+ packet_start(SSH2_MSG_KEXGSS_ERROR);
+ packet_put_int(maj);
+ packet_put_int(min);
+ packet_put_cstring(errstr);
+ packet_put_cstring("");
+ packet_send();
+ packet_write_wait();
+ /* XXX - We should probably log the error locally here */
+ xfree(errstr);
+ }
+}
#endif /* GSSAPI */