Home | History | Annotate | Download | only in ssh
      1 /*
      2  * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. *
      3  * Redistribution and use in source and binary forms, with or without
      4  * modification, are permitted provided that the following conditions
      5  * are met:
      6  * 1. Redistributions of source code must retain the above copyright
      7  *    notice, this list of conditions and the following disclaimer.
      8  * 2. Redistributions in binary form must reproduce the above copyright
      9  *    notice, this list of conditions and the following disclaimer in the
     10  *    documentation and/or other materials provided with the distribution.
     11  *
     12  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
     13  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     14  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     15  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     16  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     17  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     18  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     19  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     20  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     21  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     22  */
     23 /*
     24  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     25  * Use is subject to license terms.
     26  */
     27 
     28 #include "includes.h"
     29 
     30 #ifdef GSSAPI
     31 
     32 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     33 
     34 #include "ssh.h"
     35 #include "ssh2.h"
     36 #include "xmalloc.h"
     37 #include "buffer.h"
     38 #include "bufaux.h"
     39 #include "packet.h"
     40 #include "compat.h"
     41 #include <openssl/evp.h>
     42 #include "cipher.h"
     43 #include "kex.h"
     44 #include "log.h"
     45 #include "compat.h"
     46 
     47 #include <netdb.h>
     48 
     49 #include "ssh-gss.h"
     50 
     51 void
     52 ssh_gssapi_client_kex_hook(Kex *kex, char **proposal)
     53 {
     54 	gss_OID_set mechs = GSS_C_NULL_OID_SET;
     55 
     56 	if (kex == NULL || kex->serverhost == NULL)
     57 		fatal("INTERNAL ERROR (%s)", __func__);
     58 
     59 	ssh_gssapi_client_mechs(kex->serverhost, &mechs);
     60 	ssh_gssapi_modify_kex(kex, mechs, proposal);
     61 }
     62 
     63 void
     64 ssh_gssapi_client_mechs(const char *server_host, gss_OID_set *mechs)
     65 {
     66 	gss_OID_set	indicated = GSS_C_NULL_OID_SET;
     67 	gss_OID_set	acquired, supported;
     68 	gss_OID		mech;
     69 	gss_cred_id_t	creds;
     70 	Gssctxt		*ctxt = NULL;
     71 	gss_buffer_desc	tok;
     72 	OM_uint32	maj, min;
     73 	int		i;
     74 	char		*errmsg;
     75 
     76 	if (!mechs)
     77 		return;
     78 	*mechs = GSS_C_NULL_OID_SET;
     79 
     80 	maj = gss_indicate_mechs(&min, &indicated);
     81 	if (GSS_ERROR(maj)) {
     82 		debug("No GSS-API mechanisms are installed");
     83 		return;
     84 	}
     85 
     86 	maj = gss_create_empty_oid_set(&min, &supported);
     87 	if (GSS_ERROR(maj)) {
     88 		errmsg = ssh_gssapi_last_error(NULL, &maj, &min);
     89 		debug("Failed to allocate resources (%s) for GSS-API", errmsg);
     90 		xfree(errmsg);
     91 		(void) gss_release_oid_set(&min, &indicated);
     92 		return;
     93 	}
     94 	maj = gss_acquire_cred(&min, GSS_C_NO_NAME, 0, indicated,
     95 	    GSS_C_INITIATE, &creds, &acquired, NULL);
     96 
     97 	if (GSS_ERROR(maj)) {
     98 		errmsg = ssh_gssapi_last_error(NULL, &maj, &min);
     99 		debug("Failed to acquire GSS-API credentials for any "
    100 		    "mechanisms (%s)", errmsg);
    101 		xfree(errmsg);
    102 		(void) gss_release_oid_set(&min, &indicated);
    103 		(void) gss_release_oid_set(&min, &supported);
    104 		return;
    105 	}
    106 	(void) gss_release_cred(&min, &creds);
    107 
    108 	for (i = 0; i < acquired->count; i++) {
    109 		mech = &acquired->elements[i];
    110 
    111 		if (ssh_gssapi_is_spnego(mech))
    112 			continue;
    113 
    114 		ssh_gssapi_build_ctx(&ctxt, 1, mech);
    115 		if (!ctxt)
    116 			continue;
    117 
    118 		/*
    119 		 * This is useful for mechs like Kerberos, which can
    120 		 * detect unknown target princs here, but not for
    121 		 * mechs like SPKM, which cannot detect unknown princs
    122 		 * until context tokens are actually exchanged.
    123 		 *
    124 		 * 'Twould be useful to have a test that could save us
    125 		 * the bother of trying this for SPKM and the such...
    126 		 */
    127 		maj = ssh_gssapi_init_ctx(ctxt, server_host, 0, NULL, &tok);
    128 		if (GSS_ERROR(maj)) {
    129 			errmsg = ssh_gssapi_last_error(ctxt, NULL, NULL);
    130 			debug("Skipping GSS-API mechanism %s (%s)",
    131 			    ssh_gssapi_oid_to_name(mech), errmsg);
    132 			xfree(errmsg);
    133 			continue;
    134 		}
    135 
    136 		(void) gss_release_buffer(&min, &tok);
    137 
    138 		maj = gss_add_oid_set_member(&min, mech, &supported);
    139 		if (GSS_ERROR(maj)) {
    140 			errmsg = ssh_gssapi_last_error(NULL, &maj, &min);
    141 			debug("Failed to allocate resources (%s) for GSS-API",
    142 			    errmsg);
    143 			xfree(errmsg);
    144 		}
    145 	}
    146 
    147 	*mechs = supported;
    148 }
    149 
    150 
    151 /*
    152  * Wrapper to init_sec_context. Requires that the context contains:
    153  *
    154  *	oid
    155  * 	server name (from ssh_gssapi_import_name)
    156  */
    157 OM_uint32
    158 ssh_gssapi_init_ctx(Gssctxt *ctx, const char *server_host, int deleg_creds,
    159 		    gss_buffer_t recv_tok, gss_buffer_t send_tok)
    160 {
    161 	int flags = GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG;
    162 
    163 	debug("%s(%p, %s, %d, %p, %p)", __func__, ctx, server_host,
    164 	    deleg_creds, recv_tok, send_tok);
    165 
    166 	if (deleg_creds) {
    167 		flags |= GSS_C_DELEG_FLAG;
    168 		debug("Delegating GSS-API credentials");
    169 	}
    170 
    171 	/* Build target principal */
    172 	if (ctx->desired_name == GSS_C_NO_NAME &&
    173 	    !ssh_gssapi_import_name(ctx, server_host)) {
    174 		return (ctx->major);
    175 	}
    176 
    177 	ctx->major = gss_init_sec_context(&ctx->minor, GSS_C_NO_CREDENTIAL,
    178 	    &ctx->context, ctx->desired_name, ctx->desired_mech, flags,
    179 	    0, /* default lifetime */
    180 	    NULL, /* no channel bindings */
    181 	    recv_tok,
    182 	    NULL, /* actual mech type */
    183 	    send_tok, &ctx->flags,
    184 	    NULL); /* actual lifetime */
    185 
    186 	if (GSS_ERROR(ctx->major))
    187 		ssh_gssapi_error(ctx, "calling GSS_Init_sec_context()");
    188 
    189 	return (ctx->major);
    190 }
    191 #endif /* GSSAPI */
    192