Commit 1c1b6fa1 authored by Simon Wilkinson's avatar Simon Wilkinson Committed by Colin Watson

GSSAPI key exchange support

This patch has been rejected upstream: "None of the OpenSSH developers are
in favour of adding this, and this situation has not changed for several
years.  This is not a slight on Simon's patch, which is of fine quality, but
just that a) we don't trust GSSAPI implementations that much and b) we don't
like adding new KEX since they are pre-auth attack surface.  This one is
particularly scary, since it requires hooks out to typically root-owned
system resources."

However, quite a lot of people rely on this in Debian, and it's better to
have it merged into the main openssh package rather than having separate
-krb5 packages (as we used to have).  It seems to have a generally good
security history.

Bug: https://bugzilla.mindrot.org/show_bug.cgi?id=1242
Last-Updated: 2014-10-07

Patch-Name: gssapi.patch
parent 487bdb3a
20110101
- Finally update for OpenSSH 5.6p1
- Add GSSAPIServerIdentity option from Jim Basney
20100308
- [ Makefile.in, key.c, key.h ]
Updates for OpenSSH 5.4p1
- [ servconf.c ]
Include GSSAPI options in the sshd -T configuration dump, and flag
some older configuration options as being unsupported. Thanks to Colin
Watson.
-
20100124
- [ sshconnect2.c ]
Adapt to deal with additional element in Authmethod structure. Thanks to
Colin Watson
20090615
- [ gss-genr.c gss-serv.c kexgssc.c kexgsss.c monitor.c sshconnect2.c
sshd.c ]
Fix issues identified by Greg Hudson following a code review
Check return value of gss_indicate_mechs
Protect GSSAPI calls in monitor, so they can only be used if enabled
Check return values of bignum functions in key exchange
Use BN_clear_free to clear other side's DH value
Make ssh_gssapi_id_kex more robust
Only configure kex table pointers if GSSAPI is enabled
Don't leak mechanism list, or gss mechanism list
Cast data.length before printing
If serverkey isn't provided, use an empty string, rather than NULL
20090201
- [ gss-genr.c gss-serv.c kex.h kexgssc.c readconf.c readconf.h ssh-gss.h
ssh_config.5 sshconnet2.c ]
Add support for the GSSAPIClientIdentity option, which allows the user
to specify which GSSAPI identity to use to contact a given server
20080404
- [ gss-serv.c ]
Add code to actually implement GSSAPIStrictAcceptCheck, which had somehow
been omitted from a previous version of this patch. Reported by Borislav
Stoichkov
20070317
- [ gss-serv-krb5.c ]
Remove C99ism, where new_ccname was being declared in the middle of a
function
20061220
- [ servconf.c ]
Make default for GSSAPIStrictAcceptorCheck be Yes, to match previous, and
documented, behaviour. Reported by Dan Watson.
20060910
- [ gss-genr.c kexgssc.c kexgsss.c kex.h monitor.c sshconnect2.c sshd.c
ssh-gss.h ]
add support for gss-group14-sha1 key exchange mechanisms
- [ gss-serv.c servconf.c servconf.h sshd_config sshd_config.5 ]
Add GSSAPIStrictAcceptorCheck option to allow the disabling of
acceptor principal checking on multi-homed machines.
<Bugzilla #928>
- [ sshd_config ssh_config ]
Add settings for GSSAPIKeyExchange and GSSAPITrustDNS to the sample
configuration files
- [ kexgss.c kegsss.c sshconnect2.c sshd.c ]
Code cleanup. Replace strlen/xmalloc/snprintf sequences with xasprintf()
Limit length of error messages displayed by client
20060909
- [ gss-genr.c gss-serv.c ]
move ssh_gssapi_acquire_cred() and ssh_gssapi_server_ctx to be server
only, where they belong
<Bugzilla #1225>
20060829
- [ gss-serv-krb5.c ]
Fix CCAPI credentials cache name when creating KRB5CCNAME environment
variable
20060828
- [ gss-genr.c ]
Avoid Heimdal context freeing problem
<Fixed upstream 20060829>
20060818
- [ gss-genr.c ssh-gss.h sshconnect2.c ]
Make sure that SPENGO is disabled
<Bugzilla #1218 - Fixed upstream 20060818>
20060421
- [ gssgenr.c, sshconnect2.c ]
a few type changes (signed versus unsigned, int versus size_t) to
fix compiler errors/warnings
(from jbasney AT ncsa.uiuc.edu)
- [ kexgssc.c, sshconnect2.c ]
fix uninitialized variable warnings
(from jbasney AT ncsa.uiuc.edu)
- [ gssgenr.c ]
pass oid to gss_display_status (helpful when using GSSAPI mechglue)
(from jbasney AT ncsa.uiuc.edu)
<Bugzilla #1220 >
- [ gss-serv-krb5.c ]
#ifdef HAVE_GSSAPI_KRB5 should be #ifdef HAVE_GSSAPI_KRB5_H
(from jbasney AT ncsa.uiuc.edu)
<Fixed upstream 20060304>
- [ readconf.c, readconf.h, ssh_config.5, sshconnect2.c
add client-side GssapiKeyExchange option
(from jbasney AT ncsa.uiuc.edu)
- [ sshconnect2.c ]
add support for GssapiTrustDns option for gssapi-with-mic
(from jbasney AT ncsa.uiuc.edu)
<gssapi-with-mic support is Bugzilla #1008>
......@@ -82,6 +82,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \
atomicio.o key.o dispatch.o kex.o mac.o uidswap.o uuencode.o misc.o \
monitor_fdpass.o rijndael.o ssh-dss.o ssh-ecdsa.o ssh-rsa.o dh.o \
kexdh.o kexgex.o kexdhc.o kexgexc.o bufec.o kexecdh.o kexecdhc.o \
kexgssc.o \
msg.o progressmeter.o dns.o entropy.o gss-genr.o umac.o umac128.o \
ssh-pkcs11.o krl.o smult_curve25519_ref.o \
kexc25519.o kexc25519c.o poly1305.o chacha.o cipher-chachapoly.o \
......@@ -101,7 +102,7 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o auth-rsa.o auth-rh-rsa.o \
auth2-none.o auth2-passwd.o auth2-pubkey.o \
monitor_mm.o monitor.o monitor_wrap.o kexdhs.o kexgexs.o kexecdhs.o \
kexc25519s.o auth-krb5.o \
auth2-gss.o gss-serv.o gss-serv-krb5.o \
auth2-gss.o gss-serv.o gss-serv-krb5.o kexgsss.o \
loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \
sftp-server.o sftp-common.o \
roaming_common.o roaming_serv.o \
......
......@@ -183,8 +183,13 @@ auth_krb5_password(Authctxt *authctxt, const char *password)
len = strlen(authctxt->krb5_ticket_file) + 6;
authctxt->krb5_ccname = xmalloc(len);
#ifdef USE_CCAPI
snprintf(authctxt->krb5_ccname, len, "API:%s",
authctxt->krb5_ticket_file);
#else
snprintf(authctxt->krb5_ccname, len, "FILE:%s",
authctxt->krb5_ticket_file);
#endif
#ifdef USE_PAM
if (options.use_pam)
......@@ -241,15 +246,22 @@ krb5_cleanup_proc(Authctxt *authctxt)
#ifndef HEIMDAL
krb5_error_code
ssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) {
int tmpfd, ret, oerrno;
int ret, oerrno;
char ccname[40];
mode_t old_umask;
#ifdef USE_CCAPI
char cctemplate[] = "API:krb5cc_%d";
#else
char cctemplate[] = "FILE:/tmp/krb5cc_%d_XXXXXXXXXX";
int tmpfd;
#endif
ret = snprintf(ccname, sizeof(ccname),
"FILE:/tmp/krb5cc_%d_XXXXXXXXXX", geteuid());
cctemplate, geteuid());
if (ret < 0 || (size_t)ret >= sizeof(ccname))
return ENOMEM;
#ifndef USE_CCAPI
old_umask = umask(0177);
tmpfd = mkstemp(ccname + strlen("FILE:"));
oerrno = errno;
......@@ -266,6 +278,7 @@ ssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) {
return oerrno;
}
close(tmpfd);
#endif
return (krb5_cc_resolve(ctx, ccname, ccache));
}
......
/* $OpenBSD: auth2-gss.c,v 1.21 2014/02/26 20:28:44 djm Exp $ */
/*
* Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
* Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
......@@ -53,6 +53,40 @@ static void input_gssapi_mic(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 *);
/*
* The 'gssapi_keyex' userauth mechanism.
*/
static int
userauth_gsskeyex(Authctxt *authctxt)
{
int authenticated = 0;
Buffer b;
gss_buffer_desc mic, gssbuf;
u_int len;
mic.value = packet_get_string(&len);
mic.length = len;
packet_check_eom();
ssh_gssapi_buildmic(&b, authctxt->user, authctxt->service,
"gssapi-keyex");
gssbuf.value = buffer_ptr(&b);
gssbuf.length = buffer_len(&b);
/* gss_kex_context is NULL with privsep, so we can't check it here */
if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gss_kex_context,
&gssbuf, &mic))))
authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user,
authctxt->pw));
buffer_free(&b);
free(mic.value);
return (authenticated);
}
/*
* We only support those mechanisms that we know about (ie ones that we know
* how to check local user kuserok and the like)
......@@ -236,7 +270,8 @@ input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt)
packet_check_eom();
authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user));
authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user,
authctxt->pw));
authctxt->postponed = 0;
dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
......@@ -271,7 +306,8 @@ input_gssapi_mic(int type, u_int32_t plen, void *ctxt)
gssbuf.length = buffer_len(&b);
if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gssctxt, &gssbuf, &mic))))
authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user));
authenticated =
PRIVSEP(ssh_gssapi_userok(authctxt->user, authctxt->pw));
else
logit("GSSAPI MIC check failed");
......@@ -286,6 +322,12 @@ input_gssapi_mic(int type, u_int32_t plen, void *ctxt)
userauth_finish(authctxt, authenticated, "gssapi-with-mic", NULL);
}
Authmethod method_gsskeyex = {
"gssapi-keyex",
userauth_gsskeyex,
&options.gss_authentication
};
Authmethod method_gssapi = {
"gssapi-with-mic",
userauth_gssapi,
......
......@@ -70,6 +70,7 @@ extern Authmethod method_passwd;
extern Authmethod method_kbdint;
extern Authmethod method_hostbased;
#ifdef GSSAPI
extern Authmethod method_gsskeyex;
extern Authmethod method_gssapi;
#endif
......@@ -77,6 +78,7 @@ Authmethod *authmethods[] = {
&method_none,
&method_pubkey,
#ifdef GSSAPI
&method_gsskeyex,
&method_gssapi,
#endif
&method_passwd,
......
......@@ -111,6 +111,10 @@
#include "msg.h"
#include "roaming.h"
#ifdef GSSAPI
#include "ssh-gss.h"
#endif
/* import options */
extern Options options;
......@@ -1596,6 +1600,15 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
/* Do channel operations unless rekeying in progress. */
if (!rekeying) {
channel_after_select(readset, writeset);
#ifdef GSSAPI
if (options.gss_renewal_rekey &&
ssh_gssapi_credentials_updated(NULL)) {
debug("credentials updated - forcing rekey");
need_rekeying = 1;
}
#endif
if (need_rekeying || packet_need_rekeying()) {
debug("need rekeying");
xxx_kex->done = 0;
......
......@@ -1622,6 +1622,9 @@
/* Use btmp to log bad logins */
#undef USE_BTMP
/* platform uses an in-memory credentials cache */
#undef USE_CCAPI
/* Use libedit for sftp */
#undef USE_LIBEDIT
......@@ -1637,6 +1640,9 @@
/* Use PIPES instead of a socketpair() */
#undef USE_PIPES
/* platform has the Security Authorization Session API */
#undef USE_SECURITY_SESSION_API
/* Define if you have Solaris process contracts */
#undef USE_SOLARIS_PROCESS_CONTRACTS
......
......@@ -7168,6 +7168,63 @@ $as_echo "#define SSH_TUN_COMPAT_AF 1" >>confdefs.h
$as_echo "#define SSH_TUN_PREPEND_AF 1" >>confdefs.h
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if we have the Security Authorization Session API" >&5
$as_echo_n "checking if we have the Security Authorization Session API... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <Security/AuthSession.h>
int
main ()
{
SessionCreate(0, 0);
;
return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
ac_cv_use_security_session_api="yes"
$as_echo "#define USE_SECURITY_SESSION_API 1" >>confdefs.h
LIBS="$LIBS -framework Security"
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
else
ac_cv_use_security_session_api="no"
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if we have an in-memory credentials cache" >&5
$as_echo_n "checking if we have an in-memory credentials cache... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <Kerberos/Kerberos.h>
int
main ()
{
cc_context_t c;
(void) cc_initialize (&c, 0, NULL, NULL);
;
return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"; then :
$as_echo "#define USE_CCAPI 1" >>confdefs.h
LIBS="$LIBS -framework Security"
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
if test "x$ac_cv_use_security_session_api" = "xno"; then
as_fn_error $? "*** Need a security framework to use the credentials cache API ***" "$LINENO" 5
fi
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
ac_fn_c_check_decl "$LINENO" "AU_IPv4" "ac_cv_have_decl_AU_IPv4" "$ac_includes_default"
if test "x$ac_cv_have_decl_AU_IPv4" = xyes; then :
......
......@@ -584,6 +584,30 @@ main() { if (NSVersionOfRunTimeLibrary("System") >= (60 << 16))
[Use tunnel device compatibility to OpenBSD])
AC_DEFINE([SSH_TUN_PREPEND_AF], [1],
[Prepend the address family to IP tunnel traffic])
AC_MSG_CHECKING([if we have the Security Authorization Session API])
AC_TRY_COMPILE([#include <Security/AuthSession.h>],
[SessionCreate(0, 0);],
[ac_cv_use_security_session_api="yes"
AC_DEFINE([USE_SECURITY_SESSION_API], [1],
[platform has the Security Authorization Session API])
LIBS="$LIBS -framework Security"
AC_MSG_RESULT([yes])],
[ac_cv_use_security_session_api="no"
AC_MSG_RESULT([no])])
AC_MSG_CHECKING([if we have an in-memory credentials cache])
AC_TRY_COMPILE(
[#include <Kerberos/Kerberos.h>],
[cc_context_t c;
(void) cc_initialize (&c, 0, NULL, NULL);],
[AC_DEFINE([USE_CCAPI], [1],
[platform uses an in-memory credentials cache])
LIBS="$LIBS -framework Security"
AC_MSG_RESULT([yes])
if test "x$ac_cv_use_security_session_api" = "xno"; then
AC_MSG_ERROR([*** Need a security framework to use the credentials cache API ***])
fi],
[AC_MSG_RESULT([no])]
)
m4_pattern_allow([AU_IPv])
AC_CHECK_DECL([AU_IPv4], [],
AC_DEFINE([AU_IPv4], [0], [System only supports IPv4 audit records])
......
/* $OpenBSD: gss-genr.c,v 1.22 2013/11/08 00:39:15 djm Exp $ */
/*
* Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved.
* Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
......@@ -39,12 +39,167 @@
#include "buffer.h"
#include "log.h"
#include "ssh2.h"
#include "cipher.h"
#include "key.h"
#include "kex.h"
#include <openssl/evp.h>
#include "ssh-gss.h"
extern u_char *session_id2;
extern u_int session_id2_len;
typedef struct {
char *encoded;
gss_OID oid;
} ssh_gss_kex_mapping;
/*
* XXX - It would be nice to find a more elegant way of handling the
* XXX passing of the key exchange context to the userauth routines
*/
Gssctxt *gss_kex_context = NULL;
static ssh_gss_kex_mapping *gss_enc2oid = NULL;
int
ssh_gssapi_oid_table_ok(void) {
return (gss_enc2oid != NULL);
}
/*
* Return a list of the gss-group1-sha1 mechanisms supported by this program
*
* We test mechanisms to ensure that we can use them, to avoid starting
* a key exchange with a bad mechanism
*/
char *
ssh_gssapi_client_mechanisms(const char *host, const char *client) {
gss_OID_set gss_supported;
OM_uint32 min_status;
if (GSS_ERROR(gss_indicate_mechs(&min_status, &gss_supported)))
return NULL;
return(ssh_gssapi_kex_mechs(gss_supported, ssh_gssapi_check_mechanism,
host, client));
}
char *
ssh_gssapi_kex_mechs(gss_OID_set gss_supported, ssh_gssapi_check_fn *check,
const char *host, const char *client) {
Buffer buf;
size_t i;
int oidpos, enclen;
char *mechs, *encoded;
u_char digest[EVP_MAX_MD_SIZE];
char deroid[2];
const EVP_MD *evp_md = EVP_md5();
EVP_MD_CTX md;
if (gss_enc2oid != NULL) {
for (i = 0; gss_enc2oid[i].encoded != NULL; i++)
free(gss_enc2oid[i].encoded);
free(gss_enc2oid);
}
gss_enc2oid = xmalloc(sizeof(ssh_gss_kex_mapping) *
(gss_supported->count + 1));
buffer_init(&buf);
oidpos = 0;
for (i = 0; i < gss_supported->count; i++) {
if (gss_supported->elements[i].length < 128 &&
(*check)(NULL, &(gss_supported->elements[i]), host, client)) {
deroid[0] = SSH_GSS_OIDTYPE;
deroid[1] = gss_supported->elements[i].length;
EVP_DigestInit(&md, evp_md);
EVP_DigestUpdate(&md, deroid, 2);
EVP_DigestUpdate(&md,
gss_supported->elements[i].elements,
gss_supported->elements[i].length);
EVP_DigestFinal(&md, digest, NULL);
encoded = xmalloc(EVP_MD_size(evp_md) * 2);
enclen = __b64_ntop(digest, EVP_MD_size(evp_md),
encoded, EVP_MD_size(evp_md) * 2);
if (oidpos != 0)
buffer_put_char(&buf, ',');
buffer_append(&buf, KEX_GSS_GEX_SHA1_ID,
sizeof(KEX_GSS_GEX_SHA1_ID) - 1);
buffer_append(&buf, encoded, enclen);
buffer_put_char(&buf, ',');
buffer_append(&buf, KEX_GSS_GRP1_SHA1_ID,
sizeof(KEX_GSS_GRP1_SHA1_ID) - 1);
buffer_append(&buf, encoded, enclen);
buffer_put_char(&buf, ',');
buffer_append(&buf, KEX_GSS_GRP14_SHA1_ID,
sizeof(KEX_GSS_GRP14_SHA1_ID) - 1);
buffer_append(&buf, encoded, enclen);
gss_enc2oid[oidpos].oid = &(gss_supported->elements[i]);
gss_enc2oid[oidpos].encoded = encoded;
oidpos++;
}
}
gss_enc2oid[oidpos].oid = NULL;
gss_enc2oid[oidpos].encoded = NULL;
buffer_put_char(&buf, '\0');
mechs = xmalloc(buffer_len(&buf));
buffer_get(&buf, mechs, buffer_len(&buf));
buffer_free(&buf);
if (strlen(mechs) == 0) {
free(mechs);
mechs = NULL;
}
return (mechs);
}
gss_OID
ssh_gssapi_id_kex(Gssctxt *ctx, char *name, int kex_type) {
int i = 0;
switch (kex_type) {
case KEX_GSS_GRP1_SHA1:
if (strlen(name) < sizeof(KEX_GSS_GRP1_SHA1_ID))
return GSS_C_NO_OID;
name += sizeof(KEX_GSS_GRP1_SHA1_ID) - 1;
break;
case KEX_GSS_GRP14_SHA1:
if (strlen(name) < sizeof(KEX_GSS_GRP14_SHA1_ID))
return GSS_C_NO_OID;
name += sizeof(KEX_GSS_GRP14_SHA1_ID) - 1;
break;
case KEX_GSS_GEX_SHA1:
if (strlen(name) < sizeof(KEX_GSS_GEX_SHA1_ID))
return GSS_C_NO_OID;
name += sizeof(KEX_GSS_GEX_SHA1_ID) - 1;
break;
default:
return GSS_C_NO_OID;
}
while (gss_enc2oid[i].encoded != NULL &&
strcmp(name, gss_enc2oid[i].encoded) != 0)
i++;
if (gss_enc2oid[i].oid != NULL && ctx != NULL)
ssh_gssapi_set_oid(ctx, gss_enc2oid[i].oid);
return gss_enc2oid[i].oid;
}
/* Check that the OID in a data stream matches that in the context */
int
ssh_gssapi_check_oid(Gssctxt *ctx, void *data, size_t len)
......@@ -197,7 +352,7 @@ ssh_gssapi_init_ctx(Gssctxt *ctx, int deleg_creds, gss_buffer_desc *recv_tok,
}
ctx->major = gss_init_sec_context(&ctx->minor,
GSS_C_NO_CREDENTIAL, &ctx->context, ctx->name, ctx->oid,
ctx->client_creds, &ctx->context, ctx->name, ctx->oid,
GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG | deleg_flag,
0, NULL, recv_tok, NULL, send_tok, flags, NULL);
......@@ -226,9 +381,43 @@ ssh_gssapi_import_name(Gssctxt *ctx, const char *host)
return (ctx->major);
}
OM_uint32
ssh_gssapi_client_identity(Gssctxt *ctx, const char *name)
{
gss_buffer_desc gssbuf;
gss_name_t gssname;
OM_uint32 status;
gss_OID_set oidset;
gssbuf.value = (void *) name;
gssbuf.length = strlen(gssbuf.value);
gss_create_empty_oid_set(&status, &oidset);
gss_add_oid_set_member(&status, ctx->oid, &oidset);
ctx->major = gss_import_name(&ctx->minor, &gssbuf,
GSS_C_NT_USER_NAME, &gssname);
if (!ctx->major)
ctx->major = gss_acquire_cred(&ctx->minor,
gssname, 0, oidset, GSS_C_INITIATE,
&ctx->client_creds, NULL, NULL);
gss_release_name(&status, &gssname);
gss_release_oid_set(&status, &oidset);
if (ctx->major)
ssh_gssapi_error(ctx);
return(ctx->major);
}
OM_uint32
ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash)
{
if (ctx == NULL)
return -1;
if ((ctx->major = gss_get_mic(&ctx->minor, ctx->context,
GSS_C_QOP_DEFAULT, buffer, hash)))
ssh_gssapi_error(ctx);
......@@ -236,6 +425,19 @@ ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash)
return (ctx->major);
}
/* Priviledged when used by server */
OM_uint32
ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic)
{
if (ctx == NULL)
return -1;
ctx->major = gss_verify_mic(&ctx->minor, ctx->context,
gssbuf, gssmic, NULL);
return (ctx->major);
}
void
ssh_gssapi_buildmic(Buffer *b, const char *user, const char *service,
const char *context)
......@@ -249,11 +451,16 @@ ssh_gssapi_buildmic(Buffer *b, const char *user, const char *service,
}
int
ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host)
ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host,
const char *client)
{
gss_buffer_desc token = GSS_C_EMPTY_BUFFER;
OM_uint32 major, minor;
gss_OID_desc spnego_oid = {6, (void *)"\x2B\x06\x01\x05\x05\x02"};
Gssctxt *intctx = NULL;
if (ctx == NULL)
ctx = &intctx;
/* RFC 4462 says we MUST NOT do SPNEGO */
if (oid->length == spnego_oid.length &&
......@@ -263,6 +470,10 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host)
ssh_gssapi_build_ctx(ctx);
ssh_gssapi_set_oid(*ctx, oid);
major = ssh_gssapi_import_name(*ctx, host);
if (!GSS_ERROR(major) && client)
major = ssh_gssapi_client_identity(*ctx, client);
if (!GSS_ERROR(major)) {
major = ssh_gssapi_init_ctx(*ctx, 0, GSS_C_NO_BUFFER, &token,
NULL);
......@@ -272,10 +483,66 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host)
GSS_C_NO_BUFFER);
}
if (GSS_ERROR(major))
if (GSS_ERROR(major) || intctx != NULL)
ssh_gssapi_delete_ctx(ctx);
return (!GSS_ERROR(major));
}
int
ssh_gssapi_credentials_updated(Gssctxt *ctxt) {
static gss_name_t saved_name = GSS_C_NO_NAME;
static OM_uint32 saved_lifetime = 0;
static gss_OID saved_mech = GSS_C_NO_OID;
static gss_name_t name;
static OM_uint32 last_call = 0;
OM_uint32 lifetime, now, major, minor;
int equal;
now = time(NULL);
if (ctxt) {
debug("Rekey has happened - updating saved versions");
if (saved_name != GSS_C_NO_NAME)
gss_release_name(&minor, &saved_name);
major = gss_inquire_cred(&minor, GSS_C_NO_CREDENTIAL,
&saved_name, &saved_lifetime, NULL, NULL);
if (!GSS_ERROR(major)) {
saved_mech = ctxt->oid;
saved_lifetime+= now;
} else {
/* Handle the error */
}
return 0;
}
if (now - last_call < 10)
return 0;
last_call = now;
if (saved_mech == GSS_C_NO_OID)
return 0;
major = gss_inquire_cred(&minor, GSS_C_NO_CREDENTIAL,
&name, &lifetime, NULL, NULL);
if (major == GSS_S_CREDENTIALS_EXPIRED)
return 0;
else if (GSS_ERROR(major))
return 0;
major = gss_compare_name(&minor, saved_name, name, &equal);
gss_release_name(&minor, &name);
if (GSS_ERROR(major))
return 0;
if (equal &&