diff options
author | djm@openbsd.org <djm@openbsd.org> | 2016-01-13 23:04:47 +0000 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2016-01-14 10:06:01 +1100 |
commit | ed4ce82dbfa8a3a3c8ea6fa0db113c71e234416c (patch) | |
tree | 008ac3334471370857e32b48893cb6f07d28e987 /clientloop.c | |
parent | 9a728cc918fad67c8a9a71201088b1e150340ba4 (diff) |
upstream commit
eliminate fallback from untrusted X11 forwarding to trusted
forwarding when the X server disables the SECURITY extension; Reported by
Thomas Hoger; ok deraadt@
Upstream-ID: f76195bd2064615a63ef9674a0e4096b0713f938
Diffstat (limited to 'clientloop.c')
-rw-r--r-- | clientloop.c | 114 |
1 files changed, 70 insertions, 44 deletions
diff --git a/clientloop.c b/clientloop.c index f55545194..c0386d56b 100644 --- a/clientloop.c +++ b/clientloop.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: clientloop.c,v 1.278 2015/12/26 07:46:03 semarie Exp $ */ | 1 | /* $OpenBSD: clientloop.c,v 1.279 2016/01/13 23:04:47 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -288,6 +288,9 @@ client_x11_display_valid(const char *display) | |||
288 | { | 288 | { |
289 | size_t i, dlen; | 289 | size_t i, dlen; |
290 | 290 | ||
291 | if (display == NULL) | ||
292 | return 0; | ||
293 | |||
291 | dlen = strlen(display); | 294 | dlen = strlen(display); |
292 | for (i = 0; i < dlen; i++) { | 295 | for (i = 0; i < dlen; i++) { |
293 | if (!isalnum((u_char)display[i]) && | 296 | if (!isalnum((u_char)display[i]) && |
@@ -301,34 +304,33 @@ client_x11_display_valid(const char *display) | |||
301 | 304 | ||
302 | #define SSH_X11_PROTO "MIT-MAGIC-COOKIE-1" | 305 | #define SSH_X11_PROTO "MIT-MAGIC-COOKIE-1" |
303 | #define X11_TIMEOUT_SLACK 60 | 306 | #define X11_TIMEOUT_SLACK 60 |
304 | void | 307 | int |
305 | client_x11_get_proto(const char *display, const char *xauth_path, | 308 | client_x11_get_proto(const char *display, const char *xauth_path, |
306 | u_int trusted, u_int timeout, char **_proto, char **_data) | 309 | u_int trusted, u_int timeout, char **_proto, char **_data) |
307 | { | 310 | { |
308 | char cmd[1024]; | 311 | char cmd[1024], line[512], xdisplay[512]; |
309 | char line[512]; | 312 | char xauthfile[PATH_MAX], xauthdir[PATH_MAX]; |
310 | char xdisplay[512]; | ||
311 | static char proto[512], data[512]; | 313 | static char proto[512], data[512]; |
312 | FILE *f; | 314 | FILE *f; |
313 | int got_data = 0, generated = 0, do_unlink = 0, i; | 315 | int got_data = 0, generated = 0, do_unlink = 0, i, r; |
314 | char xauthdir[PATH_MAX] = "", xauthfile[PATH_MAX] = ""; | ||
315 | struct stat st; | 316 | struct stat st; |
316 | u_int now, x11_timeout_real; | 317 | u_int now, x11_timeout_real; |
317 | 318 | ||
318 | *_proto = proto; | 319 | *_proto = proto; |
319 | *_data = data; | 320 | *_data = data; |
320 | proto[0] = data[0] = '\0'; | 321 | proto[0] = data[0] = xauthfile[0] = xauthdir[0] = '\0'; |
321 | 322 | ||
322 | if (xauth_path == NULL ||(stat(xauth_path, &st) == -1)) { | 323 | if (!client_x11_display_valid(display)) { |
323 | debug("No xauth program."); | 324 | logit("DISPLAY \"%s\" invalid; disabling X11 forwarding", |
324 | } else if (!client_x11_display_valid(display)) { | ||
325 | logit("DISPLAY '%s' invalid, falling back to fake xauth data", | ||
326 | display); | 325 | display); |
327 | } else { | 326 | return -1; |
328 | if (display == NULL) { | 327 | } |
329 | debug("x11_get_proto: DISPLAY not set"); | 328 | if (xauth_path != NULL && stat(xauth_path, &st) == -1) { |
330 | return; | 329 | debug("No xauth program."); |
331 | } | 330 | xauth_path = NULL; |
331 | } | ||
332 | |||
333 | if (xauth_path != NULL) { | ||
332 | /* | 334 | /* |
333 | * Handle FamilyLocal case where $DISPLAY does | 335 | * Handle FamilyLocal case where $DISPLAY does |
334 | * not match an authorization entry. For this we | 336 | * not match an authorization entry. For this we |
@@ -337,43 +339,60 @@ client_x11_get_proto(const char *display, const char *xauth_path, | |||
337 | * is not perfect. | 339 | * is not perfect. |
338 | */ | 340 | */ |
339 | if (strncmp(display, "localhost:", 10) == 0) { | 341 | if (strncmp(display, "localhost:", 10) == 0) { |
340 | snprintf(xdisplay, sizeof(xdisplay), "unix:%s", | 342 | if ((r = snprintf(xdisplay, sizeof(xdisplay), "unix:%s", |
341 | display + 10); | 343 | display + 10)) < 0 || |
344 | (size_t)r >= sizeof(xdisplay)) { | ||
345 | error("%s: display name too long", __func__); | ||
346 | return -1; | ||
347 | } | ||
342 | display = xdisplay; | 348 | display = xdisplay; |
343 | } | 349 | } |
344 | if (trusted == 0) { | 350 | if (trusted == 0) { |
345 | mktemp_proto(xauthdir, PATH_MAX); | ||
346 | /* | 351 | /* |
352 | * Generate an untrusted X11 auth cookie. | ||
353 | * | ||
347 | * The authentication cookie should briefly outlive | 354 | * The authentication cookie should briefly outlive |
348 | * ssh's willingness to forward X11 connections to | 355 | * ssh's willingness to forward X11 connections to |
349 | * avoid nasty fail-open behaviour in the X server. | 356 | * avoid nasty fail-open behaviour in the X server. |
350 | */ | 357 | */ |
358 | mktemp_proto(xauthdir, sizeof(xauthdir)); | ||
359 | if (mkdtemp(xauthdir) == NULL) { | ||
360 | error("%s: mkdtemp: %s", | ||
361 | __func__, strerror(errno)); | ||
362 | return -1; | ||
363 | } | ||
364 | do_unlink = 1; | ||
365 | if ((r = snprintf(xauthfile, sizeof(xauthfile), | ||
366 | "%s/xauthfile", xauthdir)) < 0 || | ||
367 | (size_t)r >= sizeof(xauthfile)) { | ||
368 | error("%s: xauthfile path too long", __func__); | ||
369 | unlink(xauthfile); | ||
370 | rmdir(xauthdir); | ||
371 | return -1; | ||
372 | } | ||
373 | |||
351 | if (timeout >= UINT_MAX - X11_TIMEOUT_SLACK) | 374 | if (timeout >= UINT_MAX - X11_TIMEOUT_SLACK) |
352 | x11_timeout_real = UINT_MAX; | 375 | x11_timeout_real = UINT_MAX; |
353 | else | 376 | else |
354 | x11_timeout_real = timeout + X11_TIMEOUT_SLACK; | 377 | x11_timeout_real = timeout + X11_TIMEOUT_SLACK; |
355 | if (mkdtemp(xauthdir) != NULL) { | 378 | if ((r = snprintf(cmd, sizeof(cmd), |
356 | do_unlink = 1; | 379 | "%s -f %s generate %s " SSH_X11_PROTO |
357 | snprintf(xauthfile, PATH_MAX, "%s/xauthfile", | 380 | " untrusted timeout %u 2>" _PATH_DEVNULL, |
358 | xauthdir); | 381 | xauth_path, xauthfile, display, |
359 | snprintf(cmd, sizeof(cmd), | 382 | x11_timeout_real)) < 0 || |
360 | "%s -f %s generate %s " SSH_X11_PROTO | 383 | (size_t)r >= sizeof(cmd)) |
361 | " untrusted timeout %u 2>" _PATH_DEVNULL, | 384 | fatal("%s: cmd too long", __func__); |
362 | xauth_path, xauthfile, display, | 385 | debug2("%s: %s", __func__, cmd); |
363 | x11_timeout_real); | 386 | if (x11_refuse_time == 0) { |
364 | debug2("x11_get_proto: %s", cmd); | 387 | now = monotime() + 1; |
365 | if (x11_refuse_time == 0) { | 388 | if (UINT_MAX - timeout < now) |
366 | now = monotime() + 1; | 389 | x11_refuse_time = UINT_MAX; |
367 | if (UINT_MAX - timeout < now) | 390 | else |
368 | x11_refuse_time = UINT_MAX; | 391 | x11_refuse_time = now + timeout; |
369 | else | 392 | channel_set_x11_refuse_time(x11_refuse_time); |
370 | x11_refuse_time = now + timeout; | ||
371 | channel_set_x11_refuse_time( | ||
372 | x11_refuse_time); | ||
373 | } | ||
374 | if (system(cmd) == 0) | ||
375 | generated = 1; | ||
376 | } | 393 | } |
394 | if (system(cmd) == 0) | ||
395 | generated = 1; | ||
377 | } | 396 | } |
378 | 397 | ||
379 | /* | 398 | /* |
@@ -395,9 +414,7 @@ client_x11_get_proto(const char *display, const char *xauth_path, | |||
395 | got_data = 1; | 414 | got_data = 1; |
396 | if (f) | 415 | if (f) |
397 | pclose(f); | 416 | pclose(f); |
398 | } else | 417 | } |
399 | error("Warning: untrusted X11 forwarding setup failed: " | ||
400 | "xauth key data not generated"); | ||
401 | } | 418 | } |
402 | 419 | ||
403 | if (do_unlink) { | 420 | if (do_unlink) { |
@@ -405,6 +422,13 @@ client_x11_get_proto(const char *display, const char *xauth_path, | |||
405 | rmdir(xauthdir); | 422 | rmdir(xauthdir); |
406 | } | 423 | } |
407 | 424 | ||
425 | /* Don't fall back to fake X11 data for untrusted forwarding */ | ||
426 | if (!trusted && !got_data) { | ||
427 | error("Warning: untrusted X11 forwarding setup failed: " | ||
428 | "xauth key data not generated"); | ||
429 | return -1; | ||
430 | } | ||
431 | |||
408 | /* | 432 | /* |
409 | * If we didn't get authentication data, just make up some | 433 | * If we didn't get authentication data, just make up some |
410 | * data. The forwarding code will check the validity of the | 434 | * data. The forwarding code will check the validity of the |
@@ -427,6 +451,8 @@ client_x11_get_proto(const char *display, const char *xauth_path, | |||
427 | rnd >>= 8; | 451 | rnd >>= 8; |
428 | } | 452 | } |
429 | } | 453 | } |
454 | |||
455 | return 0; | ||
430 | } | 456 | } |
431 | 457 | ||
432 | /* | 458 | /* |