]> andersk Git - gssapi-openssh.git/blob - openssh/auth2-gss.c
minor updates from Simon's openssh-3.6.1p2-gssapi-20030430.diff patch
[gssapi-openssh.git] / openssh / auth2-gss.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 #include "auth.h"
29 #include "ssh2.h"
30 #include "ssh1.h"
31 #include "xmalloc.h"
32 #include "log.h"
33 #include "dispatch.h"
34 #include "servconf.h"
35 #include "compat.h"
36 #include "packet.h"
37 #include "monitor_wrap.h"
38
39 #include "ssh-gss.h"
40
41 extern ServerOptions options;
42 unsigned char ssh1_key_digest[16];
43
44 static int
45 userauth_external(Authctxt *authctxt)
46 {
47         packet_check_eom();
48
49         return(PRIVSEP(ssh_gssapi_userok(authctxt->user)));
50 }
51
52 static void ssh_gssapi_userauth_error(Gssctxt *ctxt);
53 static void input_gssapi_token(int type, u_int32_t plen, void *ctxt);
54 static void input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt);
55 static void input_gssapi_errtok(int, u_int32_t, void *);
56
57 /* We only support those mechanisms that we know about (ie ones that we know
58  * how to check local user kuserok and the like
59  */
60 static int
61 userauth_gssapi(Authctxt *authctxt)
62 {
63         gss_OID_desc    oid= {0,NULL};
64         Gssctxt         *ctxt = NULL;
65         int             mechs;
66         gss_OID_set     supported;
67         int             present;
68         OM_uint32       ms;
69         u_int           len;
70         char *          doid = NULL;
71         
72         if (!authctxt->valid || authctxt->user == NULL)
73                 return 0;
74                 
75         if (datafellows & SSH_OLD_GSSAPI) {
76                 debug("Early drafts of GSSAPI userauth not supported");
77                 return 0;
78         }
79         
80         mechs=packet_get_int();
81         if (mechs==0) {
82                 debug("Mechanism negotiation is not supported");
83                 return 0;
84         }
85
86         ssh_gssapi_supported_oids(&supported);
87         do {
88                 mechs--;
89                 
90                 if (doid)
91                         xfree(doid);
92                 
93                 debug("Trying to get OID string");
94                 doid = packet_get_string(&len);
95                 debug("Got string");
96                 
97                 if (doid[0]!=0x06 || doid[1]!=len-2) {
98                         log("Mechanism OID received using the old encoding form");
99                         oid.elements = doid;
100                         oid.length = len;
101                 } else {
102                         oid.elements = doid + 2;
103                         oid.length   = len - 2;
104                 }
105                 gss_test_oid_set_member(&ms, &oid, supported, &present);
106         } while (mechs>0 && !present);
107         
108         if (!present) {
109                 xfree(doid);
110                 return(0);
111         }
112                 
113         if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt,&oid)))) {
114                 ssh_gssapi_userauth_error(ctxt);
115                 return(0);
116         }
117         
118         authctxt->methoddata=(void *)ctxt;
119
120         /* Send SSH_MSG_USERAUTH_GSSAPI_RESPONSE */
121
122         if (!compat20) {
123
124         packet_start(SSH_SMSG_AUTH_GSSAPI_RESPONSE);
125         packet_put_string(oid.elements,oid.length);
126
127         } else {
128
129         packet_start(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE);
130
131         /* Just return whatever they sent */
132         packet_put_string(doid,len);
133
134         } /* !compat20 */
135         
136         packet_send();
137         packet_write_wait();
138         xfree(doid);
139
140         if (!compat20)
141         dispatch_set(SSH_MSG_AUTH_GSSAPI_TOKEN,
142                                 &input_gssapi_token);
143         else
144         dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, 
145                      &input_gssapi_token);
146         dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK,
147                      &input_gssapi_errtok);
148         authctxt->postponed = 1;
149         
150         return 0;
151 }
152
153 static void
154 input_gssapi_token(int type, u_int32_t plen, void *ctxt)
155 {
156         Authctxt *authctxt = ctxt;
157         Gssctxt *gssctxt;
158         gss_buffer_desc send_tok,recv_tok;
159         OM_uint32 maj_status, min_status;
160         u_int len;
161         
162         if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
163                 fatal("No authentication or GSSAPI context");
164                 
165         gssctxt=authctxt->methoddata;
166         recv_tok.value=packet_get_string(&len);
167         recv_tok.length=len; /* u_int vs. size_t */
168         
169         maj_status=PRIVSEP(ssh_gssapi_accept_ctx(gssctxt, &recv_tok, 
170                                                  &send_tok, NULL));
171         packet_check_eom();
172                         
173         if (GSS_ERROR(maj_status)) {
174                 ssh_gssapi_userauth_error(gssctxt);
175                 if (send_tok.length != 0) {
176                     if (!compat20)
177                         packet_start(SSH_MSG_AUTH_GSSAPI_TOKEN);
178                     else
179                         packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK);
180                         packet_put_string(send_tok.value,send_tok.length);
181                         packet_send();
182                         packet_write_wait();
183                 }
184                 authctxt->postponed = 0;
185                 dispatch_set(SSH_MSG_AUTH_GSSAPI_TOKEN, NULL);
186                 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
187                 userauth_finish(authctxt, 0, "gssapi");
188         } else {
189                 if (send_tok.length != 0) {
190                     if (!compat20)
191                         packet_start(SSH_MSG_AUTH_GSSAPI_TOKEN);
192                     else
193                         packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN);
194                         packet_put_string(send_tok.value,send_tok.length);
195                         packet_send();
196                         packet_write_wait();
197                 }
198                 if (maj_status == GSS_S_COMPLETE) {
199                         dispatch_set(SSH_MSG_AUTH_GSSAPI_TOKEN, NULL);
200                         dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN,NULL);
201                         if (!compat20)
202                         input_gssapi_exchange_complete(0, 0, ctxt);
203                         else
204                         dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE,
205                                      &input_gssapi_exchange_complete);
206                 }
207         }
208         
209         gss_release_buffer(&min_status, &send_tok);        
210 }
211
212 static void
213 input_gssapi_errtok(int type, u_int32_t plen, void *ctxt)
214 {
215         Authctxt *authctxt = ctxt;
216         Gssctxt *gssctxt;
217         gss_buffer_desc send_tok,recv_tok;
218         OM_uint32 maj_status;
219         
220         if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
221                 fatal("No authentication or GSSAPI context");
222                 
223         gssctxt=authctxt->methoddata;
224         recv_tok.value=packet_get_string(&recv_tok.length);
225         
226         /* Push the error token into GSSAPI to see what it says */
227         maj_status=PRIVSEP(ssh_gssapi_accept_ctx(gssctxt, &recv_tok, 
228                                                  &send_tok, NULL));
229         packet_check_eom();
230
231         /* We can't return anything to the client, even if we wanted to */
232         dispatch_set(SSH_MSG_AUTH_GSSAPI_TOKEN, NULL);
233         dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
234         dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK,NULL);
235
236         /* The client will have already moved on to the next auth */
237         
238 }
239
240 /* This is called when the client thinks we've completed authentication.
241  * It should only be enabled in the dispatch handler by the function above,
242  * which only enables it once the GSSAPI exchange is complete.
243  */
244  
245 static void
246 input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt)
247 {
248         Authctxt *authctxt = ctxt;
249         Gssctxt *gssctxt;
250         int authenticated;
251         
252         if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
253                 fatal("No authentication or GSSAPI context");
254                 
255         if ((strcmp(authctxt->user, "") == 0) && (authctxt->pw == NULL)) {
256             char *lname = NULL;
257             PRIVSEP(ssh_gssapi_localname(&lname));
258             if (lname && lname[0] != '\0') {
259                 xfree(authctxt->user);
260                 authctxt->user = lname;
261                 debug("set username to %s from gssapi context", lname);
262                 authctxt->pw = PRIVSEP(getpwnamallow(authctxt->user));
263             } else {
264                 debug("failed to set username from gssapi context");
265             }
266         }
267         if (authctxt->pw) {
268 #ifdef USE_PAM
269             PRIVSEP(start_pam(authctxt->pw->pw_name));
270 #endif
271         } else {
272             authctxt->valid = 0;
273             authenticated = 0;
274             goto finish;
275         }
276
277         gssctxt=authctxt->methoddata;
278         
279         /* ssh1 needs to exchange the hash of the keys */
280         if (!compat20) {
281
282                 OM_uint32 min_status;
283                 gss_buffer_desc dummy, msg_tok;
284
285                 /* ssh1 wraps the keys, in the monitor */
286
287                 dummy.value=malloc(sizeof(ssh1_key_digest));
288                 memcpy(dummy.value,ssh1_key_digest,sizeof(ssh1_key_digest));
289                 dummy.length=sizeof(ssh1_key_digest);
290                 if (GSS_ERROR(PRIVSEP(ssh_gssapi_sign(gssctxt,&dummy,&msg_tok))))
291                     fatal("Couldn't wrap keys");
292  
293                 packet_start(SSH_SMSG_AUTH_GSSAPI_HASH);
294                 packet_put_string((char *)msg_tok.value,msg_tok.length);
295                 packet_send();
296                 packet_write_wait();
297                 gss_release_buffer(&min_status,&msg_tok);
298         }
299
300   
301         /* We don't need to check the status, because the stored credentials
302          * which userok uses are only populated once the context init step
303          * has returned complete.
304          */
305
306         authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user));
307
308 finish:
309         authctxt->postponed = 0;
310         dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
311         dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL);
312         dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL);
313         userauth_finish(authctxt, authenticated, "gssapi");
314 }
315
316 static void ssh_gssapi_userauth_error(Gssctxt *ctxt) {
317         char *errstr;
318         OM_uint32 maj,min;
319         
320         errstr=PRIVSEP(ssh_gssapi_last_error(ctxt,&maj,&min));
321         if (errstr) {
322             if (!compat20) {
323                 packet_send_debug(errstr);
324             } else {
325                 packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERROR);
326                 packet_put_int(maj);
327                 packet_put_int(min);
328                 packet_put_cstring(errstr);
329                 packet_put_cstring("");
330                 packet_send();
331                 packet_write_wait();
332                 xfree(errstr);
333             }
334         }
335 }
336
337 Authmethod method_external = {
338         "external-keyx",
339         userauth_external,
340         &options.gss_authentication
341 };
342         
343 Authmethod method_gssapi = {
344         "gssapi",
345         userauth_gssapi,
346         &options.gss_authentication
347 };
348
349 #endif /* GSSAPI */
This page took 0.179144 seconds and 5 git commands to generate.