[auth2.c auth2-gss.c auth.h compat.c compat.h gss-genr.c gss-serv-krb5.c
     gss-serv.c monitor.c monitor.h monitor_wrap.c monitor_wrap.h readconf.c
     readconf.h servconf.c servconf.h session.c session.h ssh-gss.h
     ssh_config.5 sshconnect2.c sshd_config sshd_config.5]
     support GSS API user authentication; patches from Simon Wilkinson,
     stripped down and tested by Jakob and myself.
This commit is contained in:
Darren Tucker 2003-08-26 11:49:55 +10:00
parent 30912f7259
commit 0efd155c3c
24 changed files with 1646 additions and 24 deletions

View File

@ -2,6 +2,14 @@
- (djm) Bug #629: Mark ssh_config option "pamauthenticationviakbdint" - (djm) Bug #629: Mark ssh_config option "pamauthenticationviakbdint"
as deprecated. Remove mention from README.privsep. Patch from as deprecated. Remove mention from README.privsep. Patch from
aet AT cc.hut.fi aet AT cc.hut.fi
- (dtucker) OpenBSD CVS Sync
- markus@cvs.openbsd.org 2003/08/22 10:56:09
[auth2.c auth2-gss.c auth.h compat.c compat.h gss-genr.c gss-serv-krb5.c
gss-serv.c monitor.c monitor.h monitor_wrap.c monitor_wrap.h readconf.c
readconf.h servconf.c servconf.h session.c session.h ssh-gss.h
ssh_config.5 sshconnect2.c sshd_config sshd_config.5]
support GSS API user authentication; patches from Simon Wilkinson,
stripped down and tested by Jakob and myself.
20030825 20030825
- (djm) Bug #621: Select OpenSC keys by usage attributes. Patch from - (djm) Bug #621: Select OpenSC keys by usage attributes. Patch from
@ -874,4 +882,4 @@
- Fix sshd BindAddress and -b options for systems using fake-getaddrinfo. - Fix sshd BindAddress and -b options for systems using fake-getaddrinfo.
Report from murple@murple.net, diagnosis from dtucker@zip.com.au Report from murple@murple.net, diagnosis from dtucker@zip.com.au
$Id: ChangeLog,v 1.2906 2003/08/26 00:48:14 djm Exp $ $Id: ChangeLog,v 1.2907 2003/08/26 01:49:55 dtucker Exp $

3
auth.h
View File

@ -1,4 +1,4 @@
/* $OpenBSD: auth.h,v 1.43 2003/07/22 13:35:22 markus Exp $ */ /* $OpenBSD: auth.h,v 1.44 2003/08/22 10:56:08 markus Exp $ */
/* /*
* Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2000 Markus Friedl. All rights reserved.
@ -67,6 +67,7 @@ struct Authctxt {
krb5_principal krb5_user; krb5_principal krb5_user;
char *krb5_ticket_file; char *krb5_ticket_file;
#endif #endif
void *methoddata;
}; };
/* /*
* Every authentication method has to handle authentication requests for * Every authentication method has to handle authentication requests for

243
auth2-gss.c Normal file
View File

@ -0,0 +1,243 @@
/* $OpenBSD: auth2-gss.c,v 1.1 2003/08/22 10:56:08 markus Exp $ */
/*
* 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.
*/
#include "includes.h"
#ifdef GSSAPI
#include "auth.h"
#include "ssh2.h"
#include "xmalloc.h"
#include "log.h"
#include "dispatch.h"
#include "servconf.h"
#include "compat.h"
#include "packet.h"
#include "monitor_wrap.h"
#include "ssh-gss.h"
extern ServerOptions options;
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
*/
static int
userauth_gssapi(Authctxt *authctxt)
{
gss_OID_desc oid = {0, NULL};
Gssctxt *ctxt = NULL;
int mechs;
gss_OID_set supported;
int present;
OM_uint32 ms;
u_int len;
char *doid = NULL;
if (!authctxt->valid || authctxt->user == NULL)
return (0);
mechs = packet_get_int();
if (mechs == 0) {
debug("Mechanism negotiation is not supported");
return (0);
}
ssh_gssapi_supported_oids(&supported);
do {
mechs--;
if (doid)
xfree(doid);
doid = packet_get_string(&len);
if (doid[0] != SSH_GSS_OIDTYPE || doid[1] != len-2) {
logit("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);
gss_release_oid_set(&ms, &supported);
if (!present) {
xfree(doid);
return (0);
}
if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, &oid))))
return (0);
authctxt->methoddata=(void *)ctxt;
packet_start(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE);
/* Return OID in same format as we received it*/
packet_put_string(doid, len);
packet_send();
xfree(doid);
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);
}
static void
input_gssapi_token(int type, u_int32_t plen, void *ctxt)
{
Authctxt *authctxt = ctxt;
Gssctxt *gssctxt;
gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
gss_buffer_desc recv_tok;
OM_uint32 maj_status, min_status;
u_int len;
if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
fatal("No authentication or GSSAPI context");
gssctxt = authctxt->methoddata;
recv_tok.value = packet_get_string(&len);
recv_tok.length = len; /* u_int vs. size_t */
packet_check_eom();
maj_status = PRIVSEP(ssh_gssapi_accept_ctx(gssctxt, &recv_tok,
&send_tok, NULL));
xfree(recv_tok.value);
if (GSS_ERROR(maj_status)) {
if (send_tok.length != 0) {
packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK);
packet_put_string(send_tok.value, send_tok.length);
packet_send();
}
authctxt->postponed = 0;
dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
userauth_finish(authctxt, 0, "gssapi");
} else {
if (send_tok.length != 0) {
packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN);
packet_put_string(send_tok.value, send_tok.length);
packet_send();
}
if (maj_status == GSS_S_COMPLETE) {
dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE,
&input_gssapi_exchange_complete);
}
}
gss_release_buffer(&min_status, &send_tok);
}
static void
input_gssapi_errtok(int type, u_int32_t plen, void *ctxt)
{
Authctxt *authctxt = ctxt;
Gssctxt *gssctxt;
gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
gss_buffer_desc 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);
packet_check_eom();
/* Push the error token into GSSAPI to see what it says */
maj_status = PRIVSEP(ssh_gssapi_accept_ctx(gssctxt, &recv_tok,
&send_tok, NULL));
xfree(recv_tok.value);
/* We can't return anything to the client, even if we wanted to */
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 */
gss_release_buffer(&maj_status, &send_tok);
}
/*
* This is called when the client thinks we've completed authentication.
* It should only be enabled in the dispatch handler by the function above,
* which only enables it once the GSSAPI exchange is complete.
*/
static void
input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt)
{
Authctxt *authctxt = ctxt;
Gssctxt *gssctxt;
int authenticated;
if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
fatal("No authentication or GSSAPI context");
gssctxt = authctxt->methoddata;
/*
* We don't need to check the status, because the stored credentials
* which userok uses are only populated once the context init step
* has returned complete.
*/
packet_check_eom();
authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user));
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");
}
Authmethod method_gssapi = {
"gssapi",
userauth_gssapi,
&options.gss_authentication
};
#endif /* GSSAPI */

18
auth2.c
View File

@ -23,7 +23,7 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$OpenBSD: auth2.c,v 1.99 2003/06/24 08:23:46 markus Exp $"); RCSID("$OpenBSD: auth2.c,v 1.100 2003/08/22 10:56:08 markus Exp $");
#include "ssh2.h" #include "ssh2.h"
#include "xmalloc.h" #include "xmalloc.h"
@ -36,6 +36,10 @@ RCSID("$OpenBSD: auth2.c,v 1.99 2003/06/24 08:23:46 markus Exp $");
#include "pathnames.h" #include "pathnames.h"
#include "monitor_wrap.h" #include "monitor_wrap.h"
#ifdef GSSAPI
#include "ssh-gss.h"
#endif
/* import */ /* import */
extern ServerOptions options; extern ServerOptions options;
extern u_char *session_id2; extern u_char *session_id2;
@ -53,10 +57,16 @@ extern Authmethod method_hostbased;
#ifdef KRB5 #ifdef KRB5
extern Authmethod method_kerberos; extern Authmethod method_kerberos;
#endif #endif
#ifdef GSSAPI
extern Authmethod method_gssapi;
#endif
Authmethod *authmethods[] = { Authmethod *authmethods[] = {
&method_none, &method_none,
&method_pubkey, &method_pubkey,
#ifdef GSSAPI
&method_gssapi,
#endif
&method_passwd, &method_passwd,
&method_kbdint, &method_kbdint,
&method_hostbased, &method_hostbased,
@ -184,6 +194,12 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt)
} }
/* reset state */ /* reset state */
auth2_challenge_stop(authctxt); auth2_challenge_stop(authctxt);
#ifdef GSSAPI
dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL);
#endif
authctxt->postponed = 0; authctxt->postponed = 0;
/* try to authenticate user */ /* try to authenticate user */

View File

@ -23,7 +23,7 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$OpenBSD: compat.c,v 1.67 2003/04/08 20:21:28 itojun Exp $"); RCSID("$OpenBSD: compat.c,v 1.68 2003/08/22 10:56:09 markus Exp $");
#include "buffer.h" #include "buffer.h"
#include "packet.h" #include "packet.h"
@ -79,7 +79,11 @@ compat_datafellows(const char *version)
{ "OpenSSH_2.5.3*", SSH_BUG_NOREKEY|SSH_BUG_EXTEOF}, { "OpenSSH_2.5.3*", SSH_BUG_NOREKEY|SSH_BUG_EXTEOF},
{ "OpenSSH_2.*," { "OpenSSH_2.*,"
"OpenSSH_3.0*," "OpenSSH_3.0*,"
"OpenSSH_3.1*", SSH_BUG_EXTEOF}, "OpenSSH_3.1*", SSH_BUG_EXTEOF|SSH_BUG_GSSAPI_BER},
{ "OpenSSH_3.2*,"
"OpenSSH_3.3*,"
"OpenSSH_3.4*,"
"OpenSSH_3.5*", SSH_BUG_GSSAPI_BER},
{ "Sun_SSH_1.0*", SSH_BUG_NOREKEY|SSH_BUG_EXTEOF}, { "Sun_SSH_1.0*", SSH_BUG_NOREKEY|SSH_BUG_EXTEOF},
{ "OpenSSH*", 0 }, { "OpenSSH*", 0 },
{ "*MindTerm*", 0 }, { "*MindTerm*", 0 },

View File

@ -1,4 +1,4 @@
/* $OpenBSD: compat.h,v 1.34 2003/04/01 10:31:26 markus Exp $ */ /* $OpenBSD: compat.h,v 1.35 2003/08/22 10:56:09 markus Exp $ */
/* /*
* Copyright (c) 1999, 2000, 2001 Markus Friedl. All rights reserved. * Copyright (c) 1999, 2000, 2001 Markus Friedl. All rights reserved.
@ -56,6 +56,7 @@
#define SSH_BUG_K5USER 0x00400000 #define SSH_BUG_K5USER 0x00400000
#define SSH_BUG_PROBE 0x00800000 #define SSH_BUG_PROBE 0x00800000
#define SSH_BUG_FIRSTKEX 0x01000000 #define SSH_BUG_FIRSTKEX 0x01000000
#define SSH_BUG_GSSAPI_BER 0x02000000
void enable_compat13(void); void enable_compat13(void);
void enable_compat20(void); void enable_compat20(void);

256
gss-genr.c Normal file
View File

@ -0,0 +1,256 @@
/* $OpenBSD: gss-genr.c,v 1.1 2003/08/22 10:56:09 markus Exp $ */
/*
* 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.
*/
#include "includes.h"
#ifdef GSSAPI
#include "xmalloc.h"
#include "bufaux.h"
#include "compat.h"
#include "log.h"
#include "monitor_wrap.h"
#include "ssh-gss.h"
/* 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)
{
return (ctx != NULL && ctx->oid != GSS_C_NO_OID &&
ctx->oid->length == len &&
memcmp(ctx->oid->elements, data, len) == 0);
}
/* Set the contexts OID from a data stream */
void
ssh_gssapi_set_oid_data(Gssctxt *ctx, void *data, size_t len)
{
if (ctx->oid != GSS_C_NO_OID) {
xfree(ctx->oid->elements);
xfree(ctx->oid);
}
ctx->oid = xmalloc(sizeof(gss_OID_desc));
ctx->oid->length = len;
ctx->oid->elements = xmalloc(len);
memcpy(ctx->oid->elements, data, len);
}
/* Set the contexts OID */
void
ssh_gssapi_set_oid(Gssctxt *ctx, gss_OID oid)
{
ssh_gssapi_set_oid_data(ctx, oid->elements, oid->length);
}
/* All this effort to report an error ... */
void
ssh_gssapi_error(Gssctxt *ctxt)
{
debug("%s", ssh_gssapi_last_error(ctxt, NULL, NULL));
}
char *
ssh_gssapi_last_error(Gssctxt *ctxt,
OM_uint32 *major_status, OM_uint32 *minor_status)
{
OM_uint32 lmin;
gss_buffer_desc msg = GSS_C_EMPTY_BUFFER;
OM_uint32 ctx;
Buffer b;
char *ret;
buffer_init(&b);
if (major_status != NULL)
*major_status = ctxt->major;
if (minor_status != NULL)
*minor_status = ctxt->minor;
ctx = 0;
/* The GSSAPI error */
do {
gss_display_status(&lmin, ctxt->major,
GSS_C_GSS_CODE, GSS_C_NULL_OID, &ctx, &msg);
buffer_append(&b, msg.value, msg.length);
buffer_put_char(&b, '\n');
gss_release_buffer(&lmin, &msg);
} while (ctx != 0);
/* The mechanism specific error */
do {
gss_display_status(&lmin, ctxt->minor,
GSS_C_MECH_CODE, GSS_C_NULL_OID, &ctx, &msg);
buffer_append(&b, msg.value, msg.length);
buffer_put_char(&b, '\n');
gss_release_buffer(&lmin, &msg);
} while (ctx != 0);
buffer_put_char(&b, '\0');
ret = xmalloc(buffer_len(&b));
buffer_get(&b, ret, buffer_len(&b));
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
ssh_gssapi_build_ctx(Gssctxt **ctx)
{
*ctx = xmalloc(sizeof (Gssctxt));
(*ctx)->major = 0;
(*ctx)->minor = 0;
(*ctx)->context = GSS_C_NO_CONTEXT;
(*ctx)->name = GSS_C_NO_NAME;
(*ctx)->oid = GSS_C_NO_OID;
(*ctx)->creds = GSS_C_NO_CREDENTIAL;
(*ctx)->client = GSS_C_NO_NAME;
(*ctx)->client_creds = GSS_C_NO_CREDENTIAL;
}
/* Delete our context, providing it has been built correctly */
void
ssh_gssapi_delete_ctx(Gssctxt **ctx)
{
OM_uint32 ms;
if ((*ctx) == NULL)
return;
if ((*ctx)->context != GSS_C_NO_CONTEXT)
gss_delete_sec_context(&ms, &(*ctx)->context, GSS_C_NO_BUFFER);
if ((*ctx)->name != GSS_C_NO_NAME)
gss_release_name(&ms, &(*ctx)->name);
if ((*ctx)->oid != GSS_C_NO_OID) {
xfree((*ctx)->oid->elements);
xfree((*ctx)->oid);
(*ctx)->oid = GSS_C_NO_OID;
}
if ((*ctx)->creds != GSS_C_NO_CREDENTIAL)
gss_release_cred(&ms, &(*ctx)->creds);
if ((*ctx)->client != GSS_C_NO_NAME)
gss_release_name(&ms, &(*ctx)->client);
if ((*ctx)->client_creds != GSS_C_NO_CREDENTIAL)
gss_release_cred(&ms, &(*ctx)->client_creds);
xfree(*ctx);
*ctx = NULL;
}
/*
* 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, int deleg_creds, gss_buffer_desc *recv_tok,
gss_buffer_desc* send_tok, OM_uint32 *flags)
{
int deleg_flag = 0;
if (deleg_creds) {
deleg_flag = GSS_C_DELEG_FLAG;
debug("Delegating credentials");
}
ctx->major = gss_init_sec_context(&ctx->minor,
GSS_C_NO_CREDENTIAL, &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);
if (GSS_ERROR(ctx->major))
ssh_gssapi_error(ctx);
return (ctx->major);
}
/* Create a service name for the given host */
OM_uint32
ssh_gssapi_import_name(Gssctxt *ctx, const char *host)
{
gss_buffer_desc gssbuf;
gssbuf.length = sizeof("host@") + strlen(host);
gssbuf.value = xmalloc(gssbuf.length);
snprintf(gssbuf.value, gssbuf.length, "host@%s", host);
if ((ctx->major = gss_import_name(&ctx->minor,
&gssbuf, GSS_C_NT_HOSTBASED_SERVICE, &ctx->name)))
ssh_gssapi_error(ctx);
xfree(gssbuf.value);
return (ctx->major);
}
/* Acquire credentials for a server running on the current host.
* Requires that the context structure contains a valid OID
*/
/* Returns a GSSAPI error code */
OM_uint32
ssh_gssapi_acquire_cred(Gssctxt *ctx)
{
OM_uint32 status;
char lname[MAXHOSTNAMELEN];
gss_OID_set oidset;
gss_create_empty_oid_set(&status, &oidset);
gss_add_oid_set_member(&status, ctx->oid, &oidset);
if (gethostname(lname, MAXHOSTNAMELEN))
return (-1);
if (GSS_ERROR(ssh_gssapi_import_name(ctx, lname)))
return (ctx->major);
if ((ctx->major = gss_acquire_cred(&ctx->minor,
ctx->name, 0, oidset, GSS_C_ACCEPT, &ctx->creds, NULL, NULL)))
ssh_gssapi_error(ctx);
gss_release_oid_set(&status, &oidset);
return (ctx->major);
}
OM_uint32
ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID oid) {
if (*ctx)
ssh_gssapi_delete_ctx(ctx);
ssh_gssapi_build_ctx(ctx);
ssh_gssapi_set_oid(*ctx, oid);
return (ssh_gssapi_acquire_cred(*ctx));
}
#endif /* GSSAPI */

168
gss-serv-krb5.c Normal file
View File

@ -0,0 +1,168 @@
/* $OpenBSD: gss-serv-krb5.c,v 1.1 2003/08/22 10:56:09 markus Exp $ */
/*
* 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.
*/
#include "includes.h"
#ifdef GSSAPI
#ifdef KRB5
#include "auth.h"
#include "xmalloc.h"
#include "log.h"
#include "servconf.h"
#include "ssh-gss.h"
extern ServerOptions options;
#include <krb5.h>
static krb5_context krb_context = NULL;
/* Initialise the krb5 library, for the stuff that GSSAPI won't do */
static int
ssh_gssapi_krb5_init()
{
krb5_error_code problem;
if (krb_context != NULL)
return 1;
problem = krb5_init_context(&krb_context);
if (problem) {
logit("Cannot initialize krb5 context");
return 0;
}
krb5_init_ets(krb_context);
return 1;
}
/* Check if this user is OK to login. This only works with krb5 - other
* GSSAPI mechanisms will need their own.
* Returns true if the user is OK to log in, otherwise returns 0
*/
static int
ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name)
{
krb5_principal princ;
int retval;
if (ssh_gssapi_krb5_init() == 0)
return 0;
if ((retval = krb5_parse_name(krb_context, client->exportedname.value,
&princ))) {
logit("krb5_parse_name(): %.100s",
krb5_get_err_text(krb_context, retval));
return 0;
}
if (krb5_kuserok(krb_context, princ, name)) {
retval = 1;
logit("Authorized to %s, krb5 principal %s (krb5_kuserok)",
name, (char *)client->displayname.value);
} else
retval = 0;
krb5_free_principal(krb_context, princ);
return retval;
}
/* This writes out any forwarded credentials from the structure populated
* during userauth. Called after we have setuid to the user */
static void
ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client)
{
krb5_ccache ccache;
krb5_error_code problem;
krb5_principal princ;
OM_uint32 maj_status, min_status;
if (client->creds == NULL) {
debug("No credentials stored");
return;
}
if (ssh_gssapi_krb5_init() == 0)
return;
if ((problem = krb5_cc_gen_new(krb_context, &krb5_fcc_ops, &ccache))) {
logit("krb5_cc_gen_new(): %.100s",
krb5_get_err_text(krb_context, problem));
return;
}
if ((problem = krb5_parse_name(krb_context,
client->exportedname.value, &princ))) {
logit("krb5_parse_name(): %.100s",
krb5_get_err_text(krb_context, problem));
krb5_cc_destroy(krb_context, ccache);
return;
}
if ((problem = krb5_cc_initialize(krb_context, ccache, princ))) {
logit("krb5_cc_initialize(): %.100s",
krb5_get_err_text(krb_context, problem));
krb5_free_principal(krb_context, princ);
krb5_cc_destroy(krb_context, ccache);
return;
}
krb5_free_principal(krb_context, princ);
if ((maj_status = gss_krb5_copy_ccache(&min_status,
client->creds, ccache))) {
logit("gss_krb5_copy_ccache() failed");
krb5_cc_destroy(krb_context, ccache);
return;
}
client->store.filename = xstrdup(krb5_cc_get_name(krb_context, ccache));
client->store.envvar = "KRB5CCNAME";
client->store.envval = xstrdup(client->store.filename);
krb5_cc_close(krb_context, ccache);
return;
}
ssh_gssapi_mech gssapi_kerberos_mech = {
"toWM5Slw5Ew8Mqkay+al2g==",
"Kerberos",
{9, "\x2A\x86\x48\x86\xF7\x12\x01\x02\x02"},
NULL,
&ssh_gssapi_krb5_userok,
NULL,
&ssh_gssapi_krb5_storecreds
};
#endif /* KRB5 */
#endif /* GSSAPI */

291
gss-serv.c Normal file
View File

@ -0,0 +1,291 @@
/* $OpenBSD: gss-serv.c,v 1.1 2003/08/22 10:56:09 markus Exp $ */
/*
* 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.
*/
#include "includes.h"
#ifdef GSSAPI
#include "bufaux.h"
#include "compat.h"
#include "auth.h"
#include "log.h"
#include "channels.h"
#include "session.h"
#include "servconf.h"
#include "monitor_wrap.h"
#include "xmalloc.h"
#include "getput.h"
#include "ssh-gss.h"
extern ServerOptions options;
static ssh_gssapi_client gssapi_client =
{ GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER,
GSS_C_NO_CREDENTIAL, NULL, {NULL, NULL, NULL}};
ssh_gssapi_mech gssapi_null_mech =
{ NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL};
#ifdef KRB5
extern ssh_gssapi_mech gssapi_kerberos_mech;
#endif
ssh_gssapi_mech* supported_mechs[]= {
#ifdef KRB5
&gssapi_kerberos_mech,
#endif
&gssapi_null_mech,
};
/* Unpriviledged */
void
ssh_gssapi_supported_oids(gss_OID_set *oidset)
{
int i = 0;
OM_uint32 min_status;
int present;
gss_OID_set supported;
gss_create_empty_oid_set(&min_status, oidset);
gss_indicate_mechs(&min_status, &supported);
while (supported_mechs[i]->name != NULL) {
if (GSS_ERROR(gss_test_oid_set_member(&min_status,
&supported_mechs[i]->oid, supported, &present)))
present = 0;
if (present)
gss_add_oid_set_member(&min_status,
&supported_mechs[i]->oid, oidset);
i++;
}
}
/* 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)
{
OM_uint32 status;
gss_OID mech;
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);
if (GSS_ERROR(ctx->major))
ssh_gssapi_error(ctx);
if (ctx->client_creds)
debug("Received some client credentials");
else
debug("Got no client credentials");
status = ctx->major;
/* Now, if we're complete and we have the right flags, then
* we flag the user as also having been authenticated
*/
if (((flags == NULL) || ((*flags & GSS_C_MUTUAL_FLAG) &&
(*flags & GSS_C_INTEG_FLAG))) && (ctx->major == GSS_S_COMPLETE)) {
if (ssh_gssapi_getclient(ctx, &gssapi_client))
fatal("Couldn't convert client name");
}
return (status);
}
/*
* This parses an exported name, extracting the mechanism specific portion
* to use for ACL checking. It verifies that the name belongs the mechanism
* originally selected.
*/
static OM_uint32
ssh_gssapi_parse_ename(Gssctxt *ctx, gss_buffer_t ename, gss_buffer_t name)
{
char *tok;
OM_uint32 offset;
OM_uint32 oidl;
tok=ename->value;
/*
* Check that ename is long enough for all of the fixed length
* header, and that the initial ID bytes are correct
*/
if (ename->length<6 || memcmp(tok,"\x04\x01", 2)!=0)
return GSS_S_FAILURE;
/*
* Extract the OID, and check it. Here GSSAPI breaks with tradition
* and does use the OID type and length bytes. To confuse things
* there are two lengths - the first including these, and the
* second without.
*/
oidl = GET_16BIT(tok+2); /* length including next two bytes */
oidl = oidl-2; /* turn it into the _real_ length of the variable OID */
/*
* Check the BER encoding for correct type and length, that the
* string is long enough and that the OID matches that in our context
*/
if (tok[4] != 0x06 || tok[5] != oidl ||
ename->length < oidl+6 ||
!ssh_gssapi_check_oid(ctx,tok+6,oidl))
return GSS_S_FAILURE;
offset = oidl+6;
if (ename->length < offset+4)
return GSS_S_FAILURE;
name->length = GET_32BIT(tok+offset);
offset += 4;
if (ename->length < offset+name->length)
return GSS_S_FAILURE;
name->value = xmalloc(name->length);
memcpy(name->value,tok+offset,name->length);
return GSS_S_COMPLETE;
}
/* 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_client *client)
{
int i = 0;
gss_buffer_desc ename;
client->mech = NULL;
while (supported_mechs[i]->name != NULL) {
if (supported_mechs[i]->oid.length == ctx->oid->length &&
(memcmp(supported_mechs[i]->oid.elements,
ctx->oid->elements, ctx->oid->length) == 0))
client->mech = supported_mechs[i];
i++;
}
if (client->mech == NULL)
return GSS_S_FAILURE;
if ((ctx->major = gss_display_name(&ctx->minor, ctx->client,
&client->displayname, NULL))) {
ssh_gssapi_error(ctx);
return (ctx->major);
}
if ((ctx->major = gss_export_name(&ctx->minor, ctx->client,
&ename))) {
ssh_gssapi_error(ctx);
return (ctx->major);
}
if ((ctx->major = ssh_gssapi_parse_ename(ctx,&ename,
&client->exportedname))) {
return (ctx->major);
}
/* We can't copy this structure, so we just move the pointer to it */
client->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)
{
if (gssapi_client.store.filename != NULL) {
/* Unlink probably isn't sufficient */
debug("removing gssapi cred file\"%s\"", gssapi_client.store.filename);
unlink(gssapi_client.store.filename);
}
}
/* As user */
void
ssh_gssapi_storecreds(void)
{
if (gssapi_client.mech && gssapi_client.mech->storecreds) {
(*gssapi_client.mech->storecreds)(&gssapi_client);
if (options.gss_cleanup_creds)
fatal_add_cleanup(ssh_gssapi_cleanup_creds, NULL);
} else
debug("ssh_gssapi_storecreds: Not a GSSAPI mechanism");
}
/* This allows GSSAPI methods to do things to the childs environment based
* on the passed authentication process and credentials.
*/
/* As user */
void
ssh_gssapi_do_child(char ***envp, u_int *envsizep)
{
if (gssapi_client.store.envvar != NULL &&
gssapi_client.store.envval != NULL) {
debug("Setting %s to %s", gssapi_client.store.envvar,
gssapi_client.store.envval);
child_set_env(envp, envsizep, gssapi_client.store.envvar,
gssapi_client.store.envval);
}
}
/* Priviledged */
int
ssh_gssapi_userok(char *user)
{
if (gssapi_client.exportedname.length == 0 ||
gssapi_client.exportedname.value == NULL) {
debug("No suitable client data");
return 0;
}
if (gssapi_client.mech && gssapi_client.mech->userok)
return ((*gssapi_client.mech->userok)(&gssapi_client, user));
else
debug("ssh_gssapi_userok: Unknown GSSAPI mechanism");
return (0);
}
#endif

View File

@ -25,7 +25,7 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$OpenBSD: monitor.c,v 1.45 2003/07/22 13:35:22 markus Exp $"); RCSID("$OpenBSD: monitor.c,v 1.46 2003/08/22 10:56:09 markus Exp $");
#include <openssl/dh.h> #include <openssl/dh.h>
@ -59,6 +59,11 @@ RCSID("$OpenBSD: monitor.c,v 1.45 2003/07/22 13:35:22 markus Exp $");
#include "ssh2.h" #include "ssh2.h"
#include "mpaux.h" #include "mpaux.h"
#ifdef GSSAPI
#include "ssh-gss.h"
static Gssctxt *gsscontext = NULL;
#endif
/* Imports */ /* Imports */
extern ServerOptions options; extern ServerOptions options;
extern u_int utmp_len; extern u_int utmp_len;
@ -128,6 +133,11 @@ int mm_answer_pam_free_ctx(int, Buffer *);
#ifdef KRB5 #ifdef KRB5
int mm_answer_krb5(int, Buffer *); int mm_answer_krb5(int, Buffer *);
#endif #endif
#ifdef GSSAPI
int mm_answer_gss_setup_ctx(int, Buffer *);
int mm_answer_gss_accept_ctx(int, Buffer *);
int mm_answer_gss_userok(int, Buffer *);
#endif
static Authctxt *authctxt; static Authctxt *authctxt;
static BIGNUM *ssh1_challenge = NULL; /* used for ssh1 rsa auth */ static BIGNUM *ssh1_challenge = NULL; /* used for ssh1 rsa auth */
@ -184,6 +194,11 @@ struct mon_table mon_dispatch_proto20[] = {
{MONITOR_REQ_KEYVERIFY, MON_AUTH, mm_answer_keyverify}, {MONITOR_REQ_KEYVERIFY, MON_AUTH, mm_answer_keyverify},
#ifdef KRB5 #ifdef KRB5
{MONITOR_REQ_KRB5, MON_ONCE|MON_AUTH, mm_answer_krb5}, {MONITOR_REQ_KRB5, MON_ONCE|MON_AUTH, mm_answer_krb5},
#endif
#ifdef GSSAPI
{MONITOR_REQ_GSSSETUP, MON_ISAUTH, mm_answer_gss_setup_ctx},
{MONITOR_REQ_GSSSTEP, MON_ISAUTH, mm_answer_gss_accept_ctx},
{MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok},
#endif #endif
{0, 0, NULL} {0, 0, NULL}
}; };
@ -357,7 +372,6 @@ monitor_child_postauth(struct monitor *pmonitor)
monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1);
monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1);
monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1);
} else { } else {
mon_dispatch = mon_dispatch_postauth15; mon_dispatch = mon_dispatch_postauth15;
monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1);
@ -1769,3 +1783,77 @@ monitor_reinit(struct monitor *mon)
mon->m_recvfd = pair[0]; mon->m_recvfd = pair[0];
mon->m_sendfd = pair[1]; mon->m_sendfd = pair[1];
} }
#ifdef GSSAPI
int
mm_answer_gss_setup_ctx(int socket, Buffer *m)
{
gss_OID_desc oid;
OM_uint32 major;
u_int len;
oid.elements = buffer_get_string(m, &len);
oid.length = len;
major = ssh_gssapi_server_ctx(&gsscontext, &oid);
xfree(oid.elements);
buffer_clear(m);
buffer_put_int(m, major);
mm_request_send(socket,MONITOR_ANS_GSSSETUP, m);
/* Now we have a context, enable the step */
monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 1);
return (0);
}
int
mm_answer_gss_accept_ctx(int socket, Buffer *m)
{
gss_buffer_desc in;
gss_buffer_desc out = GSS_C_EMPTY_BUFFER;
OM_uint32 major,minor;
OM_uint32 flags = 0; /* GSI needs this */
in.value = buffer_get_string(m, &in.length);
major = ssh_gssapi_accept_ctx(gsscontext, &in, &out, &flags);
xfree(in.value);
buffer_clear(m);
buffer_put_int(m, major);
buffer_put_string(m, out.value, out.length);
buffer_put_int(m, flags);
mm_request_send(socket, MONITOR_ANS_GSSSTEP, m);
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_GSSUSEROK, 1);
}
return (0);
}
int
mm_answer_gss_userok(int socket, Buffer *m)
{
int authenticated;
authenticated = authctxt->valid && ssh_gssapi_userok(authctxt->user);
buffer_clear(m);
buffer_put_int(m, authenticated);
debug3("%s: sending result %d", __func__, authenticated);
mm_request_send(socket, MONITOR_ANS_GSSUSEROK, m);
auth_method="gssapi";
/* Monitor loop will terminate if authenticated */
return (authenticated);
}
#endif /* GSSAPI */

View File

@ -1,4 +1,4 @@
/* $OpenBSD: monitor.h,v 1.9 2003/07/22 13:35:22 markus Exp $ */ /* $OpenBSD: monitor.h,v 1.10 2003/08/22 10:56:09 markus Exp $ */
/* /*
* Copyright 2002 Niels Provos <provos@citi.umich.edu> * Copyright 2002 Niels Provos <provos@citi.umich.edu>
@ -50,6 +50,9 @@ enum monitor_reqtype {
MONITOR_REQ_RSACHALLENGE, MONITOR_ANS_RSACHALLENGE, MONITOR_REQ_RSACHALLENGE, MONITOR_ANS_RSACHALLENGE,
MONITOR_REQ_RSARESPONSE, MONITOR_ANS_RSARESPONSE, MONITOR_REQ_RSARESPONSE, MONITOR_ANS_RSARESPONSE,
MONITOR_REQ_KRB5, MONITOR_ANS_KRB5, MONITOR_REQ_KRB5, MONITOR_ANS_KRB5,
MONITOR_REQ_GSSSETUP, MONITOR_ANS_GSSSETUP,
MONITOR_REQ_GSSSTEP, MONITOR_ANS_GSSSTEP,
MONITOR_REQ_GSSUSEROK, MONITOR_ANS_GSSUSEROK,
MONITOR_REQ_PAM_START, MONITOR_REQ_PAM_START,
MONITOR_REQ_PAM_ACCOUNT, MONITOR_ANS_PAM_ACCOUNT, MONITOR_REQ_PAM_ACCOUNT, MONITOR_ANS_PAM_ACCOUNT,
MONITOR_REQ_PAM_INIT_CTX, MONITOR_ANS_PAM_INIT_CTX, MONITOR_REQ_PAM_INIT_CTX, MONITOR_ANS_PAM_INIT_CTX,

View File

@ -25,7 +25,7 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$OpenBSD: monitor_wrap.c,v 1.28 2003/07/22 13:35:22 markus Exp $"); RCSID("$OpenBSD: monitor_wrap.c,v 1.29 2003/08/22 10:56:09 markus Exp $");
#include <openssl/bn.h> #include <openssl/bn.h>
#include <openssl/dh.h> #include <openssl/dh.h>
@ -53,6 +53,10 @@ RCSID("$OpenBSD: monitor_wrap.c,v 1.28 2003/07/22 13:35:22 markus Exp $");
#include "channels.h" #include "channels.h"
#include "session.h" #include "session.h"
#ifdef GSSAPI
#include "ssh-gss.h"
#endif
/* Imports */ /* Imports */
extern int compat20; extern int compat20;
extern Newkeys *newkeys[]; extern Newkeys *newkeys[];
@ -1100,4 +1104,69 @@ mm_auth_krb5(void *ctx, void *argp, char **userp, void *resp)
buffer_free(&m); buffer_free(&m);
return (success); return (success);
} }
#endif #endif /* KRB5 */
#ifdef GSSAPI
OM_uint32
mm_ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID oid)
{
Buffer m;
OM_uint32 major;
/* Client doesn't get to see the context */
*ctx = NULL;
buffer_init(&m);
buffer_put_string(&m, oid->elements, oid->length);
mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSSETUP, &m);
mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSSETUP, &m);
major = buffer_get_int(&m);
buffer_free(&m);
return (major);
}
OM_uint32
mm_ssh_gssapi_accept_ctx(Gssctxt *ctx, gss_buffer_desc *in,
gss_buffer_desc *out, OM_uint32 *flags)
{
Buffer m;
OM_uint32 major;
buffer_init(&m);
buffer_put_string(&m, in->value, in->length);
mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSSTEP, &m);
mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSSTEP, &m);
major = buffer_get_int(&m);
out->value = buffer_get_string(&m, &out->length);
if (flags)
*flags = buffer_get_int(&m);
buffer_free(&m);
return (major);
}
int
mm_ssh_gssapi_userok(char *user)
{
Buffer m;
int authenticated = 0;
buffer_init(&m);
mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSUSEROK, &m);
mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSUSEROK,
&m);
authenticated = buffer_get_int(&m);
buffer_free(&m);
debug3("%s: user %sauthenticated",__func__, authenticated ? "" : "not ");
return (authenticated);
}
#endif /* GSSAPI */

View File

@ -1,4 +1,4 @@
/* $OpenBSD: monitor_wrap.h,v 1.9 2003/07/22 13:35:22 markus Exp $ */ /* $OpenBSD: monitor_wrap.h,v 1.10 2003/08/22 10:56:09 markus Exp $ */
/* /*
* Copyright 2002 Niels Provos <provos@citi.umich.edu> * Copyright 2002 Niels Provos <provos@citi.umich.edu>
@ -55,6 +55,14 @@ int mm_auth_rsa_key_allowed(struct passwd *, BIGNUM *, Key **);
int mm_auth_rsa_verify_response(Key *, BIGNUM *, u_char *); int mm_auth_rsa_verify_response(Key *, BIGNUM *, u_char *);
BIGNUM *mm_auth_rsa_generate_challenge(Key *); BIGNUM *mm_auth_rsa_generate_challenge(Key *);
#ifdef GSSAPI
#include "ssh-gss.h"
OM_uint32 mm_ssh_gssapi_server_ctx(Gssctxt **ctxt, gss_OID oid);
OM_uint32 mm_ssh_gssapi_accept_ctx(Gssctxt *ctxt,
gss_buffer_desc *recv, gss_buffer_desc *send, OM_uint32 *flags);
int mm_ssh_gssapi_userok(char *user);
#endif
#ifdef USE_PAM #ifdef USE_PAM
void mm_start_pam(char *); void mm_start_pam(char *);
u_int mm_do_pam_account(void); u_int mm_do_pam_account(void);

View File

@ -12,7 +12,7 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$OpenBSD: readconf.c,v 1.117 2003/08/13 09:07:09 markus Exp $"); RCSID("$OpenBSD: readconf.c,v 1.118 2003/08/22 10:56:09 markus Exp $");
#include "ssh.h" #include "ssh.h"
#include "xmalloc.h" #include "xmalloc.h"
@ -105,7 +105,7 @@ typedef enum {
oHostKeyAlgorithms, oBindAddress, oSmartcardDevice, oHostKeyAlgorithms, oBindAddress, oSmartcardDevice,
oClearAllForwardings, oNoHostAuthenticationForLocalhost, oClearAllForwardings, oNoHostAuthenticationForLocalhost,
oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout, oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
oAddressFamily, oAddressFamily, oGssAuthentication, oGssDelegateCreds,
oDeprecated, oUnsupported oDeprecated, oUnsupported
} OpCodes; } OpCodes;
@ -140,6 +140,14 @@ static struct {
{ "kerberostgtpassing", oUnsupported }, { "kerberostgtpassing", oUnsupported },
#endif #endif
{ "afstokenpassing", oUnsupported }, { "afstokenpassing", oUnsupported },
#if defined(GSSAPI)
{ "gssapiauthentication", oGssAuthentication },
{ "gssapidelegatecreds", oGssDelegateCreds },
{ "gssapidelegatecredentials", oGssDelegateCreds },
#else
{ "gssapiauthentication", oUnsupported },
{ "gssapidelegatecredentials", oUnsupported },
#endif
{ "fallbacktorsh", oDeprecated }, { "fallbacktorsh", oDeprecated },
{ "usersh", oDeprecated }, { "usersh", oDeprecated },
{ "identityfile", oIdentityFile }, { "identityfile", oIdentityFile },
@ -389,6 +397,14 @@ parse_flag:
intptr = &options->kerberos_tgt_passing; intptr = &options->kerberos_tgt_passing;
goto parse_flag; goto parse_flag;
case oGssAuthentication:
intptr = &options->gss_authentication;
goto parse_flag;
case oGssDelegateCreds:
intptr = &options->gss_deleg_creds;
goto parse_flag;
case oBatchMode: case oBatchMode:
intptr = &options->batch_mode; intptr = &options->batch_mode;
goto parse_flag; goto parse_flag;
@ -813,6 +829,8 @@ initialize_options(Options * options)
options->challenge_response_authentication = -1; options->challenge_response_authentication = -1;
options->kerberos_authentication = -1; options->kerberos_authentication = -1;
options->kerberos_tgt_passing = -1; options->kerberos_tgt_passing = -1;
options->gss_authentication = -1;
options->gss_deleg_creds = -1;
options->password_authentication = -1; options->password_authentication = -1;
options->kbd_interactive_authentication = -1; options->kbd_interactive_authentication = -1;
options->kbd_interactive_devices = NULL; options->kbd_interactive_devices = NULL;
@ -887,6 +905,10 @@ fill_default_options(Options * options)
options->kerberos_authentication = 1; options->kerberos_authentication = 1;
if (options->kerberos_tgt_passing == -1) if (options->kerberos_tgt_passing == -1)
options->kerberos_tgt_passing = 1; options->kerberos_tgt_passing = 1;
if (options->gss_authentication == -1)
options->gss_authentication = 1;
if (options->gss_deleg_creds == -1)
options->gss_deleg_creds = 0;
if (options->password_authentication == -1) if (options->password_authentication == -1)
options->password_authentication = 1; options->password_authentication = 1;
if (options->kbd_interactive_authentication == -1) if (options->kbd_interactive_authentication == -1)

View File

@ -1,4 +1,4 @@
/* $OpenBSD: readconf.h,v 1.53 2003/08/13 08:46:30 markus Exp $ */ /* $OpenBSD: readconf.h,v 1.54 2003/08/22 10:56:09 markus Exp $ */
/* /*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -42,6 +42,8 @@ typedef struct {
/* Try S/Key or TIS, authentication. */ /* Try S/Key or TIS, authentication. */
int kerberos_authentication; /* Try Kerberos authentication. */ int kerberos_authentication; /* Try Kerberos authentication. */
int kerberos_tgt_passing; /* Try Kerberos TGT passing. */ int kerberos_tgt_passing; /* Try Kerberos TGT passing. */
int gss_authentication; /* Try GSS authentication */
int gss_deleg_creds; /* Delegate GSS credentials */
int password_authentication; /* Try password int password_authentication; /* Try password
* authentication. */ * authentication. */
int kbd_interactive_authentication; /* Try keyboard-interactive auth. */ int kbd_interactive_authentication; /* Try keyboard-interactive auth. */

View File

@ -10,7 +10,7 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$OpenBSD: servconf.c,v 1.124 2003/08/13 08:46:30 markus Exp $"); RCSID("$OpenBSD: servconf.c,v 1.125 2003/08/22 10:56:09 markus Exp $");
#include "ssh.h" #include "ssh.h"
#include "log.h" #include "log.h"
@ -73,6 +73,8 @@ initialize_server_options(ServerOptions *options)
options->kerberos_or_local_passwd = -1; options->kerberos_or_local_passwd = -1;
options->kerberos_ticket_cleanup = -1; options->kerberos_ticket_cleanup = -1;
options->kerberos_tgt_passing = -1; options->kerberos_tgt_passing = -1;
options->gss_authentication=-1;
options->gss_cleanup_creds = -1;
options->password_authentication = -1; options->password_authentication = -1;
options->kbd_interactive_authentication = -1; options->kbd_interactive_authentication = -1;
options->challenge_response_authentication = -1; options->challenge_response_authentication = -1;
@ -182,6 +184,10 @@ fill_default_server_options(ServerOptions *options)
options->kerberos_ticket_cleanup = 1; options->kerberos_ticket_cleanup = 1;
if (options->kerberos_tgt_passing == -1) if (options->kerberos_tgt_passing == -1)
options->kerberos_tgt_passing = 0; options->kerberos_tgt_passing = 0;
if (options->gss_authentication == -1)
options->gss_authentication = 0;
if (options->gss_cleanup_creds == -1)
options->gss_cleanup_creds = 1;
if (options->password_authentication == -1) if (options->password_authentication == -1)
options->password_authentication = 1; options->password_authentication = 1;
if (options->kbd_interactive_authentication == -1) if (options->kbd_interactive_authentication == -1)
@ -259,6 +265,7 @@ typedef enum {
sBanner, sUseDNS, sHostbasedAuthentication, sBanner, sUseDNS, sHostbasedAuthentication,
sHostbasedUsesNameFromPacketOnly, sClientAliveInterval, sHostbasedUsesNameFromPacketOnly, sClientAliveInterval,
sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2, sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2,
sGssAuthentication, sGssCleanupCreds,
sUsePrivilegeSeparation, sUsePrivilegeSeparation,
sDeprecated, sUnsupported sDeprecated, sUnsupported
} ServerOpCodes; } ServerOpCodes;
@ -305,6 +312,13 @@ static struct {
{ "kerberostgtpassing", sUnsupported }, { "kerberostgtpassing", sUnsupported },
#endif #endif
{ "afstokenpassing", sUnsupported }, { "afstokenpassing", sUnsupported },
#ifdef GSSAPI
{ "gssapiauthentication", sGssAuthentication },
{ "gssapicleanupcreds", sGssCleanupCreds },
#else
{ "gssapiauthentication", sUnsupported },
{ "gssapicleanupcreds", sUnsupported },
#endif
{ "passwordauthentication", sPasswordAuthentication }, { "passwordauthentication", sPasswordAuthentication },
{ "kbdinteractiveauthentication", sKbdInteractiveAuthentication }, { "kbdinteractiveauthentication", sKbdInteractiveAuthentication },
{ "challengeresponseauthentication", sChallengeResponseAuthentication }, { "challengeresponseauthentication", sChallengeResponseAuthentication },
@ -623,6 +637,14 @@ parse_flag:
intptr = &options->kerberos_tgt_passing; intptr = &options->kerberos_tgt_passing;
goto parse_flag; goto parse_flag;
case sGssAuthentication:
intptr = &options->gss_authentication;
goto parse_flag;
case sGssCleanupCreds:
intptr = &options->gss_cleanup_creds;
goto parse_flag;
case sPasswordAuthentication: case sPasswordAuthentication:
intptr = &options->password_authentication; intptr = &options->password_authentication;
goto parse_flag; goto parse_flag;

View File

@ -1,4 +1,4 @@
/* $OpenBSD: servconf.h,v 1.63 2003/08/13 08:46:30 markus Exp $ */ /* $OpenBSD: servconf.h,v 1.64 2003/08/22 10:56:09 markus Exp $ */
/* /*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -82,6 +82,8 @@ typedef struct {
* file on logout. */ * file on logout. */
int kerberos_tgt_passing; /* If true, permit Kerberos TGT int kerberos_tgt_passing; /* If true, permit Kerberos TGT
* passing. */ * passing. */
int gss_authentication; /* If true, permit GSSAPI authentication */
int gss_cleanup_creds; /* If true, destroy cred cache on logout */
int password_authentication; /* If true, permit password int password_authentication; /* If true, permit password
* authentication. */ * authentication. */
int kbd_interactive_authentication; /* If true, permit */ int kbd_interactive_authentication; /* If true, permit */

View File

@ -33,7 +33,7 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$OpenBSD: session.c,v 1.160 2003/08/13 08:33:02 markus Exp $"); RCSID("$OpenBSD: session.c,v 1.161 2003/08/22 10:56:09 markus Exp $");
#include "ssh.h" #include "ssh.h"
#include "ssh1.h" #include "ssh1.h"
@ -58,6 +58,10 @@ RCSID("$OpenBSD: session.c,v 1.160 2003/08/13 08:33:02 markus Exp $");
#include "session.h" #include "session.h"
#include "monitor_wrap.h" #include "monitor_wrap.h"
#ifdef GSSAPI
#include "ssh-gss.h"
#endif
/* func */ /* func */
Session *session_new(void); Session *session_new(void);
@ -424,6 +428,12 @@ do_exec_no_pty(Session *s, const char *command)
} }
#endif /* USE_PAM */ #endif /* USE_PAM */
#ifdef GSSAPI
temporarily_use_uid(s->pw);
ssh_gssapi_storecreds();
restore_uid();
#endif
/* Fork the child. */ /* Fork the child. */
if ((pid = fork()) == 0) { if ((pid = fork()) == 0) {
fatal_remove_all_cleanups(); fatal_remove_all_cleanups();
@ -550,6 +560,12 @@ do_exec_pty(Session *s, const char *command)
} }
#endif #endif
#ifdef GSSAPI
temporarily_use_uid(s->pw);
ssh_gssapi_storecreds();
restore_uid();
#endif
/* Fork the child. */ /* Fork the child. */
if ((pid = fork()) == 0) { if ((pid = fork()) == 0) {
fatal_remove_all_cleanups(); fatal_remove_all_cleanups();
@ -807,7 +823,7 @@ check_quietlogin(Session *s, const char *command)
* Sets the value of the given variable in the environment. If the variable * Sets the value of the given variable in the environment. If the variable
* already exists, its value is overriden. * already exists, its value is overriden.
*/ */
static void void
child_set_env(char ***envp, u_int *envsizep, const char *name, child_set_env(char ***envp, u_int *envsizep, const char *name,
const char *value) const char *value)
{ {
@ -934,6 +950,13 @@ do_setup_env(Session *s, const char *shell)
copy_environment(environ, &env, &envsize); copy_environment(environ, &env, &envsize);
#endif #endif
#ifdef GSSAPI
/* Allow any GSSAPI methods that we've used to alter
* the childs environment as they see fit
*/
ssh_gssapi_do_child(&env, &envsize);
#endif
if (!options.use_login) { if (!options.use_login) {
/* Set basic environment. */ /* Set basic environment. */
child_set_env(&env, &envsize, "USER", pw->pw_name); child_set_env(&env, &envsize, "USER", pw->pw_name);
@ -2088,4 +2111,8 @@ static void
do_authenticated2(Authctxt *authctxt) do_authenticated2(Authctxt *authctxt)
{ {
server_loop2(authctxt); server_loop2(authctxt);
#if defined(GSSAPI)
if (options.gss_cleanup_creds)
ssh_gssapi_cleanup_creds(NULL);
#endif
} }

View File

@ -1,4 +1,4 @@
/* $OpenBSD: session.h,v 1.19 2002/06/30 21:59:45 deraadt Exp $ */ /* $OpenBSD: session.h,v 1.20 2003/08/22 10:56:09 markus Exp $ */
/* /*
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
@ -68,4 +68,7 @@ Session *session_new(void);
Session *session_by_tty(char *); Session *session_by_tty(char *);
void session_close(Session *); void session_close(Session *);
void do_setusercontext(struct passwd *); void do_setusercontext(struct passwd *);
void child_set_env(char ***envp, u_int *envsizep, const char *name,
const char *value);
#endif #endif

109
ssh-gss.h Normal file
View File

@ -0,0 +1,109 @@
/*
* 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.
*/
#ifndef _SSH_GSS_H
#define _SSH_GSS_H
#ifdef GSSAPI
#include "buffer.h"
#include <gssapi.h>
/* draft-ietf-secsh-gsskeyex-06 */
#define SSH2_MSG_USERAUTH_GSSAPI_RESPONSE 60
#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 SSH_GSS_OIDTYPE 0x06
typedef struct {
char *filename;
char *envvar;
char *envval;
void *data;
} ssh_gssapi_ccache;
typedef struct {
gss_buffer_desc displayname;
gss_buffer_desc exportedname;
gss_cred_id_t creds;
struct ssh_gssapi_mech_struct *mech;
ssh_gssapi_ccache store;
} ssh_gssapi_client;
typedef struct ssh_gssapi_mech_struct {
char *enc_name;
char *name;
gss_OID_desc oid;
int (*dochild) (ssh_gssapi_client *);
int (*userok) (ssh_gssapi_client *, char *);
int (*localname) (ssh_gssapi_client *, char **);
void (*storecreds) (ssh_gssapi_client *);
} ssh_gssapi_mech;
typedef struct {
OM_uint32 major; /* both */
OM_uint32 minor; /* both */
gss_ctx_id_t context; /* both */
gss_name_t name; /* both */
gss_OID oid; /* client */
gss_cred_id_t creds; /* server */
gss_name_t client; /* server */
gss_cred_id_t client_creds; /* server */
} Gssctxt;
extern ssh_gssapi_mech *supported_mechs[];
int ssh_gssapi_check_oid(Gssctxt *ctx, void *data, size_t len);
void ssh_gssapi_set_oid_data(Gssctxt *ctx, void *data, size_t len);
void ssh_gssapi_set_oid(Gssctxt *ctx, gss_OID oid);
void ssh_gssapi_supported_oids(gss_OID_set *oidset);
ssh_gssapi_mech *ssh_gssapi_get_ctype(Gssctxt *ctxt);
OM_uint32 ssh_gssapi_import_name(Gssctxt *ctx, const char *host);
OM_uint32 ssh_gssapi_acquire_cred(Gssctxt *ctx);
OM_uint32 ssh_gssapi_init_ctx(Gssctxt *ctx, int deleg_creds,
gss_buffer_desc *recv_tok, gss_buffer_desc *send_tok, OM_uint32 *flags);
OM_uint32 ssh_gssapi_accept_ctx(Gssctxt *ctx,
gss_buffer_desc *recv_tok, gss_buffer_desc *send_tok, OM_uint32 *flags);
OM_uint32 ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *);
void ssh_gssapi_error(Gssctxt *ctx);
char *ssh_gssapi_last_error(Gssctxt *ctxt, OM_uint32 *maj, OM_uint32 *min);
void ssh_gssapi_build_ctx(Gssctxt **ctx);
void ssh_gssapi_delete_ctx(Gssctxt **ctx);
OM_uint32 ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID oid);
/* In the server */
int ssh_gssapi_userok(char *name);
void ssh_gssapi_do_child(char ***envp, u_int *envsizep);
void ssh_gssapi_cleanup_creds(void *ignored);
void ssh_gssapi_storecreds(void);
#endif /* GSSAPI */
#endif /* _SSH_GSS_H */

View File

@ -34,7 +34,7 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\" .\"
.\" $OpenBSD: ssh_config.5,v 1.17 2003/08/13 08:46:31 markus Exp $ .\" $OpenBSD: ssh_config.5,v 1.18 2003/08/22 10:56:09 markus Exp $
.Dd September 25, 1999 .Dd September 25, 1999
.Dt SSH_CONFIG 5 .Dt SSH_CONFIG 5
.Os .Os
@ -331,6 +331,18 @@ The default is
Specifies a file to use for the global Specifies a file to use for the global
host key database instead of host key database instead of
.Pa /etc/ssh/ssh_known_hosts . .Pa /etc/ssh/ssh_known_hosts .
.It Cm GSSAPIAuthentication
Specifies whether authentication based on GSSAPI may be used, either using
the result of a successful key exchange, or using GSSAPI user
authentication.
The default is
.Dq yes .
Note that this option applies to protocol version 2 only.
.It Cm GSSAPIDelegateCredentials
Forward (delegate) credentials to the server.
The default is
.Dq no .
Note that this option applies to protocol version 2 only.
.It Cm HostbasedAuthentication .It Cm HostbasedAuthentication
Specifies whether to try rhosts based authentication with public key Specifies whether to try rhosts based authentication with public key
authentication. authentication.

View File

@ -23,7 +23,7 @@
*/ */
#include "includes.h" #include "includes.h"
RCSID("$OpenBSD: sshconnect2.c,v 1.120 2003/06/24 08:23:46 markus Exp $"); RCSID("$OpenBSD: sshconnect2.c,v 1.121 2003/08/22 10:56:09 markus Exp $");
#ifdef KRB5 #ifdef KRB5
#include <krb5.h> #include <krb5.h>
@ -57,6 +57,10 @@ RCSID("$OpenBSD: sshconnect2.c,v 1.120 2003/06/24 08:23:46 markus Exp $");
#include "msg.h" #include "msg.h"
#include "pathnames.h" #include "pathnames.h"
#ifdef GSSAPI
#include "ssh-gss.h"
#endif
/* import */ /* import */
extern char *client_version_string; extern char *client_version_string;
extern char *server_version_string; extern char *server_version_string;
@ -178,6 +182,8 @@ struct Authctxt {
Sensitive *sensitive; Sensitive *sensitive;
/* kbd-interactive */ /* kbd-interactive */
int info_req_seen; int info_req_seen;
/* generic */
void *methoddata;
}; };
struct Authmethod { struct Authmethod {
char *name; /* string to compare against server's list */ char *name; /* string to compare against server's list */
@ -201,6 +207,15 @@ int userauth_kbdint(Authctxt *);
int userauth_hostbased(Authctxt *); int userauth_hostbased(Authctxt *);
int userauth_kerberos(Authctxt *); int userauth_kerberos(Authctxt *);
#ifdef GSSAPI
int userauth_gssapi(Authctxt *authctxt);
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 *); void userauth(Authctxt *, char *);
static int sign_and_send_pubkey(Authctxt *, Identity *); static int sign_and_send_pubkey(Authctxt *, Identity *);
@ -213,6 +228,12 @@ static Authmethod *authmethod_lookup(const char *name);
static char *authmethods_get(void); static char *authmethods_get(void);
Authmethod authmethods[] = { Authmethod authmethods[] = {
#ifdef GSSAPI
{"gssapi",
userauth_gssapi,
&options.gss_authentication,
NULL},
#endif
{"hostbased", {"hostbased",
userauth_hostbased, userauth_hostbased,
&options.hostbased_authentication, &options.hostbased_authentication,
@ -283,6 +304,7 @@ ssh_userauth2(const char *local_user, const char *server_user, char *host,
authctxt.success = 0; authctxt.success = 0;
authctxt.method = authmethod_lookup("none"); authctxt.method = authmethod_lookup("none");
authctxt.authlist = NULL; authctxt.authlist = NULL;
authctxt.methoddata = NULL;
authctxt.sensitive = sensitive; authctxt.sensitive = sensitive;
authctxt.info_req_seen = 0; authctxt.info_req_seen = 0;
if (authctxt.method == NULL) if (authctxt.method == NULL)
@ -306,6 +328,10 @@ ssh_userauth2(const char *local_user, const char *server_user, char *host,
void void
userauth(Authctxt *authctxt, char *authlist) userauth(Authctxt *authctxt, char *authlist)
{ {
if (authctxt->methoddata) {
xfree(authctxt->methoddata);
authctxt->methoddata = NULL;
}
if (authlist == NULL) { if (authlist == NULL) {
authlist = authctxt->authlist; authlist = authctxt->authlist;
} else { } else {
@ -361,6 +387,8 @@ input_userauth_success(int type, u_int32_t seq, void *ctxt)
fatal("input_userauth_success: no authentication context"); fatal("input_userauth_success: no authentication context");
if (authctxt->authlist) if (authctxt->authlist)
xfree(authctxt->authlist); xfree(authctxt->authlist);
if (authctxt->methoddata)
xfree(authctxt->methoddata);
authctxt->success = 1; /* break out */ authctxt->success = 1; /* break out */
} }
@ -449,6 +477,228 @@ done:
userauth(authctxt, NULL); userauth(authctxt, NULL);
} }
#ifdef GSSAPI
int
userauth_gssapi(Authctxt *authctxt)
{
Gssctxt *gssctxt = NULL;
static gss_OID_set supported = NULL;
static int mech = 0;
OM_uint32 min;
int ok = 0;
/* Try one GSSAPI method at a time, rather than sending them all at
* once. */
if (supported == NULL)
gss_indicate_mechs(&min, &supported);
/* Check to see if the mechanism is usable before we offer it */
while (mech<supported->count && !ok) {
if (gssctxt)
ssh_gssapi_delete_ctx(&gssctxt);
ssh_gssapi_build_ctx(&gssctxt);
ssh_gssapi_set_oid(gssctxt, &supported->elements[mech]);
/* My DER encoding requires length<128 */
if (supported->elements[mech].length < 128 &&
!GSS_ERROR(ssh_gssapi_import_name(gssctxt,
authctxt->host))) {
ok = 1; /* Mechanism works */
} else {
mech++;
}
}
if (!ok) return 0;
authctxt->methoddata=(void *)gssctxt;
packet_start(SSH2_MSG_USERAUTH_REQUEST);
packet_put_cstring(authctxt->server_user);
packet_put_cstring(authctxt->service);
packet_put_cstring(authctxt->method->name);
packet_put_int(1);
/* Some servers encode the OID incorrectly (as we used to) */
if (datafellows & SSH_BUG_GSSAPI_BER) {
packet_put_string(supported->elements[mech].elements,
supported->elements[mech].length);
} else {
packet_put_int((supported->elements[mech].length)+2);
packet_put_char(SSH_GSS_OIDTYPE);
packet_put_char(supported->elements[mech].length);
packet_put_raw(supported->elements[mech].elements,
supported->elements[mech].length);
}
packet_send();
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 */
return 1;
}
void
input_gssapi_response(int type, u_int32_t plen, void *ctxt)
{
Authctxt *authctxt = ctxt;
Gssctxt *gssctxt;
OM_uint32 status, ms;
int oidlen;
char *oidv;
gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
if (authctxt == NULL)
fatal("input_gssapi_response: no authentication context");
gssctxt = authctxt->methoddata;
/* Setup our OID */
oidv = packet_get_string(&oidlen);
if (datafellows & SSH_BUG_GSSAPI_BER) {
if (!ssh_gssapi_check_oid(gssctxt, oidv, oidlen))
fatal("Server returned different OID than expected");
} else {
if(oidv[0] != SSH_GSS_OIDTYPE || oidv[1] != oidlen-2) {
debug("Badly encoded mechanism OID received");
userauth(authctxt, NULL);
xfree(oidv);
return;
}
if (!ssh_gssapi_check_oid(gssctxt, oidv+2, oidlen-2))
fatal("Server returned different OID than expected");
}
packet_check_eom();
xfree(oidv);
status = ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds,
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();
gss_release_buffer(&ms, &send_tok);
}
/* Start again with next method on list */
debug("Trying to start again");
userauth(authctxt, NULL);
return;
}
/* We must have data to send */
packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN);
packet_put_string(send_tok.value, send_tok.length);
packet_send();
gss_release_buffer(&ms, &send_tok);
}
void
input_gssapi_token(int type, u_int32_t plen, void *ctxt)
{
Authctxt *authctxt = ctxt;
Gssctxt *gssctxt;
gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
gss_buffer_desc recv_tok;
OM_uint32 status, ms;
u_int slen;
if (authctxt == NULL)
fatal("input_gssapi_response: no authentication context");
gssctxt = authctxt->methoddata;
recv_tok.value = packet_get_string(&slen);
recv_tok.length = slen; /* safe typecast */
packet_check_eom();
status=ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds,
&recv_tok, &send_tok, NULL);
xfree(recv_tok.value);
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();
gss_release_buffer(&ms, &send_tok);
}
/* Start again with the next method in the list */
userauth(authctxt, NULL);
return;
}
if (send_tok.length > 0) {
packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN);
packet_put_string(send_tok.value, send_tok.length);
packet_send();
gss_release_buffer(&ms, &send_tok);
}
if (status == GSS_S_COMPLETE) {
/* If that succeeded, send a exchange complete message */
packet_start(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE);
packet_send();
}
}
void
input_gssapi_errtok(int type, u_int32_t plen, void *ctxt)
{
Authctxt *authctxt = ctxt;
Gssctxt *gssctxt;
gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
gss_buffer_desc recv_tok;
OM_uint32 status, ms;
if (authctxt == NULL)
fatal("input_gssapi_response: no authentication context");
gssctxt = authctxt->methoddata;
recv_tok.value = packet_get_string(&recv_tok.length);
packet_check_eom();
/* Stick it into GSSAPI and see what it says */
status = ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds,
&recv_tok, &send_tok, NULL);
xfree(recv_tok.value);
gss_release_buffer(&ms, &send_tok);
/* Server will be returning a failed packet after this one */
}
void
input_gssapi_error(int type, u_int32_t plen, void *ctxt)
{
OM_uint32 maj, min;
char *msg;
char *lang;
maj=packet_get_int();
min=packet_get_int();
msg=packet_get_string(NULL);
lang=packet_get_string(NULL);
packet_check_eom();
debug("Server GSSAPI Error:\n%s\n", msg);
xfree(msg);
xfree(lang);
}
#endif /* GSSAPI */
int int
userauth_none(Authctxt *authctxt) userauth_none(Authctxt *authctxt)
{ {

View File

@ -1,4 +1,4 @@
# $OpenBSD: sshd_config,v 1.63 2003/08/13 08:46:31 markus Exp $ # $OpenBSD: sshd_config,v 1.64 2003/08/22 10:56:09 markus Exp $
# This is the sshd server system-wide configuration file. See # This is the sshd server system-wide configuration file. See
# sshd_config(5) for more information. # sshd_config(5) for more information.
@ -63,6 +63,10 @@
#KerberosTicketCleanup yes #KerberosTicketCleanup yes
#KerberosTgtPassing no #KerberosTgtPassing no
# GSSAPI options
#GSSAPIAuthentication no
#GSSAPICleanupCreds yes
# Set this to 'yes' to enable PAM authentication (via challenge-response) # Set this to 'yes' to enable PAM authentication (via challenge-response)
# and session processing. Depending on your PAM configuration, this may # and session processing. Depending on your PAM configuration, this may
# bypass the setting of 'PasswordAuthentication' # bypass the setting of 'PasswordAuthentication'

View File

@ -34,7 +34,7 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\" .\"
.\" $OpenBSD: sshd_config.5,v 1.22 2003/08/13 08:46:31 markus Exp $ .\" $OpenBSD: sshd_config.5,v 1.23 2003/08/22 10:56:09 markus Exp $
.Dd September 25, 1999 .Dd September 25, 1999
.Dt SSHD_CONFIG 5 .Dt SSHD_CONFIG 5
.Os .Os
@ -225,6 +225,19 @@ or
.Dq no . .Dq no .
The default is The default is
.Dq no . .Dq no .
.It Cm GSSAPIAuthentication
Specifies whether authentication based on GSSAPI may be used, either using
the result of a successful key exchange, or using GSSAPI user
authentication.
The default is
.Dq no .
Note that this option applies to protocol version 2 only.
.It Cm GSSAPICleanupCredentials
Specifies whether to automatically destroy the user's credentials cache
on logout.
The default is
.Dq yes .
Note that this option applies to protocol version 2 only.
.It Cm HostbasedAuthentication .It Cm HostbasedAuthentication
Specifies whether rhosts or /etc/hosts.equiv authentication together Specifies whether rhosts or /etc/hosts.equiv authentication together
with successful public key client host authentication is allowed with successful public key client host authentication is allowed