]> andersk Git - gssapi-openssh.git/blob - openssh/gss-serv.c
merge with OPENSSH_3_6_1P1_SIMON_20030417
[gssapi-openssh.git] / openssh / gss-serv.c
1 /*
2  * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
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.
12  *
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.
23  */
24
25 #include "includes.h"
26
27 #ifdef GSSAPI
28
29 #include "ssh.h"
30 #include "ssh2.h"
31 #include "xmalloc.h"
32 #include "buffer.h"
33 #include "bufaux.h"
34 #include "packet.h"
35 #include "compat.h"
36 #include <openssl/evp.h>
37 #include "cipher.h"
38 #include "kex.h"
39 #include "auth.h"
40 #include "log.h"
41 #include "channels.h"
42 #include "session.h"
43 #include "dispatch.h"
44 #include "servconf.h"
45 #include "compat.h"
46 #include "monitor_wrap.h"
47
48 #include "ssh-gss.h"
49
50 extern ServerOptions options;
51 extern u_char *session_id2;
52 extern int session_id2_len;
53
54 static ssh_gssapi_client gssapi_client =
55         { {0,NULL}, GSS_C_NO_CREDENTIAL, NULL, {NULL,NULL,NULL}};
56
57 ssh_gssapi_mech gssapi_null_mech 
58   = {NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL};
59
60 #ifdef KRB5
61 extern ssh_gssapi_mech gssapi_kerberos_mech;
62 extern ssh_gssapi_mech gssapi_kerberos_mech_old;
63 #endif
64 #ifdef GSI
65 extern ssh_gssapi_mech gssapi_gsi_mech;
66 extern ssh_gssapi_mech gssapi_gsi_mech_old;
67 #endif
68
69 ssh_gssapi_mech* supported_mechs[]= {
70 #ifdef KRB5
71   &gssapi_kerberos_mech,
72   &gssapi_kerberos_mech_old, /* Support for legacy clients */
73 #endif
74 #ifdef GSI
75   &gssapi_gsi_mech,
76   &gssapi_gsi_mech_old, /* Support for legacy clients */
77 #endif
78   &gssapi_null_mech,
79 };
80
81 /* Return a list of the gss-group1-sha1-x mechanisms supported by this
82  * program.
83  *
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,
89  * etc)
90  *
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.
95  */
96
97 /* Unpriviledged */ 
98 char * 
99 ssh_gssapi_server_mechanisms() {
100         gss_OID_set     supported;
101         Gssctxt         *ctx = NULL;
102         OM_uint32       maj_status, min_status;
103         Buffer          buf;
104         int             i = 0;
105         int             first = 0;
106         int             present;
107         char *          mechs;
108
109         if (datafellows & SSH_OLD_GSSAPI) return NULL;
110         
111         ssh_gssapi_supported_oids(&supported);
112         
113         buffer_init(&buf);
114
115         while(supported_mechs[i]->name != NULL) {
116                 if ((maj_status=gss_test_oid_set_member(&min_status,
117                                                         &supported_mechs[i]->oid,
118                                                         supported,
119                                                         &present))) {
120                         present=0;
121                 }
122
123                 if (present) {
124                     if (!GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctx,
125                                            &supported_mechs[i]->oid)))) {
126                         /* Append gss_group1_sha1_x to our list */
127                         if (first++!=0)
128                                 buffer_put_char(&buf,',');
129                         buffer_append(&buf, KEX_GSS_SHA1,
130                                       sizeof(KEX_GSS_SHA1)-1);
131                         buffer_append(&buf, 
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);
137                     } else {
138                         debug("no credentials for GSSAPI mechanism %s",
139                               supported_mechs[i]->name);
140                     }
141                 } else {
142                     debug("GSSAPI mechanism %s not supported",
143                           supported_mechs[i]->name);
144                 }
145                 ssh_gssapi_delete_ctx(&ctx);
146                 i++;
147         }
148         
149         buffer_put_char(&buf,'\0');
150         
151         mechs=xmalloc(buffer_len(&buf));
152         buffer_get(&buf,mechs,buffer_len(&buf));
153         buffer_free(&buf);
154         if (strlen(mechs)==0)
155            return(NULL);
156         else
157            return(mechs);
158 }
159
160 /* Unpriviledged */
161 void ssh_gssapi_supported_oids(gss_OID_set *oidset) {
162         int i =0;
163         OM_uint32 maj_status,min_status;
164         int present;
165         gss_OID_set supported;
166         
167         gss_create_empty_oid_set(&min_status,oidset);
168         PRIVSEP(gss_indicate_mechs(&min_status, &supported));
169
170         while (supported_mechs[i]->name!=NULL) {
171                 if ((maj_status=gss_test_oid_set_member(&min_status,
172                                                        &supported_mechs[i]->oid,
173                                                        supported,
174                                                        &present))) {
175                         present=0;
176                 }
177                 if (present) {
178                         gss_add_oid_set_member(&min_status,
179                                                &supported_mechs[i]->oid,
180                                                oidset); 
181                 }
182                 i++;
183         }
184 }       
185
186 /* Find out which GSS type (out of the list we define in ssh-gss.h) a
187  * particular connection is using 
188  */
189
190 /* Priviledged (called ssh_gssapi_accept_ctx -> ssh_gssapi_getclient ->) */
191 ssh_gssapi_mech *
192 ssh_gssapi_get_ctype(Gssctxt *ctxt) {
193         int i=0;
194         
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];
200             }
201             i++;
202         }
203         return NULL;
204 }
205
206 /* Return the OID that corresponds to the given context name */
207  
208 /* Unpriviledged */
209 gss_OID 
210 ssh_gssapi_server_id_kex(char *name) {
211   int i=0;
212   
213   if (strncmp(name, KEX_GSS_SHA1, sizeof(KEX_GSS_SHA1)-1) !=0) {
214      return(NULL);
215   }
216   
217   name+=sizeof(KEX_GSS_SHA1)-1; /* Move to the start of the MIME string */
218   
219   while (supported_mechs[i]->name!=NULL &&
220          strcmp(name,supported_mechs[i]->enc_name)!=0) {
221         i++;
222   }
223
224   if (supported_mechs[i]->name==NULL)
225      return (NULL);
226
227   debug("using GSSAPI mechanism %s (%s%s)", supported_mechs[i]->name,
228         KEX_GSS_SHA1, supported_mechs[i]->enc_name);
229
230   return &supported_mechs[i]->oid;
231 }
232
233 /* Wrapper around accept_sec_context
234  * Requires that the context contains:
235  *    oid               
236  *    credentials       (from ssh_gssapi_acquire_cred)
237  */
238 /* Priviledged */
239 OM_uint32 ssh_gssapi_accept_ctx(Gssctxt *ctx,gss_buffer_desc *recv_tok,
240                                 gss_buffer_desc *send_tok, OM_uint32 *flags) 
241 {
242         OM_uint32 status;
243         gss_OID mech;
244         
245         ctx->major=gss_accept_sec_context(&ctx->minor,
246                                           &ctx->context,
247                                           ctx->creds,
248                                           recv_tok,
249                                           GSS_C_NO_CHANNEL_BINDINGS,
250                                           &ctx->client,
251                                           &mech, /* read-only pointer */
252                                           send_tok,
253                                           flags,
254                                           NULL,
255                                           &ctx->client_creds);
256         if (GSS_ERROR(ctx->major)) {
257                 ssh_gssapi_error(ctx);
258         }
259         
260         if (ctx->client_creds) {
261                 debug("Received some client credentials");
262         } else {
263                 debug("Got no client credentials");
264         }
265
266         /* FIXME: We should check that the me
267          * the one that we asked for (in ctx->oid) */
268
269         status=ctx->major;
270         
271         /* Now, if we're complete and we have the right flags, then
272          * we flag the user as also having been authenticated
273          */
274         
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,
279                                          &gssapi_client.name,
280                                          &gssapi_client.creds))
281                         fatal("Couldn't convert client name");
282         }
283
284         /* Make sure that the getclient call hasn't stamped on this */
285         return(status);
286 }
287
288 /* Extract the client details from a given context. This can only reliably
289  * be called once for a context */
290
291 /* Priviledged (called from accept_secure_ctx) */
292 OM_uint32 
293 ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_mech **type,
294                      gss_buffer_desc *name, gss_cred_id_t *creds) {
295
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);
299                 return(ctx->major);
300         }
301         
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. 
305          */
306         *creds=ctx->client_creds;
307         ctx->client_creds=GSS_C_NO_CREDENTIAL;
308         return(ctx->major);
309 }
310
311 /* As user - called through fatal cleanup hook */
312 void
313 ssh_gssapi_cleanup_creds(void *ignored)
314 {
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);
319         }
320 }
321
322 /* As user */
323 void 
324 ssh_gssapi_storecreds()
325 {
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);
330                 }
331         } else {
332                 debug("ssh_gssapi_storecreds: Not a GSSAPI mechanism");
333         }
334 }
335
336 /* This allows GSSAPI methods to do things to the childs environment based
337  * on the passed authentication process and credentials.
338  */
339 /* As user */
340 void 
341 ssh_gssapi_do_child(char ***envp, u_int *envsizep) 
342 {
343
344         if (gssapi_client.store.envvar!=NULL && 
345             gssapi_client.store.envval!=NULL) {
346             
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);
351         }
352 }
353
354 /* Priviledged */
355 int
356 ssh_gssapi_userok(char *user)
357 {
358         if (gssapi_client.name.length==0 || 
359             gssapi_client.name.value==NULL) {
360                 debug("No suitable client data");
361                 return 0;
362         }
363         if (gssapi_client.mech && gssapi_client.mech->userok) {
364                 return((*gssapi_client.mech->userok)(&gssapi_client,user));
365         } else {
366                 debug("ssh_gssapi_userok: Unknown GSSAPI mechanism");
367         }
368         return(0);
369 }
370
371 /* Priviledged */
372 int
373 ssh_gssapi_localname(char **user)
374 {
375         *user = NULL;
376         if (gssapi_client.name.length==0 || 
377             gssapi_client.name.value==NULL) {
378                 debug("No suitable client data");
379                 return(0);;
380         }
381         if (gssapi_client.mech && gssapi_client.mech->localname) {
382                 return((*gssapi_client.mech->localname)(&gssapi_client,user));
383         } else {
384                 debug("Unknown client authentication type");
385         }
386         return(0);
387 }
388 #endif
This page took 0.075017 seconds and 5 git commands to generate.