2 * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 #include <openssl/evp.h>
46 #include "monitor_wrap.h"
50 extern ServerOptions options;
51 extern u_char *session_id2;
52 extern int session_id2_len;
54 static ssh_gssapi_client gssapi_client =
55 { {0,NULL}, GSS_C_NO_CREDENTIAL, NULL, {NULL,NULL,NULL}};
57 ssh_gssapi_mech gssapi_null_mech
58 = {NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL};
61 extern ssh_gssapi_mech gssapi_kerberos_mech;
62 extern ssh_gssapi_mech gssapi_kerberos_mech_old;
65 extern ssh_gssapi_mech gssapi_gsi_mech;
66 extern ssh_gssapi_mech gssapi_gsi_mech_old;
69 ssh_gssapi_mech* supported_mechs[]= {
71 &gssapi_kerberos_mech,
72 &gssapi_kerberos_mech_old, /* Support for legacy clients */
76 &gssapi_gsi_mech_old, /* Support for legacy clients */
81 /* Return a list of the gss-group1-sha1-x mechanisms supported by this
84 * We only support the mechanisms that we've indicated in the list above,
85 * but we check that they're supported by the GSSAPI mechanism on the
86 * machine. We also check, before including them in the list, that
87 * we have the necesary information in order to carry out the key exchange
88 * (that is, that the user has credentials, the server's creds are accessible,
91 * The way that this is done is fairly nasty, as we do a lot of work that
92 * is then thrown away. This should possibly be implemented with a cache
93 * that stores the results (in an expanded Gssctxt structure), which are
94 * then used by the first calls if that key exchange mechanism is chosen.
99 ssh_gssapi_server_mechanisms() {
100 gss_OID_set supported;
102 OM_uint32 maj_status, min_status;
109 if (datafellows & SSH_OLD_GSSAPI) return NULL;
111 ssh_gssapi_supported_oids(&supported);
115 while(supported_mechs[i]->name != NULL) {
116 if ((maj_status=gss_test_oid_set_member(&min_status,
117 &supported_mechs[i]->oid,
124 if (!GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctx,
125 &supported_mechs[i]->oid)))) {
126 /* Append gss_group1_sha1_x to our list */
128 buffer_put_char(&buf,',');
129 buffer_append(&buf, KEX_GSS_SHA1,
130 sizeof(KEX_GSS_SHA1)-1);
132 supported_mechs[i]->enc_name,
133 strlen(supported_mechs[i]->enc_name));
134 debug("GSSAPI mechanism %s (%s%s) supported",
135 supported_mechs[i]->name, KEX_GSS_SHA1,
136 supported_mechs[i]->enc_name);
138 debug("no credentials for GSSAPI mechanism %s",
139 supported_mechs[i]->name);
142 debug("GSSAPI mechanism %s not supported",
143 supported_mechs[i]->name);
145 ssh_gssapi_delete_ctx(&ctx);
149 buffer_put_char(&buf,'\0');
151 mechs=xmalloc(buffer_len(&buf));
152 buffer_get(&buf,mechs,buffer_len(&buf));
154 if (strlen(mechs)==0)
161 void ssh_gssapi_supported_oids(gss_OID_set *oidset) {
163 OM_uint32 maj_status,min_status;
165 gss_OID_set supported;
167 gss_create_empty_oid_set(&min_status,oidset);
168 PRIVSEP(gss_indicate_mechs(&min_status, &supported));
170 while (supported_mechs[i]->name!=NULL) {
171 if ((maj_status=gss_test_oid_set_member(&min_status,
172 &supported_mechs[i]->oid,
178 gss_add_oid_set_member(&min_status,
179 &supported_mechs[i]->oid,
186 /* Find out which GSS type (out of the list we define in ssh-gss.h) a
187 * particular connection is using
190 /* Priviledged (called ssh_gssapi_accept_ctx -> ssh_gssapi_getclient ->) */
192 ssh_gssapi_get_ctype(Gssctxt *ctxt) {
195 while(supported_mechs[i]->name!=NULL) {
196 if (supported_mechs[i]->oid.length == ctxt->oid->length &&
197 (memcmp(supported_mechs[i]->oid.elements,
198 ctxt->oid->elements,ctxt->oid->length)==0)) {
199 return supported_mechs[i];
206 /* Return the OID that corresponds to the given context name */
210 ssh_gssapi_server_id_kex(char *name) {
213 if (strncmp(name, KEX_GSS_SHA1, sizeof(KEX_GSS_SHA1)-1) !=0) {
217 name+=sizeof(KEX_GSS_SHA1)-1; /* Move to the start of the MIME string */
219 while (supported_mechs[i]->name!=NULL &&
220 strcmp(name,supported_mechs[i]->enc_name)!=0) {
224 if (supported_mechs[i]->name==NULL)
227 debug("using GSSAPI mechanism %s (%s%s)", supported_mechs[i]->name,
228 KEX_GSS_SHA1, supported_mechs[i]->enc_name);
230 return &supported_mechs[i]->oid;
233 /* Wrapper around accept_sec_context
234 * Requires that the context contains:
236 * credentials (from ssh_gssapi_acquire_cred)
239 OM_uint32 ssh_gssapi_accept_ctx(Gssctxt *ctx,gss_buffer_desc *recv_tok,
240 gss_buffer_desc *send_tok, OM_uint32 *flags)
245 ctx->major=gss_accept_sec_context(&ctx->minor,
249 GSS_C_NO_CHANNEL_BINDINGS,
251 &mech, /* read-only pointer */
256 if (GSS_ERROR(ctx->major)) {
257 ssh_gssapi_error(ctx);
260 if (ctx->client_creds) {
261 debug("Received some client credentials");
263 debug("Got no client credentials");
266 /* FIXME: We should check that the me
267 * the one that we asked for (in ctx->oid) */
271 /* Now, if we're complete and we have the right flags, then
272 * we flag the user as also having been authenticated
275 if (((flags==NULL) || ((*flags & GSS_C_MUTUAL_FLAG) &&
276 (*flags & GSS_C_INTEG_FLAG))) &&
277 (ctx->major == GSS_S_COMPLETE)) {
278 if (ssh_gssapi_getclient(ctx,&gssapi_client.mech,
280 &gssapi_client.creds))
281 fatal("Couldn't convert client name");
284 /* Make sure that the getclient call hasn't stamped on this */
288 /* Extract the client details from a given context. This can only reliably
289 * be called once for a context */
291 /* Priviledged (called from accept_secure_ctx) */
293 ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_mech **type,
294 gss_buffer_desc *name, gss_cred_id_t *creds) {
296 *type=ssh_gssapi_get_ctype(ctx);
297 if ((ctx->major=gss_display_name(&ctx->minor,ctx->client,name,NULL))) {
298 ssh_gssapi_error(ctx);
302 /* This is icky. There appears to be no way to copy this structure,
303 * rather than the pointer to it, so we simply copy the pointer and
304 * mark the originator as empty so we don't destroy it.
306 *creds=ctx->client_creds;
307 ctx->client_creds=GSS_C_NO_CREDENTIAL;
311 /* As user - called through fatal cleanup hook */
313 ssh_gssapi_cleanup_creds(void *ignored)
315 if (gssapi_client.store.filename!=NULL) {
316 /* Unlink probably isn't sufficient */
317 debug("removing gssapi cred file\"%s\"",gssapi_client.store.filename);
318 unlink(gssapi_client.store.filename);
324 ssh_gssapi_storecreds()
326 if (gssapi_client.mech && gssapi_client.mech->storecreds) {
327 (*gssapi_client.mech->storecreds)(&gssapi_client);
328 if (options.gss_cleanup_creds) {
329 fatal_add_cleanup(ssh_gssapi_cleanup_creds, NULL);
332 debug("ssh_gssapi_storecreds: Not a GSSAPI mechanism");
336 /* This allows GSSAPI methods to do things to the childs environment based
337 * on the passed authentication process and credentials.
341 ssh_gssapi_do_child(char ***envp, u_int *envsizep)
344 if (gssapi_client.store.envvar!=NULL &&
345 gssapi_client.store.envval!=NULL) {
347 debug("Setting %s to %s", gssapi_client.store.envvar,
348 gssapi_client.store.envval);
349 child_set_env(envp, envsizep, gssapi_client.store.envvar,
350 gssapi_client.store.envval);
356 ssh_gssapi_userok(char *user)
358 if (gssapi_client.name.length==0 ||
359 gssapi_client.name.value==NULL) {
360 debug("No suitable client data");
363 if (gssapi_client.mech && gssapi_client.mech->userok) {
364 return((*gssapi_client.mech->userok)(&gssapi_client,user));
366 debug("ssh_gssapi_userok: Unknown GSSAPI mechanism");
373 ssh_gssapi_localname(char **user)
376 if (gssapi_client.name.length==0 ||
377 gssapi_client.name.value==NULL) {
378 debug("No suitable client data");
381 if (gssapi_client.mech && gssapi_client.mech->localname) {
382 return((*gssapi_client.mech->localname)(&gssapi_client,user));
384 debug("Unknown client authentication type");