]> andersk Git - gssapi-openssh.git/blame - openssh/gss-serv.c
check for existence of globus_gss_assist_map_and_authorize()
[gssapi-openssh.git] / openssh / gss-serv.c
CommitLineData
08822d99 1/* $OpenBSD: gss-serv.c,v 1.13 2005/10/13 22:24:31 stevesk Exp $ */
7cac2b65 2
5598e598 3/*
23987cb8 4 * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
5598e598 5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include "includes.h"
28
29#ifdef GSSAPI
30
5598e598 31#include "bufaux.h"
5598e598 32#include "auth.h"
33#include "log.h"
e5affddc 34#include "channels.h"
5598e598 35#include "session.h"
5598e598 36#include "servconf.h"
7cac2b65 37#include "xmalloc.h"
38#include "getput.h"
f4075211 39#include "monitor_wrap.h"
5598e598 40
41#include "ssh-gss.h"
42
bd3336ab 43extern ServerOptions options;
44
23987cb8 45static ssh_gssapi_client gssapi_client =
7cac2b65 46 { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER,
47 GSS_C_NO_CREDENTIAL, NULL, {NULL, NULL, NULL}};
5598e598 48
7cac2b65 49ssh_gssapi_mech gssapi_null_mech =
50 { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL};
44a053a3 51
5598e598 52#ifdef KRB5
23987cb8 53extern ssh_gssapi_mech gssapi_kerberos_mech;
54425c7a 54#endif
5598e598 55#ifdef GSI
23987cb8 56extern ssh_gssapi_mech gssapi_gsi_mech;
b311f64e 57#endif
58
23987cb8 59ssh_gssapi_mech* supported_mechs[]= {
5598e598 60#ifdef KRB5
7cac2b65 61 &gssapi_kerberos_mech,
5598e598 62#endif
63#ifdef GSI
7cac2b65 64 &gssapi_gsi_mech,
7b5a625b 65#endif
7cac2b65 66 &gssapi_null_mech,
23987cb8 67};
5598e598 68
b4cfa386 69#ifdef GSS_C_GLOBUS_LIMITED_PROXY_FLAG
70static int limited = 0;
71#endif
72
c06c9ae8 73/* Unprivileged */
fe4ad273 74char *
75ssh_gssapi_server_mechanisms() {
76 gss_OID_set supported;
77
78 ssh_gssapi_supported_oids(&supported);
79 return (ssh_gssapi_kex_mechs(supported, &ssh_gssapi_server_check_mech,
80 NULL));
81}
82
c06c9ae8 83/* Unprivileged */
fe4ad273 84int
85ssh_gssapi_server_check_mech(gss_OID oid, void *data) {
c06c9ae8 86 Gssctxt * ctx = NULL;
fe4ad273 87 int res;
c06c9ae8 88
fe4ad273 89 res = !GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctx, oid)));
90 ssh_gssapi_delete_ctx(&ctx);
91
92 return (res);
93}
94
c06c9ae8 95/* Unprivileged */
7cac2b65 96void
97ssh_gssapi_supported_oids(gss_OID_set *oidset)
98{
99 int i = 0;
100 OM_uint32 min_status;
101 int present;
102 gss_OID_set supported;
103
104 gss_create_empty_oid_set(&min_status, oidset);
186e1568 105 /* Ask priviledged process what mechanisms it supports. */
106 PRIVSEP(gss_indicate_mechs(&min_status, &supported));
7cac2b65 107
108 while (supported_mechs[i]->name != NULL) {
109 if (GSS_ERROR(gss_test_oid_set_member(&min_status,
110 &supported_mechs[i]->oid, supported, &present)))
111 present = 0;
112 if (present)
113 gss_add_oid_set_member(&min_status,
114 &supported_mechs[i]->oid, oidset);
115 i++;
116 }
117}
118
119
120/* Wrapper around accept_sec_context
121 * Requires that the context contains:
122 * oid
123 * credentials (from ssh_gssapi_acquire_cred)
124 */
08822d99 125/* Privileged */
7cac2b65 126OM_uint32
127ssh_gssapi_accept_ctx(Gssctxt *ctx, gss_buffer_desc *recv_tok,
128 gss_buffer_desc *send_tok, OM_uint32 *flags)
129{
130 OM_uint32 status;
131 gss_OID mech;
132
133 ctx->major = gss_accept_sec_context(&ctx->minor,
134 &ctx->context, ctx->creds, recv_tok,
135 GSS_C_NO_CHANNEL_BINDINGS, &ctx->client, &mech,
136 send_tok, flags, NULL, &ctx->client_creds);
137
138 if (GSS_ERROR(ctx->major))
139 ssh_gssapi_error(ctx);
140
141 if (ctx->client_creds)
142 debug("Received some client credentials");
143 else
144 debug("Got no client credentials");
145
146 status = ctx->major;
147
148 /* Now, if we're complete and we have the right flags, then
149 * we flag the user as also having been authenticated
150 */
151
152 if (((flags == NULL) || ((*flags & GSS_C_MUTUAL_FLAG) &&
153 (*flags & GSS_C_INTEG_FLAG))) && (ctx->major == GSS_S_COMPLETE)) {
154 if (ssh_gssapi_getclient(ctx, &gssapi_client))
155 fatal("Couldn't convert client name");
b4cfa386 156#ifdef GSS_C_GLOBUS_LIMITED_PROXY_FLAG
157 if (flags && (*flags & GSS_C_GLOBUS_LIMITED_PROXY_FLAG))
158 limited=1;
159#endif
7cac2b65 160 }
161
162 return (status);
163}
164
165/*
166 * This parses an exported name, extracting the mechanism specific portion
167 * to use for ACL checking. It verifies that the name belongs the mechanism
168 * originally selected.
169 */
170static OM_uint32
171ssh_gssapi_parse_ename(Gssctxt *ctx, gss_buffer_t ename, gss_buffer_t name)
172{
2ce0bfe4 173 u_char *tok;
7cac2b65 174 OM_uint32 offset;
175 OM_uint32 oidl;
176
08822d99 177 tok = ename->value;
7cac2b65 178
179#ifdef GSI /* GSI gss_export_name() is broken. */
180 if ((ctx->oid->length == gssapi_gsi_mech.oid.length) &&
181 (memcmp(ctx->oid->elements, gssapi_gsi_mech.oid.elements,
182 gssapi_gsi_mech.oid.length) == 0)) {
183 name->length = ename->length;
184 name->value = xmalloc(ename->length+1);
185 memcpy(name->value, ename->value, ename->length);
186 return GSS_S_COMPLETE;
187 }
188#endif
189
190 /*
191 * Check that ename is long enough for all of the fixed length
192 * header, and that the initial ID bytes are correct
193 */
194
08822d99 195 if (ename->length < 6 || memcmp(tok, "\x04\x01", 2) != 0)
7cac2b65 196 return GSS_S_FAILURE;
197
198 /*
199 * Extract the OID, and check it. Here GSSAPI breaks with tradition
200 * and does use the OID type and length bytes. To confuse things
201 * there are two lengths - the first including these, and the
202 * second without.
203 */
204
205 oidl = GET_16BIT(tok+2); /* length including next two bytes */
206 oidl = oidl-2; /* turn it into the _real_ length of the variable OID */
207
208 /*
209 * Check the BER encoding for correct type and length, that the
210 * string is long enough and that the OID matches that in our context
211 */
212 if (tok[4] != 0x06 || tok[5] != oidl ||
213 ename->length < oidl+6 ||
08822d99 214 !ssh_gssapi_check_oid(ctx, tok+6, oidl))
7cac2b65 215 return GSS_S_FAILURE;
216
217 offset = oidl+6;
218
219 if (ename->length < offset+4)
220 return GSS_S_FAILURE;
221
222 name->length = GET_32BIT(tok+offset);
223 offset += 4;
224
225 if (ename->length < offset+name->length)
226 return GSS_S_FAILURE;
227
228 name->value = xmalloc(name->length+1);
08822d99 229 memcpy(name->value, tok+offset,name->length);
7cac2b65 230 ((char *)name->value)[name->length] = 0;
231
232 return GSS_S_COMPLETE;
233}
234
235/* Extract the client details from a given context. This can only reliably
236 * be called once for a context */
237
08822d99 238/* Privileged (called from accept_secure_ctx) */
7cac2b65 239OM_uint32
240ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client)
241{
242 int i = 0;
243
244 gss_buffer_desc ename;
245
246 client->mech = NULL;
247
248 while (supported_mechs[i]->name != NULL) {
249 if (supported_mechs[i]->oid.length == ctx->oid->length &&
250 (memcmp(supported_mechs[i]->oid.elements,
251 ctx->oid->elements, ctx->oid->length) == 0))
252 client->mech = supported_mechs[i];
253 i++;
254 }
255
256 if (client->mech == NULL)
257 return GSS_S_FAILURE;
258
259 if ((ctx->major = gss_display_name(&ctx->minor, ctx->client,
260 &client->displayname, NULL))) {
261 ssh_gssapi_error(ctx);
262 return (ctx->major);
263 }
264
265 if ((ctx->major = gss_export_name(&ctx->minor, ctx->client,
266 &ename))) {
267 ssh_gssapi_error(ctx);
268 return (ctx->major);
269 }
270
271 if ((ctx->major = ssh_gssapi_parse_ename(ctx,&ename,
272 &client->exportedname))) {
273 return (ctx->major);
274 }
275
276 /* We can't copy this structure, so we just move the pointer to it */
277 client->creds = ctx->client_creds;
278 ctx->client_creds = GSS_C_NO_CREDENTIAL;
279 return (ctx->major);
280}
281
540d72c3 282/* As user - called on fatal/exit */
7cac2b65 283void
540d72c3 284ssh_gssapi_cleanup_creds(void)
7cac2b65 285{
286 if (gssapi_client.store.filename != NULL) {
287 /* Unlink probably isn't sufficient */
288 debug("removing gssapi cred file\"%s\"", gssapi_client.store.filename);
289 unlink(gssapi_client.store.filename);
290 }
291}
292
293/* As user */
294void
295ssh_gssapi_storecreds(void)
296{
297 if (gssapi_client.mech && gssapi_client.mech->storecreds) {
298 (*gssapi_client.mech->storecreds)(&gssapi_client);
7cac2b65 299 } else
300 debug("ssh_gssapi_storecreds: Not a GSSAPI mechanism");
301}
302
303/* This allows GSSAPI methods to do things to the childs environment based
304 * on the passed authentication process and credentials.
305 */
306/* As user */
307void
308ssh_gssapi_do_child(char ***envp, u_int *envsizep)
309{
310
311 if (gssapi_client.store.envvar != NULL &&
312 gssapi_client.store.envval != NULL) {
7cac2b65 313 debug("Setting %s to %s", gssapi_client.store.envvar,
08822d99 314 gssapi_client.store.envval);
7cac2b65 315 child_set_env(envp, envsizep, gssapi_client.store.envvar,
2ce0bfe4 316 gssapi_client.store.envval);
7cac2b65 317 }
318}
319
08822d99 320/* Privileged */
7cac2b65 321int
322ssh_gssapi_userok(char *user)
323{
2ce0bfe4 324 OM_uint32 lmin;
325
7cac2b65 326 if (gssapi_client.exportedname.length == 0 ||
327 gssapi_client.exportedname.value == NULL) {
328 debug("No suitable client data");
329 return 0;
330 }
b4cfa386 331#ifdef GSS_C_GLOBUS_LIMITED_PROXY_FLAG
826a9049 332 if (limited && options.gsi_allow_limited_proxy != 1) {
b4cfa386 333 debug("limited proxy not acceptable for remote login");
334 return 0;
335 }
336#endif
7cac2b65 337 if (gssapi_client.mech && gssapi_client.mech->userok)
2ce0bfe4 338 if ((*gssapi_client.mech->userok)(&gssapi_client, user))
339 return 1;
340 else {
341 /* Destroy delegated credentials if userok fails */
342 gss_release_buffer(&lmin, &gssapi_client.displayname);
343 gss_release_buffer(&lmin, &gssapi_client.exportedname);
344 gss_release_cred(&lmin, &gssapi_client.creds);
345 memset(&gssapi_client, 0, sizeof(ssh_gssapi_client));
346 return 0;
347 }
7cac2b65 348 else
349 debug("ssh_gssapi_userok: Unknown GSSAPI mechanism");
350 return (0);
351}
352
e23e524c 353/* Priviledged */
23987cb8 354int
355ssh_gssapi_localname(char **user)
356{
357 *user = NULL;
7cac2b65 358 if (gssapi_client.displayname.length==0 ||
359 gssapi_client.displayname.value==NULL) {
23987cb8 360 debug("No suitable client data");
361 return(0);;
362 }
363 if (gssapi_client.mech && gssapi_client.mech->localname) {
364 return((*gssapi_client.mech->localname)(&gssapi_client,user));
365 } else {
366 debug("Unknown client authentication type");
367 }
368 return(0);
369}
540d72c3 370
23987cb8 371#endif
This page took 0.119709 seconds and 5 git commands to generate.