2 * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
37 #include "monitor_wrap.h"
41 extern ServerOptions options;
42 unsigned char ssh1_key_digest[16];
45 userauth_external(Authctxt *authctxt)
49 return(PRIVSEP(ssh_gssapi_userok(authctxt->user)));
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 *);
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
61 userauth_gssapi(Authctxt *authctxt)
63 gss_OID_desc oid= {0,NULL};
66 gss_OID_set supported;
72 if (!authctxt->valid || authctxt->user == NULL)
75 if (datafellows & SSH_OLD_GSSAPI) {
76 debug("Early drafts of GSSAPI userauth not supported");
80 mechs=packet_get_int();
82 debug("Mechanism negotiation is not supported");
86 ssh_gssapi_supported_oids(&supported);
93 debug("Trying to get OID string");
94 doid = packet_get_string(&len);
97 if (doid[0]!=0x06 || doid[1]!=len-2) {
98 log("Mechanism OID received using the old encoding form");
102 oid.elements = doid + 2;
103 oid.length = len - 2;
105 gss_test_oid_set_member(&ms, &oid, supported, &present);
106 } while (mechs>0 && !present);
113 if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt,&oid)))) {
114 ssh_gssapi_userauth_error(ctxt);
118 authctxt->methoddata=(void *)ctxt;
120 /* Send SSH_MSG_USERAUTH_GSSAPI_RESPONSE */
124 packet_start(SSH_SMSG_AUTH_GSSAPI_RESPONSE);
125 packet_put_string(oid.elements,oid.length);
129 packet_start(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE);
131 /* Just return whatever they sent */
132 packet_put_string(doid,len);
141 dispatch_set(SSH_MSG_AUTH_GSSAPI_TOKEN,
142 &input_gssapi_token);
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;
154 input_gssapi_token(int type, u_int32_t plen, void *ctxt)
156 Authctxt *authctxt = ctxt;
158 gss_buffer_desc send_tok,recv_tok;
159 OM_uint32 maj_status, min_status;
162 if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
163 fatal("No authentication or GSSAPI context");
165 gssctxt=authctxt->methoddata;
166 recv_tok.value=packet_get_string(&len);
167 recv_tok.length=len; /* int vs. size_t */
169 maj_status=PRIVSEP(ssh_gssapi_accept_ctx(gssctxt, &recv_tok,
173 if (GSS_ERROR(maj_status)) {
174 ssh_gssapi_userauth_error(gssctxt);
175 if (send_tok.length != 0) {
177 packet_start(SSH_MSG_AUTH_GSSAPI_TOKEN);
179 packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK);
180 packet_put_string(send_tok.value,send_tok.length);
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");
189 if (send_tok.length != 0) {
191 packet_start(SSH_MSG_AUTH_GSSAPI_TOKEN);
193 packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN);
194 packet_put_string(send_tok.value,send_tok.length);
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);
202 input_gssapi_exchange_complete(0, 0, ctxt);
204 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE,
205 &input_gssapi_exchange_complete);
209 gss_release_buffer(&min_status, &send_tok);
213 input_gssapi_errtok(int type, u_int32_t plen, void *ctxt)
215 Authctxt *authctxt = ctxt;
217 gss_buffer_desc send_tok,recv_tok;
218 OM_uint32 maj_status;
220 if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
221 fatal("No authentication or GSSAPI context");
223 gssctxt=authctxt->methoddata;
224 recv_tok.value=packet_get_string(&recv_tok.length);
226 /* Push the error token into GSSAPI to see what it says */
227 maj_status=PRIVSEP(ssh_gssapi_accept_ctx(gssctxt, &recv_tok,
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);
236 /* The client will have already moved on to the next auth */
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.
246 input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt)
248 Authctxt *authctxt = ctxt;
252 if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
253 fatal("No authentication or GSSAPI context");
255 if ((strcmp(authctxt->user, "") == 0) && (authctxt->pw == 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));
264 debug("failed to set username from gssapi context");
269 PRIVSEP(start_pam(authctxt->pw->pw_name));
277 gssctxt=authctxt->methoddata;
279 /* ssh1 needs to exchange the hash of the keys */
282 OM_uint32 min_status;
283 gss_buffer_desc dummy, msg_tok;
285 /* ssh1 wraps the keys, in the monitor */
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");
293 packet_start(SSH_SMSG_AUTH_GSSAPI_HASH);
294 packet_put_string((char *)msg_tok.value,msg_tok.length);
297 gss_release_buffer(&min_status,&msg_tok);
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.
306 authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user));
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");
316 static void ssh_gssapi_userauth_error(Gssctxt *ctxt) {
320 errstr=PRIVSEP(ssh_gssapi_last_error(ctxt,&maj,&min));
323 packet_send_debug(errstr);
325 packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERROR);
328 packet_put_cstring(errstr);
329 packet_put_cstring("");
337 Authmethod method_external = {
340 &options.gss_authentication
343 Authmethod method_gssapi = {
346 &options.gss_authentication