ssh-gss.c revision cd7d5faf5bbb52336a6f85578a90b31a648ac3fa
/*
* 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
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include "includes.h"
#ifdef GSSAPI
#include "ssh.h"
#include "ssh2.h"
#include "xmalloc.h"
#include "buffer.h"
#include "bufaux.h"
#include "packet.h"
#include "compat.h"
#include "cipher.h"
#include "kex.h"
#include "log.h"
#include "compat.h"
#include "xlist.h"
#include <netdb.h>
#include "ssh-gss.h"
#ifdef HAVE_GSS_OID_TO_MECH
#include <gssapi/gssapi_ext.h>
#endif /* HAVE_GSS_OID_TO_MECH */
typedef struct {
char *encoded;
const char *old_kexalgs);
/*
* Populate gss_enc2oid table and return list of kexnames.
*
* If called with both mechs == GSS_C_NULL_OID_SET and kexname_list == NULL
* then cached gss_enc2oid table is cleaned up.
*/
void
{
ssh_gss_kex_mapping **new_gss_enc2oid, **p;
char *enc_name;
int i;
if (kexname_list != NULL)
/* Cleanup gss_enc2oid table */
if ((*p)->encoded)
ssh_gssapi_release_oid(&(*p)->oid);
xfree(*p);
}
if (gss_enc2oid)
}
return; /* nothing left to do */
if (mechs) {
/* Populate gss_enc2oid table */
&enc_name);
if (!enc_name)
continue;
new_gss_enc2oid[i] =
xmalloc(sizeof (ssh_gss_kex_mapping));
(new_gss_enc2oid[i])->oid =
}
/* Do this last to avoid run-ins with fatal_cleanups */
}
if (!kexname_list)
return; /* nothing left to do */
/* Make kex name list */
buffer_init(&buf);
for (p = gss_enc2oid; p && *p; p++) {
}
if (buffer_len(&buf) == 0) {
buffer_free(&buf);
return;
}
buffer_free(&buf);
}
void
{
ssh_gss_kex_mapping **p;
return;
if (gss_enc2oid) {
for (p = gss_enc2oid; p && *p; p++) {
}
}
if (*kexname)
return; /* found */
}
void
{
ssh_gss_kex_mapping **p;
return;
if (!gss_enc2oid)
return;
for (p = gss_enc2oid; p && *p; p++) {
return;
}
}
}
static
void
{
char *encoded;
return;
/* No GSS mechs have OIDs as long as 128 -- simplify DER encoding */
if (oidlen > 128)
return; /* fail gracefully */
/*
* NOTE: If we need to support SSH_BUG_GSSAPI_BER this is where
* we'd do it.
*
* That means using "Se3H81ismmOC3OE+FwYCiQ==" for the Kerberos
* V mech and "N3+k7/4wGxHyuP8Yxi4RhA==" for the GSI mech. Ick.
*/
buffer_init(&buf);
/* UNIVERSAL class tag for OBJECT IDENTIFIER */
/* OID elements */
/* Make digest */
buffer_free(&buf);
/* Base 64 encoding */
buffer_init(&buf);
buffer_free(&buf);
}
static char *
{
char *gss_kexalgs, *new_kexalgs;
int len;
if (mechs == GSS_C_NULL_OID_SET)
return (gss_kexalgs);
return (new_kexalgs);
}
void
{
char *kexalgs, *orig_kexalgs, *p;
char **hostalgs;
int i;
}
return; /* didn't offer GSS last time, not offering now */
goto mod_offer; /* didn't offer last time or not offering now */
/* Check if mechs is congruent to kex->mechs (last offered) */
break;
}
}
return; /* no change in offer from last time */
}
/*
* Remove previously offered mechs from PROPOSAL_KEX_ALGS proposal
*
* ASSUMPTION: GSS-API kex algs always go in front, so removing
* them is a matter of skipping them.
*/
while (p != NULL && *p != '\0' &&
break;
p++;
kexalgs = p;
}
/* Not offering GSS kex algorithms now -> all done */
if (mechs == GSS_C_NULL_OID_SET)
return;
/* Remember mechs we're offering */
return;
&dup_mechs);
return;
}
}
/* Add mechs to kex algorithms ... */
kexalgs);
/*
* ... and add null host key alg, if it wasn't there before, but
* not if we're the server and we have other host key algs to
* offer.
*
* NOTE: Never remove "null" host key alg once added.
*/
return;
}
}
int len;
}
}
}
/*
* Yes, we harcode OIDs for some things, for now it's all we can do.
*
* We have to reference particular mechanisms due to lack of generality
* in the GSS-API in several areas: authorization, mapping principal
* names to usernames, "storing" delegated credentials, and discovering
* whether a mechanism is a pseudo-mechanism that negotiates mechanisms.
*
* Even if they were in some header file or if __gss_mech_to_oid()
* the mechanism names, and since the mechanisms have no standard names
* other than their OIDs it's actually worse [less portable] to hardcode
* names than OIDs, so we hardcode OIDs.
*
* SPNEGO is a difficult problem though -- it MUST NOT be used in SSHv2,
* but that's true of all possible pseudo-mechanisms that can perform
* mechanism negotiation, and SPNEGO could have new OIDs in the future.
* Ideally we could query each mechanism for its feature set and then
* ignore any mechanisms that negotiate mechanisms, but, alas, there's
* no interface to do that.
*
* In the future, if the necessary generic GSS interfaces for the issues
* listed above are made available (even if they differ by platform, as
* we can expect authorization interfaces will), then we can stop
* referencing specific mechanism OIDs here.
*/
int
{
}
int
{
memcmp("\x2A\x86\x48\x86\xF7\x12\x01\x02\x02",
}
int
{
memcmp("\053\006\004\001\052\002\032\002\005",
}
int
{
memcmp("\x2B\x06\x01\x04\x01\x9B\x50\x01\x01",
}
const char *
{
#ifdef HAVE_GSS_OID_TO_MECH
return (__gss_oid_to_mech(oid));
#else
if (ssh_gssapi_is_krb5(oid))
return ("Kerberos");
if (ssh_gssapi_is_gsi(oid))
return ("GSI");
return ("(unknown)");
#endif /* HAVE_GSS_OID_TO_MECH */
}
char *
{
#ifdef HAVE_GSS_OID_TO_STR
char *str;
return (xstrdup("<gss_oid_to_str() failed>"));
return (str);
#else
return (xstrdup("<gss_oid_to_str() unsupported>"));
#endif /* HAVE_GSS_OID_TO_STR */
}
/* Check that the OID in a data stream matches that in the context */
int
{
}
/* Set the contexts OID from a data stream */
void
{
}
}
/* Set the contexts OID */
void
{
}
/* All this effort to report an error ... */
void
{
else
/* ssh_gssapi_last_error() can't return NULL */
}
char *
{
Buffer b;
char *ret;
buffer_init(&b);
if (ctxt) {
/* Get status codes from the Gssctxt */
/* Output them if desired */
if (major_status)
*major_status = maj;
if (minor_status)
*minor_status = min;
/* Get mechanism for minor status display */
} else if (major_status && minor_status) {
maj = *major_status;
min = *major_status;
} else {
min = 0;
}
more = 0;
/* The GSSAPI error */
do {
buffer_put_char(&b, '\n');
} while (more != 0);
/* The mechanism specific error */
do {
/*
* If mech == GSS_C_NULL_OID we may get the default
* mechanism, whatever that is, and that may not be
* useful.
*/
&msg);
buffer_put_char(&b, '\n');
} while (more != 0);
buffer_put_char(&b, '\0');
buffer_free(&b);
return (ret);
}
/*
* Initialise our GSSAPI context. We use this opaque structure to contain all
* of the data which both the client and server need to persist across
* {accept,init}_sec_context calls, so that when we do it from the userauth
* stuff life is a little easier
*/
void
{
/* This happens to be redundant given the memset() above */
}
{
return (new_oid);
}
{
return (ssh_gssapi_dup_oid(&oid));
}
void
{
return;
if (*oid == GSS_C_NULL_OID)
return; /* libgss did own this gss_OID and released it */
*oid = GSS_C_NULL_OID;
}
struct gss_name {
void *mech_name;
};
/* Delete our context, providing it has been built correctly */
void
{
return;
#if 0
/* XXX */
#endif
#if 0
#endif
}
/* Create a GSS hostbased service principal name for a given server hostname */
int
{
int ret;
/* Build target principal */
return (0);
}
return (1);
}
{
}
{
}
#endif /* GSSAPI */