diff options
author | Damien Miller <djm@mindrot.org> | 2006-01-31 21:49:27 +1100 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2006-01-31 21:49:27 +1100 |
commit | 3eec6b73a2c446225fce546d61d83cfc695fbaa0 (patch) | |
tree | 425fe13ba7b751c6d9878eb592e2d6a014a468bd /scp.c | |
parent | b5dd55cccc7096d3db59378bba44920183f34110 (diff) |
- djm@cvs.openbsd.org 2006/01/31 10:19:02
[misc.c misc.h scp.c sftp.c]
fix local arbitrary command execution vulnerability on local/local and
remote/remote copies (CVE-2006-0225, bz #1094), patch by
t8m AT centrum.cz, polished by dtucker@ and myself; ok markus@
Diffstat (limited to 'scp.c')
-rw-r--r-- | scp.c | 132 |
1 files changed, 87 insertions, 45 deletions
@@ -71,7 +71,7 @@ | |||
71 | */ | 71 | */ |
72 | 72 | ||
73 | #include "includes.h" | 73 | #include "includes.h" |
74 | RCSID("$OpenBSD: scp.c,v 1.128 2005/12/06 22:38:27 reyk Exp $"); | 74 | RCSID("$OpenBSD: scp.c,v 1.129 2006/01/31 10:19:02 djm Exp $"); |
75 | 75 | ||
76 | #include "xmalloc.h" | 76 | #include "xmalloc.h" |
77 | #include "atomicio.h" | 77 | #include "atomicio.h" |
@@ -118,6 +118,48 @@ killchild(int signo) | |||
118 | exit(1); | 118 | exit(1); |
119 | } | 119 | } |
120 | 120 | ||
121 | static int | ||
122 | do_local_cmd(arglist *a) | ||
123 | { | ||
124 | u_int i; | ||
125 | int status; | ||
126 | pid_t pid; | ||
127 | |||
128 | if (a->num == 0) | ||
129 | fatal("do_local_cmd: no arguments"); | ||
130 | |||
131 | if (verbose_mode) { | ||
132 | fprintf(stderr, "Executing:"); | ||
133 | for (i = 0; i < a->num; i++) | ||
134 | fprintf(stderr, " %s", a->list[i]); | ||
135 | fprintf(stderr, "\n"); | ||
136 | } | ||
137 | if ((pid = fork()) == -1) | ||
138 | fatal("do_local_cmd: fork: %s", strerror(errno)); | ||
139 | |||
140 | if (pid == 0) { | ||
141 | execvp(a->list[0], a->list); | ||
142 | perror(a->list[0]); | ||
143 | exit(1); | ||
144 | } | ||
145 | |||
146 | do_cmd_pid = pid; | ||
147 | signal(SIGTERM, killchild); | ||
148 | signal(SIGINT, killchild); | ||
149 | signal(SIGHUP, killchild); | ||
150 | |||
151 | while (waitpid(pid, &status, 0) == -1) | ||
152 | if (errno != EINTR) | ||
153 | fatal("do_local_cmd: waitpid: %s", strerror(errno)); | ||
154 | |||
155 | do_cmd_pid = -1; | ||
156 | |||
157 | if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) | ||
158 | return (-1); | ||
159 | |||
160 | return (0); | ||
161 | } | ||
162 | |||
121 | /* | 163 | /* |
122 | * This function executes the given command as the specified user on the | 164 | * This function executes the given command as the specified user on the |
123 | * given host. This returns < 0 if execution fails, and >= 0 otherwise. This | 165 | * given host. This returns < 0 if execution fails, and >= 0 otherwise. This |
@@ -162,7 +204,7 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout, int argc) | |||
162 | close(pin[0]); | 204 | close(pin[0]); |
163 | close(pout[1]); | 205 | close(pout[1]); |
164 | 206 | ||
165 | args.list[0] = ssh_program; | 207 | replacearg(&args, 0, "%s", ssh_program); |
166 | if (remuser != NULL) | 208 | if (remuser != NULL) |
167 | addargs(&args, "-l%s", remuser); | 209 | addargs(&args, "-l%s", remuser); |
168 | addargs(&args, "%s", host); | 210 | addargs(&args, "%s", host); |
@@ -227,8 +269,9 @@ main(int argc, char **argv) | |||
227 | 269 | ||
228 | __progname = ssh_get_progname(argv[0]); | 270 | __progname = ssh_get_progname(argv[0]); |
229 | 271 | ||
272 | memset(&args, '\0', sizeof(args)); | ||
230 | args.list = NULL; | 273 | args.list = NULL; |
231 | addargs(&args, "ssh"); /* overwritten with ssh_program */ | 274 | addargs(&args, "%s", ssh_program); |
232 | addargs(&args, "-x"); | 275 | addargs(&args, "-x"); |
233 | addargs(&args, "-oForwardAgent no"); | 276 | addargs(&args, "-oForwardAgent no"); |
234 | addargs(&args, "-oPermitLocalCommand no"); | 277 | addargs(&args, "-oPermitLocalCommand no"); |
@@ -368,6 +411,10 @@ toremote(char *targ, int argc, char **argv) | |||
368 | { | 411 | { |
369 | int i, len; | 412 | int i, len; |
370 | char *bp, *host, *src, *suser, *thost, *tuser, *arg; | 413 | char *bp, *host, *src, *suser, *thost, *tuser, *arg; |
414 | arglist alist; | ||
415 | |||
416 | memset(&alist, '\0', sizeof(alist)); | ||
417 | alist.list = NULL; | ||
371 | 418 | ||
372 | *targ++ = 0; | 419 | *targ++ = 0; |
373 | if (*targ == 0) | 420 | if (*targ == 0) |
@@ -385,56 +432,48 @@ toremote(char *targ, int argc, char **argv) | |||
385 | tuser = NULL; | 432 | tuser = NULL; |
386 | } | 433 | } |
387 | 434 | ||
435 | if (tuser != NULL && !okname(tuser)) { | ||
436 | xfree(arg); | ||
437 | return; | ||
438 | } | ||
439 | |||
388 | for (i = 0; i < argc - 1; i++) { | 440 | for (i = 0; i < argc - 1; i++) { |
389 | src = colon(argv[i]); | 441 | src = colon(argv[i]); |
390 | if (src) { /* remote to remote */ | 442 | if (src) { /* remote to remote */ |
391 | static char *ssh_options = | 443 | freeargs(&alist); |
392 | "-x -o'ClearAllForwardings yes'"; | 444 | addargs(&alist, "%s", ssh_program); |
445 | if (verbose_mode) | ||
446 | addargs(&alist, "-v"); | ||
447 | addargs(&alist, "-x"); | ||
448 | addargs(&alist, "-oClearAllForwardings yes"); | ||
449 | addargs(&alist, "-n"); | ||
450 | |||
393 | *src++ = 0; | 451 | *src++ = 0; |
394 | if (*src == 0) | 452 | if (*src == 0) |
395 | src = "."; | 453 | src = "."; |
396 | host = strrchr(argv[i], '@'); | 454 | host = strrchr(argv[i], '@'); |
397 | len = strlen(ssh_program) + strlen(argv[i]) + | 455 | |
398 | strlen(src) + (tuser ? strlen(tuser) : 0) + | ||
399 | strlen(thost) + strlen(targ) + | ||
400 | strlen(ssh_options) + CMDNEEDS + 20; | ||
401 | bp = xmalloc(len); | ||
402 | if (host) { | 456 | if (host) { |
403 | *host++ = 0; | 457 | *host++ = 0; |
404 | host = cleanhostname(host); | 458 | host = cleanhostname(host); |
405 | suser = argv[i]; | 459 | suser = argv[i]; |
406 | if (*suser == '\0') | 460 | if (*suser == '\0') |
407 | suser = pwd->pw_name; | 461 | suser = pwd->pw_name; |
408 | else if (!okname(suser)) { | 462 | else if (!okname(suser)) |
409 | xfree(bp); | ||
410 | continue; | 463 | continue; |
411 | } | 464 | addargs(&alist, "-l"); |
412 | if (tuser && !okname(tuser)) { | 465 | addargs(&alist, "%s", suser); |
413 | xfree(bp); | ||
414 | continue; | ||
415 | } | ||
416 | snprintf(bp, len, | ||
417 | "%s%s %s -n " | ||
418 | "-l %s %s %s %s '%s%s%s:%s'", | ||
419 | ssh_program, verbose_mode ? " -v" : "", | ||
420 | ssh_options, suser, host, cmd, src, | ||
421 | tuser ? tuser : "", tuser ? "@" : "", | ||
422 | thost, targ); | ||
423 | } else { | 466 | } else { |
424 | host = cleanhostname(argv[i]); | 467 | host = cleanhostname(argv[i]); |
425 | snprintf(bp, len, | ||
426 | "exec %s%s %s -n %s " | ||
427 | "%s %s '%s%s%s:%s'", | ||
428 | ssh_program, verbose_mode ? " -v" : "", | ||
429 | ssh_options, host, cmd, src, | ||
430 | tuser ? tuser : "", tuser ? "@" : "", | ||
431 | thost, targ); | ||
432 | } | 468 | } |
433 | if (verbose_mode) | 469 | addargs(&alist, "%s", host); |
434 | fprintf(stderr, "Executing: %s\n", bp); | 470 | addargs(&alist, "%s", cmd); |
435 | if (system(bp) != 0) | 471 | addargs(&alist, "%s", src); |
472 | addargs(&alist, "%s%s%s:%s", | ||
473 | tuser ? tuser : "", tuser ? "@" : "", | ||
474 | thost, targ); | ||
475 | if (do_local_cmd(&alist) != 0) | ||
436 | errs = 1; | 476 | errs = 1; |
437 | (void) xfree(bp); | ||
438 | } else { /* local to remote */ | 477 | } else { /* local to remote */ |
439 | if (remin == -1) { | 478 | if (remin == -1) { |
440 | len = strlen(targ) + CMDNEEDS + 20; | 479 | len = strlen(targ) + CMDNEEDS + 20; |
@@ -458,20 +497,23 @@ tolocal(int argc, char **argv) | |||
458 | { | 497 | { |
459 | int i, len; | 498 | int i, len; |
460 | char *bp, *host, *src, *suser; | 499 | char *bp, *host, *src, *suser; |
500 | arglist alist; | ||
501 | |||
502 | memset(&alist, '\0', sizeof(alist)); | ||
503 | alist.list = NULL; | ||
461 | 504 | ||
462 | for (i = 0; i < argc - 1; i++) { | 505 | for (i = 0; i < argc - 1; i++) { |
463 | if (!(src = colon(argv[i]))) { /* Local to local. */ | 506 | if (!(src = colon(argv[i]))) { /* Local to local. */ |
464 | len = strlen(_PATH_CP) + strlen(argv[i]) + | 507 | freeargs(&alist); |
465 | strlen(argv[argc - 1]) + 20; | 508 | addargs(&alist, "%s", _PATH_CP); |
466 | bp = xmalloc(len); | 509 | if (iamrecursive) |
467 | (void) snprintf(bp, len, "exec %s%s%s %s %s", _PATH_CP, | 510 | addargs(&alist, "-r"); |
468 | iamrecursive ? " -r" : "", pflag ? " -p" : "", | 511 | if (pflag) |
469 | argv[i], argv[argc - 1]); | 512 | addargs(&alist, "-p"); |
470 | if (verbose_mode) | 513 | addargs(&alist, "%s", argv[i]); |
471 | fprintf(stderr, "Executing: %s\n", bp); | 514 | addargs(&alist, "%s", argv[argc-1]); |
472 | if (system(bp)) | 515 | if (do_local_cmd(&alist)) |
473 | ++errs; | 516 | ++errs; |
474 | (void) xfree(bp); | ||
475 | continue; | 517 | continue; |
476 | } | 518 | } |
477 | *src++ = 0; | 519 | *src++ = 0; |