]> andersk Git - openssh.git/blob - gss-serv.c
- djm@cvs.openbsd.org 2006/03/25 22:22:43
[openssh.git] / gss-serv.c
1 /* $OpenBSD: gss-serv.c,v 1.16 2006/03/25 22:22:43 djm Exp $ */
2
3 /*
4  * Copyright (c) 2001-2003 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 "bufaux.h"
32 #include "auth.h"
33 #include "log.h"
34 #include "channels.h"
35 #include "session.h"
36 #include "servconf.h"
37 #include "xmalloc.h"
38 #include "getput.h"
39
40 #include "ssh-gss.h"
41
42 static ssh_gssapi_client gssapi_client =
43     { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER,
44     GSS_C_NO_CREDENTIAL, NULL, {NULL, NULL, NULL}};
45
46 ssh_gssapi_mech gssapi_null_mech =
47     { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL};
48
49 #ifdef KRB5
50 extern ssh_gssapi_mech gssapi_kerberos_mech;
51 #endif
52
53 ssh_gssapi_mech* supported_mechs[]= {
54 #ifdef KRB5
55         &gssapi_kerberos_mech,
56 #endif
57         &gssapi_null_mech,
58 };
59
60 /* Unprivileged */
61 void
62 ssh_gssapi_supported_oids(gss_OID_set *oidset)
63 {
64         int i = 0;
65         OM_uint32 min_status;
66         int present;
67         gss_OID_set supported;
68
69         gss_create_empty_oid_set(&min_status, oidset);
70         gss_indicate_mechs(&min_status, &supported);
71
72         while (supported_mechs[i]->name != NULL) {
73                 if (GSS_ERROR(gss_test_oid_set_member(&min_status,
74                     &supported_mechs[i]->oid, supported, &present)))
75                         present = 0;
76                 if (present)
77                         gss_add_oid_set_member(&min_status,
78                             &supported_mechs[i]->oid, oidset);
79                 i++;
80         }
81
82         gss_release_oid_set(&min_status, &supported);
83 }
84
85
86 /* Wrapper around accept_sec_context
87  * Requires that the context contains:
88  *    oid
89  *    credentials       (from ssh_gssapi_acquire_cred)
90  */
91 /* Privileged */
92 OM_uint32
93 ssh_gssapi_accept_ctx(Gssctxt *ctx, gss_buffer_desc *recv_tok,
94     gss_buffer_desc *send_tok, OM_uint32 *flags)
95 {
96         OM_uint32 status;
97         gss_OID mech;
98
99         ctx->major = gss_accept_sec_context(&ctx->minor,
100             &ctx->context, ctx->creds, recv_tok,
101             GSS_C_NO_CHANNEL_BINDINGS, &ctx->client, &mech,
102             send_tok, flags, NULL, &ctx->client_creds);
103
104         if (GSS_ERROR(ctx->major))
105                 ssh_gssapi_error(ctx);
106
107         if (ctx->client_creds)
108                 debug("Received some client credentials");
109         else
110                 debug("Got no client credentials");
111
112         status = ctx->major;
113
114         /* Now, if we're complete and we have the right flags, then
115          * we flag the user as also having been authenticated
116          */
117
118         if (((flags == NULL) || ((*flags & GSS_C_MUTUAL_FLAG) &&
119             (*flags & GSS_C_INTEG_FLAG))) && (ctx->major == GSS_S_COMPLETE)) {
120                 if (ssh_gssapi_getclient(ctx, &gssapi_client))
121                         fatal("Couldn't convert client name");
122         }
123
124         return (status);
125 }
126
127 /*
128  * This parses an exported name, extracting the mechanism specific portion
129  * to use for ACL checking. It verifies that the name belongs the mechanism
130  * originally selected.
131  */
132 static OM_uint32
133 ssh_gssapi_parse_ename(Gssctxt *ctx, gss_buffer_t ename, gss_buffer_t name)
134 {
135         u_char *tok;
136         OM_uint32 offset;
137         OM_uint32 oidl;
138
139         tok = ename->value;
140
141         /*
142          * Check that ename is long enough for all of the fixed length
143          * header, and that the initial ID bytes are correct
144          */
145
146         if (ename->length < 6 || memcmp(tok, "\x04\x01", 2) != 0)
147                 return GSS_S_FAILURE;
148
149         /*
150          * Extract the OID, and check it. Here GSSAPI breaks with tradition
151          * and does use the OID type and length bytes. To confuse things
152          * there are two lengths - the first including these, and the
153          * second without.
154          */
155
156         oidl = GET_16BIT(tok+2); /* length including next two bytes */
157         oidl = oidl-2; /* turn it into the _real_ length of the variable OID */
158
159         /*
160          * Check the BER encoding for correct type and length, that the
161          * string is long enough and that the OID matches that in our context
162          */
163         if (tok[4] != 0x06 || tok[5] != oidl ||
164             ename->length < oidl+6 ||
165             !ssh_gssapi_check_oid(ctx, tok+6, oidl))
166                 return GSS_S_FAILURE;
167
168         offset = oidl+6;
169
170         if (ename->length < offset+4)
171                 return GSS_S_FAILURE;
172
173         name->length = GET_32BIT(tok+offset);
174         offset += 4;
175
176         if (ename->length < offset+name->length)
177                 return GSS_S_FAILURE;
178
179         name->value = xmalloc(name->length+1);
180         memcpy(name->value, tok+offset, name->length);
181         ((char *)name->value)[name->length] = 0;
182
183         return GSS_S_COMPLETE;
184 }
185
186 /* Extract the client details from a given context. This can only reliably
187  * be called once for a context */
188
189 /* Privileged (called from accept_secure_ctx) */
190 OM_uint32
191 ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client)
192 {
193         int i = 0;
194
195         gss_buffer_desc ename;
196
197         client->mech = NULL;
198
199         while (supported_mechs[i]->name != NULL) {
200                 if (supported_mechs[i]->oid.length == ctx->oid->length &&
201                     (memcmp(supported_mechs[i]->oid.elements,
202                     ctx->oid->elements, ctx->oid->length) == 0))
203                         client->mech = supported_mechs[i];
204                 i++;
205         }
206
207         if (client->mech == NULL)
208                 return GSS_S_FAILURE;
209
210         if ((ctx->major = gss_display_name(&ctx->minor, ctx->client,
211             &client->displayname, NULL))) {
212                 ssh_gssapi_error(ctx);
213                 return (ctx->major);
214         }
215
216         if ((ctx->major = gss_export_name(&ctx->minor, ctx->client,
217             &ename))) {
218                 ssh_gssapi_error(ctx);
219                 return (ctx->major);
220         }
221
222         if ((ctx->major = ssh_gssapi_parse_ename(ctx,&ename,
223             &client->exportedname))) {
224                 return (ctx->major);
225         }
226
227         /* We can't copy this structure, so we just move the pointer to it */
228         client->creds = ctx->client_creds;
229         ctx->client_creds = GSS_C_NO_CREDENTIAL;
230         return (ctx->major);
231 }
232
233 /* As user - called on fatal/exit */
234 void
235 ssh_gssapi_cleanup_creds(void)
236 {
237         if (gssapi_client.store.filename != NULL) {
238                 /* Unlink probably isn't sufficient */
239                 debug("removing gssapi cred file\"%s\"",
240                     gssapi_client.store.filename);
241                 unlink(gssapi_client.store.filename);
242         }
243 }
244
245 /* As user */
246 void
247 ssh_gssapi_storecreds(void)
248 {
249         if (gssapi_client.mech && gssapi_client.mech->storecreds) {
250                 (*gssapi_client.mech->storecreds)(&gssapi_client);
251         } else
252                 debug("ssh_gssapi_storecreds: Not a GSSAPI mechanism");
253 }
254
255 /* This allows GSSAPI methods to do things to the childs environment based
256  * on the passed authentication process and credentials.
257  */
258 /* As user */
259 void
260 ssh_gssapi_do_child(char ***envp, u_int *envsizep)
261 {
262
263         if (gssapi_client.store.envvar != NULL &&
264             gssapi_client.store.envval != NULL) {
265                 debug("Setting %s to %s", gssapi_client.store.envvar,
266                     gssapi_client.store.envval);
267                 child_set_env(envp, envsizep, gssapi_client.store.envvar,
268                     gssapi_client.store.envval);
269         }
270 }
271
272 /* Privileged */
273 int
274 ssh_gssapi_userok(char *user)
275 {
276         OM_uint32 lmin;
277
278         if (gssapi_client.exportedname.length == 0 ||
279             gssapi_client.exportedname.value == NULL) {
280                 debug("No suitable client data");
281                 return 0;
282         }
283         if (gssapi_client.mech && gssapi_client.mech->userok)
284                 if ((*gssapi_client.mech->userok)(&gssapi_client, user))
285                         return 1;
286                 else {
287                         /* Destroy delegated credentials if userok fails */
288                         gss_release_buffer(&lmin, &gssapi_client.displayname);
289                         gss_release_buffer(&lmin, &gssapi_client.exportedname);
290                         gss_release_cred(&lmin, &gssapi_client.creds);
291                         memset(&gssapi_client, 0, sizeof(ssh_gssapi_client));
292                         return 0;
293                 }
294         else
295                 debug("ssh_gssapi_userok: Unknown GSSAPI mechanism");
296         return (0);
297 }
298
299 /* Privileged */
300 OM_uint32
301 ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic)
302 {
303         ctx->major = gss_verify_mic(&ctx->minor, ctx->context,
304             gssbuf, gssmic, NULL);
305
306         return (ctx->major);
307 }
308
309 #endif
This page took 0.732487 seconds and 5 git commands to generate.