xref: /onnv-gate/usr/src/cmd/ssh/sshd/gss-serv.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * Redistribution and use in source and binary forms, with or without
5*0Sstevel@tonic-gate  * modification, are permitted provided that the following conditions
6*0Sstevel@tonic-gate  * are met:
7*0Sstevel@tonic-gate  * 1. Redistributions of source code must retain the above copyright
8*0Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer.
9*0Sstevel@tonic-gate  * 2. Redistributions in binary form must reproduce the above copyright
10*0Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer in the
11*0Sstevel@tonic-gate  *    documentation and/or other materials provided with the distribution.
12*0Sstevel@tonic-gate  *
13*0Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
14*0Sstevel@tonic-gate  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15*0Sstevel@tonic-gate  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16*0Sstevel@tonic-gate  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17*0Sstevel@tonic-gate  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18*0Sstevel@tonic-gate  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19*0Sstevel@tonic-gate  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20*0Sstevel@tonic-gate  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21*0Sstevel@tonic-gate  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22*0Sstevel@tonic-gate  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23*0Sstevel@tonic-gate  */
24*0Sstevel@tonic-gate /*
25*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
26*0Sstevel@tonic-gate  * Use is subject to license terms.
27*0Sstevel@tonic-gate  */
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include "includes.h"
30*0Sstevel@tonic-gate 
31*0Sstevel@tonic-gate #ifdef GSSAPI
32*0Sstevel@tonic-gate 
33*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
34*0Sstevel@tonic-gate 
35*0Sstevel@tonic-gate #include "includes.h"
36*0Sstevel@tonic-gate #include "ssh.h"
37*0Sstevel@tonic-gate #include "ssh2.h"
38*0Sstevel@tonic-gate #include "xmalloc.h"
39*0Sstevel@tonic-gate #include "buffer.h"
40*0Sstevel@tonic-gate #include "bufaux.h"
41*0Sstevel@tonic-gate #include "packet.h"
42*0Sstevel@tonic-gate #include "compat.h"
43*0Sstevel@tonic-gate #include <openssl/evp.h>
44*0Sstevel@tonic-gate #include "cipher.h"
45*0Sstevel@tonic-gate #include "kex.h"
46*0Sstevel@tonic-gate #include "auth.h"
47*0Sstevel@tonic-gate #include "log.h"
48*0Sstevel@tonic-gate #include "channels.h"
49*0Sstevel@tonic-gate #include "session.h"
50*0Sstevel@tonic-gate #include "dispatch.h"
51*0Sstevel@tonic-gate #include "servconf.h"
52*0Sstevel@tonic-gate #include "uidswap.h"
53*0Sstevel@tonic-gate #include "compat.h"
54*0Sstevel@tonic-gate #include "monitor_wrap.h"
55*0Sstevel@tonic-gate #include <pwd.h>
56*0Sstevel@tonic-gate 
57*0Sstevel@tonic-gate #include "ssh-gss.h"
58*0Sstevel@tonic-gate 
59*0Sstevel@tonic-gate extern char **environ;
60*0Sstevel@tonic-gate 
61*0Sstevel@tonic-gate extern ServerOptions options;
62*0Sstevel@tonic-gate extern u_char *session_id2;
63*0Sstevel@tonic-gate extern int session_id2_len;
64*0Sstevel@tonic-gate 
65*0Sstevel@tonic-gate Gssctxt	*xxx_gssctxt;
66*0Sstevel@tonic-gate 
67*0Sstevel@tonic-gate void
68*0Sstevel@tonic-gate ssh_gssapi_server_kex_hook(Kex *kex, char **proposal)
69*0Sstevel@tonic-gate {
70*0Sstevel@tonic-gate 	gss_OID_set mechs = GSS_C_NULL_OID_SET;
71*0Sstevel@tonic-gate 
72*0Sstevel@tonic-gate 	if (kex == NULL || !kex->server)
73*0Sstevel@tonic-gate 		fatal("INTERNAL ERROR (%s)", __func__);
74*0Sstevel@tonic-gate 
75*0Sstevel@tonic-gate 	ssh_gssapi_server_mechs(&mechs);
76*0Sstevel@tonic-gate 	ssh_gssapi_modify_kex(kex, mechs, proposal);
77*0Sstevel@tonic-gate }
78*0Sstevel@tonic-gate 
79*0Sstevel@tonic-gate void
80*0Sstevel@tonic-gate ssh_gssapi_server_mechs(gss_OID_set *mechs)
81*0Sstevel@tonic-gate {
82*0Sstevel@tonic-gate 	static gss_OID_set	supported = GSS_C_NULL_OID_SET;
83*0Sstevel@tonic-gate 	gss_OID_set	s, acquired, indicated = GSS_C_NULL_OID_SET;
84*0Sstevel@tonic-gate 	gss_cred_id_t	creds;
85*0Sstevel@tonic-gate 	OM_uint32	maj, min;
86*0Sstevel@tonic-gate 	int		i;
87*0Sstevel@tonic-gate 
88*0Sstevel@tonic-gate 	if (!mechs) {
89*0Sstevel@tonic-gate 		(void) gss_release_oid_set(&min, &supported);
90*0Sstevel@tonic-gate 		return;
91*0Sstevel@tonic-gate 	}
92*0Sstevel@tonic-gate 
93*0Sstevel@tonic-gate 	if (supported != GSS_C_NULL_OID_SET) {
94*0Sstevel@tonic-gate 		*mechs = supported;
95*0Sstevel@tonic-gate 		return;
96*0Sstevel@tonic-gate 	}
97*0Sstevel@tonic-gate 
98*0Sstevel@tonic-gate 	*mechs = GSS_C_NULL_OID_SET;
99*0Sstevel@tonic-gate 
100*0Sstevel@tonic-gate 	maj = gss_create_empty_oid_set(&min, &s);
101*0Sstevel@tonic-gate 	if (GSS_ERROR(maj)) {
102*0Sstevel@tonic-gate 		debug("Could not allocate GSS-API resources (%s)",
103*0Sstevel@tonic-gate 			ssh_gssapi_last_error(NULL, &maj, &min));
104*0Sstevel@tonic-gate 		return;
105*0Sstevel@tonic-gate 	}
106*0Sstevel@tonic-gate 
107*0Sstevel@tonic-gate 	maj = gss_indicate_mechs(&min, &indicated);
108*0Sstevel@tonic-gate 	if (GSS_ERROR(maj)) {
109*0Sstevel@tonic-gate 		debug("No GSS-API mechanisms are installed");
110*0Sstevel@tonic-gate 		return;
111*0Sstevel@tonic-gate 	}
112*0Sstevel@tonic-gate 
113*0Sstevel@tonic-gate 	maj = gss_acquire_cred(&min, GSS_C_NO_NAME, 0, indicated,
114*0Sstevel@tonic-gate 			GSS_C_ACCEPT, &creds, &acquired, NULL);
115*0Sstevel@tonic-gate 
116*0Sstevel@tonic-gate 	if (GSS_ERROR(maj))
117*0Sstevel@tonic-gate 		debug("Failed to acquire GSS-API credentials for any "
118*0Sstevel@tonic-gate 			"mechanisms (%s)",
119*0Sstevel@tonic-gate 			ssh_gssapi_last_error(NULL, &maj, &min));
120*0Sstevel@tonic-gate 
121*0Sstevel@tonic-gate 	(void) gss_release_oid_set(&min, &indicated);
122*0Sstevel@tonic-gate 	(void) gss_release_cred(&min, &creds);
123*0Sstevel@tonic-gate 
124*0Sstevel@tonic-gate 	if (acquired == GSS_C_NULL_OID_SET || acquired->count == 0)
125*0Sstevel@tonic-gate 		return;
126*0Sstevel@tonic-gate 
127*0Sstevel@tonic-gate 	for (i = 0 ; i < acquired->count ; i++ ) {
128*0Sstevel@tonic-gate 		if (ssh_gssapi_is_spnego(&acquired->elements[i]))
129*0Sstevel@tonic-gate 			continue;
130*0Sstevel@tonic-gate 
131*0Sstevel@tonic-gate 		maj = gss_add_oid_set_member(&min, &acquired->elements[i], &s);
132*0Sstevel@tonic-gate 		if (GSS_ERROR(maj)) {
133*0Sstevel@tonic-gate 			debug("Could not allocate GSS-API resources (%s)",
134*0Sstevel@tonic-gate 				ssh_gssapi_last_error(NULL, &maj, &min));
135*0Sstevel@tonic-gate 			return;
136*0Sstevel@tonic-gate 		}
137*0Sstevel@tonic-gate 	}
138*0Sstevel@tonic-gate 	(void) gss_release_oid_set(&min, &acquired);
139*0Sstevel@tonic-gate 
140*0Sstevel@tonic-gate 	if (s->count) {
141*0Sstevel@tonic-gate 		supported = s;
142*0Sstevel@tonic-gate 		*mechs = s;
143*0Sstevel@tonic-gate 	}
144*0Sstevel@tonic-gate }
145*0Sstevel@tonic-gate 
146*0Sstevel@tonic-gate /* Wrapper around accept_sec_context
147*0Sstevel@tonic-gate  * Requires that the context contains:
148*0Sstevel@tonic-gate  *    oid
149*0Sstevel@tonic-gate  *    credentials	(from ssh_gssapi_acquire_cred)
150*0Sstevel@tonic-gate  */
151*0Sstevel@tonic-gate /* Priviledged */
152*0Sstevel@tonic-gate OM_uint32 ssh_gssapi_accept_ctx(Gssctxt *ctx, gss_buffer_t recv_tok,
153*0Sstevel@tonic-gate 				gss_buffer_t send_tok)
154*0Sstevel@tonic-gate {
155*0Sstevel@tonic-gate 	/*
156*0Sstevel@tonic-gate 	 * Acquiring a cred for the ctx->desired_mech for GSS_C_NO_NAME
157*0Sstevel@tonic-gate 	 * may well be probably better than using GSS_C_NO_CREDENTIAL
158*0Sstevel@tonic-gate 	 * and then checking that ctx->desired_mech agrees with
159*0Sstevel@tonic-gate 	 * ctx->actual_mech...
160*0Sstevel@tonic-gate 	 */
161*0Sstevel@tonic-gate 	ctx->major=gss_accept_sec_context(&ctx->minor,
162*0Sstevel@tonic-gate 					  &ctx->context,
163*0Sstevel@tonic-gate 					  GSS_C_NO_CREDENTIAL,
164*0Sstevel@tonic-gate 					  recv_tok,
165*0Sstevel@tonic-gate 					  GSS_C_NO_CHANNEL_BINDINGS,
166*0Sstevel@tonic-gate 					  &ctx->src_name,
167*0Sstevel@tonic-gate 					  &ctx->actual_mech,
168*0Sstevel@tonic-gate 					  send_tok,
169*0Sstevel@tonic-gate 					  &ctx->flags,
170*0Sstevel@tonic-gate 					  NULL,
171*0Sstevel@tonic-gate 					  &ctx->deleg_creds);
172*0Sstevel@tonic-gate 	if (GSS_ERROR(ctx->major))
173*0Sstevel@tonic-gate 		ssh_gssapi_error(ctx, "accepting security context");
174*0Sstevel@tonic-gate 
175*0Sstevel@tonic-gate 	if (ctx->major == GSS_S_CONTINUE_NEEDED && send_tok->length == 0)
176*0Sstevel@tonic-gate 		fatal("Zero length GSS context token output when continue needed");
177*0Sstevel@tonic-gate 	else if (GSS_ERROR(ctx->major) && send_tok->length == 0)
178*0Sstevel@tonic-gate 		debug2("Zero length GSS context error token output");
179*0Sstevel@tonic-gate 
180*0Sstevel@tonic-gate 	if (ctx->major == GSS_S_COMPLETE &&
181*0Sstevel@tonic-gate 	    ctx->desired_mech != GSS_C_NULL_OID &&
182*0Sstevel@tonic-gate 	    (ctx->desired_mech->length != ctx->actual_mech->length ||
183*0Sstevel@tonic-gate 		memcmp(ctx->desired_mech->elements,
184*0Sstevel@tonic-gate 		    ctx->actual_mech->elements,
185*0Sstevel@tonic-gate 		    ctx->desired_mech->length) != 0)) {
186*0Sstevel@tonic-gate 		gss_OID_set supported;
187*0Sstevel@tonic-gate 		OM_uint32   min;
188*0Sstevel@tonic-gate 		int	    present = 0;
189*0Sstevel@tonic-gate 
190*0Sstevel@tonic-gate 		debug("The client did not use the GSS-API mechanism it asked for");
191*0Sstevel@tonic-gate 
192*0Sstevel@tonic-gate 		/* Let it slide as long as the mech is supported */
193*0Sstevel@tonic-gate 		ssh_gssapi_server_mechs(&supported);
194*0Sstevel@tonic-gate 		if (supported != GSS_C_NULL_OID_SET)
195*0Sstevel@tonic-gate 			(void) gss_test_oid_set_member(&min,
196*0Sstevel@tonic-gate 						       ctx->actual_mech,
197*0Sstevel@tonic-gate 						       supported, &present);
198*0Sstevel@tonic-gate 		if (!present)
199*0Sstevel@tonic-gate 			ctx->major = GSS_S_BAD_MECH;
200*0Sstevel@tonic-gate 	}
201*0Sstevel@tonic-gate 
202*0Sstevel@tonic-gate 	if (ctx->deleg_creds)
203*0Sstevel@tonic-gate 		debug("Received delegated GSS credentials");
204*0Sstevel@tonic-gate 
205*0Sstevel@tonic-gate 	if (ctx->major == GSS_S_COMPLETE) {
206*0Sstevel@tonic-gate 		ctx->major = gss_inquire_context(&ctx->minor, ctx->context,
207*0Sstevel@tonic-gate 					NULL, &ctx->dst_name, NULL, NULL,
208*0Sstevel@tonic-gate 					NULL, NULL, &ctx->established);
209*0Sstevel@tonic-gate 
210*0Sstevel@tonic-gate 		if (GSS_ERROR(ctx->major)) {
211*0Sstevel@tonic-gate 			ssh_gssapi_error(ctx, "inquiring established sec context");
212*0Sstevel@tonic-gate 			return (ctx->major);
213*0Sstevel@tonic-gate 		}
214*0Sstevel@tonic-gate 
215*0Sstevel@tonic-gate 		xxx_gssctxt = ctx;
216*0Sstevel@tonic-gate 	}
217*0Sstevel@tonic-gate 
218*0Sstevel@tonic-gate 	return (ctx->major);
219*0Sstevel@tonic-gate }
220*0Sstevel@tonic-gate 
221*0Sstevel@tonic-gate 
222*0Sstevel@tonic-gate /* As user - called through fatal cleanup hook */
223*0Sstevel@tonic-gate void
224*0Sstevel@tonic-gate ssh_gssapi_cleanup_creds(Gssctxt *ctx)
225*0Sstevel@tonic-gate {
226*0Sstevel@tonic-gate #ifdef HAVE_GSS_STORE_CRED
227*0Sstevel@tonic-gate 	/* pam_setcred() will take care of this */
228*0Sstevel@tonic-gate 	return;
229*0Sstevel@tonic-gate #else
230*0Sstevel@tonic-gate 	return;
231*0Sstevel@tonic-gate /*#error "Portability broken in cleanup of stored creds"*/
232*0Sstevel@tonic-gate #endif /* HAVE_GSS_STORE_CRED */
233*0Sstevel@tonic-gate }
234*0Sstevel@tonic-gate 
235*0Sstevel@tonic-gate void
236*0Sstevel@tonic-gate ssh_gssapi_storecreds(Gssctxt *ctx, Authctxt *authctxt)
237*0Sstevel@tonic-gate {
238*0Sstevel@tonic-gate #ifdef USE_PAM
239*0Sstevel@tonic-gate 	char **penv, **tmp_env;
240*0Sstevel@tonic-gate #endif /* USE_PAM */
241*0Sstevel@tonic-gate 
242*0Sstevel@tonic-gate 	if (authctxt == NULL) {
243*0Sstevel@tonic-gate 		error("Missing context while storing GSS-API credentials");
244*0Sstevel@tonic-gate 		return;
245*0Sstevel@tonic-gate 	}
246*0Sstevel@tonic-gate 
247*0Sstevel@tonic-gate 	if (ctx == NULL && xxx_gssctxt == NULL)
248*0Sstevel@tonic-gate 		return;
249*0Sstevel@tonic-gate 
250*0Sstevel@tonic-gate 	if (ctx == NULL)
251*0Sstevel@tonic-gate 		ctx = xxx_gssctxt;
252*0Sstevel@tonic-gate 
253*0Sstevel@tonic-gate 	if (!options.gss_cleanup_creds ||
254*0Sstevel@tonic-gate 	    ctx->deleg_creds == GSS_C_NO_CREDENTIAL) {
255*0Sstevel@tonic-gate 		debug3("Not storing delegated GSS credentials"
256*0Sstevel@tonic-gate 			" (none delegated)");
257*0Sstevel@tonic-gate 		return;
258*0Sstevel@tonic-gate 	}
259*0Sstevel@tonic-gate 
260*0Sstevel@tonic-gate 	if (!authctxt->valid || authctxt->pw == NULL) {
261*0Sstevel@tonic-gate 		debug3("Not storing delegated GSS credentials"
262*0Sstevel@tonic-gate 			" for invalid user");
263*0Sstevel@tonic-gate 		return;
264*0Sstevel@tonic-gate 	}
265*0Sstevel@tonic-gate 
266*0Sstevel@tonic-gate 	debug("Storing delegated GSS-API credentials");
267*0Sstevel@tonic-gate 
268*0Sstevel@tonic-gate 	/*
269*0Sstevel@tonic-gate 	 * The GSS-API has a flaw in that it does not provide a
270*0Sstevel@tonic-gate 	 * mechanism by which delegated credentials can be made
271*0Sstevel@tonic-gate 	 * available for acquisition by GSS_Acquire_cred() et. al.;
272*0Sstevel@tonic-gate 	 * gss_store_cred() is the proposed GSS-API extension for
273*0Sstevel@tonic-gate 	 * generically storing delegated credentials.
274*0Sstevel@tonic-gate 	 *
275*0Sstevel@tonic-gate 	 * gss_store_cred() does not speak to how credential stores are
276*0Sstevel@tonic-gate 	 * referenced.  Generically this may be done by switching to the
277*0Sstevel@tonic-gate 	 * user context of the user in whose default credential store we
278*0Sstevel@tonic-gate 	 * wish to place delegated credentials.  But environment
279*0Sstevel@tonic-gate 	 * variables could conceivably affect the choice of credential
280*0Sstevel@tonic-gate 	 * store as well, and perhaps in a mechanism-specific manner.
281*0Sstevel@tonic-gate 	 *
282*0Sstevel@tonic-gate 	 * SUNW -- On Solaris the euid selects the current credential
283*0Sstevel@tonic-gate 	 * store, but PAM modules could select alternate stores by
284*0Sstevel@tonic-gate 	 * setting, for example, KRB5CCNAME, so we also use the PAM
285*0Sstevel@tonic-gate 	 * environment temporarily.
286*0Sstevel@tonic-gate 	 */
287*0Sstevel@tonic-gate 
288*0Sstevel@tonic-gate #ifdef HAVE_GSS_STORE_CRED
289*0Sstevel@tonic-gate #ifdef USE_PAM
290*0Sstevel@tonic-gate 	/*
291*0Sstevel@tonic-gate 	 * PAM may have set mechanism-specific variables (e.g.,
292*0Sstevel@tonic-gate 	 * KRB5CCNAME).  fetch_pam_environment() protects against LD_*
293*0Sstevel@tonic-gate 	 * and other environment variables.
294*0Sstevel@tonic-gate 	 */
295*0Sstevel@tonic-gate 	penv = fetch_pam_environment(authctxt);
296*0Sstevel@tonic-gate 	tmp_env = environ;
297*0Sstevel@tonic-gate 	environ = penv;
298*0Sstevel@tonic-gate #endif /* USE_PAM */
299*0Sstevel@tonic-gate 	if (authctxt->pw->pw_uid != geteuid()) {
300*0Sstevel@tonic-gate 		temporarily_use_uid(authctxt->pw);
301*0Sstevel@tonic-gate 		ctx->major = gss_store_cred(&ctx->minor, ctx->deleg_creds,
302*0Sstevel@tonic-gate 				GSS_C_INITIATE, GSS_C_NULL_OID, 0,
303*0Sstevel@tonic-gate 				ctx->default_creds, NULL, NULL);
304*0Sstevel@tonic-gate 		restore_uid();
305*0Sstevel@tonic-gate 	} else {
306*0Sstevel@tonic-gate 		/* only when logging in as the privileged user used by sshd */
307*0Sstevel@tonic-gate 		ctx->major = gss_store_cred(&ctx->minor, ctx->deleg_creds,
308*0Sstevel@tonic-gate 				GSS_C_INITIATE, GSS_C_NULL_OID, 0,
309*0Sstevel@tonic-gate 				ctx->default_creds, NULL, NULL);
310*0Sstevel@tonic-gate 	}
311*0Sstevel@tonic-gate #ifdef USE_PAM
312*0Sstevel@tonic-gate 	environ = tmp_env;
313*0Sstevel@tonic-gate 	free_pam_environment(penv);
314*0Sstevel@tonic-gate #endif /* USE_PAM */
315*0Sstevel@tonic-gate 	if (GSS_ERROR(ctx->major))
316*0Sstevel@tonic-gate 		ssh_gssapi_error(ctx, "storing delegated credentials");
317*0Sstevel@tonic-gate 
318*0Sstevel@tonic-gate #else
319*0Sstevel@tonic-gate #ifdef KRB5_GSS
320*0Sstevel@tonic-gate #error "MIT/Heimdal krb5-specific code missing in ssh_gssapi_storecreds()"
321*0Sstevel@tonic-gate 	if (ssh_gssapi_is_krb5(ctx->mech))
322*0Sstevel@tonic-gate 		ssh_gssapi_krb5_storecreds(ctx);
323*0Sstevel@tonic-gate #endif /* KRB5_GSS */
324*0Sstevel@tonic-gate #ifdef GSI_GSS
325*0Sstevel@tonic-gate #error "GSI krb5-specific code missing in ssh_gssapi_storecreds()"
326*0Sstevel@tonic-gate 	if (ssh_gssapi_is_gsi(ctx->mech))
327*0Sstevel@tonic-gate 		ssh_gssapi_krb5_storecreds(ctx);
328*0Sstevel@tonic-gate #endif /* GSI_GSS */
329*0Sstevel@tonic-gate /*#error "Mechanism-specific code missing in ssh_gssapi_storecreds()"*/
330*0Sstevel@tonic-gate 	return;
331*0Sstevel@tonic-gate #endif /* HAVE_GSS_STORE_CRED */
332*0Sstevel@tonic-gate }
333*0Sstevel@tonic-gate 
334*0Sstevel@tonic-gate void
335*0Sstevel@tonic-gate ssh_gssapi_do_child(Gssctxt *ctx, char ***envp, u_int *envsizep)
336*0Sstevel@tonic-gate {
337*0Sstevel@tonic-gate 	/*
338*0Sstevel@tonic-gate 	 * MIT/Heimdal/GSI specific code goes here.
339*0Sstevel@tonic-gate 	 *
340*0Sstevel@tonic-gate 	 * On Solaris there's nothing to do here as the GSS store and
341*0Sstevel@tonic-gate 	 * related environment variables are to be set by PAM, if at all
342*0Sstevel@tonic-gate 	 * (no environment variables are needed to address the default
343*0Sstevel@tonic-gate 	 * credential store -- the euid does that).
344*0Sstevel@tonic-gate 	 */
345*0Sstevel@tonic-gate #ifdef KRB5_GSS
346*0Sstevel@tonic-gate #error "MIT/Heimdal krb5-specific code missing in ssh_gssapi_storecreds()"
347*0Sstevel@tonic-gate #endif /* KRB5_GSS */
348*0Sstevel@tonic-gate #ifdef GSI_GSS
349*0Sstevel@tonic-gate #error "GSI krb5-specific code missing in ssh_gssapi_storecreds()"
350*0Sstevel@tonic-gate #endif /* GSI_GSS */
351*0Sstevel@tonic-gate 	return;
352*0Sstevel@tonic-gate }
353*0Sstevel@tonic-gate 
354*0Sstevel@tonic-gate int
355*0Sstevel@tonic-gate ssh_gssapi_userok(Gssctxt *ctx, char *user)
356*0Sstevel@tonic-gate {
357*0Sstevel@tonic-gate 	if (ctx == NULL) {
358*0Sstevel@tonic-gate 		debug3("INTERNAL ERROR: %s", __func__);
359*0Sstevel@tonic-gate 		return (0);
360*0Sstevel@tonic-gate 	}
361*0Sstevel@tonic-gate 
362*0Sstevel@tonic-gate 	if (user == NULL || *user == '\0')
363*0Sstevel@tonic-gate 		return (0);
364*0Sstevel@tonic-gate 
365*0Sstevel@tonic-gate #ifdef HAVE___GSS_USEROK
366*0Sstevel@tonic-gate 	{
367*0Sstevel@tonic-gate 		int user_ok = 0;
368*0Sstevel@tonic-gate 
369*0Sstevel@tonic-gate 		ctx->major = __gss_userok(&ctx->minor, ctx->src_name, user,
370*0Sstevel@tonic-gate 			&user_ok);
371*0Sstevel@tonic-gate 		if (GSS_ERROR(ctx->major)) {
372*0Sstevel@tonic-gate 			debug2("__GSS_userok() failed");
373*0Sstevel@tonic-gate 			return (0);
374*0Sstevel@tonic-gate 		}
375*0Sstevel@tonic-gate 
376*0Sstevel@tonic-gate 		if (user_ok)
377*0Sstevel@tonic-gate 			return (1);
378*0Sstevel@tonic-gate 
379*0Sstevel@tonic-gate 		/* fall through */
380*0Sstevel@tonic-gate 	}
381*0Sstevel@tonic-gate #else
382*0Sstevel@tonic-gate #ifdef GSSAPI_SIMPLE_USEROK
383*0Sstevel@tonic-gate 	{
384*0Sstevel@tonic-gate 		/* Mechanism-generic */
385*0Sstevel@tonic-gate 		OM_uint32	min;
386*0Sstevel@tonic-gate 		gss_buffer_desc	buf, ename1, ename2;
387*0Sstevel@tonic-gate 		gss_name_t	iname, cname;
388*0Sstevel@tonic-gate 		int		eql;
389*0Sstevel@tonic-gate 
390*0Sstevel@tonic-gate 		buf.value = user;
391*0Sstevel@tonic-gate 		buf.length = strlen(user);
392*0Sstevel@tonic-gate 		ctx->major = gss_import_name(&ctx->minor, &buf,
393*0Sstevel@tonic-gate 					GSS_C_NULL_OID, &iname);
394*0Sstevel@tonic-gate 		if (GSS_ERROR(ctx->major)) {
395*0Sstevel@tonic-gate 			ssh_gssapi_error(ctx,
396*0Sstevel@tonic-gate 				"importing name for authorizing initiator");
397*0Sstevel@tonic-gate 			goto failed_simple_userok;
398*0Sstevel@tonic-gate 		}
399*0Sstevel@tonic-gate 
400*0Sstevel@tonic-gate 		ctx->major = gss_canonicalize_name(&ctx->minor, iname,
401*0Sstevel@tonic-gate 					ctx->actual_mech, &cname);
402*0Sstevel@tonic-gate 		(void) gss_release_name(&min, &iname);
403*0Sstevel@tonic-gate 		if (GSS_ERROR(ctx->major)) {
404*0Sstevel@tonic-gate 			ssh_gssapi_error(ctx, "canonicalizing name");
405*0Sstevel@tonic-gate 			goto failed_simple_userok;
406*0Sstevel@tonic-gate 		}
407*0Sstevel@tonic-gate 
408*0Sstevel@tonic-gate 		ctx->major = gss_export_name(&ctx->minor, cname, &ename1);
409*0Sstevel@tonic-gate 		(void) gss_release_name(&min, &cname);
410*0Sstevel@tonic-gate 		if (GSS_ERROR(ctx->major)) {
411*0Sstevel@tonic-gate 			ssh_gssapi_error(ctx, "exporting name");
412*0Sstevel@tonic-gate 			goto failed_simple_userok;
413*0Sstevel@tonic-gate 		}
414*0Sstevel@tonic-gate 
415*0Sstevel@tonic-gate 		ctx->major = gss_export_name(&ctx->minor, ctx->src_name,
416*0Sstevel@tonic-gate 			&ename2);
417*0Sstevel@tonic-gate 		if (GSS_ERROR(ctx->major)) {
418*0Sstevel@tonic-gate 			ssh_gssapi_error(ctx,
419*0Sstevel@tonic-gate 				"exporting client principal name");
420*0Sstevel@tonic-gate 			(void) gss_release_buffer(&min, &ename1);
421*0Sstevel@tonic-gate 			goto failed_simple_userok;
422*0Sstevel@tonic-gate 		}
423*0Sstevel@tonic-gate 
424*0Sstevel@tonic-gate 		eql = (ename1.length == ename2.length &&
425*0Sstevel@tonic-gate 			memcmp(ename1.value, ename2.value, ename1.length) == 0);
426*0Sstevel@tonic-gate 
427*0Sstevel@tonic-gate 		(void) gss_release_buffer(&min, &ename1);
428*0Sstevel@tonic-gate 		(void) gss_release_buffer(&min, &ename2);
429*0Sstevel@tonic-gate 
430*0Sstevel@tonic-gate 		if (eql)
431*0Sstevel@tonic-gate 			return (1);
432*0Sstevel@tonic-gate 		/* fall through */
433*0Sstevel@tonic-gate 	}
434*0Sstevel@tonic-gate failed_simple_userok:
435*0Sstevel@tonic-gate #endif /* GSSAPI_SIMPLE_USEROK */
436*0Sstevel@tonic-gate #ifdef HAVE_GSSCRED_API
437*0Sstevel@tonic-gate 	{
438*0Sstevel@tonic-gate 		/* Mechanism-generic, Solaris-specific */
439*0Sstevel@tonic-gate 		OM_uint32	 maj;
440*0Sstevel@tonic-gate 		uid_t		 uid;
441*0Sstevel@tonic-gate 		struct passwd	*pw;
442*0Sstevel@tonic-gate 
443*0Sstevel@tonic-gate 		maj = gsscred_name_to_unix_cred(ctx->src_name,
444*0Sstevel@tonic-gate 				ctx->actual_mech, &uid, NULL, NULL, NULL);
445*0Sstevel@tonic-gate 
446*0Sstevel@tonic-gate 		if (GSS_ERROR(maj))
447*0Sstevel@tonic-gate 			goto failed_simple_gsscred_userok;
448*0Sstevel@tonic-gate 
449*0Sstevel@tonic-gate 		if ((pw = getpwnam(user)) == NULL)
450*0Sstevel@tonic-gate 			goto failed_simple_gsscred_userok;
451*0Sstevel@tonic-gate 
452*0Sstevel@tonic-gate 		if (pw->pw_uid == uid)
453*0Sstevel@tonic-gate 			return (1);
454*0Sstevel@tonic-gate 		/* fall through */
455*0Sstevel@tonic-gate 	}
456*0Sstevel@tonic-gate failed_simple_gsscred_userok:
457*0Sstevel@tonic-gate #endif /* HAVE_GSSCRED_API */
458*0Sstevel@tonic-gate #ifdef KRB5_GSS
459*0Sstevel@tonic-gate 	if (ssh_gssapi_is_krb5(ctx->mech))
460*0Sstevel@tonic-gate 		if (ssh_gssapi_krb5_userok(ctx->src_name, user))
461*0Sstevel@tonic-gate 			return (1);
462*0Sstevel@tonic-gate #endif /* KRB5_GSS */
463*0Sstevel@tonic-gate #ifdef GSI_GSS
464*0Sstevel@tonic-gate 	if (ssh_gssapi_is_gsi(ctx->mech))
465*0Sstevel@tonic-gate 		if (ssh_gssapi_gsi_userok(ctx->src_name, user))
466*0Sstevel@tonic-gate 			return (1);
467*0Sstevel@tonic-gate #endif /* GSI_GSS */
468*0Sstevel@tonic-gate #endif /* HAVE___GSS_USEROK */
469*0Sstevel@tonic-gate 
470*0Sstevel@tonic-gate 	/* default to not authorized */
471*0Sstevel@tonic-gate 	return (0);
472*0Sstevel@tonic-gate }
473*0Sstevel@tonic-gate 
474*0Sstevel@tonic-gate char *
475*0Sstevel@tonic-gate ssh_gssapi_localname(Gssctxt *ctx)
476*0Sstevel@tonic-gate {
477*0Sstevel@tonic-gate 	if (ctx == NULL) {
478*0Sstevel@tonic-gate 		debug3("INTERNAL ERROR: %s", __func__);
479*0Sstevel@tonic-gate 		return (NULL);
480*0Sstevel@tonic-gate 	}
481*0Sstevel@tonic-gate 
482*0Sstevel@tonic-gate 	debug2("Mapping initiator GSS-API principal to local username");
483*0Sstevel@tonic-gate #ifdef HAVE_GSSCRED_API
484*0Sstevel@tonic-gate 	{
485*0Sstevel@tonic-gate 		/* Mechanism-generic, Solaris-specific */
486*0Sstevel@tonic-gate 		OM_uint32	 maj;
487*0Sstevel@tonic-gate 		uid_t		 uid;
488*0Sstevel@tonic-gate 		struct passwd	*pw;
489*0Sstevel@tonic-gate 
490*0Sstevel@tonic-gate 		if (ctx->src_name == GSS_C_NO_NAME)
491*0Sstevel@tonic-gate 			goto failed_gsscred_localname;
492*0Sstevel@tonic-gate 
493*0Sstevel@tonic-gate 		maj = gsscred_name_to_unix_cred(ctx->src_name,
494*0Sstevel@tonic-gate 				ctx->actual_mech, &uid, NULL, NULL, NULL);
495*0Sstevel@tonic-gate 
496*0Sstevel@tonic-gate 		if (GSS_ERROR(maj))
497*0Sstevel@tonic-gate 			goto failed_gsscred_localname;
498*0Sstevel@tonic-gate 
499*0Sstevel@tonic-gate 		if ((pw = getpwuid(uid)) == NULL)
500*0Sstevel@tonic-gate 			goto failed_gsscred_localname;
501*0Sstevel@tonic-gate 
502*0Sstevel@tonic-gate 		debug2("Mapped the initiator to: %s", pw->pw_name);
503*0Sstevel@tonic-gate 		return (xstrdup(pw->pw_name));
504*0Sstevel@tonic-gate 	}
505*0Sstevel@tonic-gate failed_gsscred_localname:
506*0Sstevel@tonic-gate #endif /* HAVE_GSSCRED_API */
507*0Sstevel@tonic-gate #ifdef KRB5_GSS
508*0Sstevel@tonic-gate #error "ssh_gssapi_krb5_localname() not implemented"
509*0Sstevel@tonic-gate 	if (ssh_gssapi_is_krb5(ctx->mech))
510*0Sstevel@tonic-gate 		return (ssh_gssapi_krb5_localname(ctx->src_name));
511*0Sstevel@tonic-gate #endif /* KRB5_GSS */
512*0Sstevel@tonic-gate #ifdef GSI_GSS
513*0Sstevel@tonic-gate #error "ssh_gssapi_gsi_localname() not implemented"
514*0Sstevel@tonic-gate 	if (ssh_gssapi_is_gsi(ctx->mech))
515*0Sstevel@tonic-gate 		return (ssh_gssapi_gsi_localname(ctx->src_name));
516*0Sstevel@tonic-gate #endif /* GSI_GSS */
517*0Sstevel@tonic-gate 	return (NULL);
518*0Sstevel@tonic-gate }
519*0Sstevel@tonic-gate #endif /*GSSAPI */
520