]> andersk Git - gssapi-openssh.git/blob - openssh/gss-serv.c
merge updates from OPENSSH_4_4P1_SIMON_20061002_HPN to trunk
[gssapi-openssh.git] / openssh / gss-serv.c
1 /* $OpenBSD: gss-serv.c,v 1.20 2006/08/03 03:34:42 deraadt Exp $ */
2
3 /*
4  * Copyright (c) 2001-2006 Simon Wilkinson. All rights reserved.
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
31 #include <sys/types.h>
32
33 #include <stdarg.h>
34 #include <string.h>
35 #include <unistd.h>
36
37 #include "xmalloc.h"
38 #include "buffer.h"
39 #include "key.h"
40 #include "hostfile.h"
41 #include "auth.h"
42 #include "log.h"
43 #include "channels.h"
44 #include "session.h"
45 #include "misc.h"
46 #include "servconf.h"
47
48 #include "xmalloc.h"
49 #include "ssh-gss.h"
50 #include "monitor_wrap.h"
51
52 extern ServerOptions options;
53
54 static ssh_gssapi_client gssapi_client =
55     { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER,
56     GSS_C_NO_CREDENTIAL, NULL, {NULL, NULL, NULL}};
57
58 ssh_gssapi_mech gssapi_null_mech =
59     { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL};
60
61 #ifdef KRB5
62 extern ssh_gssapi_mech gssapi_kerberos_mech;
63 #endif
64 #ifdef GSI
65 extern ssh_gssapi_mech gssapi_gsi_mech;
66 #endif
67
68 ssh_gssapi_mech* supported_mechs[]= {
69 #ifdef KRB5
70         &gssapi_kerberos_mech,
71 #endif
72 #ifdef GSI
73         &gssapi_gsi_mech,
74 #endif
75         &gssapi_null_mech,
76 };
77
78 #ifdef GSS_C_GLOBUS_LIMITED_PROXY_FLAG
79 static int limited = 0;
80 #endif
81
82 /* Unprivileged */
83 char *
84 ssh_gssapi_server_mechanisms() {
85         gss_OID_set     supported;
86
87         ssh_gssapi_supported_oids(&supported);
88         return (ssh_gssapi_kex_mechs(supported, &ssh_gssapi_server_check_mech,
89             NULL));
90 }
91
92 /* Unprivileged */
93 int
94 ssh_gssapi_server_check_mech(Gssctxt **dum, gss_OID oid, const char *data) {
95         Gssctxt *ctx = NULL;
96         int res;
97  
98         res = !GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctx, oid)));
99         ssh_gssapi_delete_ctx(&ctx);
100
101         return (res);
102 }
103
104 /* Unprivileged */
105 void
106 ssh_gssapi_supported_oids(gss_OID_set *oidset)
107 {
108         int i = 0;
109         OM_uint32 min_status;
110         int present;
111         gss_OID_set supported;
112
113         gss_create_empty_oid_set(&min_status, oidset);
114         /* Ask priviledged process what mechanisms it supports. */
115         PRIVSEP(gss_indicate_mechs(&min_status, &supported));
116
117         while (supported_mechs[i]->name != NULL) {
118                 if (GSS_ERROR(gss_test_oid_set_member(&min_status,
119                     &supported_mechs[i]->oid, supported, &present)))
120                         present = 0;
121                 if (present)
122                         gss_add_oid_set_member(&min_status,
123                             &supported_mechs[i]->oid, oidset);
124                 i++;
125         }
126
127         gss_release_oid_set(&min_status, &supported);
128 }
129
130 OM_uint32
131 ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID oid)
132 {
133         if (*ctx)
134                 ssh_gssapi_delete_ctx(ctx);
135         ssh_gssapi_build_ctx(ctx);
136         ssh_gssapi_set_oid(*ctx, oid);
137         return (ssh_gssapi_acquire_cred(*ctx));
138 }
139
140 /* Acquire credentials for a server running on the current host.
141  * Requires that the context structure contains a valid OID
142  */
143
144 /* Returns a GSSAPI error code */
145 OM_uint32
146 ssh_gssapi_acquire_cred(Gssctxt *ctx)
147 {
148         OM_uint32 status;
149         char lname[MAXHOSTNAMELEN];
150         gss_OID_set oidset;
151
152         if (options.gss_strict_acceptor) {
153                 gss_create_empty_oid_set(&status, &oidset);
154                 gss_add_oid_set_member(&status, ctx->oid, &oidset);
155
156                 if (gethostname(lname, MAXHOSTNAMELEN)) {
157                         gss_release_oid_set(&status, &oidset);
158                         return (-1);
159                 }
160
161                 if (GSS_ERROR(ssh_gssapi_import_name(ctx, lname))) {
162                         gss_release_oid_set(&status, &oidset);
163                         return (ctx->major);
164                 }
165
166                 if ((ctx->major = gss_acquire_cred(&ctx->minor,
167                     ctx->name, 0, oidset, GSS_C_ACCEPT, &ctx->creds, 
168                     NULL, NULL)))
169                         ssh_gssapi_error(ctx);
170
171                 gss_release_oid_set(&status, &oidset);
172                 return (ctx->major);
173         } else {
174                 ctx->name = GSS_C_NO_NAME;
175                 ctx->creds = GSS_C_NO_CREDENTIAL;
176         }
177         return GSS_S_COMPLETE;
178 }
179
180
181 /* Wrapper around accept_sec_context
182  * Requires that the context contains:
183  *    oid
184  *    credentials       (from ssh_gssapi_acquire_cred)
185  */
186 /* Privileged */
187 OM_uint32
188 ssh_gssapi_accept_ctx(Gssctxt *ctx, gss_buffer_desc *recv_tok,
189     gss_buffer_desc *send_tok, OM_uint32 *flags)
190 {
191         OM_uint32 status;
192         gss_OID mech;
193
194         ctx->major = gss_accept_sec_context(&ctx->minor,
195             &ctx->context, ctx->creds, recv_tok,
196             GSS_C_NO_CHANNEL_BINDINGS, &ctx->client, &mech,
197             send_tok, flags, NULL, &ctx->client_creds);
198
199         if (GSS_ERROR(ctx->major))
200                 ssh_gssapi_error(ctx);
201
202         if (ctx->client_creds)
203                 debug("Received some client credentials");
204         else
205                 debug("Got no client credentials");
206
207         status = ctx->major;
208
209         /* Now, if we're complete and we have the right flags, then
210          * we flag the user as also having been authenticated
211          */
212
213         if (((flags == NULL) || ((*flags & GSS_C_MUTUAL_FLAG) &&
214             (*flags & GSS_C_INTEG_FLAG))) && (ctx->major == GSS_S_COMPLETE)) {
215                 if (ssh_gssapi_getclient(ctx, &gssapi_client))
216                         fatal("Couldn't convert client name");
217 #ifdef GSS_C_GLOBUS_LIMITED_PROXY_FLAG
218                 if (flags && (*flags & GSS_C_GLOBUS_LIMITED_PROXY_FLAG))
219                         limited=1;
220 #endif
221         }
222
223         return (status);
224 }
225
226 /*
227  * This parses an exported name, extracting the mechanism specific portion
228  * to use for ACL checking. It verifies that the name belongs the mechanism
229  * originally selected.
230  */
231 static OM_uint32
232 ssh_gssapi_parse_ename(Gssctxt *ctx, gss_buffer_t ename, gss_buffer_t name)
233 {
234         u_char *tok;
235         OM_uint32 offset;
236         OM_uint32 oidl;
237
238         tok = ename->value;
239
240 #ifdef GSI /* GSI gss_export_name() is broken. */
241         if ((ctx->oid->length == gssapi_gsi_mech.oid.length) &&
242             (memcmp(ctx->oid->elements, gssapi_gsi_mech.oid.elements,
243                     gssapi_gsi_mech.oid.length) == 0)) {
244             name->length = ename->length;
245             name->value = xmalloc(ename->length+1);
246             memcpy(name->value, ename->value, ename->length);
247             return GSS_S_COMPLETE;
248         }
249 #endif
250
251         /*
252          * Check that ename is long enough for all of the fixed length
253          * header, and that the initial ID bytes are correct
254          */
255
256         if (ename->length < 6 || memcmp(tok, "\x04\x01", 2) != 0)
257                 return GSS_S_FAILURE;
258
259         /*
260          * Extract the OID, and check it. Here GSSAPI breaks with tradition
261          * and does use the OID type and length bytes. To confuse things
262          * there are two lengths - the first including these, and the
263          * second without.
264          */
265
266         oidl = get_u16(tok+2); /* length including next two bytes */
267         oidl = oidl-2; /* turn it into the _real_ length of the variable OID */
268
269         /*
270          * Check the BER encoding for correct type and length, that the
271          * string is long enough and that the OID matches that in our context
272          */
273         if (tok[4] != 0x06 || tok[5] != oidl ||
274             ename->length < oidl+6 ||
275             !ssh_gssapi_check_oid(ctx, tok+6, oidl))
276                 return GSS_S_FAILURE;
277
278         offset = oidl+6;
279
280         if (ename->length < offset+4)
281                 return GSS_S_FAILURE;
282
283         name->length = get_u32(tok+offset);
284         offset += 4;
285
286         if (ename->length < offset+name->length)
287                 return GSS_S_FAILURE;
288
289         name->value = xmalloc(name->length+1);
290         memcpy(name->value, tok+offset, name->length);
291         ((char *)name->value)[name->length] = 0;
292
293         return GSS_S_COMPLETE;
294 }
295
296 /* Extract the client details from a given context. This can only reliably
297  * be called once for a context */
298
299 /* Privileged (called from accept_secure_ctx) */
300 OM_uint32
301 ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client)
302 {
303         int i = 0;
304
305         gss_buffer_desc ename;
306
307         client->mech = NULL;
308
309         while (supported_mechs[i]->name != NULL) {
310                 if (supported_mechs[i]->oid.length == ctx->oid->length &&
311                     (memcmp(supported_mechs[i]->oid.elements,
312                     ctx->oid->elements, ctx->oid->length) == 0))
313                         client->mech = supported_mechs[i];
314                 i++;
315         }
316
317         if (client->mech == NULL)
318                 return GSS_S_FAILURE;
319
320         if ((ctx->major = gss_display_name(&ctx->minor, ctx->client,
321             &client->displayname, NULL))) {
322                 ssh_gssapi_error(ctx);
323                 return (ctx->major);
324         }
325
326         if ((ctx->major = gss_export_name(&ctx->minor, ctx->client,
327             &ename))) {
328                 ssh_gssapi_error(ctx);
329                 return (ctx->major);
330         }
331
332         if ((ctx->major = ssh_gssapi_parse_ename(ctx,&ename,
333             &client->exportedname))) {
334                 return (ctx->major);
335         }
336
337         /* We can't copy this structure, so we just move the pointer to it */
338         client->creds = ctx->client_creds;
339         ctx->client_creds = GSS_C_NO_CREDENTIAL;
340
341     /* needed for globus_gss_assist_map_and_authorize() */
342     client->context = ctx->context;
343
344         return (ctx->major);
345 }
346
347 /* As user - called on fatal/exit */
348 void
349 ssh_gssapi_cleanup_creds(void)
350 {
351         if (gssapi_client.store.filename != NULL) {
352                 /* Unlink probably isn't sufficient */
353                 debug("removing gssapi cred file\"%s\"",
354                     gssapi_client.store.filename);
355                 unlink(gssapi_client.store.filename);
356         }
357 }
358
359 /* As user */
360 void
361 ssh_gssapi_storecreds(void)
362 {
363         if (gssapi_client.mech && gssapi_client.mech->storecreds) {
364                 (*gssapi_client.mech->storecreds)(&gssapi_client);
365         } else
366                 debug("ssh_gssapi_storecreds: Not a GSSAPI mechanism");
367 }
368
369 /* This allows GSSAPI methods to do things to the childs environment based
370  * on the passed authentication process and credentials.
371  */
372 /* As user */
373 void
374 ssh_gssapi_do_child(char ***envp, u_int *envsizep)
375 {
376
377         if (gssapi_client.store.envvar != NULL &&
378             gssapi_client.store.envval != NULL) {
379                 debug("Setting %s to %s", gssapi_client.store.envvar,
380                     gssapi_client.store.envval);
381                 child_set_env(envp, envsizep, gssapi_client.store.envvar,
382                     gssapi_client.store.envval);
383         }
384 }
385
386 /* Privileged */
387 int
388 ssh_gssapi_userok(char *user)
389 {
390         OM_uint32 lmin;
391
392         if (gssapi_client.exportedname.length == 0 ||
393             gssapi_client.exportedname.value == NULL) {
394                 debug("No suitable client data");
395                 return 0;
396         }
397 #ifdef GSS_C_GLOBUS_LIMITED_PROXY_FLAG
398         if (limited && options.gsi_allow_limited_proxy != 1) {
399                 debug("limited proxy not acceptable for remote login");
400                 return 0;
401         }
402 #endif
403         if (gssapi_client.mech && gssapi_client.mech->userok)
404                 if ((*gssapi_client.mech->userok)(&gssapi_client, user))
405                         return 1;
406                 else {
407                         /* Destroy delegated credentials if userok fails */
408                         gss_release_buffer(&lmin, &gssapi_client.displayname);
409                         gss_release_buffer(&lmin, &gssapi_client.exportedname);
410                         gss_release_cred(&lmin, &gssapi_client.creds);
411                         memset(&gssapi_client, 0, sizeof(ssh_gssapi_client));
412                         return 0;
413                 }
414         else
415                 debug("ssh_gssapi_userok: Unknown GSSAPI mechanism");
416         return (0);
417 }
418
419 /* Priviledged */
420 int
421 ssh_gssapi_localname(char **user)
422 {
423         *user = NULL;
424         if (gssapi_client.displayname.length==0 || 
425             gssapi_client.displayname.value==NULL) {
426                 debug("No suitable client data");
427                 return(0);;
428         }
429         if (gssapi_client.mech && gssapi_client.mech->localname) {
430                 return((*gssapi_client.mech->localname)(&gssapi_client,user));
431         } else {
432                 debug("Unknown client authentication type");
433         }
434         return(0);
435 }
436
437 #endif
This page took 0.22753 seconds and 5 git commands to generate.