+/* $OpenBSD: gss-genr.c,v 1.3 2003/11/21 11:57:03 djm Exp $ */
+
/*
- * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. *
+ * 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:
#ifdef GSSAPI
-#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 "canohost.h"
-
-#include <netdb.h>
+#include "ssh2.h"
#include "ssh-gss.h"
+extern u_char *session_id2;
+extern u_int session_id2_len;
+
typedef struct {
char *encoded;
gss_OID 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) {
-
- return (ctx!=NULL && ctx->oid != GSS_C_NO_OID &&
- ctx->oid->length == len &&
- memcmp(ctx->oid->elements,data,len)==0);
+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);
+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);
+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(ssh_gssapi_last_error(ctxt,NULL,NULL));
+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) {
+ssh_gssapi_last_error(Gssctxt *ctxt,
+ OM_uint32 *major_status, OM_uint32 *minor_status)
+{
OM_uint32 lmin;
- gss_buffer_desc msg;
- 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;
+ 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, ctxt->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, ctxt->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);
+ do {
+ gss_display_status(&lmin, ctxt->major,
+ GSS_C_GSS_CODE, ctxt->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, ctxt->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
+/*
+ * 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;
+ *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 */
#if !defined(MECHGLUE)
OM_uint32 ms;
#endif
-
- /* Return if there's no context */
- if ((*ctx)==NULL)
+
+ if ((*ctx) == NULL)
return;
-
#if !defined(MECHGLUE) /* mechglue has some memory management issues */
- if ((*ctx)->context != GSS_C_NO_CONTEXT)
- gss_delete_sec_context(&ms,&(*ctx)->context,GSS_C_NO_BUFFER);
+ 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);
+ 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);
+ gss_release_cred(&ms, &(*ctx)->creds);
if ((*ctx)->client != GSS_C_NO_NAME)
- gss_release_name(&ms,&(*ctx)->client);
+ gss_release_name(&ms, &(*ctx)->client);
if ((*ctx)->client_creds != GSS_C_NO_CREDENTIAL)
- gss_release_cred(&ms,&(*ctx)->client_creds);
+ gss_release_cred(&ms, &(*ctx)->client_creds);
#endif
-
+
xfree(*ctx);
- *ctx=NULL;
+ *ctx = NULL;
}
-/* Wrapper to init_sec_context
+/*
+ * Wrapper to init_sec_context
* Requires that the context contains:
* oid
- * server name (from ssh_gssapi_import_name)
+ * server name (from ssh_gssapi_import_name)
*/
-OM_uint32
+OM_uint32
ssh_gssapi_init_ctx(Gssctxt *ctx, int deleg_creds, gss_buffer_desc *recv_tok,
- gss_buffer_desc* send_tok, OM_uint32 *flags)
+ gss_buffer_desc* send_tok, OM_uint32 *flags)
{
int deleg_flag = 0;
-
+
if (deleg_creds) {
- deleg_flag=GSS_C_DELEG_FLAG;
+ deleg_flag = GSS_C_DELEG_FLAG;
debug("Delegating credentials");
}
-
- ctx->major=gss_init_sec_context(&ctx->minor,
- GSS_C_NO_CREDENTIAL, /* def. cred */
- &ctx->context,
- ctx->name,
- ctx->oid,
- GSS_C_MUTUAL_FLAG |
- GSS_C_INTEG_FLAG |
- deleg_flag,
- 0, /* default lifetime */
- NULL, /* no channel bindings */
- recv_tok,
- NULL,
- send_tok,
- flags,
- NULL);
- if (GSS_ERROR(ctx->major)) {
- ssh_gssapi_error(ctx);
- }
- return(ctx->major);
+
+ 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) {
+ssh_gssapi_import_name(Gssctxt *ctx, const char *host)
+{
gss_buffer_desc gssbuf;
char *xhost;
-
+
/* Make a copy of the host name, in case it was returned by a
* previous call to gethostbyname(). */
xhost = xstrdup(host);
* this for us themselves */
resolve_localhost(&xhost);
- gssbuf.length = sizeof("host@")+strlen(xhost);
-
- gssbuf.value = xmalloc(gssbuf.length);
- if (gssbuf.value == NULL) {
- xfree(xhost);
- return(-1);
- }
- snprintf(gssbuf.value,gssbuf.length,"host@%s",xhost);
- if ((ctx->major=gss_import_name(&ctx->minor,
- &gssbuf,
- GSS_C_NT_HOSTBASED_SERVICE,
- &ctx->name))) {
+ gssbuf.length = sizeof("host@") + strlen(xhost);
+ gssbuf.value = xmalloc(gssbuf.length);
+ snprintf(gssbuf.value, gssbuf.length, "host@%s", xhost);
+
+ if ((ctx->major = gss_import_name(&ctx->minor,
+ &gssbuf, GSS_C_NT_HOSTBASED_SERVICE, &ctx->name)))
ssh_gssapi_error(ctx);
- }
-
+
xfree(xhost);
xfree(gssbuf.value);
- return(ctx->major);
+ 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) {
+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))) {
+ 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);
+ return (ctx->major);
}
OM_uint32
-ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_desc *buffer, gss_buffer_desc *hash) {
-
- /* ssh1 needs to exchange the hash of the keys */
- /* will us this hash to return it */
- if (!compat20) {
- if ((ctx->major=gss_wrap(&ctx->minor,ctx->context,
- 0,
- GSS_C_QOP_DEFAULT,
- buffer,
- NULL,
- hash)))
- ssh_gssapi_error(ctx);
- }
- else
-
- if ((ctx->major=gss_get_mic(&ctx->minor,ctx->context,
- GSS_C_QOP_DEFAULT, buffer, hash))) {
+ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash)
+{
+ if ((ctx->major = gss_get_mic(&ctx->minor, ctx->context,
+ GSS_C_QOP_DEFAULT, buffer, hash)))
ssh_gssapi_error(ctx);
- }
-
- return(ctx->major);
+
+ return (ctx->major);
+}
+
+void
+ssh_gssapi_buildmic(Buffer *b, const char *user, const char *service,
+ const char *context)
+{
+ buffer_init(b);
+ buffer_put_string(b, session_id2, session_id2_len);
+ buffer_put_char(b, SSH2_MSG_USERAUTH_REQUEST);
+ buffer_put_cstring(b, user);
+ buffer_put_cstring(b, service);
+ buffer_put_cstring(b, context);
}
OM_uint32
-ssh_gssapi_server_ctx(Gssctxt **ctx,gss_OID oid) {
- if (*ctx) ssh_gssapi_delete_ctx(ctx);
+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));
+ ssh_gssapi_set_oid(*ctx, oid);
+ return (ssh_gssapi_acquire_cred(*ctx));
}
int