static void ssh_gssapi_userauth_error(Gssctxt *ctxt);
static void input_gssapi_token(int type, u_int32_t plen, void *ctxt);
static void input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt);
+static void input_gssapi_errtok(int, u_int32_t, void *);
/* We only support those mechanisms that we know about (ie ones that we know
* how to check local user kuserok and the like
doid = packet_get_string(&len);
debug("Got string");
- if (datafellows & SSH_BUG_GSSAPI_BER) {
- oid.elements = doid;
- oid.length = len;
- } else {
- if (doid[0]!=0x06 || doid[1]!=len-2) {
- debug("Badly encoded mechanism OID received");
- oid.elements=NULL;
- } else {
- oid.elements = doid + 2;
- oid.length = len - 2;
- gss_test_oid_set_member(&ms, &oid, supported, &present);
- }
- }
- if (oid.elements) {
- gss_test_oid_set_member(&ms, &oid, supported, &present);
- }
+ if (doid[0]!=0x06 || doid[1]!=len-2) {
+ log("Mechanism OID received using the old encoding form");
+ oid.elements = doid;
+ oid.length = len;
+ } else {
+ oid.elements = doid + 2;
+ oid.length = len - 2;
+ }
+ gss_test_oid_set_member(&ms, &oid, supported, &present);
} while (mechs>0 && !present);
if (!present) {
packet_start(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE);
- if (datafellows & SSH_BUG_GSSAPI_BER) {
- packet_put_string(oid.elements,oid.length);
- } else {
- packet_put_string(doid,len);
- }
+ /* Just return whatever they sent */
+ packet_put_string(doid,len);
} /* !compat20 */
else
dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN,
&input_gssapi_token);
+ dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK,
+ &input_gssapi_errtok);
authctxt->postponed = 1;
return 0;
recv_tok.length=len; /* int vs. size_t */
maj_status=PRIVSEP(ssh_gssapi_accept_ctx(gssctxt, &recv_tok,
- &send_tok, NULL));
+ &send_tok, NULL));
packet_check_eom();
- if (send_tok.length != 0) {
- /* Send a packet back to the client, even if there has
- * been an error, as this may contain mechanism specific
- * error information */
- if (!compat20)
- packet_start(SSH_MSG_AUTH_GSSAPI_TOKEN);
- else
- packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN);
- packet_put_string(send_tok.value,send_tok.length);
- packet_send();
- packet_write_wait();
- gss_release_buffer(&min_status, &send_tok);
- }
-
if (GSS_ERROR(maj_status)) {
- ssh_gssapi_userauth_error(gssctxt);
+ ssh_gssapi_userauth_error(gssctxt);
+ if (send_tok.length != 0) {
+ if (!compat20)
+ packet_start(SSH_MSG_AUTH_GSSAPI_TOKEN);
+ else
+ packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK);
+ packet_put_string(send_tok.value,send_tok.length);
+ packet_send();
+ packet_write_wait();
+ }
authctxt->postponed = 0;
dispatch_set(SSH_MSG_AUTH_GSSAPI_TOKEN, NULL);
dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
userauth_finish(authctxt, 0, "gssapi");
+ } else {
+ if (send_tok.length != 0) {
+ if (!compat20)
+ packet_start(SSH_MSG_AUTH_GSSAPI_TOKEN);
+ else
+ packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN);
+ packet_put_string(send_tok.value,send_tok.length);
+ packet_send();
+ packet_write_wait();
+ }
+ if (maj_status == GSS_S_COMPLETE) {
+ dispatch_set(SSH_MSG_AUTH_GSSAPI_TOKEN, NULL);
+ dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN,NULL);
+ if (!compat20)
+ input_gssapi_exchange_complete(0, 0, ctxt);
+ else
+ dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE,
+ &input_gssapi_exchange_complete);
+ }
}
+
+ gss_release_buffer(&min_status, &send_tok);
+}
- if (maj_status == GSS_S_COMPLETE) {
- dispatch_set(SSH_MSG_AUTH_GSSAPI_TOKEN, NULL);
- dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN,NULL);
- /* ssh1 does not have an extra message here */
- if (!compat20)
- input_gssapi_exchange_complete(0, 0, ctxt);
- else
- dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE,
- &input_gssapi_exchange_complete);
- }
+static void
+input_gssapi_errtok(int type, u_int32_t plen, void *ctxt)
+{
+ Authctxt *authctxt = ctxt;
+ Gssctxt *gssctxt;
+ gss_buffer_desc send_tok,recv_tok;
+ OM_uint32 maj_status;
+
+ if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
+ fatal("No authentication or GSSAPI context");
+
+ gssctxt=authctxt->methoddata;
+ recv_tok.value=packet_get_string(&recv_tok.length);
+
+ /* Push the error token into GSSAPI to see what it says */
+ maj_status=PRIVSEP(ssh_gssapi_accept_ctx(gssctxt, &recv_tok,
+ &send_tok, NULL));
+ packet_check_eom();
+
+ /* We can't return anything to the client, even if we wanted to */
+ dispatch_set(SSH_MSG_AUTH_GSSAPI_TOKEN, NULL);
+ dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
+ dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK,NULL);
+
+ /* The client will have already moved on to the next auth */
+
}
/* This is called when the client thinks we've completed authentication.
finish:
authctxt->postponed = 0;
dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
+ dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL);
dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL);
userauth_finish(authctxt, authenticated, "gssapi");
}
errstr=PRIVSEP(ssh_gssapi_last_error(ctxt,&maj,&min));
if (errstr) {
+ if (!compat20) {
+ packet_send_debug(errstr);
+ } else {
packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERROR);
packet_put_int(maj);
packet_put_int(min);
packet_send();
packet_write_wait();
xfree(errstr);
+ }
}
}
ssh_gssapi_check_mechanism(&(supported->elements[i]),host)) {
/* Earlier versions of this code interpreted the
- * spec incorrectly with regard to OID encoding. They
- * also mis-encoded the krb5 OID. The following
- * _temporary_ code interfaces with these broken
- * servers */
+ * spec incorrectly with regard to OID encoding. They
+ * also mis-encoded the krb5 OID. The following
+ * _temporary_ code interfaces with these broken
+ * servers */
if (datafellows & SSH_BUG_GSSAPI_BER) {
char *bodge=NULL;
EVP_DigestInit(&md, evp_md);
EVP_DigestUpdate(&md,deroid,2);
EVP_DigestUpdate(&md,
- supported->elements[i].elements,
- supported->elements[i].length);
+ supported->elements[i].elements,
+ supported->elements[i].length);
EVP_DigestFinal(&md, digest, NULL);
/* Base64 encode it */
char *xhost;
/* Make a copy of the host name, in case it was returned by a
- * previous call to gethostbyname(). */
+ * previous call to gethostbyname(). */
xhost = xstrdup(host);
/* Make sure we have the FQDN. Some GSSAPI implementations don't do
- * this for us themselves */
+ * this for us themselves */
resolve_localhost(&xhost);
gssbuf.length = sizeof("host@")+strlen(xhost);
}
if ((ctx->major=gss_acquire_cred(&ctx->minor,
- ctx->name,
+ ctx->name,
0,
oidset,
GSS_C_ACCEPT,
* that stores the results (in an expanded Gssctxt structure), which are
* then used by the first calls if that key exchange mechanism is chosen.
*/
-
+
+/* Unpriviledged */
char *
ssh_gssapi_server_mechanisms() {
gss_OID_set supported;
return(mechs);
}
+/* Unpriviledged */
void ssh_gssapi_supported_oids(gss_OID_set *oidset) {
int i =0;
OM_uint32 maj_status,min_status;
/* Find out which GSS type (out of the list we define in ssh-gss.h) a
* particular connection is using
*/
+
+/* Priviledged (called ssh_gssapi_accept_ctx -> ssh_gssapi_getclient ->) */
ssh_gssapi_mech *
ssh_gssapi_get_ctype(Gssctxt *ctxt) {
int i=0;
return NULL;
}
-/* Set the GSS context's OID to the oid indicated by the given key exchange
- * name. */
+/* Return the OID that corresponds to the given context name */
+/* Unpriviledged */
gss_OID
-ssh_gssapi_id_kex(Gssctxt *ctx, char *name) {
+ssh_gssapi_server_id_kex(char *name) {
int i=0;
if (strncmp(name, KEX_GSS_SHA1, sizeof(KEX_GSS_SHA1)-1) !=0) {
name+=sizeof(KEX_GSS_SHA1)-1; /* Move to the start of the MIME string */
while (supported_mechs[i]->name!=NULL &&
- strcmp(name,supported_mechs[i]->enc_name)!=0) {
+ strcmp(name,supported_mechs[i]->enc_name)!=0) {
i++;
}
if (supported_mechs[i]->name==NULL)
return (NULL);
- if (ctx) ssh_gssapi_set_oid(ctx,&supported_mechs[i]->oid);
-
debug("using GSSAPI mechanism %s (%s%s)", supported_mechs[i]->name,
KEX_GSS_SHA1, supported_mechs[i]->enc_name);
return &supported_mechs[i]->oid;
}
-/* Wrapper arround accept_sec_context
+/* Wrapper around accept_sec_context
* Requires that the context contains:
* oid
* credentials (from ssh_gssapi_acquire_cred)
*/
+/* Priviledged */
OM_uint32 ssh_gssapi_accept_ctx(Gssctxt *ctx,gss_buffer_desc *recv_tok,
gss_buffer_desc *send_tok, OM_uint32 *flags)
{
}
/* FIXME: We should check that the me
- * the one that we asked for (in ctx->oid) */
+ * the one that we asked for (in ctx->oid) */
status=ctx->major;
/* Now, if we're complete and we have the right flags, then
- * we flag the user as also having been authenticated
- */
+ * we flag the user as also having been authenticated
+ */
if (((flags==NULL) || ((*flags & GSS_C_MUTUAL_FLAG) &&
(*flags & GSS_C_INTEG_FLAG))) &&
/* Extract the client details from a given context. This can only reliably
* be called once for a context */
+/* Priviledged (called from accept_secure_ctx) */
OM_uint32
ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_mech **type,
gss_buffer_desc *name, gss_cred_id_t *creds) {
}
/* This is icky. There appears to be no way to copy this structure,
- * rather than the pointer to it, so we simply copy the pointer and
- * mark the originator as empty so we don't destroy it.
- */
+ * rather than the pointer to it, so we simply copy the pointer and
+ * mark the originator as empty so we don't destroy it.
+ */
*creds=ctx->client_creds;
ctx->client_creds=GSS_C_NO_CREDENTIAL;
return(ctx->major);
}
+/* As user - called through fatal cleanup hook */
void
ssh_gssapi_cleanup_creds(void *ignored)
{
}
}
+/* As user */
void
ssh_gssapi_storecreds()
{
/* This allows GSSAPI methods to do things to the childs environment based
* on the passed authentication process and credentials.
- *
- * Question: If we didn't use userauth_external for some reason, should we
- * still delegate credentials?
*/
+/* As user */
void
ssh_gssapi_do_child(char ***envp, u_int *envsizep)
{
}
}
+/* Priviledged */
int
ssh_gssapi_userok(char *user)
{
return(0);
}
+/* Priviledged */
int
ssh_gssapi_localname(char **user)
{
/*
- * 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
}
token_ptr = GSS_C_NO_BUFFER;
-
+
do {
debug("Calling gss_init_sec_context");
&ret_flags);
if (GSS_ERROR(maj_status)) {
+ if (send_tok.length!=0) {
+ /* Hmmm - not sure about this */
+ packet_start(SSH2_MSG_KEXGSS_CONTINUE);
+ packet_put_string(send_tok.value,
+ send_tok.length);
+ }
fatal("gss_init_context failed");
- }
+ }
/* If we've got an old receive buffer get rid of it */
if (token_ptr != GSS_C_NO_BUFFER)
min_status=packet_get_int();
msg=packet_get_string(NULL);
lang=packet_get_string(NULL);
- fatal(msg);
+ fprintf(stderr,"GSSAPI Error: \n%s",msg);
default:
packet_disconnect("Protocol error: didn't expect packet type %d",
type);
}
token_ptr=&recv_tok;
+ } else {
+ /* No data, and not complete */
+ if (maj_status!=GSS_S_COMPLETE) {
+ fatal("Not complete, and no token output");
+ }
}
-
} while (maj_status & GSS_S_CONTINUE_NEEDED);
/* We _must_ have received a COMPLETE message in reply from the
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;
/* Initialise GSSAPI */
debug2("%s: Identifying %s",__func__,kex->name);
- oid=ssh_gssapi_id_kex(ctxt,kex->name);
+ oid=ssh_gssapi_server_id_kex(kex->name);
if (oid==NULL) {
packet_disconnect("Unknown gssapi mechanism");
}
/* Send SSH_MSG_KEXGSS_HOSTKEY here, if we want */
break;
case SSH2_MSG_KEXGSS_CONTINUE:
- if (dh_client_pub == NULL)
- packet_disconnect("Received KEXGSS_CONTINUE without initialising");
recv_tok.value=packet_get_string(&slen);
recv_tok.length=slen; /* int vs. size_t */
break;
}
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);
}
#endif
- if ((maj_status & GSS_S_CONTINUE_NEEDED) ||
- (GSS_ERROR(maj_status) && send_tok.length>0)) {
+ if (maj_status!=GSS_S_COMPLETE && send_tok.length==0) {
+ fatal("Zero length token output when incomplete");
+ }
+
+ if (dh_client_pub == NULL)
+ fatal("No client public key");
+
+ if (maj_status & GSS_S_CONTINUE_NEEDED) {
debug("Sending GSSAPI_CONTINUE");
packet_start(SSH2_MSG_KEXGSS_CONTINUE);
packet_put_string(send_tok.value,send_tok.length);
if (GSS_ERROR(maj_status)) {
kex_gss_send_error(ctxt);
+ if (send_tok.length>0) {
+ packet_start(SSH2_MSG_KEXGSS_CONTINUE);
+ packet_put_string(send_tok.value,send_tok.length);
+ packet_send();
+ packet_write_wait();
+ }
packet_disconnect("gssapi key exchange handshake failed");
}
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);
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_error(int, Buffer *);
+int mm_answer_gss_indicate_mechs(int, Buffer *);
+int mm_answer_gss_localname(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_GSSERR, MON_ISAUTH | MON_ONCE, mm_answer_gss_error},
{MONITOR_REQ_GSSMECHS, MON_ISAUTH, mm_answer_gss_indicate_mechs},
{MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok},
- {MONITOR_REQ_GSSLOCALNAME, MON_AUTH, mm_answer_gss_localname},
- {MONITOR_REQ_GSSERR, MON_ISAUTH | MON_ONCE, mm_answer_gss_error},
+ {MONITOR_REQ_GSSLOCALNAME, MON_ISAUTH, mm_answer_gss_localname},
#endif
{MONITOR_REQ_KEYALLOWED, MON_ISAUTH, mm_answer_keyallowed},
{MONITOR_REQ_KEYVERIFY, MON_AUTH, mm_answer_keyverify},
{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_GSSERR, 0, mm_answer_gss_error},
+ {MONITOR_REQ_GSSMECHS, 0, mm_answer_gss_indicate_mechs},
#endif
{MONITOR_REQ_MODULI, 0, mm_answer_moduli},
{MONITOR_REQ_SIGN, 0, mm_answer_sign},
#ifdef GSSAPI
/* and for the GSSAPI key exchange */
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_GSSERR, 1);
+ monitor_permit(mon_dispatch, MONITOR_REQ_GSSMECHS, 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_GSSERR, 1);
#endif
monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1);
monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1);
+#ifdef GSSAPI
+ /* and for the GSSAPI key exchange */
+ monitor_permit(mon_dispatch, MONITOR_REQ_GSSMECHS,1);
+ monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP,1);
+ monitor_permit(mon_dispatch, MONITOR_REQ_GSSERR,1);
+#endif
+
} else {
mon_dispatch = mon_dispatch_postauth15;
monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1);
mm_request_send(socket,MONITOR_ANS_GSSSETUP,m);
+ /* Now we have a context, enable the step and sign */
+ monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP,1);
+
return(0);
}
gss_release_buffer(&minor, &out);
+ /* Complete - now we can do signing */
+ if (major==GSS_S_COMPLETE) {
+ monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP,0);
+ monitor_permit(mon_dispatch, MONITOR_REQ_GSSSIGN,1);
+ }
return(0);
}
+
int
mm_answer_gss_userok(int socket, Buffer *m) {
int authenticated;
return(authenticated);
}
-int
-mm_answer_gss_localname(int socket, Buffer *m) {
- char *name;
-
- ssh_gssapi_localname(&name);
-
- buffer_clear(m);
- if (name) {
- buffer_put_cstring(m, name);
- debug3("%s: sending result %s", __func__, name);
- xfree(name);
- } else {
- buffer_put_cstring(m, "");
- debug3("%s: sending result \"\"", __func__);
- }
-
- mm_request_send(socket, MONITOR_ANS_GSSLOCALNAME, m);
-
- return(0);
-}
-
int
mm_answer_gss_sign(int socket, Buffer *m) {
gss_buffer_desc data,hash;
return(0);
}
+int
+mm_answer_gss_error(int socket, Buffer *m) {
+ OM_uint32 major,minor;
+ char *msg;
+
+ msg=ssh_gssapi_last_error(gsscontext,&major,&minor);
+ buffer_clear(m);
+ buffer_put_int(m,major);
+ buffer_put_int(m,minor);
+ buffer_put_cstring(m,msg);
+
+ mm_request_send(socket,MONITOR_ANS_GSSERR,m);
+
+ xfree(msg);
+
+ return(0);
+}
+
int
mm_answer_gss_indicate_mechs(int socket, Buffer *m) {
OM_uint32 major,minor;
mech_set->elements[i].length);
}
+#if !defined(MECHGLUE) /* mechglue memory management bug ??? */
+ gss_release_oid_set(&minor,&mech_set);
+#endif
+
mm_request_send(socket,MONITOR_ANS_GSSMECHS,m);
return(0);
}
int
-mm_answer_gss_error(int socket, Buffer *m) {
- OM_uint32 major,minor;
- char *msg;
+mm_answer_gss_localname(int socket, Buffer *m) {
+ char *name;
- msg=ssh_gssapi_last_error(gsscontext,&major,&minor);
- buffer_clear(m);
- buffer_put_int(m,major);
- buffer_put_int(m,minor);
- buffer_put_cstring(m,msg);
+ ssh_gssapi_localname(&name);
- mm_request_send(socket,MONITOR_ANS_GSSERR,m);
+ buffer_clear(m);
+ if (name) {
+ buffer_put_cstring(m, name);
+ debug3("%s: sending result %s", __func__, name);
+ xfree(name);
+ } else {
+ buffer_put_cstring(m, "");
+ debug3("%s: sending result \"\"", __func__);
+ }
+
+ mm_request_send(socket, MONITOR_ANS_GSSLOCALNAME, m);
- xfree(msg);
-
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_GSSUSEROK,MONITOR_ANS_GSSUSEROK,
+ MONITOR_REQ_GSSMECHS,MONITOR_ANS_GSSMECHS,
MONITOR_REQ_GSSLOCALNAME,MONITOR_ANS_GSSLOCALNAME,
MONITOR_REQ_GSIGRIDMAP,MONITOR_ANS_GSIGRIDMAP,
MONITOR_REQ_GSSERR,MONITOR_ANS_GSSERR,
return(authenticated);
}
-int
-mm_ssh_gssapi_localname(char **lname)
-{
- Buffer m;
-
- buffer_init(&m);
-
- mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSLOCALNAME, &m);
-
- mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSLOCALNAME,
- &m);
-
- *lname = buffer_get_string(&m, NULL);
-
- buffer_free(&m);
- if (lname[0] == '\0') {
- debug3("%s: gssapi identity mapping failed", __func__);
- } else {
- debug3("%s: gssapi identity mapped to %s", __func__, *lname);
- }
-
- return(0);
-}
-
OM_uint32
mm_ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_desc *data, gss_buffer_desc *hash) {
Buffer m;
return(errstr);
}
-
+
OM_uint32
mm_gss_indicate_mechs(OM_uint32 *minor_status, gss_OID_set *mech_set)
{
Buffer m;
- OM_uint32 major, lmajor, lminor;
- int i=0, count;
-
+ OM_uint32 major,minor;
+ int count;
+ gss_OID_desc oid;
buffer_init(&m);
mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSMECHS, &m);
-
mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSMECHS,
&m);
major=buffer_get_int(&m);
- lmajor=gss_create_empty_oid_set(&lminor, mech_set);
count=buffer_get_int(&m);
- for (i=0; i < count; i++) {
- gss_OID_desc member_oid;
+
+ gss_create_empty_oid_set(&minor,mech_set);
+ while(count-->0) {
u_int length;
- member_oid.elements=buffer_get_string(&m, &length);
- member_oid.length=length;
- lmajor=gss_add_oid_set_member(&lminor, &member_oid, mech_set);
+ oid.elements=buffer_get_string(&m,&length);
+ oid.length=length;
+ gss_add_oid_set_member(&minor,&oid,mech_set);
}
buffer_free(&m);
return(major);
}
+
+int
+mm_ssh_gssapi_localname(char **lname)
+{
+ Buffer m;
+
+ buffer_init(&m);
+ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSLOCALNAME, &m);
+
+ debug3("%s: waiting for MONITOR_ANS_GSSLOCALNAME", __func__);
+ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSLOCALNAME,
+ &m);
+
+ *lname = buffer_get_string(&m, NULL);
+
+ buffer_free(&m);
+ if (lname[0] == '\0') {
+ debug3("%s: gssapi identity mapping failed", __func__);
+ } else {
+ debug3("%s: gssapi identity mapped to %s", __func__, *lname);
+ }
+
+ return(0);
+}
#endif /* GSSAPI */
#ifdef GSI
OM_uint32 mm_gss_indicate_mechs(OM_uint32 *minor_status,
gss_OID_set *mech_set);
char *mm_ssh_gssapi_last_error(Gssctxt *ctxt, OM_uint32 *maj, OM_uint32 *min);
+
#endif
#ifdef GSI
#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 KEX_GSS_SHA1 "gss-group1-sha1-"
int ssh_gssapi_check_mechanism(gss_OID oid, char *host);
/* In the server */
-gss_OID ssh_gssapi_server_id_kex(Gssctxt *ctx, char *name);
+gss_OID ssh_gssapi_server_id_kex(char *name);
int ssh_gssapi_userok(char *name);
-int ssh_gssapi_localname(char **user);
+int ssh_gssapi_localname(char **name);
void ssh_gssapi_server(Kex *kex, Buffer *client_kexinit,
Buffer *server_kexinit);
#ifdef GSSAPI
int userauth_external(Authctxt *authctxt);
int userauth_gssapi(Authctxt *authctxt);
-void input_gssapi_response(int type, u_int32_t plen, void *ctxt);
-void input_gssapi_token(int type, u_int32_t plen, void *ctxt);
-void input_gssapi_hash(int type, u_int32_t plen, void *ctxt);
+void input_gssapi_response(int type, u_int32_t, void *);
+void input_gssapi_token(int type, u_int32_t, void *);
+void input_gssapi_hash(int type, u_int32_t, void *);
void input_gssapi_error(int, u_int32_t, void *);
+void input_gssapi_errtok(int, u_int32_t, void *);
#endif
void userauth(Authctxt *, char *);
int ok=0;
/* Things work better if we send one mechanism at a time, rather
- * than them all at once. This means that if we fail at some point
- * in the middle of a negotiation, we can come back and try something
- * different. */
+ * than them all at once. This means that if we fail at some point
+ * in the middle of a negotiation, we can come back and try something
+ * different. */
if (datafellows & SSH_OLD_GSSAPI) return 0;
/* Before we offer a mechanism, check that we can support it. Don't
- * bother trying to get credentials - as the standard fallback will
- * deal with that kind of failure.
- */
+ * bother trying to get credentials - as the standard fallback will
+ * deal with that kind of failure.
+ */
if (supported==NULL) gss_indicate_mechs(&min, &supported);
ssh_gssapi_set_oid(gssctxt,&supported->elements[mech]);
/* The DER encoding below only works for lengths<128,
- * so check this here
- */
+ * so check this here
+ */
if (supported->elements[mech].length<128 &&
!GSS_ERROR(ssh_gssapi_import_name(gssctxt,
authctxt->host))) {
- ok = 1; /* Mechanism works */
+ ok = 1; /* Mechanism works */
} else {
mech++;
}
packet_put_int(1);
/* The newest gsskeyex draft stipulates that OIDs should
- * be DER encoded, so we need to add the object type and
- * length information back on */
+ * be DER encoded, so we need to add the object type and
+ * length information back on */
if (datafellows & SSH_BUG_GSSAPI_BER) {
packet_put_string(supported->elements[mech].elements,
supported->elements[mech].length);
dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE,&input_gssapi_response);
dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN,&input_gssapi_token);
dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERROR,&input_gssapi_error);
+ dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK,&input_gssapi_errtok);
mech++; /* Move along to next candidate */
GSS_C_NO_BUFFER, &send_tok,
NULL);
if (GSS_ERROR(status)) {
+ if (send_tok.length>0) {
+ packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK);
+ packet_put_string(send_tok.value,send_tok.length);
+ packet_send();
+ packet_write_wait();
+ }
/* Start again with next method on list */
debug("Trying to start again");
clear_auth_state(authctxt);
packet_check_eom();
if (GSS_ERROR(status)) {
+ if (send_tok.length>0) {
+ packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK);
+ packet_put_string(send_tok.value,send_tok.length);
+ packet_send();
+ packet_write_wait();
+ }
/* Start again with the next method in the list */
clear_auth_state(authctxt);
userauth(authctxt,NULL);
}
}
+void
+input_gssapi_errtok(int type, u_int32_t plen, void *ctxt)
+{
+ Authctxt *authctxt = ctxt;
+ Gssctxt *gssctxt;
+ gss_buffer_desc send_tok,recv_tok;
+ OM_uint32 status;
+
+ if (authctxt == NULL)
+ fatal("input_gssapi_response: no authentication context");
+ gssctxt = authctxt->methoddata;
+
+ recv_tok.value=packet_get_string(&recv_tok.length);
+
+ /* Stick it into GSSAPI and see what it says */
+ status=ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds,
+ &recv_tok, &send_tok, NULL);
+
+ packet_check_eom();
+
+ /* We can't send a packet to the server */
+
+ /* The draft says that we should wait for the server to fail
+ * before starting the next authentication. So, we clear the
+ * state, but don't do anything else */
+ clear_auth_state(authctxt);
+ return;
+}
+
void
input_gssapi_error(int type, u_int32_t plen, void *ctxt)
{