&send_tok, NULL));
packet_check_eom();
- if (GSS_ERROR(maj_status)) {
- /* Failure <sniff> */
- ssh_gssapi_send_error(gssctxt->oid,maj_status,min_status);
- authctxt->postponed = 0;
- dispatch_set(SSH_MSG_AUTH_GSSAPI_TOKEN, NULL);
- dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
- userauth_finish(authctxt, 0, "gssapi");
- }
-
if (send_tok.length != 0) {
/* Send a packet back to the client */
if (!compat20)
gss_release_buffer(&min_status, &send_tok);
}
+ if (GSS_ERROR(maj_status)) {
+ /* Failure <sniff> */
+ if (gssctxt) { /* may be NULL under privsep */
+ ssh_gssapi_send_error(gssctxt->oid,maj_status,min_status);
+ } else {
+ ssh_gssapi_send_error(GSS_C_NO_OID,maj_status,min_status);
+ }
+ authctxt->postponed = 0;
+ dispatch_set(SSH_MSG_AUTH_GSSAPI_TOKEN, NULL);
+ dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
+ userauth_finish(authctxt, 0, "gssapi");
+ }
+
if (maj_status == GSS_S_COMPLETE) {
dispatch_set(SSH_MSG_AUTH_GSSAPI_TOKEN, NULL);
dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN,NULL);
if (datafellows & SSH_OLD_GSSAPI) return NULL;
- gss_indicate_mechs(&min_status, &supported);
+ PRIVSEP(gss_indicate_mechs(&min_status, &supported));
buffer_init(&buf);
gss_OID_set supported;
gss_create_empty_oid_set(&min_status,oidset);
- gss_indicate_mechs(&min_status, &supported);
+ PRIVSEP(gss_indicate_mechs(&min_status, &supported));
while (supported_mechs[i].name!=NULL) {
if ((maj_status=gss_test_oid_set_member(&min_status,
ctx = 0;
/* The GSSAPI error */
do {
- lmaj = gss_display_status(&lmin, major_status,
- GSS_C_GSS_CODE,
- mech,
- &ctx, &msg);
+ lmaj = PRIVSEP(gss_display_status(&lmin, major_status,
+ GSS_C_GSS_CODE,
+ mech,
+ &ctx, &msg));
if (lmaj == GSS_S_COMPLETE) {
debug((char *)msg.value);
if (send_packet) packet_send_debug((char *)msg.value);
/* The mechanism specific error */
do {
- lmaj = gss_display_status(&lmin, minor_status,
- GSS_C_MECH_CODE,
- mech,
- &ctx, &msg);
+ lmaj = PRIVSEP(gss_display_status(&lmin, minor_status,
+ GSS_C_MECH_CODE,
+ mech,
+ &ctx, &msg));
if (lmaj == GSS_S_COMPLETE) {
debug((char *)msg.value);
if (send_packet) packet_send_debug((char *)msg.value);
void
ssh_gssapi_delete_ctx(Gssctxt **ctx)
{
+#if !defined(MECHGLUE)
OM_uint32 ms;
+#endif
/* Return if there's no context */
if ((*ctx)==NULL)
gss_buffer_desc *send_tok, OM_uint32 *flags)
{
OM_uint32 maj_status, min_status;
+ gss_OID mech;
maj_status=gss_accept_sec_context(&min_status,
&ctx->context,
recv_tok,
GSS_C_NO_CHANNEL_BINDINGS,
&ctx->client,
- &ctx->oid,
+ &mech, /* read-only pointer */
send_tok,
flags,
NULL,
&ctx->creds,
NULL,
NULL))) {
- ssh_gssapi_error(GSS_C_NO_OID,maj_status,min_status);
+ ssh_gssapi_error(ctx->oid,maj_status,min_status);
}
gss_release_oid_set(&min_status, &oidset);
*type=ssh_gssapi_get_ctype(ctx);
if ((maj_status=gss_display_name(&min_status,ctx->client,name,NULL))) {
- ssh_gssapi_error(GSS_C_NO_OID,maj_status,min_status);
+ ssh_gssapi_error(ctx->oid,maj_status,min_status);
}
/* This is icky. There appears to be no way to copy this structure,
} while (maj_status & GSS_S_CONTINUE_NEEDED);
if (GSS_ERROR(maj_status)) {
- ssh_gssapi_send_error(ctxt->oid,maj_status,min_status);
+ ssh_gssapi_send_error(oid,maj_status,min_status);
packet_disconnect("gssapi key exchange handshake failed");
}
debug("gss_complete");
if (!(ret_flags & GSS_C_MUTUAL_FLAG)) {
- ssh_gssapi_send_error(ctxt->oid,maj_status,min_status);
+ ssh_gssapi_send_error(oid,maj_status,min_status);
packet_disconnect("gssapi mutual authentication failed");
}
if (!(ret_flags & GSS_C_INTEG_FLAG)) {
- ssh_gssapi_send_error(ctxt->oid,maj_status,min_status);
+ ssh_gssapi_send_error(oid,maj_status,min_status);
packet_disconnect("gssapi channel integrity not established");
}
gssbuf.length = 20; /* Hashlen appears to always be 20 */
if (GSS_ERROR(PRIVSEP(ssh_gssapi_sign(ctxt,&gssbuf,&msg_tok)))) {
- ssh_gssapi_send_error(ctxt->oid,maj_status,min_status);
+ 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");
}
int mm_answer_gss_userok(int, Buffer *);
int mm_answer_gss_localname(int, Buffer *);
int mm_answer_gss_sign(int, Buffer *);
+int mm_answer_gss_indicate_mechs(int, Buffer *);
+int mm_answer_gss_display_status(int, Buffer *);
#endif
#ifdef GSI
{MONITOR_REQ_GSSSETUP, MON_ISAUTH, mm_answer_gss_setup_ctx},
{MONITOR_REQ_GSSSTEP, MON_ISAUTH, mm_answer_gss_accept_ctx},
{MONITOR_REQ_GSSSIGN, MON_ONCE, mm_answer_gss_sign},
+ {MONITOR_REQ_GSSMECHS, MON_ISAUTH, mm_answer_gss_indicate_mechs},
+ {MONITOR_REQ_GSSSTAT, MON_ISAUTH, mm_answer_gss_display_status},
{MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok},
{MONITOR_REQ_GSSLOCALNAME, MON_AUTH, mm_answer_gss_localname},
#endif
{MONITOR_REQ_GSSSETUP, 0, mm_answer_gss_setup_ctx},
{MONITOR_REQ_GSSSTEP, 0, mm_answer_gss_accept_ctx},
{MONITOR_REQ_GSSSIGN, 0, mm_answer_gss_sign},
+ {MONITOR_REQ_GSSMECHS, 0, mm_answer_gss_indicate_mechs},
+ {MONITOR_REQ_GSSSTAT, 0, mm_answer_gss_display_status},
#endif
{MONITOR_REQ_MODULI, 0, mm_answer_moduli},
{MONITOR_REQ_SIGN, 0, mm_answer_sign},
{MONITOR_REQ_GSSSTEP, MON_ISAUTH, mm_answer_gss_accept_ctx},
{MONITOR_REQ_GSSSIGN, MON_ONCE, mm_answer_gss_sign},
{MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok},
+ {MONITOR_REQ_GSSMECHS, MON_ISAUTH, mm_answer_gss_indicate_mechs},
+ {MONITOR_REQ_GSSSTAT, MON_ISAUTH, mm_answer_gss_display_status},
#endif
#ifdef GSI
{MONITOR_REQ_GSIGRIDMAP, MON_PERMIT, mm_answer_gsi_gridmap},
{MONITOR_REQ_GSSSETUP, 0, mm_answer_gss_setup_ctx},
{MONITOR_REQ_GSSSTEP, 0, mm_answer_gss_accept_ctx},
{MONITOR_REQ_GSSSIGN, 0, mm_answer_gss_sign},
+ {MONITOR_REQ_GSSMECHS, 0, mm_answer_gss_indicate_mechs},
+ {MONITOR_REQ_GSSSTAT, 0, mm_answer_gss_display_status},
#endif
{MONITOR_REQ_PTY, MON_ONCE, mm_answer_pty},
{MONITOR_REQ_PTYCLEANUP, MON_ONCE, mm_answer_pty_cleanup},
monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1);
monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 1);
monitor_permit(mon_dispatch, MONITOR_REQ_GSSSIGN, 1);
+ monitor_permit(mon_dispatch, MONITOR_REQ_GSSMECHS, 1);
+ monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTAT, 1);
#endif
} else {
mon_dispatch = mon_dispatch_proto15;
monitor_permit(mon_dispatch, MONITOR_REQ_SESSKEY, 1);
#ifdef GSSAPI
monitor_permit(mon_dispatch, MONITOR_REQ_GSSSIGN, 1);
+ monitor_permit(mon_dispatch, MONITOR_REQ_GSSMECHS, 1);
+ monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTAT, 1);
#endif
#ifdef GSI
monitor_permit(mon_dispatch, MONITOR_REQ_GSIGRIDMAP, 1);
mon_dispatch = mon_dispatch_postauth15;
monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1);
}
+#ifdef GSSAPI
+ monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTAT, 1);
+#endif
if (!no_pty_flag) {
monitor_permit(mon_dispatch, MONITOR_REQ_PTY, 1);
monitor_permit(mon_dispatch, MONITOR_REQ_PTYCLEANUP, 1);
return(0);
}
+int
+mm_answer_gss_indicate_mechs(int socket, Buffer *m) {
+ OM_uint32 major,minor;
+ gss_OID_set mech_set;
+ int i;
+
+ major=gss_indicate_mechs(&minor, &mech_set);
+
+ buffer_clear(m);
+ buffer_put_int(m, major);
+ buffer_put_int(m, mech_set->count);
+ for (i=0; i < mech_set->count; i++) {
+ buffer_put_string(m, mech_set->elements[i].elements,
+ mech_set->elements[i].length);
+ }
+
+ mm_request_send(socket,MONITOR_ANS_GSSMECHS,m);
+
+ return(0);
+}
+
+int
+mm_answer_gss_display_status(int socket, Buffer *m) {
+ OM_uint32 major,minor,status_value,message_context;
+ int status_type;
+ gss_OID_desc mech_type_desc;
+ gss_OID mech_type;
+ gss_buffer_desc status_string;
+ u_int length;
+
+ status_value = buffer_get_int(m);
+ status_type = buffer_get_int(m);
+ mech_type_desc.elements = buffer_get_string(m, &length);
+ mech_type_desc.length = length;
+ if (length != 0) {
+ mech_type = &mech_type_desc;
+ } else if (gsscontext) {
+ mech_type = gsscontext->oid;
+ } else {
+ mech_type = GSS_C_NO_OID;
+ }
+ message_context = buffer_get_int(m);
+
+ major=gss_display_status(&minor, status_value, status_type, mech_type,
+ &message_context, &status_string);
+
+ buffer_clear(m);
+ buffer_put_int(m, message_context);
+ buffer_put_string(m, status_string.value, status_string.length);
+
+ mm_request_send(socket,MONITOR_ANS_GSSSTAT,m);
+
+ if (mech_type_desc.elements) {
+ xfree(mech_type_desc.elements);
+ }
+
+ return 0;
+}
+
#endif /* GSSAPI */
#ifdef GSI
MONITOR_REQ_GSSSETUP,MONITOR_ANS_GSSSETUP,
MONITOR_REQ_GSSSTEP,MONITOR_ANS_GSSSTEP,
MONITOR_REQ_GSSSIGN,MONITOR_ANS_GSSSIGN,
+ MONITOR_REQ_GSSMECHS,MONITOR_ANS_GSSMECHS,
+ MONITOR_REQ_GSSSTAT,MONITOR_ANS_GSSSTAT,
MONITOR_REQ_GSSUSEROK,MONITOR_ANS_GSSUSEROK,
MONITOR_REQ_GSSLOCALNAME,MONITOR_ANS_GSSLOCALNAME,
MONITOR_REQ_GSIGRIDMAP,MONITOR_ANS_GSIGRIDMAP,
return(major);
}
+
+OM_uint32
+mm_gss_indicate_mechs(OM_uint32 *minor_status, gss_OID_set *mech_set)
+{
+ Buffer m;
+ OM_uint32 major;
+ int i=0;
+
+ buffer_init(&m);
+
+ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSMECHS, &m);
+
+ debug3("%s: waiting for MONITOR_ANS_GSSMECHS",__func__);
+ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSMECHS,
+ &m);
+ major=buffer_get_int(&m);
+ *mech_set = xmalloc(sizeof(gss_OID_set_desc));
+ (*mech_set)->count=buffer_get_int(&m);
+ (*mech_set)->elements=xmalloc(sizeof(gss_OID_desc)*(*mech_set)->count);
+ for (i=0; i < (*mech_set)->count; i++) {
+ u_int length;
+ (*mech_set)->elements[i].elements=buffer_get_string(&m, &length);
+ (*mech_set)->elements[i].length = length;
+ }
+
+ return(major);
+}
+
+OM_uint32
+mm_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)
+{
+ Buffer m;
+ OM_uint32 major;
+
+ buffer_init(&m);
+
+ buffer_put_int(&m, status_value);
+ buffer_put_int(&m, status_type);
+ if (mech_type) {
+ buffer_put_string(&m, mech_type->elements, mech_type->length);
+ } else {
+ buffer_put_string(&m, "", 0);
+ }
+ if (message_context) {
+ buffer_put_int(&m, *message_context);
+ } else {
+ buffer_put_int(&m, 0);
+ }
+
+ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSSTAT, &m);
+
+ debug3("%s: waiting for MONITOR_ANS_GSSMECHS",__func__);
+ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSSTAT,
+ &m);
+
+ if (message_context) {
+ *message_context = buffer_get_int(&m);
+ } else {
+ buffer_get_int(&m);
+ }
+ status_string->value = buffer_get_string(&m, &status_string->length);
+
+ return major;
+}
#endif /* GSSAPI */
#ifdef GSI
gss_buffer_desc *hash);
int mm_ssh_gssapi_userok(char *user);
int mm_ssh_gssapi_localname(char **user);
+OM_uint32 mm_gss_indicate_mechs(OM_uint32 *minor_status,
+ gss_OID_set *mech_set);
+OM_uint32 mm_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);
#endif
#ifdef GSI
oKerberosAuthentication,
#endif
#ifdef GSSAPI
- oGssAuthentication, oGssDelegateCreds,
+ oGssAuthentication, oGssKeyEx, oGssDelegateCreds,
#ifdef GSI
oGssGlobusDelegateLimitedCreds,
#endif /* GSI */
#endif
#ifdef GSSAPI
{ "gssapiauthentication", oGssAuthentication },
+ { "gssapikeyexchange", oGssKeyEx },
{ "gssapidelegatecredentials", oGssDelegateCreds },
#ifdef GSI
/* For backwards compatability with old 1.2.27 client code */
intptr = &options->gss_authentication;
goto parse_flag;
+ case oGssKeyEx:
+ intptr = &options->gss_keyex;
+ goto parse_flag;
+
case oGssDelegateCreds:
intptr = &options->gss_deleg_creds;
goto parse_flag;
options->challenge_response_authentication = -1;
#ifdef GSSAPI
options->gss_authentication = -1;
+ options->gss_keyex = -1;
options->gss_deleg_creds = -1;
#ifdef GSI
options->gss_globus_deleg_limited_proxy = -1;
#ifdef GSSAPI
if (options->gss_authentication == -1)
options->gss_authentication = 1;
+ if (options->gss_keyex == -1)
+ options->gss_keyex = 1;
if (options->gss_deleg_creds == -1)
options->gss_deleg_creds = 1;
#ifdef GSI
#ifdef GSSAPI
int gss_authentication;
+ int gss_keyex;
int gss_deleg_creds;
#ifdef GSI
int gss_globus_deleg_limited_proxy;
authentication.
The default is
.Dq yes .
+.It Cm GssapiKeyExchange
+Specifies whether key exchange based on GSSAPI may be used. When using
+GSSAPI key exchange the server need not have a host key.
+The default is
+.Dq yes .
.It Cm GssapiDelegateCredentials
Specifies whether GSSAPI credentials will be delegated (forwarded) to
the server.
xxx_hostaddr = hostaddr;
#ifdef GSSAPI
+ if (options.gss_keyex) {
/* Add the GSSAPI mechanisms currently supported on this client to
* the key exchange algorithm proposal */
orig = myproposal[PROPOSAL_KEX_ALGS];
myproposal[PROPOSAL_KEX_ALGS]=xmalloc(len);
snprintf(myproposal[PROPOSAL_KEX_ALGS],len,"%s,%s",gss,orig);
}
+ }
#endif
if (options.ciphers == (char *)-1) {
#ifdef GSSAPI
/* If we've got GSSAPI algorithms, then we also support the
* 'null' hostkey, as a last resort */
- if (gss) {
+ if (options.gss_keyex && gss) {
orig=myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS];
len = strlen(orig)+sizeof(",null");
myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]=xmalloc(len);
int
userauth_gssapi(Authctxt *authctxt)
{
- int i;
Gssctxt *gssctxt;
- static int tries=0;
-
- /* For now, we only make one attempt at this. We could try offering
- * the server different GSSAPI OIDs until we get bored, I suppose.
- */
- if (tries++>0) return 0;
+ static int mech=0;
if (datafellows & SSH_OLD_GSSAPI) return 0;
+ /* Try each mechanism in turn. Give up if we've tried all
+ supported mechanisms.
+ */
+ if (mech==GSS_LAST_ENTRY) return 0;
+
/* Initialise as much of our context as we can, so failures can be
* trapped before sending any packets.
*/
* This may not be the case - we should use something along
* the lines of the code in gss_genr to remove the ones that
* aren't supported */
- packet_put_int(GSS_LAST_ENTRY);
- for (i=0;i<GSS_LAST_ENTRY;i++) {
- packet_put_string(supported_mechs[i].oid.elements,
- supported_mechs[i].oid.length);
- }
+
+ /* Try one GSSAPI mechanism at a time. */
+ packet_put_int(1);
+ packet_put_string(supported_mechs[mech].oid.elements,
+ supported_mechs[mech].oid.length);
packet_send();
packet_write_wait();
dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE,&input_gssapi_response);
dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN,&input_gssapi_token);
+ mech++; /* Move to next mechanism for next time. */
+
return 1;
}
u_int slen;
if (authctxt == NULL)
- fatal("input_gssapi_response: no authentication context");
+ fatal("input_gssapi_token: no authentication context");
gssctxt = authctxt->methoddata;
recv_tok.value=packet_get_string(&slen);