gss-clnt.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* 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
* documentation and/or other materials provided with the distribution.
*
* 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 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include "includes.h"
#ifdef GSSAPI
#pragma ident "%Z%%M% %I% %E% SMI"
#include "ssh.h"
#include "ssh2.h"
#include "xmalloc.h"
#include "buffer.h"
#include "bufaux.h"
#include "packet.h"
#include "compat.h"
#include <openssl/evp.h>
#include "cipher.h"
#include "kex.h"
#include "log.h"
#include "compat.h"
#include "monitor_wrap.h"
#include <netdb.h>
#include "ssh-gss.h"
void
ssh_gssapi_client_kex_hook(Kex *kex, char **proposal)
{
gss_OID_set mechs = GSS_C_NULL_OID_SET;
if (kex == NULL || kex->serverhost == NULL)
fatal("INTERNAL ERROR (%s)", __func__);
ssh_gssapi_client_mechs(kex->serverhost, &mechs);
ssh_gssapi_modify_kex(kex, mechs, proposal);
}
void
ssh_gssapi_client_mechs(const char *server_host, gss_OID_set *mechs)
{
gss_OID_set indicated = GSS_C_NULL_OID_SET;
gss_OID_set acquired, supported;
gss_OID mech;
gss_cred_id_t creds;
Gssctxt *ctxt = NULL;
gss_buffer_desc tok;
OM_uint32 maj, min;
int i;
if (!mechs)
return;
*mechs = GSS_C_NULL_OID_SET;
maj = gss_indicate_mechs(&min, &indicated);
if (GSS_ERROR(maj)) {
debug("No GSS-API mechanisms are installed");
return;
}
maj = gss_create_empty_oid_set(&min, &supported);
if (GSS_ERROR(maj)) {
debug("Failed to allocate resources (%s) for GSS-API",
ssh_gssapi_last_error(NULL, &maj, &min));
(void) gss_release_oid_set(&min, &indicated);
return;
}
maj = gss_acquire_cred(&min, GSS_C_NO_NAME, 0, indicated,
GSS_C_INITIATE, &creds, &acquired, NULL);
if (GSS_ERROR(maj)) {
debug("Failed to acquire GSS-API credentials for any "
"mechanisms (%s)",
ssh_gssapi_last_error(NULL, &maj, &min));
(void) gss_release_oid_set(&min, &indicated);
(void) gss_release_oid_set(&min, &supported);
return;
}
(void) gss_release_cred(&min, &creds);
for (i = 0 ; i < acquired->count ; i++) {
mech = &acquired->elements[i];
if (ssh_gssapi_is_spnego(mech))
continue;
ssh_gssapi_build_ctx(&ctxt, 1, mech);
if (!ctxt)
continue;
/*
* This is useful for mechs like Kerberos, which can
* detect unknown target princs here, but not for
* mechs like SPKM, which cannot detect unknown princs
* until context tokens are actually exchanged.
*
* 'Twould be useful to have a test that could save us
* the bother of trying this for SPKM and the such...
*/
maj = ssh_gssapi_init_ctx(ctxt, server_host, 0,
NULL, &tok);
if (GSS_ERROR(maj)) {
debug("Skipping GSS-API mechanism %s (%s)",
ssh_gssapi_oid_to_name(mech),
ssh_gssapi_last_error(ctxt, NULL, NULL));
continue;
}
(void) gss_release_buffer(&min, &tok);
maj = gss_add_oid_set_member(&min, mech, &supported);
if (GSS_ERROR(maj))
debug("Failed to allocate resources (%s) for GSS-API",
ssh_gssapi_last_error(NULL, &maj, &min));
}
*mechs = supported;
}
/* Wrapper to init_sec_context
* Requires that the context contains:
* oid
* server name (from ssh_gssapi_import_name)
*/
OM_uint32
ssh_gssapi_init_ctx(Gssctxt *ctx, const char *server_host, int deleg_creds,
gss_buffer_t recv_tok, gss_buffer_t send_tok)
{
int flags = GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG;
debug("%s(%p, %s, %d, %p, %p)", __func__, ctx, server_host,
deleg_creds, recv_tok, send_tok);
if (deleg_creds) {
flags |= GSS_C_DELEG_FLAG;
debug("Delegating GSS-API credentials");
}
/* Build target principal */
if (ctx->desired_name == GSS_C_NO_NAME &&
!ssh_gssapi_import_name(ctx, server_host))
return ctx->major;
ctx->major=gss_init_sec_context(&ctx->minor,
GSS_C_NO_CREDENTIAL,
&ctx->context,
ctx->desired_name,
ctx->desired_mech,
flags,
0, /* default lifetime */
NULL, /* no channel bindings */
recv_tok,
NULL, /* actual mech type */
send_tok,
&ctx->flags,
NULL); /* actual lifetime */
if (GSS_ERROR(ctx->major))
ssh_gssapi_error(ctx, "calling GSS_Init_sec_context()");
return(ctx->major);
}
#endif /* GSSAPI */