comparison scp.c @ 302:973fccb59ea4 ucc-axis-hack

propagate from branch 'au.asn.ucc.matt.dropbear' (head 11034278bd1917bebcbdc69cf53b1891ce9db121) to branch 'au.asn.ucc.matt.dropbear.ucc-axis-hack' (head 10a1f614fec73d0820c3f61160d9db409b9beb46)
author Matt Johnston <matt@ucc.asn.au>
date Sat, 25 Mar 2006 12:59:58 +0000
parents 740e782679be 497fddd4a94e
children b27fcd28f9dc
comparison
equal deleted inserted replaced
299:740e782679be 302:973fccb59ea4
69 * SUCH DAMAGE. 69 * SUCH DAMAGE.
70 * 70 *
71 */ 71 */
72 72
73 #include "includes.h" 73 #include "includes.h"
74 /*RCSID("$OpenBSD: scp.c,v 1.130 2006/01/31 10:35:43 djm Exp $");*/
75
74 #include "atomicio.h" 76 #include "atomicio.h"
75 #include "compat.h" 77 #include "compat.h"
76 #include "scpmisc.h" 78 #include "scpmisc.h"
77 #include "progressmeter.h" 79 #include "progressmeter.h"
78 80
79 #define _PATH_CP "/bin/cp"
80
81 #ifndef TIMEVAL_TO_TIMESPEC
82 #define TIMEVAL_TO_TIMESPEC(tv, ts) { \
83 (ts)->tv_sec = (tv)->tv_sec; \
84 (ts)->tv_nsec = (tv)->tv_usec * 1000; \
85 }
86 #endif
87
88 #ifndef timersub
89 #define timersub(tvp, uvp, vvp) \
90 do { \
91 (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \
92 (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \
93 if ((vvp)->tv_usec < 0) { \
94 (vvp)->tv_sec--; \
95 (vvp)->tv_usec += 1000000; \
96 } \
97 } while (/* CONSTCOND */ 0)
98 #endif /* timersub */
99
100
101 void bwlimit(int); 81 void bwlimit(int);
102 82
103 /* Struct for addargs */ 83 /* Struct for addargs */
104 arglist args; 84 arglist args;
105 85
106 /* Bandwidth limit */ 86 /* Bandwidth limit */
107 off_t limitbw = 0; 87 off_t limit_rate = 0;
108 88
109 /* Name of current file being transferred. */ 89 /* Name of current file being transferred. */
110 char *curfile; 90 char *curfile;
111 91
112 /* This is set to non-zero to enable verbose mode. */ 92 /* This is set to non-zero to enable verbose mode. */
113 int verbose_mode = 0; 93 int verbose_mode = 0;
114 94
115 #ifdef PROGRESS_METER
116 /* This is set to zero if the progressmeter is not desired. */ 95 /* This is set to zero if the progressmeter is not desired. */
117 int showprogress = 1; 96 int showprogress = 1;
118 #endif
119 97
120 /* This is the program to execute for the secured connection. ("ssh" or -S) */ 98 /* This is the program to execute for the secured connection. ("ssh" or -S) */
121 char *ssh_program = _PATH_SSH_PROGRAM; 99 char *ssh_program = _PATH_SSH_PROGRAM;
122 100
123 /* This is used to store the pid of ssh_program */ 101 /* This is used to store the pid of ssh_program */
124 pid_t do_cmd_pid = -1; 102 pid_t do_cmd_pid = -1;
125 103
126 static void 104 static void
127 killchild(int signo) 105 killchild(int signo)
128 { 106 {
129 if (do_cmd_pid > 1) 107 if (do_cmd_pid > 1) {
130 kill(do_cmd_pid, signo); 108 kill(do_cmd_pid, signo ? signo : SIGTERM);
131 109 waitpid(do_cmd_pid, NULL, 0);
132 _exit(1); 110 }
111
112 if (signo)
113 _exit(1);
114 exit(1);
115 }
116
117 static int
118 do_local_cmd(arglist *a)
119 {
120 u_int i;
121 int status;
122 pid_t pid;
123
124 if (a->num == 0)
125 fatal("do_local_cmd: no arguments");
126
127 if (verbose_mode) {
128 fprintf(stderr, "Executing:");
129 for (i = 0; i < a->num; i++)
130 fprintf(stderr, " %s", a->list[i]);
131 fprintf(stderr, "\n");
132 }
133 if ((pid = fork()) == -1)
134 fatal("do_local_cmd: fork: %s", strerror(errno));
135
136 if (pid == 0) {
137 execvp(a->list[0], a->list);
138 perror(a->list[0]);
139 exit(1);
140 }
141
142 do_cmd_pid = pid;
143 signal(SIGTERM, killchild);
144 signal(SIGINT, killchild);
145 signal(SIGHUP, killchild);
146
147 while (waitpid(pid, &status, 0) == -1)
148 if (errno != EINTR)
149 fatal("do_local_cmd: waitpid: %s", strerror(errno));
150
151 do_cmd_pid = -1;
152
153 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
154 return (-1);
155
156 return (0);
133 } 157 }
134 158
135 /* 159 /*
136 * This function executes the given command as the specified user on the 160 * This function executes the given command as the specified user on the
137 * given host. This returns < 0 if execution fails, and >= 0 otherwise. This 161 * given host. This returns < 0 if execution fails, and >= 0 otherwise. This
154 * descriptors 0 and 1 because that will screw up dup2 below. 178 * descriptors 0 and 1 because that will screw up dup2 below.
155 */ 179 */
156 pipe(reserved); 180 pipe(reserved);
157 181
158 /* Create a socket pair for communicating with ssh. */ 182 /* Create a socket pair for communicating with ssh. */
159 if (pipe(pin) < 0 || pipe(pout) < 0) 183 if (pipe(pin) < 0)
160 { 184 fatal("pipe: %s", strerror(errno));
161 printf( "Fatal error: pipe: %s\n", strerror(errno)); 185 if (pipe(pout) < 0)
162 exit(1); 186 fatal("pipe: %s", strerror(errno));
163 }
164 187
165 /* Free the reserved descriptors. */ 188 /* Free the reserved descriptors. */
166 close(reserved[0]); 189 close(reserved[0]);
167 close(reserved[1]); 190 close(reserved[1]);
168 191
169 // uClinux needs to build the args here before vforking, 192 /* uClinux needs to build the args here before vforking,
170 // otherwise we do it later on. 193 otherwise we do it later on. */
171 #ifdef __uClinux__ 194 #ifdef __uClinux__
172 args.list[0] = ssh_program; 195 replacearg(&args, 0, "%s", ssh_program);
173 if (remuser != NULL) 196 if (remuser != NULL)
174 addargs(&args, "-l%s", remuser); 197 addargs(&args, "-l%s", remuser);
175 addargs(&args, "%s", host); 198 addargs(&args, "%s", host);
176 addargs(&args, "%s", cmd); 199 addargs(&args, "%s", cmd);
177 #endif /* __uClinux__ */ 200 #endif /* __uClinux__ */
178 201
179 /* Fork a child to execute the command on the remote host using ssh. */ 202 /* Fork a child to execute the command on the remote host using ssh. */
180 #ifdef __uClinux__ 203 #ifndef __uClinux__
181 do_cmd_pid = vfork(); 204 do_cmd_pid = vfork();
182 #else 205 #else
183 do_cmd_pid = fork(); 206 do_cmd_pid = fork();
184 #endif /* __uClinux__ */ 207 #endif /* __uClinux__ */
208
185 if (do_cmd_pid == 0) { 209 if (do_cmd_pid == 0) {
186 /* Child. */ 210 /* Child. */
187 close(pin[1]); 211 close(pin[1]);
188 close(pout[0]); 212 close(pout[0]);
189 dup2(pin[0], 0); 213 dup2(pin[0], 0);
190 dup2(pout[1], 1); 214 dup2(pout[1], 1);
191 close(pin[0]); 215 close(pin[0]);
192 close(pout[1]); 216 close(pout[1]);
193 217
194 #ifndef __uClinux__ 218 #ifndef __uClinux__
195 args.list[0] = ssh_program; 219 replacearg(&args, 0, "%s", ssh_program);
196 if (remuser != NULL) { 220 if (remuser != NULL)
197 addargs(&args, "-l"); 221 addargs(&args, "-l%s", remuser);
198 addargs(&args, "%s", remuser);
199 }
200 addargs(&args, "%s", host); 222 addargs(&args, "%s", host);
201 addargs(&args, "%s", cmd); 223 addargs(&args, "%s", cmd);
202 #endif 224 #endif /* __uClinux__ */
203 225
204 execvp(ssh_program, args.list); 226 execvp(ssh_program, args.list);
205 perror(ssh_program); 227 perror(ssh_program);
206 exit(1); 228 exit(1);
207 } else if (do_cmd_pid == -1) { 229 } else if (do_cmd_pid == -1) {
208 printf( "Fatal error: fork: %s\n", strerror(errno)); 230 fatal("fork: %s", strerror(errno));
209 exit(1); 231 }
210 } 232
211 233
212 #if 0 //__uClinux__ 234 #ifdef __uClinux__
213 /* clean up command */ 235 /* clean up command */
214 /* pop cmd */ 236 /* pop cmd */
215 free(args->list[--args->num]); 237 xfree(args.list[args.num-1]);
216 args->list[args->num]=NULL; 238 args.list[args.num-1]=NULL;
239 args.num--;
217 /* pop host */ 240 /* pop host */
218 free(args->list[--args->num-1]); 241 xfree(args.list[args.num-1]);
219 args->list[args->num]=NULL; 242 args.list[args.num-1]=NULL;
243 args.num--;
220 /* pop user */ 244 /* pop user */
221 if (remuser != NULL) { 245 if (remuser != NULL) {
222 free(args->list[--args->num-1]); 246 xfree(args.list[args.num-1]);
223 args->list[args->num]=NULL; 247 args.list[args.num-1]=NULL;
248 args.num--;
224 } 249 }
225 #endif /* __uClinux__ */ 250 #endif /* __uClinux__ */
226 251
227 /* Parent. Close the other side, and return the local side. */ 252 /* Parent. Close the other side, and return the local side. */
228 close(pin[0]); 253 close(pin[0]);
229 *fdout = pin[1]; 254 *fdout = pin[1];
230 close(pout[1]); 255 close(pout[1]);
231 *fdin = pout[0]; 256 *fdin = pout[0];
234 signal(SIGHUP, killchild); 259 signal(SIGHUP, killchild);
235 return 0; 260 return 0;
236 } 261 }
237 262
238 typedef struct { 263 typedef struct {
239 int cnt; 264 size_t cnt;
240 char *buf; 265 char *buf;
241 } BUF; 266 } BUF;
242 267
243 BUF *allocbuf(BUF *, int, int); 268 BUF *allocbuf(BUF *, int, int);
244 void lostconn(int); 269 void lostconn(int);
265 290
266 #if defined(DBMULTI_scp) || !defined(DROPBEAR_MULTI) 291 #if defined(DBMULTI_scp) || !defined(DROPBEAR_MULTI)
267 #if defined(DBMULTI_scp) && defined(DROPBEAR_MULTI) 292 #if defined(DBMULTI_scp) && defined(DROPBEAR_MULTI)
268 int scp_main(int argc, char **argv) 293 int scp_main(int argc, char **argv)
269 #else 294 #else
295 int
270 main(int argc, char **argv) 296 main(int argc, char **argv)
271 #endif 297 #endif
272 { 298 {
273 int ch, fflag, tflag, status; 299 int ch, fflag, tflag, status;
274 double speed; 300 double speed;
275 char *targ, *endp; 301 char *targ, *endp;
276 extern char *optarg; 302 extern char *optarg;
277 extern int optind; 303 extern int optind;
278 304
305 /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
306 sanitise_stdfd();
307
308 memset(&args, '\0', sizeof(args));
279 args.list = NULL; 309 args.list = NULL;
280 addargs(&args, "ssh"); /* overwritten with ssh_program */ 310 addargs(&args, "%s", ssh_program);
281 addargs(&args, "-x"); 311 addargs(&args, "-x");
282 addargs(&args, "-oForwardAgent no"); 312 addargs(&args, "-oForwardAgent no");
313 addargs(&args, "-oPermitLocalCommand no");
283 addargs(&args, "-oClearAllForwardings yes"); 314 addargs(&args, "-oClearAllForwardings yes");
284 315
285 fflag = tflag = 0; 316 fflag = tflag = 0;
286 while ((ch = getopt(argc, argv, "dfl:prtvBCc:i:P:q1246S:o:F:")) != -1) 317 while ((ch = getopt(argc, argv, "dfl:prtvBCc:i:P:q1246S:o:F:")) != -1)
287 switch (ch) { 318 switch (ch) {
307 break; 338 break;
308 case 'l': 339 case 'l':
309 speed = strtod(optarg, &endp); 340 speed = strtod(optarg, &endp);
310 if (speed <= 0 || *endp != '\0') 341 if (speed <= 0 || *endp != '\0')
311 usage(); 342 usage();
312 limitbw = speed * 1024; 343 limit_rate = speed * 1024;
313 break; 344 break;
314 case 'p': 345 case 'p':
315 pflag = 1; 346 pflag = 1;
316 break; 347 break;
317 case 'r': 348 case 'r':
324 addargs(&args, "-v"); 355 addargs(&args, "-v");
325 verbose_mode = 1; 356 verbose_mode = 1;
326 break; 357 break;
327 #ifdef PROGRESS_METER 358 #ifdef PROGRESS_METER
328 case 'q': 359 case 'q':
360 addargs(&args, "-q");
329 showprogress = 0; 361 showprogress = 0;
330 break; 362 break;
331 #endif 363 #endif
332 364
333 /* Server options. */ 365 /* Server options. */
349 usage(); 381 usage();
350 } 382 }
351 argc -= optind; 383 argc -= optind;
352 argv += optind; 384 argv += optind;
353 385
354 if ((pwd = getpwuid(userid = getuid())) == NULL) { 386 if ((pwd = getpwuid(userid = getuid())) == NULL)
355 printf( "unknown user %u", (u_int) userid); 387 fatal("unknown user %u", (u_int) userid);
356 } 388
357
358 #ifdef PROGRESS_METER
359 if (!isatty(STDERR_FILENO)) 389 if (!isatty(STDERR_FILENO))
360 showprogress = 0; 390 showprogress = 0;
361 #endif
362 391
363 remin = STDIN_FILENO; 392 remin = STDIN_FILENO;
364 remout = STDOUT_FILENO; 393 remout = STDOUT_FILENO;
365 394
366 if (fflag) { 395 if (fflag) {
390 (void) signal(SIGPIPE, lostconn); 419 (void) signal(SIGPIPE, lostconn);
391 420
392 if ((targ = colon(argv[argc - 1]))) /* Dest is remote host. */ 421 if ((targ = colon(argv[argc - 1]))) /* Dest is remote host. */
393 toremote(targ, argc, argv); 422 toremote(targ, argc, argv);
394 else { 423 else {
395 tolocal(argc, argv); /* Dest is local host. */
396 if (targetshouldbedirectory) 424 if (targetshouldbedirectory)
397 verifydir(argv[argc - 1]); 425 verifydir(argv[argc - 1]);
426 tolocal(argc, argv); /* Dest is local host. */
398 } 427 }
399 /* 428 /*
400 * Finally check the exit status of the ssh process, if one was forked 429 * Finally check the exit status of the ssh process, if one was forked
401 * and no error has occured yet 430 * and no error has occured yet
402 */ 431 */
412 errs = 1; 441 errs = 1;
413 } 442 }
414 } 443 }
415 exit(errs != 0); 444 exit(errs != 0);
416 } 445 }
417 #endif /* DBMULTI stuff */ 446 #endif /* DBMULTI_scp stuff */
418 447
419 void 448 void
420 toremote(char *targ, int argc, char **argv) 449 toremote(char *targ, int argc, char **argv)
421 { 450 {
422 int i, len; 451 int i, len;
423 char *bp, *host, *src, *suser, *thost, *tuser; 452 char *bp, *host, *src, *suser, *thost, *tuser, *arg;
453 arglist alist;
454
455 memset(&alist, '\0', sizeof(alist));
456 alist.list = NULL;
424 457
425 *targ++ = 0; 458 *targ++ = 0;
426 if (*targ == 0) 459 if (*targ == 0)
427 targ = "."; 460 targ = ".";
428 461
429 if ((thost = strrchr(argv[argc - 1], '@'))) { 462 arg = xstrdup(argv[argc - 1]);
463 if ((thost = strrchr(arg, '@'))) {
430 /* user@host */ 464 /* user@host */
431 *thost++ = 0; 465 *thost++ = 0;
432 tuser = argv[argc - 1]; 466 tuser = arg;
433 if (*tuser == '\0') 467 if (*tuser == '\0')
434 tuser = NULL; 468 tuser = NULL;
435 } else { 469 } else {
436 thost = argv[argc - 1]; 470 thost = arg;
437 tuser = NULL; 471 tuser = NULL;
472 }
473
474 if (tuser != NULL && !okname(tuser)) {
475 xfree(arg);
476 return;
438 } 477 }
439 478
440 for (i = 0; i < argc - 1; i++) { 479 for (i = 0; i < argc - 1; i++) {
441 src = colon(argv[i]); 480 src = colon(argv[i]);
442 if (src) { /* remote to remote */ 481 if (src) { /* remote to remote */
443 static char *ssh_options = 482 freeargs(&alist);
444 "-x -o'ClearAllForwardings yes'"; 483 addargs(&alist, "%s", ssh_program);
484 if (verbose_mode)
485 addargs(&alist, "-v");
486 addargs(&alist, "-x");
487 addargs(&alist, "-oClearAllForwardings yes");
488 addargs(&alist, "-n");
489
445 *src++ = 0; 490 *src++ = 0;
446 if (*src == 0) 491 if (*src == 0)
447 src = "."; 492 src = ".";
448 host = strrchr(argv[i], '@'); 493 host = strrchr(argv[i], '@');
449 len = strlen(ssh_program) + strlen(argv[i]) + 494
450 strlen(src) + (tuser ? strlen(tuser) : 0) +
451 strlen(thost) + strlen(targ) +
452 strlen(ssh_options) + CMDNEEDS + 20;
453 bp = xmalloc(len);
454 if (host) { 495 if (host) {
455 *host++ = 0; 496 *host++ = 0;
456 host = cleanhostname(host); 497 host = cleanhostname(host);
457 suser = argv[i]; 498 suser = argv[i];
458 if (*suser == '\0') 499 if (*suser == '\0')
459 suser = pwd->pw_name; 500 suser = pwd->pw_name;
460 else if (!okname(suser)) { 501 else if (!okname(suser))
461 xfree(bp);
462 continue; 502 continue;
463 } 503 addargs(&alist, "-l");
464 if (tuser && !okname(tuser)) { 504 addargs(&alist, "%s", suser);
465 xfree(bp);
466 continue;
467 }
468 snprintf(bp, len,
469 "%s%s %s -n "
470 "-l %s %s %s %s '%s%s%s:%s'",
471 ssh_program, verbose_mode ? " -v" : "",
472 ssh_options, suser, host, cmd, src,
473 tuser ? tuser : "", tuser ? "@" : "",
474 thost, targ);
475 } else { 505 } else {
476 host = cleanhostname(argv[i]); 506 host = cleanhostname(argv[i]);
477 snprintf(bp, len,
478 "exec %s%s %s -n %s "
479 "%s %s '%s%s%s:%s'",
480 ssh_program, verbose_mode ? " -v" : "",
481 ssh_options, host, cmd, src,
482 tuser ? tuser : "", tuser ? "@" : "",
483 thost, targ);
484 } 507 }
485 if (verbose_mode) 508 addargs(&alist, "%s", host);
486 printf( "Executing: %s\n", bp); 509 addargs(&alist, "%s", cmd);
487 (void) system(bp); 510 addargs(&alist, "%s", src);
488 (void) xfree(bp); 511 addargs(&alist, "%s%s%s:%s",
512 tuser ? tuser : "", tuser ? "@" : "",
513 thost, targ);
514 if (do_local_cmd(&alist) != 0)
515 errs = 1;
489 } else { /* local to remote */ 516 } else { /* local to remote */
490 if (remin == -1) { 517 if (remin == -1) {
491 len = strlen(targ) + CMDNEEDS + 20; 518 len = strlen(targ) + CMDNEEDS + 20;
492 bp = xmalloc(len); 519 bp = xmalloc(len);
493 (void) snprintf(bp, len, "%s -t %s", cmd, targ); 520 (void) snprintf(bp, len, "%s -t %s", cmd, targ);
507 void 534 void
508 tolocal(int argc, char **argv) 535 tolocal(int argc, char **argv)
509 { 536 {
510 int i, len; 537 int i, len;
511 char *bp, *host, *src, *suser; 538 char *bp, *host, *src, *suser;
539 arglist alist;
540
541 memset(&alist, '\0', sizeof(alist));
542 alist.list = NULL;
512 543
513 for (i = 0; i < argc - 1; i++) { 544 for (i = 0; i < argc - 1; i++) {
514 if (!(src = colon(argv[i]))) { /* Local to local. */ 545 if (!(src = colon(argv[i]))) { /* Local to local. */
515 len = strlen(_PATH_CP) + strlen(argv[i]) + 546 freeargs(&alist);
516 strlen(argv[argc - 1]) + 20; 547 addargs(&alist, "%s", _PATH_CP);
517 bp = xmalloc(len); 548 if (iamrecursive)
518 (void) snprintf(bp, len, "exec %s%s%s %s %s", _PATH_CP, 549 addargs(&alist, "-r");
519 iamrecursive ? " -r" : "", pflag ? " -p" : "", 550 if (pflag)
520 argv[i], argv[argc - 1]); 551 addargs(&alist, "-p");
521 if (verbose_mode) 552 addargs(&alist, "%s", argv[i]);
522 printf( "Executing: %s\n", bp); 553 addargs(&alist, "%s", argv[argc-1]);
523 if (system(bp)) 554 if (do_local_cmd(&alist))
524 ++errs; 555 ++errs;
525 (void) xfree(bp);
526 continue; 556 continue;
527 } 557 }
528 *src++ = 0; 558 *src++ = 0;
529 if (*src == 0) 559 if (*src == 0)
530 src = "."; 560 src = ".";
557 source(int argc, char **argv) 587 source(int argc, char **argv)
558 { 588 {
559 struct stat stb; 589 struct stat stb;
560 static BUF buffer; 590 static BUF buffer;
561 BUF *bp; 591 BUF *bp;
562 off_t i, amt, result, statbytes; 592 off_t i, amt, statbytes;
563 int fd, haderr, indx; 593 size_t result;
594 int fd = -1, haderr, indx;
564 char *last, *name, buf[2048]; 595 char *last, *name, buf[2048];
565 int len; 596 int len;
566 597
567 for (indx = 0; indx < argc; ++indx) { 598 for (indx = 0; indx < argc; ++indx) {
568 name = argv[indx]; 599 name = argv[indx];
612 goto next; 643 goto next;
613 } 644 }
614 #define FILEMODEMASK (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO) 645 #define FILEMODEMASK (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO)
615 snprintf(buf, sizeof buf, "C%04o %lld %s\n", 646 snprintf(buf, sizeof buf, "C%04o %lld %s\n",
616 (u_int) (stb.st_mode & FILEMODEMASK), 647 (u_int) (stb.st_mode & FILEMODEMASK),
617 (int64_t)stb.st_size, last); 648 (long long)stb.st_size, last);
618 if (verbose_mode) { 649 if (verbose_mode) {
619 printf( "Sending file modes: %s", buf); 650 printf( "Sending file modes: %s", buf);
620 } 651 }
621 (void) atomicio(vwrite, remout, buf, strlen(buf)); 652 (void) atomicio(vwrite, remout, buf, strlen(buf));
622 if (response() < 0) 653 if (response() < 0)
623 goto next; 654 goto next;
624 if ((bp = allocbuf(&buffer, fd, 2048)) == NULL) { 655 if ((bp = allocbuf(&buffer, fd, 2048)) == NULL) {
625 next: (void) close(fd); 656 next: if (fd != -1) {
657 (void) close(fd);
658 fd = -1;
659 }
626 continue; 660 continue;
627 } 661 }
628 #ifdef PROGRESS_METER 662 #if PROGRESS_METER
629 if (showprogress) 663 if (showprogress)
630 start_progress_meter(curfile, stb.st_size, &statbytes); 664 start_progress_meter(curfile, stb.st_size, &statbytes);
631 #endif 665 #endif
632 /* Keep writing after an error so that we stay sync'd up. */ 666 /* Keep writing after an error so that we stay sync'd up. */
633 for (haderr = i = 0; i < stb.st_size; i += bp->cnt) { 667 for (haderr = i = 0; i < stb.st_size; i += bp->cnt) {
635 if (i + amt > stb.st_size) 669 if (i + amt > stb.st_size)
636 amt = stb.st_size - i; 670 amt = stb.st_size - i;
637 if (!haderr) { 671 if (!haderr) {
638 result = atomicio(read, fd, bp->buf, amt); 672 result = atomicio(read, fd, bp->buf, amt);
639 if (result != amt) 673 if (result != amt)
640 haderr = result >= 0 ? EIO : errno; 674 haderr = errno;
641 } 675 }
642 if (haderr) 676 if (haderr)
643 (void) atomicio(vwrite, remout, bp->buf, amt); 677 (void) atomicio(vwrite, remout, bp->buf, amt);
644 else { 678 else {
645 result = atomicio(vwrite, remout, bp->buf, amt); 679 result = atomicio(vwrite, remout, bp->buf, amt);
646 if (result != amt) 680 if (result != amt)
647 haderr = result >= 0 ? EIO : errno; 681 haderr = errno;
648 statbytes += result; 682 statbytes += result;
649 } 683 }
650 if (limitbw) 684 if (limit_rate)
651 bwlimit(amt); 685 bwlimit(amt);
652 } 686 }
653 #ifdef PROGRESS_METER 687 #ifdef PROGRESS_METER
654 if (showprogress) 688 if (showprogress)
655 stop_progress_meter(); 689 stop_progress_meter();
656 #endif 690 #endif
657 691
658 if (close(fd) < 0 && !haderr) 692 if (fd != -1) {
659 haderr = errno; 693 if (close(fd) < 0 && !haderr)
694 haderr = errno;
695 fd = -1;
696 }
660 if (!haderr) 697 if (!haderr)
661 (void) atomicio(vwrite, remout, "", 1); 698 (void) atomicio(vwrite, remout, "", 1);
662 else 699 else
663 run_err("%s: %s", name, strerror(haderr)); 700 run_err("%s: %s", name, strerror(haderr));
664 (void) response(); 701 (void) response();
721 void 758 void
722 bwlimit(int amount) 759 bwlimit(int amount)
723 { 760 {
724 static struct timeval bwstart, bwend; 761 static struct timeval bwstart, bwend;
725 static int lamt, thresh = 16384; 762 static int lamt, thresh = 16384;
726 uint64_t wait; 763 u_int64_t waitlen;
727 struct timespec ts, rm; 764 struct timespec ts, rm;
728 765
729 if (!timerisset(&bwstart)) { 766 if (!timerisset(&bwstart)) {
730 gettimeofday(&bwstart, NULL); 767 gettimeofday(&bwstart, NULL);
731 return; 768 return;
739 timersub(&bwend, &bwstart, &bwend); 776 timersub(&bwend, &bwstart, &bwend);
740 if (!timerisset(&bwend)) 777 if (!timerisset(&bwend))
741 return; 778 return;
742 779
743 lamt *= 8; 780 lamt *= 8;
744 wait = (double)1000000L * lamt / limitbw; 781 waitlen = (double)1000000L * lamt / limit_rate;
745 782
746 bwstart.tv_sec = wait / 1000000L; 783 bwstart.tv_sec = waitlen / 1000000L;
747 bwstart.tv_usec = wait % 1000000L; 784 bwstart.tv_usec = waitlen % 1000000L;
748 785
749 if (timercmp(&bwstart, &bwend, >)) { 786 if (timercmp(&bwstart, &bwend, >)) {
750 timersub(&bwstart, &bwend, &bwend); 787 timersub(&bwstart, &bwend, &bwend);
751 788
752 /* Adjust the wait time */ 789 /* Adjust the wait time */
779 struct stat stb; 816 struct stat stb;
780 enum { 817 enum {
781 YES, NO, DISPLAYED 818 YES, NO, DISPLAYED
782 } wrerr; 819 } wrerr;
783 BUF *bp; 820 BUF *bp;
784 off_t i, j; 821 off_t i;
785 int amt, count, exists, first, mask, mode, ofd, omode; 822 size_t j, count;
823 int amt, exists, first, mask, mode, ofd, omode;
786 off_t size, statbytes; 824 off_t size, statbytes;
787 int setimes, targisdir, wrerrno = 0; 825 int setimes, targisdir, wrerrno = 0;
788 char ch, *cp, *np, *targ, *why, *vect[1], buf[2048]; 826 char ch, *cp, *np, *targ, *why, *vect[1], buf[2048];
789 struct timeval tv[2]; 827 struct timeval tv[2];
790 828
791 #define atime tv[0] 829 #define atime tv[0]
792 #define mtime tv[1] 830 #define mtime tv[1]
793 #define SCREWUP(str) do { why = str; goto screwup; } while (0) 831 #define SCREWUP(str) { why = str; goto screwup; }
794 832
795 setimes = targisdir = 0; 833 setimes = targisdir = 0;
796 mask = umask(0); 834 mask = umask(0);
797 if (!pflag) 835 if (!pflag)
798 (void) umask(mask); 836 (void) umask(mask);
807 (void) atomicio(vwrite, remout, "", 1); 845 (void) atomicio(vwrite, remout, "", 1);
808 if (stat(targ, &stb) == 0 && S_ISDIR(stb.st_mode)) 846 if (stat(targ, &stb) == 0 && S_ISDIR(stb.st_mode))
809 targisdir = 1; 847 targisdir = 1;
810 for (first = 1;; first = 0) { 848 for (first = 1;; first = 0) {
811 cp = buf; 849 cp = buf;
812 if (atomicio(read, remin, cp, 1) <= 0) 850 if (atomicio(read, remin, cp, 1) != 1)
813 return; 851 return;
814 if (*cp++ == '\n') 852 if (*cp++ == '\n')
815 SCREWUP("unexpected <newline>"); 853 SCREWUP("unexpected <newline>");
816 do { 854 do {
817 if (atomicio(read, remin, &ch, sizeof(ch)) != sizeof(ch)) 855 if (atomicio(read, remin, &ch, sizeof(ch)) != sizeof(ch))
818 SCREWUP("lost connection"); 856 SCREWUP("lost connection");
819 *cp++ = ch; 857 *cp++ = ch;
820 } while (cp < &buf[sizeof(buf) - 1] && ch != '\n'); 858 } while (cp < &buf[sizeof(buf) - 1] && ch != '\n');
821 *cp = 0; 859 *cp = 0;
860 if (verbose_mode)
861 fprintf(stderr, "Sink: %s", buf);
822 862
823 if (buf[0] == '\01' || buf[0] == '\02') { 863 if (buf[0] == '\01' || buf[0] == '\02') {
824 if (iamremote == 0) 864 if (iamremote == 0)
825 (void) atomicio(vwrite, STDERR_FILENO, 865 (void) atomicio(vwrite, STDERR_FILENO,
826 buf + 1, strlen(buf + 1)); 866 buf + 1, strlen(buf + 1));
880 920
881 for (size = 0; isdigit(*cp);) 921 for (size = 0; isdigit(*cp);)
882 size = size * 10 + (*cp++ - '0'); 922 size = size * 10 + (*cp++ - '0');
883 if (*cp++ != ' ') 923 if (*cp++ != ' ')
884 SCREWUP("size not delimited"); 924 SCREWUP("size not delimited");
925 if ((strchr(cp, '/') != NULL) || (strcmp(cp, "..") == 0)) {
926 run_err("error: unexpected filename: %s", cp);
927 exit(1);
928 }
885 if (targisdir) { 929 if (targisdir) {
886 static char *namebuf; 930 static char *namebuf;
887 static int cursize; 931 static size_t cursize;
888 size_t need; 932 size_t need;
889 933
890 need = strlen(targ) + strlen(cp) + 250; 934 need = strlen(targ) + strlen(cp) + 250;
891 if (need > cursize) { 935 if (need > cursize) {
892 if (namebuf) 936 if (namebuf)
901 np = targ; 945 np = targ;
902 curfile = cp; 946 curfile = cp;
903 exists = stat(np, &stb) == 0; 947 exists = stat(np, &stb) == 0;
904 if (buf[0] == 'D') { 948 if (buf[0] == 'D') {
905 int mod_flag = pflag; 949 int mod_flag = pflag;
950 if (!iamrecursive)
951 SCREWUP("received directory without -r");
906 if (exists) { 952 if (exists) {
907 if (!S_ISDIR(stb.st_mode)) { 953 if (!S_ISDIR(stb.st_mode)) {
908 errno = ENOTDIR; 954 errno = ENOTDIR;
909 goto bad; 955 goto bad;
910 } 956 }
954 amt = 4096; 1000 amt = 4096;
955 if (i + amt > size) 1001 if (i + amt > size)
956 amt = size - i; 1002 amt = size - i;
957 count += amt; 1003 count += amt;
958 do { 1004 do {
959 j = read(remin, cp, amt); 1005 j = atomicio(read, remin, cp, amt);
960 if (j == -1 && (errno == EINTR || 1006 if (j == 0) {
961 errno == EAGAIN)) {
962 continue;
963 } else if (j <= 0) {
964 run_err("%s", j ? strerror(errno) : 1007 run_err("%s", j ? strerror(errno) :
965 "dropped connection"); 1008 "dropped connection");
966 exit(1); 1009 exit(1);
967 } 1010 }
968 amt -= j; 1011 amt -= j;
969 cp += j; 1012 cp += j;
970 statbytes += j; 1013 statbytes += j;
971 } while (amt > 0); 1014 } while (amt > 0);
972 1015
973 if (limitbw) 1016 if (limit_rate)
974 bwlimit(4096); 1017 bwlimit(4096);
975 1018
976 if (count == bp->cnt) { 1019 if (count == bp->cnt) {
977 /* Keep reading so we stay sync'd up. */ 1020 /* Keep reading so we stay sync'd up. */
978 if (wrerr == NO) { 1021 if (wrerr == NO) {
979 j = atomicio(vwrite, ofd, bp->buf, count); 1022 if (atomicio(vwrite, ofd, bp->buf,
980 if (j != count) { 1023 count) != count) {
981 wrerr = YES; 1024 wrerr = YES;
982 wrerrno = j >= 0 ? EIO : errno; 1025 wrerrno = errno;
983 } 1026 }
984 } 1027 }
985 count = 0; 1028 count = 0;
986 cp = bp->buf; 1029 cp = bp->buf;
987 } 1030 }
989 #ifdef PROGRESS_METER 1032 #ifdef PROGRESS_METER
990 if (showprogress) 1033 if (showprogress)
991 stop_progress_meter(); 1034 stop_progress_meter();
992 #endif 1035 #endif
993 if (count != 0 && wrerr == NO && 1036 if (count != 0 && wrerr == NO &&
994 (j = atomicio(vwrite, ofd, bp->buf, count)) != count) { 1037 atomicio(vwrite, ofd, bp->buf, count) != count) {
995 wrerr = YES; 1038 wrerr = YES;
996 wrerrno = j >= 0 ? EIO : errno; 1039 wrerrno = errno;
997 } 1040 }
998 if (wrerr == NO && ftruncate(ofd, size) != 0) { 1041 if (wrerr == NO && ftruncate(ofd, size) != 0) {
999 run_err("%s: truncate: %s", np, strerror(errno)); 1042 run_err("%s: truncate: %s", np, strerror(errno));
1000 wrerr = DISPLAYED; 1043 wrerr = DISPLAYED;
1001 } 1044 }
1002 if (pflag) { 1045 if (pflag) {
1003 if (exists || omode != mode) 1046 if (exists || omode != mode)
1004 #ifdef HAVE_FCHMOD 1047 #ifdef HAVE_FCHMOD
1005 if (fchmod(ofd, omode)) 1048 if (fchmod(ofd, omode)) {
1006 #else /* HAVE_FCHMOD */ 1049 #else /* HAVE_FCHMOD */
1007 if (chmod(np, omode)) 1050 if (chmod(np, omode)) {
1008 #endif /* HAVE_FCHMOD */ 1051 #endif /* HAVE_FCHMOD */
1009 run_err("%s: set mode: %s", 1052 run_err("%s: set mode: %s",
1010 np, strerror(errno)); 1053 np, strerror(errno));
1054 wrerr = DISPLAYED;
1055 }
1011 } else { 1056 } else {
1012 if (!exists && omode != mode) 1057 if (!exists && omode != mode)
1013 #ifdef HAVE_FCHMOD 1058 #ifdef HAVE_FCHMOD
1014 if (fchmod(ofd, omode & ~mask)) 1059 if (fchmod(ofd, omode & ~mask)) {
1015 #else /* HAVE_FCHMOD */ 1060 #else /* HAVE_FCHMOD */
1016 if (chmod(np, omode & ~mask)) 1061 if (chmod(np, omode & ~mask)) {
1017 #endif /* HAVE_FCHMOD */ 1062 #endif /* HAVE_FCHMOD */
1018 run_err("%s: set mode: %s", 1063 run_err("%s: set mode: %s",
1019 np, strerror(errno)); 1064 np, strerror(errno));
1065 wrerr = DISPLAYED;
1066 }
1020 } 1067 }
1021 if (close(ofd) == -1) { 1068 if (close(ofd) == -1) {
1022 wrerr = YES; 1069 wrerr = YES;
1023 wrerrno = errno; 1070 wrerrno = errno;
1024 } 1071 }
1082 1129
1083 void 1130 void
1084 usage(void) 1131 usage(void)
1085 { 1132 {
1086 (void) printf( 1133 (void) printf(
1087 "usage: scp [-pqrvBC1246] [-F config] [-S program] [-P port]\n" 1134 "usage: scp [-1246BCpqrv] [-c cipher] [-F ssh_config] [-i identity_file]\n"
1088 " [-c cipher] [-i identity] [-l limit] [-o option]\n" 1135 " [-l limit] [-o ssh_option] [-P port] [-S program]\n"
1089 " [[user@]host1:]file1 [...] [[user@]host2:]file2\n"); 1136 " [[user@]host1:]file1 [...] [[user@]host2:]file2\n");
1090 exit(1); 1137 exit(1);
1091 } 1138 }
1092 1139
1093 void 1140 void
1124 if (S_ISDIR(stb.st_mode)) 1171 if (S_ISDIR(stb.st_mode))
1125 return; 1172 return;
1126 errno = ENOTDIR; 1173 errno = ENOTDIR;
1127 } 1174 }
1128 run_err("%s: %s", cp, strerror(errno)); 1175 run_err("%s: %s", cp, strerror(errno));
1129 exit(1); 1176 killchild(0);
1130 } 1177 }
1131 1178
1132 int 1179 int
1133 okname(char *cp0) 1180 okname(char *cp0)
1134 { 1181 {