summaryrefslogtreecommitdiff
path: root/scp.c
diff options
context:
space:
mode:
authormillert@openbsd.org <millert@openbsd.org>2017-10-21 23:06:24 +0000
committerDamien Miller <djm@mindrot.org>2017-10-23 16:10:08 +1100
commit887669ef032d63cf07f53cada216fa8a0c9a7d72 (patch)
tree089b20255da21a489d7bc796a8ee86bd0b8f028f /scp.c
parentd27bff293cfeb2252f4c7a58babe5ad3262c6c98 (diff)
upstream commit
Add URI support to ssh, sftp and scp. For example ssh://user@host or sftp://user@host/path. The connection parameters described in draft-ietf-secsh-scp-sftp-ssh-uri-04 are not implemented since the ssh fingerprint format in the draft uses md5 with no way to specify the hash function type. OK djm@ Upstream-ID: 4ba3768b662d6722de59e6ecb00abf2d4bf9cacc
Diffstat (limited to 'scp.c')
-rw-r--r--scp.c199
1 files changed, 105 insertions, 94 deletions
diff --git a/scp.c b/scp.c
index a533eb097..2103a54ea 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.193 2017/10/21 23:06:24 millert 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
@@ -231,7 +235,7 @@ do_local_cmd(arglist *a)
231 */ 235 */
232 236
233int 237int
234do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout) 238do_cmd(char *host, char *remuser, int port, char *cmd, int *fdin, int *fdout)
235{ 239{
236 int pin[2], pout[2], reserved[2]; 240 int pin[2], pout[2], reserved[2];
237 241
@@ -241,6 +245,9 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout)
241 ssh_program, host, 245 ssh_program, host,
242 remuser ? remuser : "(unspecified)", cmd); 246 remuser ? remuser : "(unspecified)", cmd);
243 247
248 if (port == -1)
249 port = sshport;
250
244 /* 251 /*
245 * Reserve two descriptors so that the real pipes won't get 252 * Reserve two descriptors so that the real pipes won't get
246 * descriptors 0 and 1 because that will screw up dup2 below. 253 * descriptors 0 and 1 because that will screw up dup2 below.
@@ -274,6 +281,10 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout)
274 close(pout[1]); 281 close(pout[1]);
275 282
276 replacearg(&args, 0, "%s", ssh_program); 283 replacearg(&args, 0, "%s", ssh_program);
284 if (port != -1) {
285 addargs(&args, "-p");
286 addargs(&args, "%d", port);
287 }
277 if (remuser != NULL) { 288 if (remuser != NULL) {
278 addargs(&args, "-l"); 289 addargs(&args, "-l");
279 addargs(&args, "%s", remuser); 290 addargs(&args, "%s", remuser);
@@ -305,7 +316,7 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout)
305 * This way the input and output of two commands can be connected. 316 * This way the input and output of two commands can be connected.
306 */ 317 */
307int 318int
308do_cmd2(char *host, char *remuser, char *cmd, int fdin, int fdout) 319do_cmd2(char *host, char *remuser, int port, char *cmd, int fdin, int fdout)
309{ 320{
310 pid_t pid; 321 pid_t pid;
311 int status; 322 int status;
@@ -316,6 +327,9 @@ do_cmd2(char *host, char *remuser, char *cmd, int fdin, int fdout)
316 ssh_program, host, 327 ssh_program, host,
317 remuser ? remuser : "(unspecified)", cmd); 328 remuser ? remuser : "(unspecified)", cmd);
318 329
330 if (port == -1)
331 port = sshport;
332
319 /* Fork a child to execute the command on the remote host using ssh. */ 333 /* Fork a child to execute the command on the remote host using ssh. */
320 pid = fork(); 334 pid = fork();
321 if (pid == 0) { 335 if (pid == 0) {
@@ -323,6 +337,10 @@ do_cmd2(char *host, char *remuser, char *cmd, int fdin, int fdout)
323 dup2(fdout, 1); 337 dup2(fdout, 1);
324 338
325 replacearg(&args, 0, "%s", ssh_program); 339 replacearg(&args, 0, "%s", ssh_program);
340 if (port != -1) {
341 addargs(&args, "-p");
342 addargs(&args, "%d", port);
343 }
326 if (remuser != NULL) { 344 if (remuser != NULL) {
327 addargs(&args, "-l"); 345 addargs(&args, "-l");
328 addargs(&args, "%s", remuser); 346 addargs(&args, "%s", remuser);
@@ -367,14 +385,14 @@ void rsource(char *, struct stat *);
367void sink(int, char *[]); 385void sink(int, char *[]);
368void source(int, char *[]); 386void source(int, char *[]);
369void tolocal(int, char *[]); 387void tolocal(int, char *[]);
370void toremote(char *, int, char *[]); 388void toremote(int, char *[]);
371void usage(void); 389void usage(void);
372 390
373int 391int
374main(int argc, char **argv) 392main(int argc, char **argv)
375{ 393{
376 int ch, fflag, tflag, status, n; 394 int ch, fflag, tflag, status, n;
377 char *targ, **newargv; 395 char **newargv;
378 const char *errstr; 396 const char *errstr;
379 extern char *optarg; 397 extern char *optarg;
380 extern int optind; 398 extern int optind;
@@ -430,10 +448,9 @@ main(int argc, char **argv)
430 addargs(&args, "%s", optarg); 448 addargs(&args, "%s", optarg);
431 break; 449 break;
432 case 'P': 450 case 'P':
433 addargs(&remote_remote_args, "-p"); 451 sshport = a2port(optarg);
434 addargs(&remote_remote_args, "%s", optarg); 452 if (sshport <= 0)
435 addargs(&args, "-p"); 453 fatal("bad port \"%s\"\n", optarg);
436 addargs(&args, "%s", optarg);
437 break; 454 break;
438 case 'B': 455 case 'B':
439 addargs(&remote_remote_args, "-oBatchmode=yes"); 456 addargs(&remote_remote_args, "-oBatchmode=yes");
@@ -533,8 +550,8 @@ main(int argc, char **argv)
533 550
534 (void) signal(SIGPIPE, lostconn); 551 (void) signal(SIGPIPE, lostconn);
535 552
536 if ((targ = colon(argv[argc - 1]))) /* Dest is remote host. */ 553 if (colon(argv[argc - 1])) /* Dest is remote host. */
537 toremote(targ, argc, argv); 554 toremote(argc, argv);
538 else { 555 else {
539 if (targetshouldbedirectory) 556 if (targetshouldbedirectory)
540 verifydir(argv[argc - 1]); 557 verifydir(argv[argc - 1]);
@@ -590,71 +607,65 @@ do_times(int fd, int verb, const struct stat *sb)
590} 607}
591 608
592void 609void
593toremote(char *targ, int argc, char **argv) 610toremote(int argc, char **argv)
594{ 611{
595 char *bp, *host, *src, *suser, *thost, *tuser, *arg; 612 char *suser = NULL, *host = NULL, *src = NULL;
613 char *bp, *tuser, *thost, *targ;
614 int sport = -1, tport = -1;
596 arglist alist; 615 arglist alist;
597 int i; 616 int i, r;
598 u_int j; 617 u_int j;
599 618
600 memset(&alist, '\0', sizeof(alist)); 619 memset(&alist, '\0', sizeof(alist));
601 alist.list = NULL; 620 alist.list = NULL;
602 621
603 *targ++ = 0; 622 /* Parse target */
604 if (*targ == 0) 623 r = parse_uri("scp", argv[argc - 1], &tuser, &thost, &tport, &targ);
605 targ = "."; 624 if (r == -1)
606 625 goto out; /* invalid URI */
607 arg = xstrdup(argv[argc - 1]); 626 if (r != 0) {
608 if ((thost = strrchr(arg, '@'))) { 627 if (parse_user_host_path(argv[argc - 1], &tuser, &thost,
609 /* user@host */ 628 &targ) == -1)
610 *thost++ = 0; 629 goto out;
611 tuser = arg;
612 if (*tuser == '\0')
613 tuser = NULL;
614 } else {
615 thost = arg;
616 tuser = NULL;
617 }
618
619 if (tuser != NULL && !okname(tuser)) {
620 free(arg);
621 return;
622 } 630 }
631 if (tuser != NULL && !okname(tuser))
632 goto out;
623 633
634 /* Parse source files */
624 for (i = 0; i < argc - 1; i++) { 635 for (i = 0; i < argc - 1; i++) {
625 src = colon(argv[i]); 636 free(suser);
626 if (src && throughlocal) { /* extended remote to remote */ 637 free(host);
627 *src++ = 0; 638 free(src);
628 if (*src == 0) 639 r = parse_uri("scp", argv[i], &suser, &host, &sport, &src);
629 src = "."; 640 if (r == -1)
630 host = strrchr(argv[i], '@'); 641 continue; /* invalid URI */
631 if (host) { 642 if (r != 0)
632 *host++ = 0; 643 parse_user_host_path(argv[i], &suser, &host, &src);
633 host = cleanhostname(host); 644 if (suser != NULL && !okname(suser)) {
634 suser = argv[i]; 645 ++errs;
635 if (*suser == '\0') 646 continue;
636 suser = pwd->pw_name; 647 }
637 else if (!okname(suser)) 648 if (host && throughlocal) { /* extended remote to remote */
638 continue;
639 } else {
640 host = cleanhostname(argv[i]);
641 suser = NULL;
642 }
643 xasprintf(&bp, "%s -f %s%s", cmd, 649 xasprintf(&bp, "%s -f %s%s", cmd,
644 *src == '-' ? "-- " : "", src); 650 *src == '-' ? "-- " : "", src);
645 if (do_cmd(host, suser, bp, &remin, &remout) < 0) 651 if (do_cmd(host, suser, sport, bp, &remin, &remout) < 0)
646 exit(1); 652 exit(1);
647 free(bp); 653 free(bp);
648 host = cleanhostname(thost);
649 xasprintf(&bp, "%s -t %s%s", cmd, 654 xasprintf(&bp, "%s -t %s%s", cmd,
650 *targ == '-' ? "-- " : "", targ); 655 *targ == '-' ? "-- " : "", targ);
651 if (do_cmd2(host, tuser, bp, remin, remout) < 0) 656 if (do_cmd2(thost, tuser, tport, bp, remin, remout) < 0)
652 exit(1); 657 exit(1);
653 free(bp); 658 free(bp);
654 (void) close(remin); 659 (void) close(remin);
655 (void) close(remout); 660 (void) close(remout);
656 remin = remout = -1; 661 remin = remout = -1;
657 } else if (src) { /* standard remote to remote */ 662 } else if (host) { /* standard remote to remote */
663 if (tport != -1 && tport != SSH_DEFAULT_PORT) {
664 /* This would require the remote support URIs */
665 fatal("target port not supported with two "
666 "remote hosts without the -3 option");
667 }
668
658 freeargs(&alist); 669 freeargs(&alist);
659 addargs(&alist, "%s", ssh_program); 670 addargs(&alist, "%s", ssh_program);
660 addargs(&alist, "-x"); 671 addargs(&alist, "-x");
@@ -664,23 +675,14 @@ toremote(char *targ, int argc, char **argv)
664 addargs(&alist, "%s", 675 addargs(&alist, "%s",
665 remote_remote_args.list[j]); 676 remote_remote_args.list[j]);
666 } 677 }
667 *src++ = 0; 678
668 if (*src == 0) 679 if (sport != -1) {
669 src = "."; 680 addargs(&alist, "-p");
670 host = strrchr(argv[i], '@'); 681 addargs(&alist, "%d", sport);
671 682 }
672 if (host) { 683 if (suser) {
673 *host++ = 0;
674 host = cleanhostname(host);
675 suser = argv[i];
676 if (*suser == '\0')
677 suser = pwd->pw_name;
678 else if (!okname(suser))
679 continue;
680 addargs(&alist, "-l"); 684 addargs(&alist, "-l");
681 addargs(&alist, "%s", suser); 685 addargs(&alist, "%s", suser);
682 } else {
683 host = cleanhostname(argv[i]);
684 } 686 }
685 addargs(&alist, "--"); 687 addargs(&alist, "--");
686 addargs(&alist, "%s", host); 688 addargs(&alist, "%s", host);
@@ -695,8 +697,7 @@ toremote(char *targ, int argc, char **argv)
695 if (remin == -1) { 697 if (remin == -1) {
696 xasprintf(&bp, "%s -t %s%s", cmd, 698 xasprintf(&bp, "%s -t %s%s", cmd,
697 *targ == '-' ? "-- " : "", targ); 699 *targ == '-' ? "-- " : "", targ);
698 host = cleanhostname(thost); 700 if (do_cmd(thost, tuser, tport, bp, &remin,
699 if (do_cmd(host, tuser, bp, &remin,
700 &remout) < 0) 701 &remout) < 0)
701 exit(1); 702 exit(1);
702 if (response() < 0) 703 if (response() < 0)
@@ -706,21 +707,41 @@ toremote(char *targ, int argc, char **argv)
706 source(1, argv + i); 707 source(1, argv + i);
707 } 708 }
708 } 709 }
709 free(arg); 710out:
711 free(tuser);
712 free(thost);
713 free(targ);
714 free(suser);
715 free(host);
716 free(src);
710} 717}
711 718
712void 719void
713tolocal(int argc, char **argv) 720tolocal(int argc, char **argv)
714{ 721{
715 char *bp, *host, *src, *suser; 722 char *bp, *host = NULL, *src = NULL, *suser = NULL;
716 arglist alist; 723 arglist alist;
717 int i; 724 int i, r, sport = -1;
718 725
719 memset(&alist, '\0', sizeof(alist)); 726 memset(&alist, '\0', sizeof(alist));
720 alist.list = NULL; 727 alist.list = NULL;
721 728
722 for (i = 0; i < argc - 1; i++) { 729 for (i = 0; i < argc - 1; i++) {
723 if (!(src = colon(argv[i]))) { /* Local to local. */ 730 free(suser);
731 free(host);
732 free(src);
733 r = parse_uri("scp", argv[i], &suser, &host, &sport, &src);
734 if (r == -1) {
735 ++errs;
736 continue;
737 }
738 if (r != 0)
739 parse_user_host_path(argv[i], &suser, &host, &src);
740 if (suser != NULL && !okname(suser)) {
741 ++errs;
742 continue;
743 }
744 if (!host) { /* Local to local. */
724 freeargs(&alist); 745 freeargs(&alist);
725 addargs(&alist, "%s", _PATH_CP); 746 addargs(&alist, "%s", _PATH_CP);
726 if (iamrecursive) 747 if (iamrecursive)
@@ -734,22 +755,10 @@ tolocal(int argc, char **argv)
734 ++errs; 755 ++errs;
735 continue; 756 continue;
736 } 757 }
737 *src++ = 0; 758 /* Remote to local. */
738 if (*src == 0)
739 src = ".";
740 if ((host = strrchr(argv[i], '@')) == NULL) {
741 host = argv[i];
742 suser = NULL;
743 } else {
744 *host++ = 0;
745 suser = argv[i];
746 if (*suser == '\0')
747 suser = pwd->pw_name;
748 }
749 host = cleanhostname(host);
750 xasprintf(&bp, "%s -f %s%s", 759 xasprintf(&bp, "%s -f %s%s",
751 cmd, *src == '-' ? "-- " : "", src); 760 cmd, *src == '-' ? "-- " : "", src);
752 if (do_cmd(host, suser, bp, &remin, &remout) < 0) { 761 if (do_cmd(host, suser, sport, bp, &remin, &remout) < 0) {
753 free(bp); 762 free(bp);
754 ++errs; 763 ++errs;
755 continue; 764 continue;
@@ -759,6 +768,9 @@ tolocal(int argc, char **argv)
759 (void) close(remin); 768 (void) close(remin);
760 remin = remout = -1; 769 remin = remout = -1;
761 } 770 }
771 free(suser);
772 free(host);
773 free(src);
762} 774}
763 775
764void 776void
@@ -1275,8 +1287,7 @@ usage(void)
1275{ 1287{
1276 (void) fprintf(stderr, 1288 (void) fprintf(stderr,
1277 "usage: scp [-346BCpqrv] [-c cipher] [-F ssh_config] [-i identity_file]\n" 1289 "usage: scp [-346BCpqrv] [-c cipher] [-F ssh_config] [-i identity_file]\n"
1278 " [-l limit] [-o ssh_option] [-P port] [-S program]\n" 1290 " [-l limit] [-o ssh_option] [-P port] [-S program] source ... target\n");
1279 " [[user@]host1:]file1 ... [[user@]host2:]file2\n");
1280 exit(1); 1291 exit(1);
1281} 1292}
1282 1293