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
ssh_gssapi_client_kex_hook(Kex * kex,char ** proposal)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
ssh_gssapi_client_mechs(const char * server_host,gss_OID_set * mechs)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
ssh_gssapi_init_ctx(Gssctxt * ctx,const char * server_host,int deleg_creds,gss_buffer_t recv_tok,gss_buffer_t send_tok)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