]> andersk Git - gssapi-openssh.git/blame - openssh/auth2-gss.c
merged OPENSSH_4_2P1_GSSAPI_20051220 to GPT branch
[gssapi-openssh.git] / openssh / auth2-gss.c
CommitLineData
34fee935 1/* $OpenBSD: auth2-gss.c,v 1.10 2005/07/17 07:17:54 djm Exp $ */
70791e56 2
ff2d7a98 3/*
88928908 4 * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
ff2d7a98 5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include "includes.h"
28
29#ifdef GSSAPI
70791e56 30
ff2d7a98 31#include "auth.h"
32#include "ssh2.h"
ff2d7a98 33#include "xmalloc.h"
34#include "log.h"
35#include "dispatch.h"
36#include "servconf.h"
37#include "compat.h"
38#include "packet.h"
39#include "monitor_wrap.h"
40
41#include "ssh-gss.h"
42
43extern ServerOptions options;
ff2d7a98 44
88928908 45static void ssh_gssapi_userauth_error(Gssctxt *ctxt);
ff2d7a98 46static void input_gssapi_token(int type, u_int32_t plen, void *ctxt);
416fd2a8 47static void input_gssapi_mic(int type, u_int32_t plen, void *ctxt);
ff2d7a98 48static void input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt);
88928908 49static void input_gssapi_errtok(int, u_int32_t, void *);
ff2d7a98 50
416fd2a8 51static int gssapi_with_mic = 1; /* flag to toggle "gssapi-with-mic" vs.
52 "gssapi" */
53
57877bbc 54static int
55userauth_external(Authctxt *authctxt)
56{
57 packet_check_eom();
58
1b56ff3d 59 if (authctxt->valid && authctxt->user && authctxt->user[0]) {
60 return(PRIVSEP(ssh_gssapi_userok(authctxt->user)));
57877bbc 61 }
62 return 0;
63}
64
34fee935 65/*
66 * The 'gssapi_keyex' userauth mechanism.
67 */
68static int
69userauth_gsskeyex(Authctxt *authctxt)
70{
71 int authenticated = 0;
72 Buffer b, b2;
73 gss_buffer_desc mic, gssbuf, gssbuf2;
74 u_int len;
75
76 mic.value = packet_get_string(&len);
77 mic.length = len;
78
79 packet_check_eom();
80
81 ssh_gssapi_buildmic(&b, authctxt->user, authctxt->service,
82 "gssapi-keyex");
83
84 gssbuf.value = buffer_ptr(&b);
85 gssbuf.length = buffer_len(&b);
86
87 /* client may have used empty username to determine target
88 name from GSSAPI context */
89 ssh_gssapi_buildmic(&b2, "", authctxt->service, "gssapi-keyex");
90
91 gssbuf2.value = buffer_ptr(&b2);
92 gssbuf2.length = buffer_len(&b2);
93
94 /* gss_kex_context is NULL with privsep, so we can't check it here */
95 if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gss_kex_context,
96 &gssbuf, &mic))) ||
97 !GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gss_kex_context,
98 &gssbuf2, &mic)))) {
99 if (authctxt->valid && authctxt->user && authctxt->user[0]) {
100 authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user));
101 }
102 }
103
104 buffer_free(&b);
105 buffer_free(&b2);
106 xfree(mic.value);
107
108 return (authenticated);
109}
110
70791e56 111/*
112 * We only support those mechanisms that we know about (ie ones that we know
ff2d7a98 113 * how to check local user kuserok and the like
114 */
115static int
116userauth_gssapi(Authctxt *authctxt)
117{
1b56ff3d 118 gss_OID_desc goid = {0, NULL};
70791e56 119 Gssctxt *ctxt = NULL;
120 int mechs;
121 gss_OID_set supported;
122 int present;
123 OM_uint32 ms;
124 u_int len;
34fee935 125 u_char *doid = NULL;
70791e56 126
1b56ff3d 127 /* authctxt->valid may be 0 if we haven't yet determined
128 username from gssapi context. */
129
57877bbc 130 if (authctxt->user == NULL)
70791e56 131 return (0);
132
133 mechs = packet_get_int();
134 if (mechs == 0) {
135 debug("Mechanism negotiation is not supported");
136 return (0);
88928908 137 }
ff2d7a98 138
70791e56 139 ssh_gssapi_supported_oids(&supported);
140 do {
141 mechs--;
ff2d7a98 142
70791e56 143 if (doid)
144 xfree(doid);
88928908 145
416fd2a8 146 present = 0;
70791e56 147 doid = packet_get_string(&len);
88928908 148
34fee935 149 if (len > 2 && doid[0] == SSH_GSS_OIDTYPE &&
150 doid[1] == len - 2) {
1b56ff3d 151 goid.elements = doid + 2;
152 goid.length = len - 2;
34fee935 153 gss_test_oid_set_member(&ms, &goid, supported,
154 &present);
155 } else {
156 logit("Badly formed OID received");
70791e56 157 }
70791e56 158 } while (mechs > 0 && !present);
159
160 gss_release_oid_set(&ms, &supported);
161
162 if (!present) {
163 xfree(doid);
34fee935 164 authctxt->server_caused_failure = 1;
70791e56 165 return (0);
166 }
167
1b56ff3d 168 if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, &goid)))) {
70791e56 169 xfree(doid);
34fee935 170 authctxt->server_caused_failure = 1;
70791e56 171 return (0);
172 }
173
174 authctxt->methoddata=(void *)ctxt;
175
176 packet_start(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE);
177
416fd2a8 178 /* Return the OID that we received */
70791e56 179 packet_put_string(doid, len);
88928908 180
70791e56 181 packet_send();
182 xfree(doid);
183
184 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, &input_gssapi_token);
185 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, &input_gssapi_errtok);
186 authctxt->postponed = 1;
187
188 return (0);
ff2d7a98 189}
190
191static void
192input_gssapi_token(int type, u_int32_t plen, void *ctxt)
193{
70791e56 194 Authctxt *authctxt = ctxt;
195 Gssctxt *gssctxt;
196 gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
197 gss_buffer_desc recv_tok;
2a304a95 198 OM_uint32 maj_status, min_status, flags=0;
70791e56 199 u_int len;
200
201 if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
202 fatal("No authentication or GSSAPI context");
203
204 gssctxt = authctxt->methoddata;
205 recv_tok.value = packet_get_string(&len);
206 recv_tok.length = len; /* u_int vs. size_t */
207
208 packet_check_eom();
209
210 maj_status = PRIVSEP(ssh_gssapi_accept_ctx(gssctxt, &recv_tok,
416fd2a8 211 &send_tok, &flags));
70791e56 212
213 xfree(recv_tok.value);
214
215 if (GSS_ERROR(maj_status)) {
88928908 216 ssh_gssapi_userauth_error(gssctxt);
217 if (send_tok.length != 0) {
88928908 218 packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK);
70791e56 219 packet_put_string(send_tok.value, send_tok.length);
220 packet_send();
221 }
222 authctxt->postponed = 0;
223 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
416fd2a8 224 userauth_finish(authctxt, 0,
225 gssapi_with_mic ? "gssapi-with-mic" :
226 "gssapi");
70791e56 227 } else {
228 if (send_tok.length != 0) {
229 packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN);
230 packet_put_string(send_tok.value, send_tok.length);
231 packet_send();
232 }
233 if (maj_status == GSS_S_COMPLETE) {
234 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
416fd2a8 235 if (flags & GSS_C_INTEG_FLAG && gssapi_with_mic)
236 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_MIC,
237 &input_gssapi_mic);
238 else
239 dispatch_set(
240 SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE,
241 &input_gssapi_exchange_complete);
70791e56 242 }
243 }
244
245 gss_release_buffer(&min_status, &send_tok);
88928908 246}
247
248static void
249input_gssapi_errtok(int type, u_int32_t plen, void *ctxt)
250{
70791e56 251 Authctxt *authctxt = ctxt;
252 Gssctxt *gssctxt;
253 gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
254 gss_buffer_desc recv_tok;
255 OM_uint32 maj_status;
256 u_int len;
257
258 if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
259 fatal("No authentication or GSSAPI context");
260
261 gssctxt = authctxt->methoddata;
262 recv_tok.value = packet_get_string(&len);
263 recv_tok.length = len;
264
265 packet_check_eom();
266
267 /* Push the error token into GSSAPI to see what it says */
268 maj_status = PRIVSEP(ssh_gssapi_accept_ctx(gssctxt, &recv_tok,
269 &send_tok, NULL));
270
271 xfree(recv_tok.value);
88928908 272
273 /* We can't return anything to the client, even if we wanted to */
88928908 274 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
70791e56 275 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL);
88928908 276
277 /* The client will have already moved on to the next auth */
70791e56 278
279 gss_release_buffer(&maj_status, &send_tok);
ff2d7a98 280}
281
416fd2a8 282static void
283gssapi_set_implicit_username(Authctxt *authctxt)
284{
1b56ff3d 285 if ((authctxt->user == NULL) || (authctxt->user[0] == '\0')) {
416fd2a8 286 char *lname = NULL;
287 PRIVSEP(ssh_gssapi_localname(&lname));
288 if (lname && lname[0] != '\0') {
1b56ff3d 289 if (authctxt->user) xfree(authctxt->user);
416fd2a8 290 authctxt->user = lname;
291 debug("set username to %s from gssapi context", lname);
292 authctxt->pw = PRIVSEP(getpwnamallow(authctxt->user));
57877bbc 293 if (authctxt->pw) {
294 authctxt->valid = 1;
295 }
416fd2a8 296 } else {
297 debug("failed to set username from gssapi context");
298 }
299 }
300 if (authctxt->pw) {
301#ifdef USE_PAM
2a304a95 302 if (options.use_pam)
57877bbc 303 PRIVSEP(start_pam(authctxt));
416fd2a8 304#endif
305 }
306}
307
70791e56 308/*
309 * This is called when the client thinks we've completed authentication.
ff2d7a98 310 * It should only be enabled in the dispatch handler by the function above,
311 * which only enables it once the GSSAPI exchange is complete.
312 */
70791e56 313
ff2d7a98 314static void
315input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt)
316{
70791e56 317 Authctxt *authctxt = ctxt;
318 Gssctxt *gssctxt;
319 int authenticated;
320
ff2d7a98 321 if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
70791e56 322 fatal("No authentication or GSSAPI context");
323
416fd2a8 324 gssapi_set_implicit_username(authctxt);
c2397a66 325
70791e56 326 gssctxt = authctxt->methoddata;
ff2d7a98 327
70791e56 328 /*
416fd2a8 329 * We don't need to check the status, because we're only enabled in
330 * the dispatcher once the exchange is complete
ff2d7a98 331 */
332
70791e56 333 packet_check_eom();
334
1b56ff3d 335 /* user should be set if valid but we double-check here */
336 if (authctxt->valid && authctxt->user && authctxt->user[0]) {
416fd2a8 337 authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user));
338 } else {
339 authenticated = 0;
340 }
ff2d7a98 341
70791e56 342 authctxt->postponed = 0;
343 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
344 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL);
416fd2a8 345 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_MIC, NULL);
70791e56 346 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL);
416fd2a8 347 userauth_finish(authctxt, authenticated,
348 gssapi_with_mic ? "gssapi-with-mic" : "gssapi");
349}
350
351static int
352userauth_gssapi_with_mic(Authctxt *authctxt)
353{
354 gssapi_with_mic = 1;
355 return userauth_gssapi(authctxt);
356}
357
358static int
359userauth_gssapi_without_mic(Authctxt *authctxt)
360{
361 gssapi_with_mic = 0;
362 return userauth_gssapi(authctxt);
363}
364
365static void
366input_gssapi_mic(int type, u_int32_t plen, void *ctxt)
367{
368 Authctxt *authctxt = ctxt;
369 Gssctxt *gssctxt;
370 int authenticated = 0;
371 Buffer b;
372 gss_buffer_desc mic, gssbuf;
373 u_int len;
374
375 if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
376 fatal("No authentication or GSSAPI context");
377
378 gssapi_set_implicit_username(authctxt);
379
380 gssctxt = authctxt->methoddata;
381
382 mic.value = packet_get_string(&len);
383 mic.length = len;
384
385 ssh_gssapi_buildmic(&b, authctxt->user, authctxt->service,
386 "gssapi-with-mic");
387
388 gssbuf.value = buffer_ptr(&b);
389 gssbuf.length = buffer_len(&b);
390
391 if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gssctxt, &gssbuf, &mic))))
1b56ff3d 392 if (authctxt->valid && authctxt->user && authctxt->user[0]) {
416fd2a8 393 authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user));
394 } else {
395 authenticated = 0;
396 }
397 else
398 logit("GSSAPI MIC check failed");
399
400 buffer_free(&b);
401 xfree(mic.value);
402
403 authctxt->postponed = 0;
404 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
405 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL);
406 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_MIC, NULL);
407 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL);
408 userauth_finish(authctxt, authenticated, "gssapi-with-mic");
ff2d7a98 409}
410
88928908 411static void ssh_gssapi_userauth_error(Gssctxt *ctxt) {
412 char *errstr;
413 OM_uint32 maj,min;
414
415 errstr=PRIVSEP(ssh_gssapi_last_error(ctxt,&maj,&min));
416 if (errstr) {
88928908 417 packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERROR);
418 packet_put_int(maj);
419 packet_put_int(min);
420 packet_put_cstring(errstr);
421 packet_put_cstring("");
422 packet_send();
423 packet_write_wait();
424 xfree(errstr);
88928908 425 }
426}
427
ff2d7a98 428Authmethod method_external = {
429 "external-keyx",
430 userauth_external,
431 &options.gss_authentication
432};
433
34fee935 434Authmethod method_gsskeyex = {
435 "gssapi-keyex",
436 userauth_gsskeyex,
437 &options.gss_authentication
438};
439
ff2d7a98 440Authmethod method_gssapi = {
416fd2a8 441 "gssapi-with-mic",
442 userauth_gssapi_with_mic,
443 &options.gss_authentication
444};
445
446Authmethod method_gssapi_compat = {
70791e56 447 "gssapi",
416fd2a8 448 userauth_gssapi_without_mic,
70791e56 449 &options.gss_authentication
ff2d7a98 450};
451
452#endif /* GSSAPI */
This page took 0.119985 seconds and 5 git commands to generate.