xref: /titanic_41/usr/src/cmd/ssh/ssh/gss-clnt.c (revision dbc3eca239c53a46b827193bc820625a1ea8a28a)
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 2007 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,
128 				NULL, &tok);
129 		if (GSS_ERROR(maj)) {
130 			errmsg = ssh_gssapi_last_error(ctxt, NULL, NULL);
131 			debug("Skipping GSS-API mechanism %s (%s)",
132 			    ssh_gssapi_oid_to_name(mech), errmsg);
133 			xfree(errmsg);
134 			continue;
135 		}
136 
137 		(void) gss_release_buffer(&min, &tok);
138 
139 		maj = gss_add_oid_set_member(&min, mech, &supported);
140 		if (GSS_ERROR(maj)) {
141 			errmsg = ssh_gssapi_last_error(NULL, &maj, &min);
142 			debug("Failed to allocate resources (%s) for GSS-API",
143 			    errmsg);
144 			xfree(errmsg);
145 		}
146 	}
147 
148 	*mechs = supported;
149 }
150 
151 
152 /* Wrapper to init_sec_context
153  * Requires that the context contains:
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       	ctx->major=gss_init_sec_context(&ctx->minor,
177       					GSS_C_NO_CREDENTIAL,
178       					&ctx->context,
179       					ctx->desired_name,
180       					ctx->desired_mech,
181       					flags,
182       					0, /* default lifetime */
183       					NULL, /* no channel bindings */
184       					recv_tok,
185       					NULL, /* actual mech type */
186       					send_tok,
187       					&ctx->flags,
188       					NULL); /* actual lifetime */
189 
190       	if (GSS_ERROR(ctx->major))
191 		ssh_gssapi_error(ctx, "calling GSS_Init_sec_context()");
192 
193       	return(ctx->major);
194 }
195 #endif /* GSSAPI */
196