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