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