summaryrefslogtreecommitdiff
path: root/scp.c
diff options
context:
space:
mode:
Diffstat (limited to 'scp.c')
-rw-r--r--scp.c222
1 files changed, 130 insertions, 92 deletions
diff --git a/scp.c b/scp.c
index 12e3199d8..2bbf6938e 100644
--- a/scp.c
+++ b/scp.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: scp.c,v 1.192 2017/05/31 09:15:42 deraadt Exp $ */ 1/* $OpenBSD: scp.c,v 1.195 2018/02/10 06:15:12 djm Exp $ */
2/* 2/*
3 * scp - secure remote copy. This is basically patched BSD rcp which 3 * scp - secure remote copy. This is basically patched BSD rcp which
4 * uses ssh to do the data transfer (instead of using rcmd). 4 * uses ssh to do the data transfer (instead of using rcmd).
@@ -112,6 +112,7 @@
112#endif 112#endif
113 113
114#include "xmalloc.h" 114#include "xmalloc.h"
115#include "ssh.h"
115#include "atomicio.h" 116#include "atomicio.h"
116#include "pathnames.h" 117#include "pathnames.h"
117#include "log.h" 118#include "log.h"
@@ -123,8 +124,8 @@ extern char *__progname;
123 124
124#define COPY_BUFLEN 16384 125#define COPY_BUFLEN 16384
125 126
126int do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout); 127int do_cmd(char *host, char *remuser, int port, char *cmd, int *fdin, int *fdout);
127int do_cmd2(char *host, char *remuser, char *cmd, int fdin, int fdout); 128int do_cmd2(char *host, char *remuser, int port, char *cmd, int fdin, int fdout);
128 129
129/* Struct for addargs */ 130/* Struct for addargs */
130arglist args; 131arglist args;
@@ -149,6 +150,9 @@ int showprogress = 1;
149 */ 150 */
150int throughlocal = 0; 151int throughlocal = 0;
151 152
153/* Non-standard port to use for the ssh connection or -1. */
154int sshport = -1;
155
152/* This is the program to execute for the secured connection. ("ssh" or -S) */ 156/* This is the program to execute for the secured connection. ("ssh" or -S) */
153char *ssh_program = _PATH_SSH_PROGRAM; 157char *ssh_program = _PATH_SSH_PROGRAM;
154 158
@@ -239,7 +243,7 @@ do_local_cmd(arglist *a)
239 */ 243 */
240 244
241int 245int
242do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout) 246do_cmd(char *host, char *remuser, int port, char *cmd, int *fdin, int *fdout)
243{ 247{
244 int pin[2], pout[2], reserved[2]; 248 int pin[2], pout[2], reserved[2];
245 249
@@ -249,6 +253,9 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout)
249 ssh_program, host, 253 ssh_program, host,
250 remuser ? remuser : "(unspecified)", cmd); 254 remuser ? remuser : "(unspecified)", cmd);
251 255
256 if (port == -1)
257 port = sshport;
258
252 /* 259 /*
253 * Reserve two descriptors so that the real pipes won't get 260 * Reserve two descriptors so that the real pipes won't get
254 * descriptors 0 and 1 because that will screw up dup2 below. 261 * descriptors 0 and 1 because that will screw up dup2 below.
@@ -282,6 +289,10 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout)
282 close(pout[1]); 289 close(pout[1]);
283 290
284 replacearg(&args, 0, "%s", ssh_program); 291 replacearg(&args, 0, "%s", ssh_program);
292 if (port != -1) {
293 addargs(&args, "-p");
294 addargs(&args, "%d", port);
295 }
285 if (remuser != NULL) { 296 if (remuser != NULL) {
286 addargs(&args, "-l"); 297 addargs(&args, "-l");
287 addargs(&args, "%s", remuser); 298 addargs(&args, "%s", remuser);
@@ -313,7 +324,7 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout)
313 * This way the input and output of two commands can be connected. 324 * This way the input and output of two commands can be connected.
314 */ 325 */
315int 326int
316do_cmd2(char *host, char *remuser, char *cmd, int fdin, int fdout) 327do_cmd2(char *host, char *remuser, int port, char *cmd, int fdin, int fdout)
317{ 328{
318 pid_t pid; 329 pid_t pid;
319 int status; 330 int status;
@@ -324,6 +335,9 @@ do_cmd2(char *host, char *remuser, char *cmd, int fdin, int fdout)
324 ssh_program, host, 335 ssh_program, host,
325 remuser ? remuser : "(unspecified)", cmd); 336 remuser ? remuser : "(unspecified)", cmd);
326 337
338 if (port == -1)
339 port = sshport;
340
327 /* Fork a child to execute the command on the remote host using ssh. */ 341 /* Fork a child to execute the command on the remote host using ssh. */
328 pid = fork(); 342 pid = fork();
329 if (pid == 0) { 343 if (pid == 0) {
@@ -331,6 +345,10 @@ do_cmd2(char *host, char *remuser, char *cmd, int fdin, int fdout)
331 dup2(fdout, 1); 345 dup2(fdout, 1);
332 346
333 replacearg(&args, 0, "%s", ssh_program); 347 replacearg(&args, 0, "%s", ssh_program);
348 if (port != -1) {
349 addargs(&args, "-p");
350 addargs(&args, "%d", port);
351 }
334 if (remuser != NULL) { 352 if (remuser != NULL) {
335 addargs(&args, "-l"); 353 addargs(&args, "-l");
336 addargs(&args, "%s", remuser); 354 addargs(&args, "%s", remuser);
@@ -375,14 +393,14 @@ void rsource(char *, struct stat *);
375void sink(int, char *[]); 393void sink(int, char *[]);
376void source(int, char *[]); 394void source(int, char *[]);
377void tolocal(int, char *[]); 395void tolocal(int, char *[]);
378void toremote(char *, int, char *[]); 396void toremote(int, char *[]);
379void usage(void); 397void usage(void);
380 398
381int 399int
382main(int argc, char **argv) 400main(int argc, char **argv)
383{ 401{
384 int ch, fflag, tflag, status, n; 402 int ch, fflag, tflag, status, n;
385 char *targ, **newargv; 403 char **newargv;
386 const char *errstr; 404 const char *errstr;
387 extern char *optarg; 405 extern char *optarg;
388 extern int optind; 406 extern int optind;
@@ -408,6 +426,8 @@ main(int argc, char **argv)
408 addargs(&args, "-oForwardAgent=no"); 426 addargs(&args, "-oForwardAgent=no");
409 addargs(&args, "-oPermitLocalCommand=no"); 427 addargs(&args, "-oPermitLocalCommand=no");
410 addargs(&args, "-oClearAllForwardings=yes"); 428 addargs(&args, "-oClearAllForwardings=yes");
429 addargs(&args, "-oRemoteCommand=none");
430 addargs(&args, "-oRequestTTY=no");
411 431
412 fflag = tflag = 0; 432 fflag = tflag = 0;
413 while ((ch = getopt(argc, argv, "dfl:prtvBCc:i:P:q12346S:o:F:")) != -1) 433 while ((ch = getopt(argc, argv, "dfl:prtvBCc:i:P:q12346S:o:F:")) != -1)
@@ -438,10 +458,9 @@ main(int argc, char **argv)
438 addargs(&args, "%s", optarg); 458 addargs(&args, "%s", optarg);
439 break; 459 break;
440 case 'P': 460 case 'P':
441 addargs(&remote_remote_args, "-p"); 461 sshport = a2port(optarg);
442 addargs(&remote_remote_args, "%s", optarg); 462 if (sshport <= 0)
443 addargs(&args, "-p"); 463 fatal("bad port \"%s\"\n", optarg);
444 addargs(&args, "%s", optarg);
445 break; 464 break;
446 case 'B': 465 case 'B':
447 addargs(&remote_remote_args, "-oBatchmode=yes"); 466 addargs(&remote_remote_args, "-oBatchmode=yes");
@@ -541,8 +560,8 @@ main(int argc, char **argv)
541 560
542 (void) signal(SIGPIPE, lostconn); 561 (void) signal(SIGPIPE, lostconn);
543 562
544 if ((targ = colon(argv[argc - 1]))) /* Dest is remote host. */ 563 if (colon(argv[argc - 1])) /* Dest is remote host. */
545 toremote(targ, argc, argv); 564 toremote(argc, argv);
546 else { 565 else {
547 if (targetshouldbedirectory) 566 if (targetshouldbedirectory)
548 verifydir(argv[argc - 1]); 567 verifydir(argv[argc - 1]);
@@ -597,72 +616,90 @@ do_times(int fd, int verb, const struct stat *sb)
597 return (response()); 616 return (response());
598} 617}
599 618
619static int
620parse_scp_uri(const char *uri, char **userp, char **hostp, int *portp,
621 char **pathp)
622{
623 int r;
624
625 r = parse_uri("scp", uri, userp, hostp, portp, pathp);
626 if (r == 0 && *pathp == NULL)
627 *pathp = xstrdup(".");
628 return r;
629}
630
600void 631void
601toremote(char *targ, int argc, char **argv) 632toremote(int argc, char **argv)
602{ 633{
603 char *bp, *host, *src, *suser, *thost, *tuser, *arg; 634 char *suser = NULL, *host = NULL, *src = NULL;
635 char *bp, *tuser, *thost, *targ;
636 int sport = -1, tport = -1;
604 arglist alist; 637 arglist alist;
605 int i; 638 int i, r;
606 u_int j; 639 u_int j;
607 640
608 memset(&alist, '\0', sizeof(alist)); 641 memset(&alist, '\0', sizeof(alist));
609 alist.list = NULL; 642 alist.list = NULL;
610 643
611 *targ++ = 0; 644 /* Parse target */
612 if (*targ == 0) 645 r = parse_scp_uri(argv[argc - 1], &tuser, &thost, &tport, &targ);
613 targ = "."; 646 if (r == -1) {
614 647 fmprintf(stderr, "%s: invalid uri\n", argv[argc - 1]);
615 arg = xstrdup(argv[argc - 1]); 648 ++errs;
616 if ((thost = strrchr(arg, '@'))) { 649 goto out;
617 /* user@host */ 650 }
618 *thost++ = 0; 651 if (r != 0) {
619 tuser = arg; 652 if (parse_user_host_path(argv[argc - 1], &tuser, &thost,
620 if (*tuser == '\0') 653 &targ) == -1) {
621 tuser = NULL; 654 fmprintf(stderr, "%s: invalid target\n", argv[argc - 1]);
622 } else { 655 ++errs;
623 thost = arg; 656 goto out;
624 tuser = NULL; 657 }
625 } 658 }
626
627 if (tuser != NULL && !okname(tuser)) { 659 if (tuser != NULL && !okname(tuser)) {
628 free(arg); 660 ++errs;
629 return; 661 goto out;
630 } 662 }
631 663
664 /* Parse source files */
632 for (i = 0; i < argc - 1; i++) { 665 for (i = 0; i < argc - 1; i++) {
633 src = colon(argv[i]); 666 free(suser);
634 if (src && throughlocal) { /* extended remote to remote */ 667 free(host);
635 *src++ = 0; 668 free(src);
636 if (*src == 0) 669 r = parse_scp_uri(argv[i], &suser, &host, &sport, &src);
637 src = "."; 670 if (r == -1) {
638 host = strrchr(argv[i], '@'); 671 fmprintf(stderr, "%s: invalid uri\n", argv[i]);
639 if (host) { 672 ++errs;
640 *host++ = 0; 673 continue;
641 host = cleanhostname(host); 674 }
642 suser = argv[i]; 675 if (r != 0) {
643 if (*suser == '\0') 676 parse_user_host_path(argv[i], &suser, &host, &src);
644 suser = pwd->pw_name; 677 }
645 else if (!okname(suser)) 678 if (suser != NULL && !okname(suser)) {
646 continue; 679 ++errs;
647 } else { 680 continue;
648 host = cleanhostname(argv[i]); 681 }
649 suser = NULL; 682 if (host && throughlocal) { /* extended remote to remote */
650 }
651 xasprintf(&bp, "%s -f %s%s", cmd, 683 xasprintf(&bp, "%s -f %s%s", cmd,
652 *src == '-' ? "-- " : "", src); 684 *src == '-' ? "-- " : "", src);
653 if (do_cmd(host, suser, bp, &remin, &remout) < 0) 685 if (do_cmd(host, suser, sport, bp, &remin, &remout) < 0)
654 exit(1); 686 exit(1);
655 free(bp); 687 free(bp);
656 host = cleanhostname(thost);
657 xasprintf(&bp, "%s -t %s%s", cmd, 688 xasprintf(&bp, "%s -t %s%s", cmd,
658 *targ == '-' ? "-- " : "", targ); 689 *targ == '-' ? "-- " : "", targ);
659 if (do_cmd2(host, tuser, bp, remin, remout) < 0) 690 if (do_cmd2(thost, tuser, tport, bp, remin, remout) < 0)
660 exit(1); 691 exit(1);
661 free(bp); 692 free(bp);
662 (void) close(remin); 693 (void) close(remin);
663 (void) close(remout); 694 (void) close(remout);
664 remin = remout = -1; 695 remin = remout = -1;
665 } else if (src) { /* standard remote to remote */ 696 } else if (host) { /* standard remote to remote */
697 if (tport != -1 && tport != SSH_DEFAULT_PORT) {
698 /* This would require the remote support URIs */
699 fatal("target port not supported with two "
700 "remote hosts without the -3 option");
701 }
702
666 freeargs(&alist); 703 freeargs(&alist);
667 addargs(&alist, "%s", ssh_program); 704 addargs(&alist, "%s", ssh_program);
668 addargs(&alist, "-x"); 705 addargs(&alist, "-x");
@@ -672,23 +709,14 @@ toremote(char *targ, int argc, char **argv)
672 addargs(&alist, "%s", 709 addargs(&alist, "%s",
673 remote_remote_args.list[j]); 710 remote_remote_args.list[j]);
674 } 711 }
675 *src++ = 0; 712
676 if (*src == 0) 713 if (sport != -1) {
677 src = "."; 714 addargs(&alist, "-p");
678 host = strrchr(argv[i], '@'); 715 addargs(&alist, "%d", sport);
679 716 }
680 if (host) { 717 if (suser) {
681 *host++ = 0;
682 host = cleanhostname(host);
683 suser = argv[i];
684 if (*suser == '\0')
685 suser = pwd->pw_name;
686 else if (!okname(suser))
687 continue;
688 addargs(&alist, "-l"); 718 addargs(&alist, "-l");
689 addargs(&alist, "%s", suser); 719 addargs(&alist, "%s", suser);
690 } else {
691 host = cleanhostname(argv[i]);
692 } 720 }
693 addargs(&alist, "--"); 721 addargs(&alist, "--");
694 addargs(&alist, "%s", host); 722 addargs(&alist, "%s", host);
@@ -703,8 +731,7 @@ toremote(char *targ, int argc, char **argv)
703 if (remin == -1) { 731 if (remin == -1) {
704 xasprintf(&bp, "%s -t %s%s", cmd, 732 xasprintf(&bp, "%s -t %s%s", cmd,
705 *targ == '-' ? "-- " : "", targ); 733 *targ == '-' ? "-- " : "", targ);
706 host = cleanhostname(thost); 734 if (do_cmd(thost, tuser, tport, bp, &remin,
707 if (do_cmd(host, tuser, bp, &remin,
708 &remout) < 0) 735 &remout) < 0)
709 exit(1); 736 exit(1);
710 if (response() < 0) 737 if (response() < 0)
@@ -714,21 +741,42 @@ toremote(char *targ, int argc, char **argv)
714 source(1, argv + i); 741 source(1, argv + i);
715 } 742 }
716 } 743 }
717 free(arg); 744out:
745 free(tuser);
746 free(thost);
747 free(targ);
748 free(suser);
749 free(host);
750 free(src);
718} 751}
719 752
720void 753void
721tolocal(int argc, char **argv) 754tolocal(int argc, char **argv)
722{ 755{
723 char *bp, *host, *src, *suser; 756 char *bp, *host = NULL, *src = NULL, *suser = NULL;
724 arglist alist; 757 arglist alist;
725 int i; 758 int i, r, sport = -1;
726 759
727 memset(&alist, '\0', sizeof(alist)); 760 memset(&alist, '\0', sizeof(alist));
728 alist.list = NULL; 761 alist.list = NULL;
729 762
730 for (i = 0; i < argc - 1; i++) { 763 for (i = 0; i < argc - 1; i++) {
731 if (!(src = colon(argv[i]))) { /* Local to local. */ 764 free(suser);
765 free(host);
766 free(src);
767 r = parse_scp_uri(argv[i], &suser, &host, &sport, &src);
768 if (r == -1) {
769 fmprintf(stderr, "%s: invalid uri\n", argv[i]);
770 ++errs;
771 continue;
772 }
773 if (r != 0)
774 parse_user_host_path(argv[i], &suser, &host, &src);
775 if (suser != NULL && !okname(suser)) {
776 ++errs;
777 continue;
778 }
779 if (!host) { /* Local to local. */
732 freeargs(&alist); 780 freeargs(&alist);
733 addargs(&alist, "%s", _PATH_CP); 781 addargs(&alist, "%s", _PATH_CP);
734 if (iamrecursive) 782 if (iamrecursive)
@@ -742,22 +790,10 @@ tolocal(int argc, char **argv)
742 ++errs; 790 ++errs;
743 continue; 791 continue;
744 } 792 }
745 *src++ = 0; 793 /* Remote to local. */
746 if (*src == 0)
747 src = ".";
748 if ((host = strrchr(argv[i], '@')) == NULL) {
749 host = argv[i];
750 suser = NULL;
751 } else {
752 *host++ = 0;
753 suser = argv[i];
754 if (*suser == '\0')
755 suser = pwd->pw_name;
756 }
757 host = cleanhostname(host);
758 xasprintf(&bp, "%s -f %s%s", 794 xasprintf(&bp, "%s -f %s%s",
759 cmd, *src == '-' ? "-- " : "", src); 795 cmd, *src == '-' ? "-- " : "", src);
760 if (do_cmd(host, suser, bp, &remin, &remout) < 0) { 796 if (do_cmd(host, suser, sport, bp, &remin, &remout) < 0) {
761 free(bp); 797 free(bp);
762 ++errs; 798 ++errs;
763 continue; 799 continue;
@@ -767,6 +803,9 @@ tolocal(int argc, char **argv)
767 (void) close(remin); 803 (void) close(remin);
768 remin = remout = -1; 804 remin = remout = -1;
769 } 805 }
806 free(suser);
807 free(host);
808 free(src);
770} 809}
771 810
772void 811void
@@ -1283,8 +1322,7 @@ usage(void)
1283{ 1322{
1284 (void) fprintf(stderr, 1323 (void) fprintf(stderr,
1285 "usage: scp [-346BCpqrv] [-c cipher] [-F ssh_config] [-i identity_file]\n" 1324 "usage: scp [-346BCpqrv] [-c cipher] [-F ssh_config] [-i identity_file]\n"
1286 " [-l limit] [-o ssh_option] [-P port] [-S program]\n" 1325 " [-l limit] [-o ssh_option] [-P port] [-S program] source ... target\n");
1287 " [[user@]host1:]file1 ... [[user@]host2:]file2\n");
1288 exit(1); 1326 exit(1);
1289} 1327}
1290 1328