xref: /onnv-gate/usr/src/cmd/ssh/sshd/gss-serv.c (revision 6080:dcbf9e5d9874)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * Redistribution and use in source and binary forms, with or without
50Sstevel@tonic-gate  * modification, are permitted provided that the following conditions
60Sstevel@tonic-gate  * are met:
70Sstevel@tonic-gate  * 1. Redistributions of source code must retain the above copyright
80Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer.
90Sstevel@tonic-gate  * 2. Redistributions in binary form must reproduce the above copyright
100Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer in the
110Sstevel@tonic-gate  *    documentation and/or other materials provided with the distribution.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
140Sstevel@tonic-gate  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
150Sstevel@tonic-gate  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
160Sstevel@tonic-gate  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
170Sstevel@tonic-gate  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
180Sstevel@tonic-gate  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
190Sstevel@tonic-gate  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
200Sstevel@tonic-gate  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
210Sstevel@tonic-gate  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
220Sstevel@tonic-gate  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
230Sstevel@tonic-gate  */
240Sstevel@tonic-gate /*
25*6080Sjp161948  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
260Sstevel@tonic-gate  * Use is subject to license terms.
270Sstevel@tonic-gate  */
280Sstevel@tonic-gate 
290Sstevel@tonic-gate #include "includes.h"
300Sstevel@tonic-gate 
310Sstevel@tonic-gate #ifdef GSSAPI
320Sstevel@tonic-gate 
330Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
340Sstevel@tonic-gate 
350Sstevel@tonic-gate #include "includes.h"
360Sstevel@tonic-gate #include "ssh.h"
370Sstevel@tonic-gate #include "ssh2.h"
380Sstevel@tonic-gate #include "xmalloc.h"
390Sstevel@tonic-gate #include "buffer.h"
400Sstevel@tonic-gate #include "bufaux.h"
410Sstevel@tonic-gate #include "packet.h"
420Sstevel@tonic-gate #include "compat.h"
430Sstevel@tonic-gate #include <openssl/evp.h>
440Sstevel@tonic-gate #include "cipher.h"
450Sstevel@tonic-gate #include "kex.h"
460Sstevel@tonic-gate #include "auth.h"
470Sstevel@tonic-gate #include "log.h"
480Sstevel@tonic-gate #include "channels.h"
490Sstevel@tonic-gate #include "session.h"
500Sstevel@tonic-gate #include "dispatch.h"
510Sstevel@tonic-gate #include "servconf.h"
520Sstevel@tonic-gate #include "uidswap.h"
530Sstevel@tonic-gate #include "compat.h"
540Sstevel@tonic-gate #include <pwd.h>
550Sstevel@tonic-gate 
560Sstevel@tonic-gate #include "ssh-gss.h"
570Sstevel@tonic-gate 
580Sstevel@tonic-gate extern char **environ;
590Sstevel@tonic-gate 
600Sstevel@tonic-gate extern ServerOptions options;
61*6080Sjp161948 extern uchar_t *session_id2;
620Sstevel@tonic-gate extern int session_id2_len;
630Sstevel@tonic-gate 
640Sstevel@tonic-gate Gssctxt	*xxx_gssctxt;
650Sstevel@tonic-gate 
660Sstevel@tonic-gate void
ssh_gssapi_server_kex_hook(Kex * kex,char ** proposal)670Sstevel@tonic-gate ssh_gssapi_server_kex_hook(Kex *kex, char **proposal)
680Sstevel@tonic-gate {
690Sstevel@tonic-gate 	gss_OID_set mechs = GSS_C_NULL_OID_SET;
700Sstevel@tonic-gate 
710Sstevel@tonic-gate 	if (kex == NULL || !kex->server)
720Sstevel@tonic-gate 		fatal("INTERNAL ERROR (%s)", __func__);
730Sstevel@tonic-gate 
740Sstevel@tonic-gate 	ssh_gssapi_server_mechs(&mechs);
750Sstevel@tonic-gate 	ssh_gssapi_modify_kex(kex, mechs, proposal);
760Sstevel@tonic-gate }
770Sstevel@tonic-gate 
780Sstevel@tonic-gate void
ssh_gssapi_server_mechs(gss_OID_set * mechs)790Sstevel@tonic-gate ssh_gssapi_server_mechs(gss_OID_set *mechs)
800Sstevel@tonic-gate {
810Sstevel@tonic-gate 	static gss_OID_set	supported = GSS_C_NULL_OID_SET;
820Sstevel@tonic-gate 	gss_OID_set	s, acquired, indicated = GSS_C_NULL_OID_SET;
830Sstevel@tonic-gate 	gss_cred_id_t	creds;
840Sstevel@tonic-gate 	OM_uint32	maj, min;
850Sstevel@tonic-gate 	int		i;
860Sstevel@tonic-gate 
870Sstevel@tonic-gate 	if (!mechs) {
880Sstevel@tonic-gate 		(void) gss_release_oid_set(&min, &supported);
890Sstevel@tonic-gate 		return;
900Sstevel@tonic-gate 	}
910Sstevel@tonic-gate 
920Sstevel@tonic-gate 	if (supported != GSS_C_NULL_OID_SET) {
930Sstevel@tonic-gate 		*mechs = supported;
940Sstevel@tonic-gate 		return;
950Sstevel@tonic-gate 	}
960Sstevel@tonic-gate 
970Sstevel@tonic-gate 	*mechs = GSS_C_NULL_OID_SET;
980Sstevel@tonic-gate 
990Sstevel@tonic-gate 	maj = gss_create_empty_oid_set(&min, &s);
1000Sstevel@tonic-gate 	if (GSS_ERROR(maj)) {
1010Sstevel@tonic-gate 		debug("Could not allocate GSS-API resources (%s)",
102*6080Sjp161948 		    ssh_gssapi_last_error(NULL, &maj, &min));
1030Sstevel@tonic-gate 		return;
1040Sstevel@tonic-gate 	}
1050Sstevel@tonic-gate 
1060Sstevel@tonic-gate 	maj = gss_indicate_mechs(&min, &indicated);
1070Sstevel@tonic-gate 	if (GSS_ERROR(maj)) {
1080Sstevel@tonic-gate 		debug("No GSS-API mechanisms are installed");
1090Sstevel@tonic-gate 		return;
1100Sstevel@tonic-gate 	}
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate 	maj = gss_acquire_cred(&min, GSS_C_NO_NAME, 0, indicated,
113*6080Sjp161948 	    GSS_C_ACCEPT, &creds, &acquired, NULL);
1140Sstevel@tonic-gate 
1150Sstevel@tonic-gate 	if (GSS_ERROR(maj))
1160Sstevel@tonic-gate 		debug("Failed to acquire GSS-API credentials for any "
117*6080Sjp161948 		    "mechanisms (%s)", ssh_gssapi_last_error(NULL, &maj, &min));
1180Sstevel@tonic-gate 
1190Sstevel@tonic-gate 	(void) gss_release_oid_set(&min, &indicated);
1200Sstevel@tonic-gate 	(void) gss_release_cred(&min, &creds);
1210Sstevel@tonic-gate 
1220Sstevel@tonic-gate 	if (acquired == GSS_C_NULL_OID_SET || acquired->count == 0)
1230Sstevel@tonic-gate 		return;
1240Sstevel@tonic-gate 
125*6080Sjp161948 	for (i = 0; i < acquired->count; i++) {
1260Sstevel@tonic-gate 		if (ssh_gssapi_is_spnego(&acquired->elements[i]))
1270Sstevel@tonic-gate 			continue;
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate 		maj = gss_add_oid_set_member(&min, &acquired->elements[i], &s);
1300Sstevel@tonic-gate 		if (GSS_ERROR(maj)) {
1310Sstevel@tonic-gate 			debug("Could not allocate GSS-API resources (%s)",
132*6080Sjp161948 			    ssh_gssapi_last_error(NULL, &maj, &min));
1330Sstevel@tonic-gate 			return;
1340Sstevel@tonic-gate 		}
1350Sstevel@tonic-gate 	}
1360Sstevel@tonic-gate 	(void) gss_release_oid_set(&min, &acquired);
1370Sstevel@tonic-gate 
1380Sstevel@tonic-gate 	if (s->count) {
1390Sstevel@tonic-gate 		supported = s;
1400Sstevel@tonic-gate 		*mechs = s;
1410Sstevel@tonic-gate 	}
1420Sstevel@tonic-gate }
1430Sstevel@tonic-gate 
144*6080Sjp161948 /*
145*6080Sjp161948  * Wrapper around accept_sec_context. Requires that the context contains:
146*6080Sjp161948  *
1470Sstevel@tonic-gate  *    oid
1480Sstevel@tonic-gate  *    credentials	(from ssh_gssapi_acquire_cred)
1490Sstevel@tonic-gate  */
1500Sstevel@tonic-gate /* Priviledged */
151*6080Sjp161948 OM_uint32
ssh_gssapi_accept_ctx(Gssctxt * ctx,gss_buffer_t recv_tok,gss_buffer_t send_tok)152*6080Sjp161948 ssh_gssapi_accept_ctx(Gssctxt *ctx, gss_buffer_t recv_tok,
153*6080Sjp161948     gss_buffer_t send_tok)
1540Sstevel@tonic-gate {
1550Sstevel@tonic-gate 	/*
1560Sstevel@tonic-gate 	 * Acquiring a cred for the ctx->desired_mech for GSS_C_NO_NAME
1570Sstevel@tonic-gate 	 * may well be probably better than using GSS_C_NO_CREDENTIAL
1580Sstevel@tonic-gate 	 * and then checking that ctx->desired_mech agrees with
1590Sstevel@tonic-gate 	 * ctx->actual_mech...
1600Sstevel@tonic-gate 	 */
161*6080Sjp161948 	ctx->major = gss_accept_sec_context(&ctx->minor, &ctx->context,
162*6080Sjp161948 	    GSS_C_NO_CREDENTIAL, recv_tok, GSS_C_NO_CHANNEL_BINDINGS,
163*6080Sjp161948 	    &ctx->src_name, &ctx->actual_mech, send_tok, &ctx->flags,
164*6080Sjp161948 	    NULL, &ctx->deleg_creds);
165*6080Sjp161948 
1660Sstevel@tonic-gate 	if (GSS_ERROR(ctx->major))
1670Sstevel@tonic-gate 		ssh_gssapi_error(ctx, "accepting security context");
1680Sstevel@tonic-gate 
1690Sstevel@tonic-gate 	if (ctx->major == GSS_S_CONTINUE_NEEDED && send_tok->length == 0)
170*6080Sjp161948 		fatal("Zero length GSS context token output when "
171*6080Sjp161948 		    "continue needed");
1720Sstevel@tonic-gate 	else if (GSS_ERROR(ctx->major) && send_tok->length == 0)
1730Sstevel@tonic-gate 		debug2("Zero length GSS context error token output");
1740Sstevel@tonic-gate 
1750Sstevel@tonic-gate 	if (ctx->major == GSS_S_COMPLETE &&
1760Sstevel@tonic-gate 	    ctx->desired_mech != GSS_C_NULL_OID &&
1770Sstevel@tonic-gate 	    (ctx->desired_mech->length != ctx->actual_mech->length ||
178*6080Sjp161948 	    memcmp(ctx->desired_mech->elements, ctx->actual_mech->elements,
179*6080Sjp161948 	    ctx->desired_mech->length) != 0)) {
180*6080Sjp161948 
1810Sstevel@tonic-gate 		gss_OID_set supported;
182*6080Sjp161948 		OM_uint32 min;
183*6080Sjp161948 		int present = 0;
1840Sstevel@tonic-gate 
185*6080Sjp161948 		debug("The client did not use the GSS-API mechanism it "
186*6080Sjp161948 		    "asked for");
1870Sstevel@tonic-gate 
1880Sstevel@tonic-gate 		/* Let it slide as long as the mech is supported */
1890Sstevel@tonic-gate 		ssh_gssapi_server_mechs(&supported);
190*6080Sjp161948 		if (supported != GSS_C_NULL_OID_SET) {
191*6080Sjp161948 			(void) gss_test_oid_set_member(&min, ctx->actual_mech,
192*6080Sjp161948 			    supported, &present);
193*6080Sjp161948 		}
1940Sstevel@tonic-gate 		if (!present)
1950Sstevel@tonic-gate 			ctx->major = GSS_S_BAD_MECH;
1960Sstevel@tonic-gate 	}
1970Sstevel@tonic-gate 
1980Sstevel@tonic-gate 	if (ctx->deleg_creds)
1990Sstevel@tonic-gate 		debug("Received delegated GSS credentials");
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate 	if (ctx->major == GSS_S_COMPLETE) {
2020Sstevel@tonic-gate 		ctx->major = gss_inquire_context(&ctx->minor, ctx->context,
203*6080Sjp161948 		    NULL, &ctx->dst_name, NULL, NULL, NULL, NULL,
204*6080Sjp161948 		    &ctx->established);
2050Sstevel@tonic-gate 
2060Sstevel@tonic-gate 		if (GSS_ERROR(ctx->major)) {
207*6080Sjp161948 			ssh_gssapi_error(ctx,
208*6080Sjp161948 			    "inquiring established sec context");
2090Sstevel@tonic-gate 			return (ctx->major);
2100Sstevel@tonic-gate 		}
2110Sstevel@tonic-gate 
2120Sstevel@tonic-gate 		xxx_gssctxt = ctx;
2130Sstevel@tonic-gate 	}
2140Sstevel@tonic-gate 
2150Sstevel@tonic-gate 	return (ctx->major);
2160Sstevel@tonic-gate }
2170Sstevel@tonic-gate 
2180Sstevel@tonic-gate 
2190Sstevel@tonic-gate /* As user - called through fatal cleanup hook */
2200Sstevel@tonic-gate void
ssh_gssapi_cleanup_creds(Gssctxt * ctx)2210Sstevel@tonic-gate ssh_gssapi_cleanup_creds(Gssctxt *ctx)
2220Sstevel@tonic-gate {
2230Sstevel@tonic-gate #ifdef HAVE_GSS_STORE_CRED
2240Sstevel@tonic-gate 	/* pam_setcred() will take care of this */
2250Sstevel@tonic-gate 	return;
2260Sstevel@tonic-gate #else
2270Sstevel@tonic-gate 	return;
228*6080Sjp161948 /* #error "Portability broken in cleanup of stored creds" */
2290Sstevel@tonic-gate #endif /* HAVE_GSS_STORE_CRED */
2300Sstevel@tonic-gate }
2310Sstevel@tonic-gate 
2320Sstevel@tonic-gate void
ssh_gssapi_storecreds(Gssctxt * ctx,Authctxt * authctxt)2330Sstevel@tonic-gate ssh_gssapi_storecreds(Gssctxt *ctx, Authctxt *authctxt)
2340Sstevel@tonic-gate {
2350Sstevel@tonic-gate #ifdef USE_PAM
2360Sstevel@tonic-gate 	char **penv, **tmp_env;
2370Sstevel@tonic-gate #endif /* USE_PAM */
238*6080Sjp161948 
2390Sstevel@tonic-gate 	if (authctxt == NULL) {
2400Sstevel@tonic-gate 		error("Missing context while storing GSS-API credentials");
2410Sstevel@tonic-gate 		return;
2420Sstevel@tonic-gate 	}
2430Sstevel@tonic-gate 
2440Sstevel@tonic-gate 	if (ctx == NULL && xxx_gssctxt == NULL)
2450Sstevel@tonic-gate 		return;
2460Sstevel@tonic-gate 
2470Sstevel@tonic-gate 	if (ctx == NULL)
2480Sstevel@tonic-gate 		ctx = xxx_gssctxt;
2490Sstevel@tonic-gate 
250*6080Sjp161948 	if (!options.gss_cleanup_creds ||
2510Sstevel@tonic-gate 	    ctx->deleg_creds == GSS_C_NO_CREDENTIAL) {
2520Sstevel@tonic-gate 		debug3("Not storing delegated GSS credentials"
253*6080Sjp161948 		    " (none delegated)");
2540Sstevel@tonic-gate 		return;
2550Sstevel@tonic-gate 	}
2560Sstevel@tonic-gate 
2570Sstevel@tonic-gate 	if (!authctxt->valid || authctxt->pw == NULL) {
2580Sstevel@tonic-gate 		debug3("Not storing delegated GSS credentials"
259*6080Sjp161948 		    " for invalid user");
2600Sstevel@tonic-gate 		return;
2610Sstevel@tonic-gate 	}
2620Sstevel@tonic-gate 
2630Sstevel@tonic-gate 	debug("Storing delegated GSS-API credentials");
2640Sstevel@tonic-gate 
2650Sstevel@tonic-gate 	/*
2660Sstevel@tonic-gate 	 * The GSS-API has a flaw in that it does not provide a
2670Sstevel@tonic-gate 	 * mechanism by which delegated credentials can be made
2680Sstevel@tonic-gate 	 * available for acquisition by GSS_Acquire_cred() et. al.;
2690Sstevel@tonic-gate 	 * gss_store_cred() is the proposed GSS-API extension for
2700Sstevel@tonic-gate 	 * generically storing delegated credentials.
2710Sstevel@tonic-gate 	 *
2720Sstevel@tonic-gate 	 * gss_store_cred() does not speak to how credential stores are
2730Sstevel@tonic-gate 	 * referenced.  Generically this may be done by switching to the
2740Sstevel@tonic-gate 	 * user context of the user in whose default credential store we
2750Sstevel@tonic-gate 	 * wish to place delegated credentials.  But environment
2760Sstevel@tonic-gate 	 * variables could conceivably affect the choice of credential
2770Sstevel@tonic-gate 	 * store as well, and perhaps in a mechanism-specific manner.
2780Sstevel@tonic-gate 	 *
2790Sstevel@tonic-gate 	 * SUNW -- On Solaris the euid selects the current credential
2800Sstevel@tonic-gate 	 * store, but PAM modules could select alternate stores by
2810Sstevel@tonic-gate 	 * setting, for example, KRB5CCNAME, so we also use the PAM
2820Sstevel@tonic-gate 	 * environment temporarily.
2830Sstevel@tonic-gate 	 */
2840Sstevel@tonic-gate 
2850Sstevel@tonic-gate #ifdef HAVE_GSS_STORE_CRED
2860Sstevel@tonic-gate #ifdef USE_PAM
2870Sstevel@tonic-gate 	/*
2880Sstevel@tonic-gate 	 * PAM may have set mechanism-specific variables (e.g.,
2890Sstevel@tonic-gate 	 * KRB5CCNAME).  fetch_pam_environment() protects against LD_*
2900Sstevel@tonic-gate 	 * and other environment variables.
2910Sstevel@tonic-gate 	 */
2920Sstevel@tonic-gate 	penv = fetch_pam_environment(authctxt);
2930Sstevel@tonic-gate 	tmp_env = environ;
2940Sstevel@tonic-gate 	environ = penv;
2950Sstevel@tonic-gate #endif /* USE_PAM */
2960Sstevel@tonic-gate 	if (authctxt->pw->pw_uid != geteuid()) {
2970Sstevel@tonic-gate 		temporarily_use_uid(authctxt->pw);
2980Sstevel@tonic-gate 		ctx->major = gss_store_cred(&ctx->minor, ctx->deleg_creds,
299*6080Sjp161948 		    GSS_C_INITIATE, GSS_C_NULL_OID, 0, ctx->default_creds,
300*6080Sjp161948 		    NULL, NULL);
3010Sstevel@tonic-gate 		restore_uid();
3020Sstevel@tonic-gate 	} else {
3030Sstevel@tonic-gate 		/* only when logging in as the privileged user used by sshd */
3040Sstevel@tonic-gate 		ctx->major = gss_store_cred(&ctx->minor, ctx->deleg_creds,
305*6080Sjp161948 		    GSS_C_INITIATE, GSS_C_NULL_OID, 0, ctx->default_creds,
306*6080Sjp161948 		    NULL, NULL);
3070Sstevel@tonic-gate 	}
3080Sstevel@tonic-gate #ifdef USE_PAM
3090Sstevel@tonic-gate 	environ = tmp_env;
3100Sstevel@tonic-gate 	free_pam_environment(penv);
3110Sstevel@tonic-gate #endif /* USE_PAM */
3120Sstevel@tonic-gate 	if (GSS_ERROR(ctx->major))
3130Sstevel@tonic-gate 		ssh_gssapi_error(ctx, "storing delegated credentials");
3140Sstevel@tonic-gate 
3150Sstevel@tonic-gate #else
3160Sstevel@tonic-gate #ifdef KRB5_GSS
3170Sstevel@tonic-gate #error "MIT/Heimdal krb5-specific code missing in ssh_gssapi_storecreds()"
3180Sstevel@tonic-gate 	if (ssh_gssapi_is_krb5(ctx->mech))
3190Sstevel@tonic-gate 		ssh_gssapi_krb5_storecreds(ctx);
3200Sstevel@tonic-gate #endif /* KRB5_GSS */
3210Sstevel@tonic-gate #ifdef GSI_GSS
3220Sstevel@tonic-gate #error "GSI krb5-specific code missing in ssh_gssapi_storecreds()"
3230Sstevel@tonic-gate 	if (ssh_gssapi_is_gsi(ctx->mech))
3240Sstevel@tonic-gate 		ssh_gssapi_krb5_storecreds(ctx);
3250Sstevel@tonic-gate #endif /* GSI_GSS */
326*6080Sjp161948 /* #error "Mechanism-specific code missing in ssh_gssapi_storecreds()" */
3270Sstevel@tonic-gate 	return;
3280Sstevel@tonic-gate #endif /* HAVE_GSS_STORE_CRED */
3290Sstevel@tonic-gate }
3300Sstevel@tonic-gate 
3310Sstevel@tonic-gate void
ssh_gssapi_do_child(Gssctxt * ctx,char *** envp,uint_t * envsizep)332*6080Sjp161948 ssh_gssapi_do_child(Gssctxt *ctx, char ***envp, uint_t *envsizep)
3330Sstevel@tonic-gate {
3340Sstevel@tonic-gate 	/*
3350Sstevel@tonic-gate 	 * MIT/Heimdal/GSI specific code goes here.
3360Sstevel@tonic-gate 	 *
3370Sstevel@tonic-gate 	 * On Solaris there's nothing to do here as the GSS store and
3380Sstevel@tonic-gate 	 * related environment variables are to be set by PAM, if at all
3390Sstevel@tonic-gate 	 * (no environment variables are needed to address the default
3400Sstevel@tonic-gate 	 * credential store -- the euid does that).
3410Sstevel@tonic-gate 	 */
3420Sstevel@tonic-gate #ifdef KRB5_GSS
3430Sstevel@tonic-gate #error "MIT/Heimdal krb5-specific code missing in ssh_gssapi_storecreds()"
3440Sstevel@tonic-gate #endif /* KRB5_GSS */
3450Sstevel@tonic-gate #ifdef GSI_GSS
3460Sstevel@tonic-gate #error "GSI krb5-specific code missing in ssh_gssapi_storecreds()"
3470Sstevel@tonic-gate #endif /* GSI_GSS */
3480Sstevel@tonic-gate }
3490Sstevel@tonic-gate 
3500Sstevel@tonic-gate int
ssh_gssapi_userok(Gssctxt * ctx,char * user)3510Sstevel@tonic-gate ssh_gssapi_userok(Gssctxt *ctx, char *user)
3520Sstevel@tonic-gate {
3530Sstevel@tonic-gate 	if (ctx == NULL) {
3540Sstevel@tonic-gate 		debug3("INTERNAL ERROR: %s", __func__);
3550Sstevel@tonic-gate 		return (0);
3560Sstevel@tonic-gate 	}
3570Sstevel@tonic-gate 
3580Sstevel@tonic-gate 	if (user == NULL || *user == '\0')
3590Sstevel@tonic-gate 		return (0);
3600Sstevel@tonic-gate 
3610Sstevel@tonic-gate #ifdef HAVE___GSS_USEROK
3620Sstevel@tonic-gate 	{
3630Sstevel@tonic-gate 		int user_ok = 0;
3640Sstevel@tonic-gate 
3650Sstevel@tonic-gate 		ctx->major = __gss_userok(&ctx->minor, ctx->src_name, user,
366*6080Sjp161948 		    &user_ok);
3670Sstevel@tonic-gate 		if (GSS_ERROR(ctx->major)) {
3680Sstevel@tonic-gate 			debug2("__GSS_userok() failed");
3690Sstevel@tonic-gate 			return (0);
3700Sstevel@tonic-gate 		}
3710Sstevel@tonic-gate 
3720Sstevel@tonic-gate 		if (user_ok)
3730Sstevel@tonic-gate 			return (1);
3740Sstevel@tonic-gate 
3750Sstevel@tonic-gate 		/* fall through */
3760Sstevel@tonic-gate 	}
3770Sstevel@tonic-gate #else
3780Sstevel@tonic-gate #ifdef GSSAPI_SIMPLE_USEROK
3790Sstevel@tonic-gate 	{
3800Sstevel@tonic-gate 		/* Mechanism-generic */
3810Sstevel@tonic-gate 		OM_uint32	min;
3820Sstevel@tonic-gate 		gss_buffer_desc	buf, ename1, ename2;
3830Sstevel@tonic-gate 		gss_name_t	iname, cname;
3840Sstevel@tonic-gate 		int		eql;
3850Sstevel@tonic-gate 
3860Sstevel@tonic-gate 		buf.value = user;
3870Sstevel@tonic-gate 		buf.length = strlen(user);
3880Sstevel@tonic-gate 		ctx->major = gss_import_name(&ctx->minor, &buf,
389*6080Sjp161948 		    GSS_C_NULL_OID, &iname);
3900Sstevel@tonic-gate 		if (GSS_ERROR(ctx->major)) {
3910Sstevel@tonic-gate 			ssh_gssapi_error(ctx,
392*6080Sjp161948 			    "importing name for authorizing initiator");
3930Sstevel@tonic-gate 			goto failed_simple_userok;
3940Sstevel@tonic-gate 		}
3950Sstevel@tonic-gate 
3960Sstevel@tonic-gate 		ctx->major = gss_canonicalize_name(&ctx->minor, iname,
397*6080Sjp161948 		    ctx->actual_mech, &cname);
3980Sstevel@tonic-gate 		(void) gss_release_name(&min, &iname);
3990Sstevel@tonic-gate 		if (GSS_ERROR(ctx->major)) {
4000Sstevel@tonic-gate 			ssh_gssapi_error(ctx, "canonicalizing name");
4010Sstevel@tonic-gate 			goto failed_simple_userok;
4020Sstevel@tonic-gate 		}
4030Sstevel@tonic-gate 
4040Sstevel@tonic-gate 		ctx->major = gss_export_name(&ctx->minor, cname, &ename1);
4050Sstevel@tonic-gate 		(void) gss_release_name(&min, &cname);
4060Sstevel@tonic-gate 		if (GSS_ERROR(ctx->major)) {
4070Sstevel@tonic-gate 			ssh_gssapi_error(ctx, "exporting name");
4080Sstevel@tonic-gate 			goto failed_simple_userok;
4090Sstevel@tonic-gate 		}
4100Sstevel@tonic-gate 
4110Sstevel@tonic-gate 		ctx->major = gss_export_name(&ctx->minor, ctx->src_name,
412*6080Sjp161948 		    &ename2);
4130Sstevel@tonic-gate 		if (GSS_ERROR(ctx->major)) {
4140Sstevel@tonic-gate 			ssh_gssapi_error(ctx,
415*6080Sjp161948 			    "exporting client principal name");
4160Sstevel@tonic-gate 			(void) gss_release_buffer(&min, &ename1);
4170Sstevel@tonic-gate 			goto failed_simple_userok;
4180Sstevel@tonic-gate 		}
4190Sstevel@tonic-gate 
4200Sstevel@tonic-gate 		eql = (ename1.length == ename2.length &&
421*6080Sjp161948 		    memcmp(ename1.value, ename2.value, ename1.length) == 0);
4220Sstevel@tonic-gate 
4230Sstevel@tonic-gate 		(void) gss_release_buffer(&min, &ename1);
4240Sstevel@tonic-gate 		(void) gss_release_buffer(&min, &ename2);
4250Sstevel@tonic-gate 
4260Sstevel@tonic-gate 		if (eql)
4270Sstevel@tonic-gate 			return (1);
4280Sstevel@tonic-gate 		/* fall through */
4290Sstevel@tonic-gate 	}
4300Sstevel@tonic-gate failed_simple_userok:
4310Sstevel@tonic-gate #endif /* GSSAPI_SIMPLE_USEROK */
4320Sstevel@tonic-gate #ifdef HAVE_GSSCRED_API
4330Sstevel@tonic-gate 	{
4340Sstevel@tonic-gate 		/* Mechanism-generic, Solaris-specific */
4350Sstevel@tonic-gate 		OM_uint32	 maj;
4360Sstevel@tonic-gate 		uid_t		 uid;
4370Sstevel@tonic-gate 		struct passwd	*pw;
4380Sstevel@tonic-gate 
4390Sstevel@tonic-gate 		maj = gsscred_name_to_unix_cred(ctx->src_name,
440*6080Sjp161948 		    ctx->actual_mech, &uid, NULL, NULL, NULL);
4410Sstevel@tonic-gate 
4420Sstevel@tonic-gate 		if (GSS_ERROR(maj))
4430Sstevel@tonic-gate 			goto failed_simple_gsscred_userok;
4440Sstevel@tonic-gate 
4450Sstevel@tonic-gate 		if ((pw = getpwnam(user)) == NULL)
4460Sstevel@tonic-gate 			goto failed_simple_gsscred_userok;
4470Sstevel@tonic-gate 
4480Sstevel@tonic-gate 		if (pw->pw_uid == uid)
4490Sstevel@tonic-gate 			return (1);
4500Sstevel@tonic-gate 		/* fall through */
4510Sstevel@tonic-gate 	}
452*6080Sjp161948 
4530Sstevel@tonic-gate failed_simple_gsscred_userok:
4540Sstevel@tonic-gate #endif /* HAVE_GSSCRED_API */
4550Sstevel@tonic-gate #ifdef KRB5_GSS
4560Sstevel@tonic-gate 	if (ssh_gssapi_is_krb5(ctx->mech))
4570Sstevel@tonic-gate 		if (ssh_gssapi_krb5_userok(ctx->src_name, user))
4580Sstevel@tonic-gate 			return (1);
4590Sstevel@tonic-gate #endif /* KRB5_GSS */
4600Sstevel@tonic-gate #ifdef GSI_GSS
4610Sstevel@tonic-gate 	if (ssh_gssapi_is_gsi(ctx->mech))
4620Sstevel@tonic-gate 		if (ssh_gssapi_gsi_userok(ctx->src_name, user))
4630Sstevel@tonic-gate 			return (1);
4640Sstevel@tonic-gate #endif /* GSI_GSS */
4650Sstevel@tonic-gate #endif /* HAVE___GSS_USEROK */
4660Sstevel@tonic-gate 
4670Sstevel@tonic-gate 	/* default to not authorized */
4680Sstevel@tonic-gate 	return (0);
4690Sstevel@tonic-gate }
4700Sstevel@tonic-gate 
4710Sstevel@tonic-gate char *
ssh_gssapi_localname(Gssctxt * ctx)4720Sstevel@tonic-gate ssh_gssapi_localname(Gssctxt *ctx)
4730Sstevel@tonic-gate {
4740Sstevel@tonic-gate 	if (ctx == NULL) {
4750Sstevel@tonic-gate 		debug3("INTERNAL ERROR: %s", __func__);
4760Sstevel@tonic-gate 		return (NULL);
4770Sstevel@tonic-gate 	}
4780Sstevel@tonic-gate 
4790Sstevel@tonic-gate 	debug2("Mapping initiator GSS-API principal to local username");
4800Sstevel@tonic-gate #ifdef HAVE_GSSCRED_API
4810Sstevel@tonic-gate 	{
4820Sstevel@tonic-gate 		/* Mechanism-generic, Solaris-specific */
4830Sstevel@tonic-gate 		OM_uint32	 maj;
4840Sstevel@tonic-gate 		uid_t		 uid;
4850Sstevel@tonic-gate 		struct passwd	*pw;
4860Sstevel@tonic-gate 
4870Sstevel@tonic-gate 		if (ctx->src_name == GSS_C_NO_NAME)
4880Sstevel@tonic-gate 			goto failed_gsscred_localname;
4890Sstevel@tonic-gate 
4900Sstevel@tonic-gate 		maj = gsscred_name_to_unix_cred(ctx->src_name,
491*6080Sjp161948 		    ctx->actual_mech, &uid, NULL, NULL, NULL);
4920Sstevel@tonic-gate 
4930Sstevel@tonic-gate 		if (GSS_ERROR(maj))
4940Sstevel@tonic-gate 			goto failed_gsscred_localname;
4950Sstevel@tonic-gate 
4960Sstevel@tonic-gate 		if ((pw = getpwuid(uid)) == NULL)
4970Sstevel@tonic-gate 			goto failed_gsscred_localname;
4980Sstevel@tonic-gate 
4990Sstevel@tonic-gate 		debug2("Mapped the initiator to: %s", pw->pw_name);
5000Sstevel@tonic-gate 		return (xstrdup(pw->pw_name));
5010Sstevel@tonic-gate 	}
5020Sstevel@tonic-gate failed_gsscred_localname:
5030Sstevel@tonic-gate #endif /* HAVE_GSSCRED_API */
5040Sstevel@tonic-gate #ifdef KRB5_GSS
5050Sstevel@tonic-gate #error "ssh_gssapi_krb5_localname() not implemented"
5060Sstevel@tonic-gate 	if (ssh_gssapi_is_krb5(ctx->mech))
5070Sstevel@tonic-gate 		return (ssh_gssapi_krb5_localname(ctx->src_name));
5080Sstevel@tonic-gate #endif /* KRB5_GSS */
5090Sstevel@tonic-gate #ifdef GSI_GSS
5100Sstevel@tonic-gate #error "ssh_gssapi_gsi_localname() not implemented"
5110Sstevel@tonic-gate 	if (ssh_gssapi_is_gsi(ctx->mech))
5120Sstevel@tonic-gate 		return (ssh_gssapi_gsi_localname(ctx->src_name));
5130Sstevel@tonic-gate #endif /* GSI_GSS */
5140Sstevel@tonic-gate 	return (NULL);
5150Sstevel@tonic-gate }
516*6080Sjp161948 #endif /* GSSAPI */
517