Index: misc.c =================================================================== RCS file: /cvs/src/usr.bin/ssh/misc.c,v retrieving revision 1.41 retrieving revision 1.42 diff -u -p -r1.41 -r1.42 --- scpmisc.c 5 Jan 2006 23:43:53 -0000 1.41 +++ scpmisc.c 31 Jan 2006 10:19:02 -0000 1.42 @@ -383,12 +383,15 @@ void addargs(arglist *args, char *fmt, ...) { va_list ap; - char buf[1024]; + char *cp; - int nalloc; + u_int nalloc; + int r; va_start(ap, fmt); - vsnprintf(buf, sizeof(buf), fmt, ap); + r = vasprintf(&cp, fmt, ap); va_end(ap); + if (r == -1) + fatal("addargs: argument too long"); nalloc = args->nalloc; if (args->list == NULL) { @@ -399,6 +402,40 @@ addargs(arglist *args, char *fmt, ...) args->list = xrealloc(args->list, nalloc * sizeof(char *)); args->nalloc = nalloc; - args->list[args->num++] = xstrdup(buf); + args->list[args->num++] = cp; args->list[args->num] = NULL; +} + +void +replacearg(arglist *args, u_int which, char *fmt, ...) +{ + va_list ap; + char *cp; + int r; + + va_start(ap, fmt); + r = vasprintf(&cp, fmt, ap); + va_end(ap); + if (r == -1) + fatal("replacearg: argument too long"); + + if (which >= args->num) + fatal("replacearg: tried to replace invalid arg %d >= %d", + which, args->num); + xfree(args->list[which]); + args->list[which] = cp; +} + +void +freeargs(arglist *args) +{ + u_int i; + + if (args->list != NULL) { + for (i = 0; i < args->num; i++) + xfree(args->list[i]); + xfree(args->list); + args->nalloc = args->num = 0; + args->list = NULL; + } } Index: misc.h =================================================================== RCS file: /cvs/src/usr.bin/ssh/misc.h,v retrieving revision 1.28 retrieving revision 1.29 diff -u -p -r1.28 -r1.29 --- scpmisc.h 8 Dec 2005 18:34:11 -0000 1.28 +++ scpmisc.h 31 Jan 2006 10:19:02 -0000 1.29 @@ -38,10 +38,20 @@ struct arglist { typedef struct arglist arglist; struct arglist { char **list; - int num; - int nalloc; + u_int num; + u_int nalloc; }; -void addargs(arglist *, char *, ...); +void addargs(arglist *, char *, ...) + __attribute__((format(printf, 2, 3))); +void replacearg(arglist *, u_int, char *, ...) + __attribute__((format(printf, 3, 4))); +void freeargs(arglist *); + +#define fatal(fmt, args...) \ + do { \ + fprintf(stderr, fmt, ## args); \ + exit (255); \ + } while (0) /* from xmalloc.h */ void *xmalloc(size_t); Index: scp.c =================================================================== RCS file: /cvs/src/usr.bin/ssh/scp.c,v retrieving revision 1.128 retrieving revision 1.129 diff -u -p -r1.128 -r1.129 --- scp.c 6 Dec 2005 22:38:27 -0000 1.128 +++ scp.c 31 Jan 2006 10:19:02 -0000 1.129 @@ -118,6 +118,48 @@ killchild(int signo) _exit(1); } +static int +do_local_cmd(arglist *a) +{ + u_int i; + int status; + pid_t pid; + + if (a->num == 0) + fatal("do_local_cmd: no arguments"); + + if (verbose_mode) { + fprintf(stderr, "Executing:"); + for (i = 0; i < a->num; i++) + fprintf(stderr, " %s", a->list[i]); + fprintf(stderr, "\n"); + } + if ((pid = fork()) == -1) + fatal("do_local_cmd: fork: %s", strerror(errno)); + + if (pid == 0) { + execvp(a->list[0], a->list); + perror(a->list[0]); + exit(1); + } + + do_cmd_pid = pid; + signal(SIGTERM, killchild); + signal(SIGINT, killchild); + signal(SIGHUP, killchild); + + while (waitpid(pid, &status, 0) == -1) + if (errno != EINTR) + fatal("do_local_cmd: waitpid: %s", strerror(errno)); + + do_cmd_pid = -1; + + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) + return (-1); + + return (0); +} + /* * This function executes the given command as the specified user on the * given host. This returns < 0 if execution fails, and >= 0 otherwise. This @@ -162,7 +204,7 @@ do_cmd(char *host, char *remuser, char * close(pin[0]); close(pout[1]); - args.list[0] = ssh_program; + replacearg(&args, 0, "%s", ssh_program); if (remuser != NULL) { addargs(&args, "-l"); addargs(&args, "%s", remuser); @@ -225,8 +267,9 @@ main(int argc, char **argv) extern char *optarg; extern int optind; + memset(&args, '\0', sizeof(args)); args.list = NULL; - addargs(&args, "ssh"); /* overwritten with ssh_program */ + addargs(&args, "%s", ssh_program); addargs(&args, "-x"); addargs(&args, "-oForwardAgent no"); addargs(&args, "-oClearAllForwardings yes"); @@ -363,6 +406,10 @@ toremote(char *targ, int argc, char **ar { int i, len; char *bp, *host, *src, *suser, *thost, *tuser; + arglist alist; + + memset(&alist, '\0', sizeof(alist)); + alist.list = NULL; *targ++ = 0; if (*targ == 0) @@ -380,55 +427,46 @@ toremote(char *targ, int argc, char **ar tuser = NULL; } + if (tuser != NULL && !okname(tuser)) + return; + for (i = 0; i < argc - 1; i++) { src = colon(argv[i]); if (src) { /* remote to remote */ - static char *ssh_options = - "-x -o'ClearAllForwardings yes'"; + freeargs(&alist); + addargs(&alist, "%s", ssh_program); + if (verbose_mode) + addargs(&alist, "-v"); + addargs(&alist, "-x"); + addargs(&alist, "-oClearAllForwardings yes"); + addargs(&alist, "-n"); + *src++ = 0; if (*src == 0) src = "."; host = strrchr(argv[i], '@'); - len = strlen(ssh_program) + strlen(argv[i]) + - strlen(src) + (tuser ? strlen(tuser) : 0) + - strlen(thost) + strlen(targ) + - strlen(ssh_options) + CMDNEEDS + 20; - bp = xmalloc(len); + if (host) { *host++ = 0; host = cleanhostname(host); suser = argv[i]; if (*suser == '\0') suser = pwd->pw_name; - else if (!okname(suser)) { - xfree(bp); - continue; - } - if (tuser && !okname(tuser)) { - xfree(bp); + else if (!okname(suser)) continue; - } - snprintf(bp, len, - "%s%s %s -n " - "-l %s %s %s %s '%s%s%s:%s'", - ssh_program, verbose_mode ? " -v" : "", - ssh_options, suser, host, cmd, src, - tuser ? tuser : "", tuser ? "@" : "", - thost, targ); + addargs(&alist, "-l"); + addargs(&alist, "%s", suser); } else { host = cleanhostname(argv[i]); - snprintf(bp, len, - "exec %s%s %s -n %s " - "%s %s '%s%s%s:%s'", - ssh_program, verbose_mode ? " -v" : "", - ssh_options, host, cmd, src, - tuser ? tuser : "", tuser ? "@" : "", - thost, targ); } - if (verbose_mode) - fprintf(stderr, "Executing: %s\n", bp); - (void) system(bp); + addargs(&alist, "%s", host); + addargs(&alist, "%s", cmd); + addargs(&alist, "%s", src); + addargs(&alist, "%s%s%s:%s", + tuser ? tuser : "", tuser ? "@" : "", + thost, targ); + if (do_local_cmd(&alist) != 0) + errs = 1; - (void) xfree(bp); } else { /* local to remote */ if (remin == -1) { len = strlen(targ) + CMDNEEDS + 20; @@ -453,20 +492,23 @@ tolocal(int argc, char **argv) { int i, len; char *bp, *host, *src, *suser; + arglist alist; + + memset(&alist, '\0', sizeof(alist)); + alist.list = NULL; for (i = 0; i < argc - 1; i++) { if (!(src = colon(argv[i]))) { /* Local to local. */ - len = strlen(_PATH_CP) + strlen(argv[i]) + - strlen(argv[argc - 1]) + 20; - bp = xmalloc(len); - (void) snprintf(bp, len, "exec %s%s%s %s %s", _PATH_CP, - iamrecursive ? " -r" : "", pflag ? " -p" : "", - argv[i], argv[argc - 1]); - if (verbose_mode) - fprintf(stderr, "Executing: %s\n", bp); - if (system(bp)) + freeargs(&alist); + addargs(&alist, "%s", _PATH_CP); + if (iamrecursive) + addargs(&alist, "-r"); + if (pflag) + addargs(&alist, "-p"); + addargs(&alist, "%s", argv[i]); + addargs(&alist, "%s", argv[argc-1]); + if (do_local_cmd(&alist)) ++errs; - (void) xfree(bp); continue; } *src++ = 0;