Bug in Kerberos support for openssh.
Eric Youngdale
eric at andante.org
Tue Feb 28 02:39:45 EST 2006
It took me a while to track this down. I am using MIT Kerberos 1.4.3
and libgssapi-0.7. With some patches that came with Suse 10, but that
doesn't appear to be relevant. I have been using openssh-4.2p1 (with
Simon's patches) and openssh-4p3p2 out of the box. I see the same
problem no matter which version of openssh I am using. I am using two
Suse Linux x86 boxes as a test environment, and was able to reproduce
the problem there. The KDC is a Windows Server 2003 box, but that
probably isn't relevant.
The failure mode is that when I connect using ssh, the connection gets
set up most of the way. It finds something it doesn't like, and then
tears down the connection. In the server logs, I would see messages
like this:
debug1: userauth-request for user vatester service ssh-connection method
gssapi-with-mic
debug1: attempt 1 failures 1
debug2: input_userauth_request: try method gssapi-with-mic
Postponed gssapi-with-mic for vatester from 10.18.3.52 port 1960 ssh2
debug1: Got no client credentials
debug1: An invalid name was supplied
A parameter was malformed
Validation error
Couldn't convert client name
debug1: do_cleanup
I spent some time in the debugger, and found that essentially the
problem was that ssh is calling
ctx->major = gss_accept_sec_context(&ctx->minor,
&ctx->context, ctx->creds, recv_tok,
GSS_C_NO_CHANNEL_BINDINGS, &ctx->client, &mech,
send_tok, flags, NULL, &ctx->client_creds);
and saving off ctx->client for later use. Under the hood, ctx->client
is simply a gss_union_name_t.
Later on (not much further later), ssh calls
if ((ctx->major = gss_export_name(&ctx->minor, ctx->client,
&ename))) {
ssh_gssapi_error(ctx);
return (ctx->major);
}
Here ctx->client is passed in but gss_export_name assumes that the input
name is a krb5_principal. Not surprisingly, the datatype mismatch
causes the call to fail. Could have caused it to crash, I suppose -
that would have been a much clearer indication of what the trouble was.
I did manage to hack the thing to work - I first hacked libgssapi.so to
include a new function:
OM_uint32 KRB5_CALLCONV
gss_hack_ssh_to_fix_stupid_bug(minor_status,
input_name,
output_name)
OM_uint32 * minor_status;
gss_name_t input_name;
gss_name_t * output_name;
{
gss_union_name_t union_name;
union_name = (gss_union_name_t) input_name;
*output_name = union_name->mech_name;
return 0;
}
and then hacked gss-serv.c to have this:
#if 0
/* FIXME(eric) - this is the wrong type for this type of
* lookup.
*/
if ((ctx->major = gss_export_name(&ctx->minor, ctx->client,
&ename))) {
ssh_gssapi_error(ctx);
return (ctx->major);
}
#else
{
extern gss_hack_ssh_to_fix_stupid_bug(OM_uint32 *
minor_status,
gss_name_t input_name,
gss_name_t *output_name);
void * pname;
gss_hack_ssh_to_fix_stupid_bug(NULL, ctx->client, &pname);
if ((ctx->major = gss_export_name(&ctx->minor, pname,
&ename))) {
ssh_gssapi_error(ctx);
return (ctx->major);
}
}
#endif
With these two changes, ssh is now able to authenticate with Kerberos,
and I get a nice shell prompt on the remote machine. Server logs look
good too:
WARNING: /usr/local/etc/moduli does not exist, using fixed modulus
Authorized to vatester, krb5 principal vatester at VADEV.COM (krb5_kuserok)
Accepted gssapi-with-mic for vatester from 10.18.3.52 port 2729 ssh2
I honestly have no clue how this could have ever have worked - my guess
is that at one point in the past libgssapi didn't use the
gss_union_name_t, and just used krb5_principal as a return parameter
from gss_accept_sec_context(). I leave it to the people who know the
history of this thing, and who better understand the intent of the
original code to best figure out how to fix this.
More information about the openssh-unix-dev
mailing list