]> andersk Git - gssapi-openssh.git/blob - openssh/gss-serv.c
merge of OPENSSH_3_6_1P1_SIMON_20030411
[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 char * 
98 ssh_gssapi_server_mechanisms() {
99         gss_OID_set     supported;
100         Gssctxt         *ctx = NULL;
101         OM_uint32       maj_status, min_status;
102         Buffer          buf;
103         int             i = 0;
104         int             first = 0;
105         int             present;
106         char *          mechs;
107
108         if (datafellows & SSH_OLD_GSSAPI) return NULL;
109         
110         ssh_gssapi_supported_oids(&supported);
111         
112         buffer_init(&buf);
113
114         while(supported_mechs[i]->name != NULL) {
115                 if ((maj_status=gss_test_oid_set_member(&min_status,
116                                                         &supported_mechs[i]->oid,
117                                                         supported,
118                                                         &present))) {
119                         present=0;
120                 }
121
122                 if (present) {
123                     if (!GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctx,
124                                            &supported_mechs[i]->oid)))) {
125                         /* Append gss_group1_sha1_x to our list */
126                         if (first++!=0)
127                                 buffer_put_char(&buf,',');
128                         buffer_append(&buf, KEX_GSS_SHA1,
129                                       sizeof(KEX_GSS_SHA1)-1);
130                         buffer_append(&buf, 
131                                       supported_mechs[i]->enc_name,
132                                       strlen(supported_mechs[i]->enc_name));
133                         debug("GSSAPI mechanism %s (%s%s) supported",
134                               supported_mechs[i]->name, KEX_GSS_SHA1,
135                               supported_mechs[i]->enc_name);
136                     } else {
137                         debug("no credentials for GSSAPI mechanism %s",
138                               supported_mechs[i]->name);
139                     }
140                 } else {
141                     debug("GSSAPI mechanism %s not supported",
142                           supported_mechs[i]->name);
143                 }
144                 ssh_gssapi_delete_ctx(&ctx);
145                 i++;
146         }
147         
148         buffer_put_char(&buf,'\0');
149         
150         mechs=xmalloc(buffer_len(&buf));
151         buffer_get(&buf,mechs,buffer_len(&buf));
152         buffer_free(&buf);
153         if (strlen(mechs)==0)
154            return(NULL);
155         else
156            return(mechs);
157 }
158
159 void ssh_gssapi_supported_oids(gss_OID_set *oidset) {
160         int i =0;
161         OM_uint32 maj_status,min_status;
162         int present;
163         gss_OID_set supported;
164         
165         gss_create_empty_oid_set(&min_status,oidset);
166         PRIVSEP(gss_indicate_mechs(&min_status, &supported));
167
168         while (supported_mechs[i]->name!=NULL) {
169                 if ((maj_status=gss_test_oid_set_member(&min_status,
170                                                        &supported_mechs[i]->oid,
171                                                        supported,
172                                                        &present))) {
173                         present=0;
174                 }
175                 if (present) {
176                         gss_add_oid_set_member(&min_status,
177                                                &supported_mechs[i]->oid,
178                                                oidset); 
179                 }
180                 i++;
181         }
182 }       
183
184 /* Find out which GSS type (out of the list we define in ssh-gss.h) a
185  * particular connection is using 
186  */
187 ssh_gssapi_mech *
188 ssh_gssapi_get_ctype(Gssctxt *ctxt) {
189         int i=0;
190         
191         while(supported_mechs[i]->name!=NULL) {
192             if (supported_mechs[i]->oid.length == ctxt->oid->length &&
193                 (memcmp(supported_mechs[i]->oid.elements,
194                         ctxt->oid->elements,ctxt->oid->length)==0)) {
195                 return supported_mechs[i];
196             }
197             i++;
198         }
199         return NULL;
200 }
201
202 /* Set the GSS context's OID to the oid indicated by the given key exchange
203  * name. */
204  
205 gss_OID 
206 ssh_gssapi_id_kex(Gssctxt *ctx, char *name) {
207   int i=0;
208   
209   if (strncmp(name, KEX_GSS_SHA1, sizeof(KEX_GSS_SHA1)-1) !=0) {
210      return(NULL);
211   }
212   
213   name+=sizeof(KEX_GSS_SHA1)-1; /* Move to the start of the MIME string */
214   
215   while (supported_mechs[i]->name!=NULL &&
216         strcmp(name,supported_mechs[i]->enc_name)!=0) {
217         i++;
218   }
219
220   if (supported_mechs[i]->name==NULL)
221      return (NULL);
222
223   if (ctx) ssh_gssapi_set_oid(ctx,&supported_mechs[i]->oid);
224
225   debug("using GSSAPI mechanism %s (%s%s)", supported_mechs[i]->name,
226         KEX_GSS_SHA1, supported_mechs[i]->enc_name);
227
228   return &supported_mechs[i]->oid;
229 }
230
231 /* Wrapper arround accept_sec_context
232  * Requires that the context contains:
233  *    oid               
234  *    credentials       (from ssh_gssapi_acquire_cred)
235  */
236 OM_uint32 ssh_gssapi_accept_ctx(Gssctxt *ctx,gss_buffer_desc *recv_tok,
237                                 gss_buffer_desc *send_tok, OM_uint32 *flags) 
238 {
239         OM_uint32 status;
240         gss_OID mech;
241         
242         ctx->major=gss_accept_sec_context(&ctx->minor,
243                                           &ctx->context,
244                                           ctx->creds,
245                                           recv_tok,
246                                           GSS_C_NO_CHANNEL_BINDINGS,
247                                           &ctx->client,
248                                           &mech, /* read-only pointer */
249                                           send_tok,
250                                           flags,
251                                           NULL,
252                                           &ctx->client_creds);
253         if (GSS_ERROR(ctx->major)) {
254                 ssh_gssapi_error(ctx);
255         }
256         
257         if (ctx->client_creds) {
258                 debug("Received some client credentials");
259         } else {
260                 debug("Got no client credentials");
261         }
262
263         /* FIXME: We should check that the me
264         * the one that we asked for (in ctx->oid) */
265
266         status=ctx->major;
267         
268         /* Now, if we're complete and we have the right flags, then
269         * we flag the user as also having been authenticated
270         */
271         
272         if (((flags==NULL) || ((*flags & GSS_C_MUTUAL_FLAG) && 
273                                (*flags & GSS_C_INTEG_FLAG))) &&
274             (ctx->major == GSS_S_COMPLETE)) {
275                 if (ssh_gssapi_getclient(ctx,&gssapi_client.mech,
276                                          &gssapi_client.name,
277                                          &gssapi_client.creds))
278                         fatal("Couldn't convert client name");
279         }
280
281         /* Make sure that the getclient call hasn't stamped on this */
282         return(status);
283 }
284
285 /* Extract the client details from a given context. This can only reliably
286  * be called once for a context */
287
288 OM_uint32 
289 ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_mech **type,
290                      gss_buffer_desc *name, gss_cred_id_t *creds) {
291
292         *type=ssh_gssapi_get_ctype(ctx);
293         if ((ctx->major=gss_display_name(&ctx->minor,ctx->client,name,NULL))) {
294                 ssh_gssapi_error(ctx);
295                 return(ctx->major);
296         }
297         
298         /* This is icky. There appears to be no way to copy this structure,
299         * rather than the pointer to it, so we simply copy the pointer and
300         * mark the originator as empty so we don't destroy it. 
301         */
302         *creds=ctx->client_creds;
303         ctx->client_creds=GSS_C_NO_CREDENTIAL;
304         return(ctx->major);
305 }
306
307 void
308 ssh_gssapi_cleanup_creds(void *ignored)
309 {
310         if (gssapi_client.store.filename!=NULL) {
311                 /* Unlink probably isn't sufficient */
312                 debug("removing gssapi cred file\"%s\"",gssapi_client.store.filename);
313                 unlink(gssapi_client.store.filename);
314         }
315 }
316
317 void 
318 ssh_gssapi_storecreds()
319 {
320         if (gssapi_client.mech && gssapi_client.mech->storecreds) {
321                 (*gssapi_client.mech->storecreds)(&gssapi_client);
322                 if (options.gss_cleanup_creds) {
323                         fatal_add_cleanup(ssh_gssapi_cleanup_creds, NULL);
324                 }
325         } else {
326                 debug("ssh_gssapi_storecreds: Not a GSSAPI mechanism");
327         }
328 }
329
330 /* This allows GSSAPI methods to do things to the childs environment based
331  * on the passed authentication process and credentials.
332  *
333  * Question: If we didn't use userauth_external for some reason, should we
334  * still delegate credentials?
335  */
336 void 
337 ssh_gssapi_do_child(char ***envp, u_int *envsizep) 
338 {
339
340         if (gssapi_client.store.envvar!=NULL && 
341             gssapi_client.store.envval!=NULL) {
342             
343                 debug("Setting %s to %s", gssapi_client.store.envvar,
344                                           gssapi_client.store.envval);                            
345                 child_set_env(envp, envsizep, gssapi_client.store.envvar, 
346                                               gssapi_client.store.envval);
347         }
348 }
349
350 int
351 ssh_gssapi_userok(char *user)
352 {
353         if (gssapi_client.name.length==0 || 
354             gssapi_client.name.value==NULL) {
355                 debug("No suitable client data");
356                 return 0;
357         }
358         if (gssapi_client.mech && gssapi_client.mech->userok) {
359                 return((*gssapi_client.mech->userok)(&gssapi_client,user));
360         } else {
361                 debug("ssh_gssapi_userok: Unknown GSSAPI mechanism");
362         }
363         return(0);
364 }
365
366 int
367 ssh_gssapi_localname(char **user)
368 {
369         *user = NULL;
370         if (gssapi_client.name.length==0 || 
371             gssapi_client.name.value==NULL) {
372                 debug("No suitable client data");
373                 return(0);;
374         }
375         if (gssapi_client.mech && gssapi_client.mech->localname) {
376                 return((*gssapi_client.mech->localname)(&gssapi_client,user));
377         } else {
378                 debug("Unknown client authentication type");
379         }
380         return(0);
381 }
382 #endif
This page took 0.065444 seconds and 5 git commands to generate.