diff options
-rw-r--r-- | ChangeLog | 66 | ||||
-rw-r--r-- | Makefile.in | 13 | ||||
-rw-r--r-- | pathnames.h | 8 | ||||
-rw-r--r-- | sftp-client.c | 51 | ||||
-rw-r--r-- | sftp-common.c | 10 | ||||
-rw-r--r-- | sftp-int.c | 199 | ||||
-rw-r--r-- | sftp.1 | 119 | ||||
-rw-r--r-- | sftp.c | 97 |
8 files changed, 363 insertions, 200 deletions
@@ -1,3 +1,67 @@ | |||
1 | 20010210 | ||
2 | - (djm) Sync sftp and scp stuff from OpenBSD: | ||
3 | - djm@cvs.openbsd.org 2001/02/07 03:55:13 | ||
4 | [sftp-client.c] | ||
5 | Don't free handles before we are done with them. Based on work from | ||
6 | Corinna Vinschen <vinschen@redhat.com>. ok markus@ | ||
7 | - djm@cvs.openbsd.org 2001/02/06 22:32:53 | ||
8 | [sftp.1] | ||
9 | Punctuation fix from Pekka Savola <pekkas@netcore.fi> | ||
10 | - deraadt@cvs.openbsd.org 2001/02/07 04:07:29 | ||
11 | [sftp.1] | ||
12 | pretty up significantly | ||
13 | - itojun@cvs.openbsd.org 2001/02/07 06:49:42 | ||
14 | [sftp.1] | ||
15 | .Bl-.El mismatch. markus ok | ||
16 | - djm@cvs.openbsd.org 2001/02/07 06:12:30 | ||
17 | [sftp-int.c] | ||
18 | Check that target is a directory before doing ls; ok markus@ | ||
19 | - itojun@cvs.openbsd.org 2001/02/07 11:01:18 | ||
20 | [scp.c sftp-client.c sftp-server.c] | ||
21 | unsigned long long -> %llu, not %qu. markus ok | ||
22 | - stevesk@cvs.openbsd.org 2001/02/07 11:10:39 | ||
23 | [sftp.1 sftp-int.c] | ||
24 | more man page cleanup and sync of help text with man page; ok markus@ | ||
25 | - markus@cvs.openbsd.org 2001/02/07 14:58:34 | ||
26 | [sftp-client.c] | ||
27 | older servers reply with SSH2_FXP_NAME + count==0 instead of EOF | ||
28 | - djm@cvs.openbsd.org 2001/02/07 15:27:19 | ||
29 | [sftp.c] | ||
30 | Don't forward agent and X11 in sftp. Suggestion from Roumen Petrov | ||
31 | <roumen.petrov@skalasoft.com> | ||
32 | - stevesk@cvs.openbsd.org 2001/02/07 15:36:04 | ||
33 | [sftp-int.c] | ||
34 | portable; ok markus@ | ||
35 | - stevesk@cvs.openbsd.org 2001/02/07 15:55:47 | ||
36 | [sftp-int.c] | ||
37 | lowercase cmds[].c also; ok markus@ | ||
38 | - markus@cvs.openbsd.org 2001/02/07 17:04:52 | ||
39 | [pathnames.h sftp.c] | ||
40 | allow sftp over ssh protocol 1; ok djm@ | ||
41 | - deraadt@cvs.openbsd.org 2001/02/08 07:38:55 | ||
42 | [scp.c] | ||
43 | memory leak fix, and snprintf throughout | ||
44 | - deraadt@cvs.openbsd.org 2001/02/08 08:02:02 | ||
45 | [sftp-int.c] | ||
46 | plug a memory leak | ||
47 | - stevesk@cvs.openbsd.org 2001/02/08 10:11:23 | ||
48 | [session.c sftp-client.c] | ||
49 | %i -> %d | ||
50 | - stevesk@cvs.openbsd.org 2001/02/08 10:57:59 | ||
51 | [sftp-int.c] | ||
52 | typo | ||
53 | - stevesk@cvs.openbsd.org 2001/02/08 15:28:07 | ||
54 | [sftp-int.c pathnames.h] | ||
55 | _PATH_LS; ok markus@ | ||
56 | - djm@cvs.openbsd.org 2001/02/09 04:46:25 | ||
57 | [sftp-int.c] | ||
58 | Check for NULL attribs for chown, chmod & chgrp operations, only send | ||
59 | relevant attribs back to server; ok markus@ | ||
60 | - (djm) Update makefile.in for _PATH_SFTP_SERVER | ||
61 | |||
62 | |||
63 | |||
64 | |||
1 | 20010209 | 65 | 20010209 |
2 | - (bal) patch to vis.c to deal with HAVE_VIS right by Robert Mooney | 66 | - (bal) patch to vis.c to deal with HAVE_VIS right by Robert Mooney |
3 | <rjmooney@mediaone.net> | 67 | <rjmooney@mediaone.net> |
@@ -3703,4 +3767,4 @@ | |||
3703 | - Wrote replacements for strlcpy and mkdtemp | 3767 | - Wrote replacements for strlcpy and mkdtemp |
3704 | - Released 1.0pre1 | 3768 | - Released 1.0pre1 |
3705 | 3769 | ||
3706 | $Id: ChangeLog,v 1.709 2001/02/09 11:55:16 djm Exp $ | 3770 | $Id: ChangeLog,v 1.710 2001/02/09 13:40:03 djm Exp $ |
diff --git a/Makefile.in b/Makefile.in index af82ea15b..f64e25504 100644 --- a/Makefile.in +++ b/Makefile.in | |||
@@ -1,4 +1,4 @@ | |||
1 | # $Id: Makefile.in,v 1.149 2001/02/07 23:07:09 djm Exp $ | 1 | # $Id: Makefile.in,v 1.150 2001/02/09 13:40:03 djm Exp $ |
2 | 2 | ||
3 | prefix=@prefix@ | 3 | prefix=@prefix@ |
4 | exec_prefix=@exec_prefix@ | 4 | exec_prefix=@exec_prefix@ |
@@ -16,10 +16,15 @@ DESTDIR= | |||
16 | VPATH=@srcdir@ | 16 | VPATH=@srcdir@ |
17 | SSH_PROGRAM=@bindir@/ssh | 17 | SSH_PROGRAM=@bindir@/ssh |
18 | ASKPASS_PROGRAM=$(libexecdir)/ssh-askpass | 18 | ASKPASS_PROGRAM=$(libexecdir)/ssh-askpass |
19 | SFTP_SERVER=$(libexecdir)/sftp-server | ||
20 | |||
21 | PATHS= -DETCDIR=\"$(sysconfdir)\" \ | ||
22 | -D_PATH_SSH_PROGRAM=\"$(SSH_PROGRAM)\" \ | ||
23 | -D_PATH_SSH_ASKPASS_DEFAULT=\"$(ASKPASS_PROGRAM)\" \ | ||
24 | -D_PATH_SFTP_SERVER=\"$(SFTP_SERVER)\" | ||
19 | 25 | ||
20 | CC=@CC@ | 26 | CC=@CC@ |
21 | LD=@LD@ | 27 | LD=@LD@ |
22 | PATHS=-DETCDIR=\"$(sysconfdir)\" -D_PATH_SSH_PROGRAM=\"$(SSH_PROGRAM)\" -D_PATH_SSH_ASKPASS_DEFAULT=\"$(ASKPASS_PROGRAM)\" | ||
23 | CFLAGS=@CFLAGS@ | 28 | CFLAGS=@CFLAGS@ |
24 | CPPFLAGS=@CPPFLAGS@ -I. -I$(srcdir)/openbsd-compat -I$(srcdir) $(PATHS) @DEFS@ | 29 | CPPFLAGS=@CPPFLAGS@ -I. -I$(srcdir)/openbsd-compat -I$(srcdir) $(PATHS) @DEFS@ |
25 | LIBS=@LIBS@ | 30 | LIBS=@LIBS@ |
@@ -162,7 +167,7 @@ install-files: | |||
162 | $(INSTALL) -m 0775 -s ssh-keyscan $(DESTDIR)$(bindir)/ssh-keyscan | 167 | $(INSTALL) -m 0775 -s ssh-keyscan $(DESTDIR)$(bindir)/ssh-keyscan |
163 | $(INSTALL) -m 0755 -s sshd $(DESTDIR)$(sbindir)/sshd | 168 | $(INSTALL) -m 0755 -s sshd $(DESTDIR)$(sbindir)/sshd |
164 | @NO_SFTP@$(INSTALL) -m 0755 -s sftp $(DESTDIR)$(bindir)/sftp | 169 | @NO_SFTP@$(INSTALL) -m 0755 -s sftp $(DESTDIR)$(bindir)/sftp |
165 | @NO_SFTP@$(INSTALL) -m 0755 -s sftp-server $(DESTDIR)$(libexecdir)/sftp-server | 170 | @NO_SFTP@$(INSTALL) -m 0755 -s sftp-server $(DESTDIR)$(SFTP_SERVER) |
166 | $(INSTALL) -m 644 ssh.[01].out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1 | 171 | $(INSTALL) -m 644 ssh.[01].out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1 |
167 | $(INSTALL) -m 644 scp.[01].out $(DESTDIR)$(mandir)/$(mansubdir)1/scp.1 | 172 | $(INSTALL) -m 644 scp.[01].out $(DESTDIR)$(mandir)/$(mansubdir)1/scp.1 |
168 | $(INSTALL) -m 644 ssh-add.[01].out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-add.1 | 173 | $(INSTALL) -m 644 ssh-add.[01].out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-add.1 |
@@ -250,7 +255,7 @@ uninstall: | |||
250 | -rm -f $(DESTDIR)$(bindir)/ssh-keyscan$(EXEEXT) | 255 | -rm -f $(DESTDIR)$(bindir)/ssh-keyscan$(EXEEXT) |
251 | -rm -f $(DESTDIR)$(bindir)/sftp$(EXEEXT) | 256 | -rm -f $(DESTDIR)$(bindir)/sftp$(EXEEXT) |
252 | -rm -f $(DESTDIR)$(sbindir)/sshd$(EXEEXT) | 257 | -rm -f $(DESTDIR)$(sbindir)/sshd$(EXEEXT) |
253 | -rm -r $(DESTDIR)$(libexecdir)/sftp-server$(EXEEXT) | 258 | -rm -r $(DESTDIR)$(SFTP_SERVER)$(EXEEXT) |
254 | -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1 | 259 | -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1 |
255 | -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/scp.1 | 260 | -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/scp.1 |
256 | -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-add.1 | 261 | -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-add.1 |
diff --git a/pathnames.h b/pathnames.h index 85d8a1fe2..3f116bdbb 100644 --- a/pathnames.h +++ b/pathnames.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: pathnames.h,v 1.2 2001/01/29 01:58:17 niklas Exp $ */ | 1 | /* $OpenBSD: pathnames.h,v 1.4 2001/02/08 22:28:07 stevesk Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
@@ -116,6 +116,12 @@ | |||
116 | #define _PATH_CP "cp" | 116 | #define _PATH_CP "cp" |
117 | #endif | 117 | #endif |
118 | 118 | ||
119 | /* for sftp */ | ||
120 | #ifndef _PATH_SFTP_SERVER | ||
121 | #define _PATH_SFTP_SERVER "/usr/libexec/sftp-server" | ||
122 | #endif | ||
123 | #define _PATH_LS "ls" | ||
124 | |||
119 | /* path to login program */ | 125 | /* path to login program */ |
120 | #ifndef LOGIN_PROGRAM | 126 | #ifndef LOGIN_PROGRAM |
121 | # ifdef LOGIN_PROGRAM_FALLBACK | 127 | # ifdef LOGIN_PROGRAM_FALLBACK |
diff --git a/sftp-client.c b/sftp-client.c index e8b9007fe..490c00bdd 100644 --- a/sftp-client.c +++ b/sftp-client.c | |||
@@ -29,7 +29,7 @@ | |||
29 | /* XXX: copy between two remote sites */ | 29 | /* XXX: copy between two remote sites */ |
30 | 30 | ||
31 | #include "includes.h" | 31 | #include "includes.h" |
32 | RCSID("$OpenBSD: sftp-client.c,v 1.4 2001/02/06 23:30:28 djm Exp $"); | 32 | RCSID("$OpenBSD: sftp-client.c,v 1.8 2001/02/08 17:11:23 stevesk Exp $"); |
33 | 33 | ||
34 | #include "ssh.h" | 34 | #include "ssh.h" |
35 | #include "buffer.h" | 35 | #include "buffer.h" |
@@ -338,7 +338,9 @@ do_ls(int fd_in, int fd_out, char *path) | |||
338 | SSH2_FXP_NAME, type); | 338 | SSH2_FXP_NAME, type); |
339 | 339 | ||
340 | count = buffer_get_int(&msg); | 340 | count = buffer_get_int(&msg); |
341 | debug3("Received %i SSH2_FXP_NAME responses", count); | 341 | if (count == 0) |
342 | break; | ||
343 | debug3("Received %d SSH2_FXP_NAME responses", count); | ||
342 | for(i = 0; i < count; i++) { | 344 | for(i = 0; i < count; i++) { |
343 | char *filename, *longname; | 345 | char *filename, *longname; |
344 | Attrib *a; | 346 | Attrib *a; |
@@ -556,6 +558,7 @@ do_download(int fd_in, int fd_out, char *remote_path, char *local_path, | |||
556 | char *handle; | 558 | char *handle; |
557 | Buffer msg; | 559 | Buffer msg; |
558 | Attrib junk, *a; | 560 | Attrib junk, *a; |
561 | int status; | ||
559 | 562 | ||
560 | a = do_stat(fd_in, fd_out, remote_path); | 563 | a = do_stat(fd_in, fd_out, remote_path); |
561 | if (a == NULL) | 564 | if (a == NULL) |
@@ -635,7 +638,7 @@ do_download(int fd_in, int fd_out, char *remote_path, char *local_path, | |||
635 | if (id != expected_id) | 638 | if (id != expected_id) |
636 | fatal("ID mismatch (%d != %d)", id, expected_id); | 639 | fatal("ID mismatch (%d != %d)", id, expected_id); |
637 | if (type == SSH2_FXP_STATUS) { | 640 | if (type == SSH2_FXP_STATUS) { |
638 | int status = buffer_get_int(&msg); | 641 | status = buffer_get_int(&msg); |
639 | 642 | ||
640 | if (status == SSH2_FX_EOF) | 643 | if (status == SSH2_FX_EOF) |
641 | break; | 644 | break; |
@@ -644,10 +647,7 @@ do_download(int fd_in, int fd_out, char *remote_path, char *local_path, | |||
644 | "file \"%s\" : %s", remote_path, | 647 | "file \"%s\" : %s", remote_path, |
645 | fx2txt(status)); | 648 | fx2txt(status)); |
646 | do_close(fd_in, fd_out, handle, handle_len); | 649 | do_close(fd_in, fd_out, handle, handle_len); |
647 | xfree(handle); | 650 | goto done; |
648 | close(local_fd); | ||
649 | buffer_free(&msg); | ||
650 | return(status); | ||
651 | } | 651 | } |
652 | } else if (type != SSH2_FXP_DATA) { | 652 | } else if (type != SSH2_FXP_DATA) { |
653 | fatal("Expected SSH2_FXP_DATA(%d) packet, got %d", | 653 | fatal("Expected SSH2_FXP_DATA(%d) packet, got %d", |
@@ -659,27 +659,27 @@ do_download(int fd_in, int fd_out, char *remote_path, char *local_path, | |||
659 | fatal("Received more data than asked for %d > %d", | 659 | fatal("Received more data than asked for %d > %d", |
660 | len, COPY_SIZE); | 660 | len, COPY_SIZE); |
661 | 661 | ||
662 | debug3("In read loop, got %d offset %lld", len, | 662 | debug3("In read loop, got %d offset %llu", len, |
663 | (unsigned long long)offset); | 663 | (unsigned long long)offset); |
664 | if (atomicio(write, local_fd, data, len) != len) { | 664 | if (atomicio(write, local_fd, data, len) != len) { |
665 | error("Couldn't write to \"%s\": %s", local_path, | 665 | error("Couldn't write to \"%s\": %s", local_path, |
666 | strerror(errno)); | 666 | strerror(errno)); |
667 | do_close(fd_in, fd_out, handle, handle_len); | 667 | do_close(fd_in, fd_out, handle, handle_len); |
668 | xfree(handle); | 668 | status = -1; |
669 | close(local_fd); | ||
670 | xfree(data); | 669 | xfree(data); |
671 | buffer_free(&msg); | 670 | goto done; |
672 | return(-1); | ||
673 | } | 671 | } |
674 | 672 | ||
675 | offset += len; | 673 | offset += len; |
676 | xfree(data); | 674 | xfree(data); |
677 | } | 675 | } |
678 | xfree(handle); | 676 | status = do_close(fd_in, fd_out, handle, handle_len); |
679 | buffer_free(&msg); | ||
680 | close(local_fd); | ||
681 | 677 | ||
682 | return(do_close(fd_in, fd_out, handle, handle_len)); | 678 | done: |
679 | close(local_fd); | ||
680 | buffer_free(&msg); | ||
681 | xfree(handle); | ||
682 | return status; | ||
683 | } | 683 | } |
684 | 684 | ||
685 | int | 685 | int |
@@ -693,6 +693,7 @@ do_upload(int fd_in, int fd_out, char *local_path, char *remote_path, | |||
693 | Buffer msg; | 693 | Buffer msg; |
694 | struct stat sb; | 694 | struct stat sb; |
695 | Attrib a; | 695 | Attrib a; |
696 | int status; | ||
696 | 697 | ||
697 | if ((local_fd = open(local_path, O_RDONLY, 0)) == -1) { | 698 | if ((local_fd = open(local_path, O_RDONLY, 0)) == -1) { |
698 | error("Couldn't open local file \"%s\" for reading: %s", | 699 | error("Couldn't open local file \"%s\" for reading: %s", |
@@ -743,7 +744,6 @@ do_upload(int fd_in, int fd_out, char *local_path, char *remote_path, | |||
743 | for(;;) { | 744 | for(;;) { |
744 | int len; | 745 | int len; |
745 | char data[COPY_SIZE]; | 746 | char data[COPY_SIZE]; |
746 | u_int status; | ||
747 | 747 | ||
748 | /* | 748 | /* |
749 | * Can't use atomicio here because it returns 0 on EOF, thus losing | 749 | * Can't use atomicio here because it returns 0 on EOF, thus losing |
@@ -774,24 +774,29 @@ do_upload(int fd_in, int fd_out, char *local_path, char *remote_path, | |||
774 | error("Couldn't write to remote file \"%s\": %s", | 774 | error("Couldn't write to remote file \"%s\": %s", |
775 | remote_path, fx2txt(status)); | 775 | remote_path, fx2txt(status)); |
776 | do_close(fd_in, fd_out, handle, handle_len); | 776 | do_close(fd_in, fd_out, handle, handle_len); |
777 | xfree(handle); | ||
778 | close(local_fd); | 777 | close(local_fd); |
779 | return(-1); | 778 | goto done; |
780 | } | 779 | } |
781 | debug3("In write loop, got %d offset %llu", len, | 780 | debug3("In write loop, got %d offset %llu", len, |
782 | (unsigned long long)offset); | 781 | (unsigned long long)offset); |
783 | 782 | ||
784 | offset += len; | 783 | offset += len; |
785 | } | 784 | } |
786 | xfree(handle); | ||
787 | buffer_free(&msg); | ||
788 | 785 | ||
789 | if (close(local_fd) == -1) { | 786 | if (close(local_fd) == -1) { |
790 | error("Couldn't close local file \"%s\": %s", local_path, | 787 | error("Couldn't close local file \"%s\": %s", local_path, |
791 | strerror(errno)); | 788 | strerror(errno)); |
792 | do_close(fd_in, fd_out, handle, handle_len); | 789 | do_close(fd_in, fd_out, handle, handle_len); |
793 | return(-1); | 790 | status = -1; |
791 | goto done; | ||
794 | } | 792 | } |
795 | 793 | ||
796 | return(do_close(fd_in, fd_out, handle, handle_len)); | 794 | status = do_close(fd_in, fd_out, handle, handle_len); |
795 | |||
796 | done: | ||
797 | xfree(handle); | ||
798 | buffer_free(&msg); | ||
799 | return status; | ||
797 | } | 800 | } |
801 | |||
802 | |||
diff --git a/sftp-common.c b/sftp-common.c index aed9b339a..3310eabab 100644 --- a/sftp-common.c +++ b/sftp-common.c | |||
@@ -24,7 +24,7 @@ | |||
24 | */ | 24 | */ |
25 | 25 | ||
26 | #include "includes.h" | 26 | #include "includes.h" |
27 | RCSID("$OpenBSD: sftp-common.c,v 1.1 2001/02/04 11:11:54 djm Exp $"); | 27 | RCSID("$OpenBSD: sftp-common.c,v 1.2 2001/02/06 23:50:10 markus Exp $"); |
28 | 28 | ||
29 | #include "buffer.h" | 29 | #include "buffer.h" |
30 | #include "bufaux.h" | 30 | #include "bufaux.h" |
@@ -121,13 +121,13 @@ fx2txt(int status) | |||
121 | { | 121 | { |
122 | switch (status) { | 122 | switch (status) { |
123 | case SSH2_FX_OK: | 123 | case SSH2_FX_OK: |
124 | return("No Error"); | 124 | return("No error"); |
125 | case SSH2_FX_EOF: | 125 | case SSH2_FX_EOF: |
126 | return("End of File"); | 126 | return("End of file"); |
127 | case SSH2_FX_NO_SUCH_FILE: | 127 | case SSH2_FX_NO_SUCH_FILE: |
128 | return("No Such File"); | 128 | return("No such file or directory"); |
129 | case SSH2_FX_PERMISSION_DENIED: | 129 | case SSH2_FX_PERMISSION_DENIED: |
130 | return("Permission Denied"); | 130 | return("Permission denied"); |
131 | case SSH2_FX_FAILURE: | 131 | case SSH2_FX_FAILURE: |
132 | return("Failure"); | 132 | return("Failure"); |
133 | case SSH2_FX_BAD_MESSAGE: | 133 | case SSH2_FX_BAD_MESSAGE: |
diff --git a/sftp-int.c b/sftp-int.c index 02e0d38c0..8b5ae3aef 100644 --- a/sftp-int.c +++ b/sftp-int.c | |||
@@ -24,10 +24,11 @@ | |||
24 | 24 | ||
25 | /* XXX: finish implementation of all commands */ | 25 | /* XXX: finish implementation of all commands */ |
26 | /* XXX: do fnmatch() instead of using raw pathname */ | 26 | /* XXX: do fnmatch() instead of using raw pathname */ |
27 | /* XXX: globbed ls */ | ||
27 | /* XXX: recursive operations */ | 28 | /* XXX: recursive operations */ |
28 | 29 | ||
29 | #include "includes.h" | 30 | #include "includes.h" |
30 | RCSID("$OpenBSD: sftp-int.c,v 1.7 2001/02/05 00:02:32 deraadt Exp $"); | 31 | RCSID("$OpenBSD: sftp-int.c,v 1.19 2001/02/09 11:46:24 djm Exp $"); |
31 | 32 | ||
32 | #include "buffer.h" | 33 | #include "buffer.h" |
33 | #include "xmalloc.h" | 34 | #include "xmalloc.h" |
@@ -70,28 +71,29 @@ struct CMD { | |||
70 | }; | 71 | }; |
71 | 72 | ||
72 | const struct CMD cmds[] = { | 73 | const struct CMD cmds[] = { |
73 | { "CD", I_CHDIR }, | 74 | { "cd", I_CHDIR }, |
74 | { "CHDIR", I_CHDIR }, | 75 | { "chdir", I_CHDIR }, |
75 | { "CHGRP", I_CHGRP }, | 76 | { "chgrp", I_CHGRP }, |
76 | { "CHMOD", I_CHMOD }, | 77 | { "chmod", I_CHMOD }, |
77 | { "CHOWN", I_CHOWN }, | 78 | { "chown", I_CHOWN }, |
78 | { "EXIT", I_QUIT }, | 79 | { "dir", I_LS }, |
79 | { "GET", I_GET }, | 80 | { "exit", I_QUIT }, |
80 | { "HELP", I_HELP }, | 81 | { "get", I_GET }, |
81 | { "LCD", I_LCHDIR }, | 82 | { "help", I_HELP }, |
82 | { "LCHDIR", I_LCHDIR }, | 83 | { "lcd", I_LCHDIR }, |
83 | { "LLS", I_LLS }, | 84 | { "lchdir", I_LCHDIR }, |
84 | { "LMKDIR", I_LMKDIR }, | 85 | { "lls", I_LLS }, |
85 | { "LPWD", I_LPWD }, | 86 | { "lmkdir", I_LMKDIR }, |
86 | { "LS", I_LS }, | 87 | { "lpwd", I_LPWD }, |
87 | { "LUMASK", I_LUMASK }, | 88 | { "ls", I_LS }, |
88 | { "MKDIR", I_MKDIR }, | 89 | { "lumask", I_LUMASK }, |
89 | { "PUT", I_PUT }, | 90 | { "mkdir", I_MKDIR }, |
90 | { "PWD", I_PWD }, | 91 | { "put", I_PUT }, |
91 | { "QUIT", I_QUIT }, | 92 | { "pwd", I_PWD }, |
92 | { "RENAME", I_RENAME }, | 93 | { "quit", I_QUIT }, |
93 | { "RM", I_RM }, | 94 | { "rename", I_RENAME }, |
94 | { "RMDIR", I_RMDIR }, | 95 | { "rm", I_RM }, |
96 | { "rmdir", I_RMDIR }, | ||
95 | { "!", I_SHELL }, | 97 | { "!", I_SHELL }, |
96 | { "?", I_HELP }, | 98 | { "?", I_HELP }, |
97 | { NULL, -1} | 99 | { NULL, -1} |
@@ -101,28 +103,29 @@ void | |||
101 | help(void) | 103 | help(void) |
102 | { | 104 | { |
103 | printf("Available commands:\n"); | 105 | printf("Available commands:\n"); |
104 | printf("CD path Change remote directory to 'path'\n"); | 106 | printf("cd path Change remote directory to 'path'\n"); |
105 | printf("LCD path Change local directory to 'path'\n"); | 107 | printf("lcd path Change local directory to 'path'\n"); |
106 | printf("CHGRP grp path Change group of file 'path' to 'grp'\n"); | 108 | printf("chgrp grp path Change group of file 'path' to 'grp'\n"); |
107 | printf("CHMOD mode path Change permissions of file 'path' to 'mode'\n"); | 109 | printf("chmod mode path Change permissions of file 'path' to 'mode'\n"); |
108 | printf("CHOWN own path Change owner of file 'path' to 'own'\n"); | 110 | printf("chown own path Change owner of file 'path' to 'own'\n"); |
109 | printf("HELP Display this help text\n"); | 111 | printf("help Display this help text\n"); |
110 | printf("GET remote-path [local-path] Download file\n"); | 112 | printf("get remote-path [local-path] Download file\n"); |
111 | printf("LLS [ls options] [path] Display local directory listing\n"); | 113 | printf("lls [ls-options [path]] Display local directory listing\n"); |
112 | printf("LMKDIR path Create local directory\n"); | 114 | printf("lmkdir path Create local directory\n"); |
113 | printf("LPWD Print local working directory\n"); | 115 | printf("lpwd Print local working directory\n"); |
114 | printf("LS [path] Display remote directory listing\n"); | 116 | printf("ls [path] Display remote directory listing\n"); |
115 | printf("LUMASK umask Set local umask to 'umask'\n"); | 117 | printf("lumask umask Set local umask to 'umask'\n"); |
116 | printf("MKDIR path Create remote directory\n"); | 118 | printf("mkdir path Create remote directory\n"); |
117 | printf("PUT local-path [remote-path] Upload file\n"); | 119 | printf("put local-path [remote-path] Upload file\n"); |
118 | printf("PWD Display remote working directory\n"); | 120 | printf("pwd Display remote working directory\n"); |
119 | printf("EXIT Quit sftp\n"); | 121 | printf("exit Quit sftp\n"); |
120 | printf("QUIT Quit sftp\n"); | 122 | printf("quit Quit sftp\n"); |
121 | printf("RENAME oldpath newpath Rename remote file\n"); | 123 | printf("rename oldpath newpath Rename remote file\n"); |
122 | printf("RMDIR path Remove remote directory\n"); | 124 | printf("rmdir path Remove remote directory\n"); |
123 | printf("RM path Delete remote file\n"); | 125 | printf("rm path Delete remote file\n"); |
124 | printf("!command Execute 'command' in local shell\n"); | 126 | printf("!command Execute 'command' in local shell\n"); |
125 | printf("! Escape to local shell\n"); | 127 | printf("! Escape to local shell\n"); |
128 | printf("? Synonym for help\n"); | ||
126 | } | 129 | } |
127 | 130 | ||
128 | void | 131 | void |
@@ -166,13 +169,15 @@ void | |||
166 | local_do_ls(const char *args) | 169 | local_do_ls(const char *args) |
167 | { | 170 | { |
168 | if (!args || !*args) | 171 | if (!args || !*args) |
169 | local_do_shell("ls"); | 172 | local_do_shell(_PATH_LS); |
170 | else { | 173 | else { |
171 | char *buf = xmalloc(8 + strlen(args) + 1); | 174 | int len = strlen(_PATH_LS " ") + strlen(args) + 1; |
175 | char *buf = xmalloc(len); | ||
172 | 176 | ||
173 | /* XXX: quoting - rip quoting code from ftp? */ | 177 | /* XXX: quoting - rip quoting code from ftp? */ |
174 | sprintf(buf, "/bin/ls %s", args); | 178 | snprintf(buf, len, _PATH_LS " %s", args); |
175 | local_do_shell(buf); | 179 | local_do_shell(buf); |
180 | xfree(buf); | ||
176 | } | 181 | } |
177 | } | 182 | } |
178 | 183 | ||
@@ -198,7 +203,7 @@ parse_getput_flags(const char **cpp, int *pflag) | |||
198 | 203 | ||
199 | /* Check for flags */ | 204 | /* Check for flags */ |
200 | if (cp[0] == '-' && cp[1] && strchr(WHITESPACE, cp[2])) { | 205 | if (cp[0] == '-' && cp[1] && strchr(WHITESPACE, cp[2])) { |
201 | switch (*cp) { | 206 | switch (cp[1]) { |
202 | case 'P': | 207 | case 'P': |
203 | *pflag = 1; | 208 | *pflag = 1; |
204 | break; | 209 | break; |
@@ -216,50 +221,49 @@ parse_getput_flags(const char **cpp, int *pflag) | |||
216 | int | 221 | int |
217 | get_pathname(const char **cpp, char **path) | 222 | get_pathname(const char **cpp, char **path) |
218 | { | 223 | { |
219 | const char *quot, *cp = *cpp; | 224 | const char *cp = *cpp, *end; |
225 | char quot; | ||
220 | int i; | 226 | int i; |
221 | 227 | ||
222 | cp += strspn(cp, WHITESPACE); | 228 | cp += strspn(cp, WHITESPACE); |
223 | if (!*cp) { | 229 | if (!*cp) { |
224 | *cpp = cp; | 230 | *cpp = cp; |
225 | *path = NULL; | 231 | *path = NULL; |
226 | return(0); | 232 | return (0); |
227 | } | 233 | } |
228 | 234 | ||
229 | /* Check for quoted filenames */ | 235 | /* Check for quoted filenames */ |
230 | if (*cp == '\"' || *cp == '\'') { | 236 | if (*cp == '\"' || *cp == '\'') { |
231 | quot = cp++; | 237 | quot = *cp++; |
232 | for(i = 0; cp[i] && cp[i] != *quot; i++) | 238 | |
233 | ; | 239 | end = strchr(cp, quot); |
234 | if (!cp[i]) { | 240 | if (end == NULL) { |
235 | error("Unterminated quote"); | 241 | error("Unterminated quote"); |
236 | *path = NULL; | 242 | goto fail; |
237 | return(-1); | ||
238 | } | 243 | } |
239 | if (i == 0) { | 244 | if (cp == end) { |
240 | error("Empty quotes"); | 245 | error("Empty quotes"); |
241 | *path = NULL; | 246 | goto fail; |
242 | return(-1); | ||
243 | } | 247 | } |
244 | *path = xmalloc(i + 1); | 248 | *cpp = end + 1 + strspn(end + 1, WHITESPACE); |
245 | memcpy(*path, cp, i); | 249 | } else { |
246 | (*path)[i] = '\0'; | 250 | /* Read to end of filename */ |
247 | cp += i + 1; | 251 | end = strpbrk(cp, WHITESPACE); |
248 | *cpp = cp + strspn(cp, WHITESPACE); | 252 | if (end == NULL) |
249 | return(0); | 253 | end = strchr(cp, '\0'); |
254 | *cpp = end + strspn(end, WHITESPACE); | ||
250 | } | 255 | } |
251 | 256 | ||
252 | /* Read to end of filename */ | 257 | i = end - cp; |
253 | for(i = 0; cp[i] && cp[i] != ' '; i++) | ||
254 | ; | ||
255 | 258 | ||
256 | *path = xmalloc(i + 1); | 259 | *path = xmalloc(i + 1); |
257 | memcpy(*path, cp, i); | 260 | memcpy(*path, cp, i); |
258 | (*path)[i] = '\0'; | 261 | (*path)[i] = '\0'; |
259 | cp += i; | ||
260 | *cpp = cp + strspn(cp, WHITESPACE); | ||
261 | |||
262 | return(0); | 262 | return(0); |
263 | |||
264 | fail: | ||
265 | *path = NULL; | ||
266 | return (-1); | ||
263 | } | 267 | } |
264 | 268 | ||
265 | int | 269 | int |
@@ -270,7 +274,6 @@ infer_path(const char *p, char **ifp) | |||
270 | debug("XXX: P = \"%s\"", p); | 274 | debug("XXX: P = \"%s\"", p); |
271 | 275 | ||
272 | cp = strrchr(p, '/'); | 276 | cp = strrchr(p, '/'); |
273 | |||
274 | if (cp == NULL) { | 277 | if (cp == NULL) { |
275 | *ifp = xstrdup(p); | 278 | *ifp = xstrdup(p); |
276 | return(0); | 279 | return(0); |
@@ -421,14 +424,13 @@ parse_args(const char **cpp, int *pflag, unsigned long *n_arg, | |||
421 | } | 424 | } |
422 | 425 | ||
423 | *cpp = cp; | 426 | *cpp = cp; |
424 | |||
425 | return(cmdnum); | 427 | return(cmdnum); |
426 | } | 428 | } |
427 | 429 | ||
428 | int | 430 | int |
429 | parse_dispatch_command(int in, int out, const char *cmd, char **pwd) | 431 | parse_dispatch_command(int in, int out, const char *cmd, char **pwd) |
430 | { | 432 | { |
431 | char *path1, *path2; | 433 | char *path1, *path2, *tmp; |
432 | int pflag, cmdnum; | 434 | int pflag, cmdnum; |
433 | unsigned long n_arg; | 435 | unsigned long n_arg; |
434 | Attrib a, *aa; | 436 | Attrib a, *aa; |
@@ -471,12 +473,44 @@ parse_dispatch_command(int in, int out, const char *cmd, char **pwd) | |||
471 | break; | 473 | break; |
472 | case I_CHDIR: | 474 | case I_CHDIR: |
473 | path1 = make_absolute(path1, *pwd); | 475 | path1 = make_absolute(path1, *pwd); |
476 | if ((tmp = do_realpath(in, out, path1)) == NULL) | ||
477 | break; | ||
478 | if ((aa = do_stat(in, out, tmp)) == NULL) { | ||
479 | xfree(tmp); | ||
480 | break; | ||
481 | } | ||
482 | if (!(aa->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)) { | ||
483 | error("Can't change directory: Can't check target"); | ||
484 | xfree(tmp); | ||
485 | break; | ||
486 | } | ||
487 | if (!S_ISDIR(aa->perm)) { | ||
488 | error("Can't change directory: \"%s\" is not " | ||
489 | "a directory", tmp); | ||
490 | xfree(tmp); | ||
491 | break; | ||
492 | } | ||
474 | xfree(*pwd); | 493 | xfree(*pwd); |
475 | *pwd = do_realpath(in, out, path1); | 494 | *pwd = tmp; |
476 | break; | 495 | break; |
477 | case I_LS: | 496 | case I_LS: |
497 | if (!path1) { | ||
498 | do_ls(in, out, *pwd); | ||
499 | break; | ||
500 | } | ||
478 | path1 = make_absolute(path1, *pwd); | 501 | path1 = make_absolute(path1, *pwd); |
479 | do_ls(in, out, path1?path1:*pwd); | 502 | if ((tmp = do_realpath(in, out, path1)) == NULL) |
503 | break; | ||
504 | xfree(path1); | ||
505 | path1 = tmp; | ||
506 | if ((aa = do_stat(in, out, path1)) == NULL) | ||
507 | break; | ||
508 | if ((aa->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) && | ||
509 | !S_ISDIR(aa->perm)) { | ||
510 | error("Can't ls: \"%s\" is not a directory", path1); | ||
511 | break; | ||
512 | } | ||
513 | do_ls(in, out, path1); | ||
480 | break; | 514 | break; |
481 | case I_LCHDIR: | 515 | case I_LCHDIR: |
482 | if (chdir(path1) == -1) | 516 | if (chdir(path1) == -1) |
@@ -485,7 +519,7 @@ parse_dispatch_command(int in, int out, const char *cmd, char **pwd) | |||
485 | break; | 519 | break; |
486 | case I_LMKDIR: | 520 | case I_LMKDIR: |
487 | if (mkdir(path1, 0777) == -1) | 521 | if (mkdir(path1, 0777) == -1) |
488 | error("Couldn't create local directory to " | 522 | error("Couldn't create local directory " |
489 | "\"%s\": %s", path1, strerror(errno)); | 523 | "\"%s\": %s", path1, strerror(errno)); |
490 | break; | 524 | break; |
491 | case I_LLS: | 525 | case I_LLS: |
@@ -506,23 +540,27 @@ parse_dispatch_command(int in, int out, const char *cmd, char **pwd) | |||
506 | break; | 540 | break; |
507 | case I_CHOWN: | 541 | case I_CHOWN: |
508 | path1 = make_absolute(path1, *pwd); | 542 | path1 = make_absolute(path1, *pwd); |
509 | aa = do_stat(in, out, path1); | 543 | if (!(aa = do_stat(in, out, path1))) |
544 | break; | ||
510 | if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) { | 545 | if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) { |
511 | error("Can't get current ownership of " | 546 | error("Can't get current ownership of " |
512 | "remote file \"%s\"", path1); | 547 | "remote file \"%s\"", path1); |
513 | break; | 548 | break; |
514 | } | 549 | } |
550 | aa->flags &= SSH2_FILEXFER_ATTR_UIDGID; | ||
515 | aa->uid = n_arg; | 551 | aa->uid = n_arg; |
516 | do_setstat(in, out, path1, aa); | 552 | do_setstat(in, out, path1, aa); |
517 | break; | 553 | break; |
518 | case I_CHGRP: | 554 | case I_CHGRP: |
519 | path1 = make_absolute(path1, *pwd); | 555 | path1 = make_absolute(path1, *pwd); |
520 | aa = do_stat(in, out, path1); | 556 | if (!(aa = do_stat(in, out, path1))) |
557 | break; | ||
521 | if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) { | 558 | if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) { |
522 | error("Can't get current ownership of " | 559 | error("Can't get current ownership of " |
523 | "remote file \"%s\"", path1); | 560 | "remote file \"%s\"", path1); |
524 | break; | 561 | break; |
525 | } | 562 | } |
563 | aa->flags &= SSH2_FILEXFER_ATTR_UIDGID; | ||
526 | aa->gid = n_arg; | 564 | aa->gid = n_arg; |
527 | do_setstat(in, out, path1, aa); | 565 | do_setstat(in, out, path1, aa); |
528 | break; | 566 | break; |
@@ -550,7 +588,6 @@ parse_dispatch_command(int in, int out, const char *cmd, char **pwd) | |||
550 | xfree(path1); | 588 | xfree(path1); |
551 | if (path2) | 589 | if (path2) |
552 | xfree(path2); | 590 | xfree(path2); |
553 | |||
554 | return(0); | 591 | return(0); |
555 | } | 592 | } |
556 | 593 | ||
@@ -564,8 +601,8 @@ interactive_loop(int fd_in, int fd_out) | |||
564 | if (pwd == NULL) | 601 | if (pwd == NULL) |
565 | fatal("Need cwd"); | 602 | fatal("Need cwd"); |
566 | 603 | ||
567 | setvbuf(stdout, (char *)NULL, _IOLBF, 0); | 604 | setvbuf(stdout, NULL, _IOLBF, 0); |
568 | setvbuf(stdin, (char *)NULL, _IOLBF, 0); | 605 | setvbuf(stdin, NULL, _IOLBF, 0); |
569 | 606 | ||
570 | for(;;) { | 607 | for(;;) { |
571 | char *cp; | 608 | char *cp; |
@@ -1,4 +1,4 @@ | |||
1 | .\" $OpenBSD: sftp.1,v 1.1 2001/02/04 11:11:54 djm Exp $ | 1 | .\" $OpenBSD: sftp.1,v 1.5 2001/02/07 18:10:39 stevesk Exp $ |
2 | .\" | 2 | .\" |
3 | .\" Copyright (c) 2001 Damien Miller. All rights reserved. | 3 | .\" Copyright (c) 2001 Damien Miller. All rights reserved. |
4 | .\" | 4 | .\" |
@@ -30,7 +30,7 @@ | |||
30 | .Nd Secure file tranfer program | 30 | .Nd Secure file tranfer program |
31 | .Sh SYNOPSIS | 31 | .Sh SYNOPSIS |
32 | .Nm sftp | 32 | .Nm sftp |
33 | .Op Fl v Li | Fl C | 33 | .Op Fl vC |
34 | .Op Fl o Ar ssh_option | 34 | .Op Fl o Ar ssh_option |
35 | .Op Ar hostname | user@hostname | 35 | .Op Ar hostname | user@hostname |
36 | .Sh DESCRIPTION | 36 | .Sh DESCRIPTION |
@@ -44,113 +44,122 @@ It may also use many features of ssh, such as public key authentication and | |||
44 | compression. | 44 | compression. |
45 | .Nm | 45 | .Nm |
46 | connects and logs into the specified | 46 | connects and logs into the specified |
47 | .Ar hostname | 47 | .Ar hostname , |
48 | then enters an interactive command mode. | 48 | then enters an interactive command mode. |
49 | .Pp | 49 | .Pp |
50 | The options are as follows: | 50 | The options are as follows: |
51 | .Bl -tag -width Ds | 51 | .Bl -tag -width Ds |
52 | .It Fl v | ||
53 | Raise logging level. This option is also passed to ssh. | ||
52 | .It Fl C | 54 | .It Fl C |
53 | Enables compression (via ssh's | 55 | Enables compression (via ssh's |
54 | .Fl C | 56 | .Fl C |
55 | flag) | 57 | flag) |
56 | .It Fl v | ||
57 | Raise logging level. This option is also passed to ssh. | ||
58 | .It Fl o Ar ssh_option | 58 | .It Fl o Ar ssh_option |
59 | Specify an option to be directly passed to | 59 | Specify an option to be directly passed to |
60 | .Xr ssh 1 . | 60 | .Xr ssh 1 . |
61 | .El | 61 | .El |
62 | .Sh INTERACTIVE COMMANDS | 62 | .Sh INTERACTIVE COMMANDS |
63 | Once in interactive mode | 63 | Once in interactive mode, |
64 | .Nm , | 64 | .Nm |
65 | understands a set of commands similar to those of | 65 | understands a set of commands similar to those of |
66 | .Xr ftp 1 . | 66 | .Xr ftp 1 . |
67 | Commands are case insensitive. | 67 | Commands are case insensitive. |
68 | .Bl -tag -width Ds | 68 | .Bl -tag -width Ds |
69 | .It Ic CD Ar path | 69 | .It Ic cd Ar path |
70 | Change remote directory to | 70 | Change remote directory to |
71 | .Ar path | 71 | .Ar path . |
72 | .It Ic LCD Ar path | 72 | .It Ic lcd Ar path |
73 | Change local directory to | 73 | Change local directory to |
74 | .Ar path | 74 | .Ar path . |
75 | .It Ic CHGRP Ar grp Ar path | 75 | .It Ic chgrp Ar grp Ar path |
76 | Change group of file | 76 | Change group of file |
77 | .Ar path to | 77 | .Ar path |
78 | to | ||
78 | .Ar grp . | 79 | .Ar grp . |
79 | .Ar grp | 80 | .Ar grp |
80 | must be numeric. | 81 | must be a numeric GID. |
81 | .It Ic CHMOD Ar mode Ar path | 82 | .It Ic chmod Ar mode Ar path |
82 | Change permissions of file | 83 | Change permissions of file |
83 | .Ar path to | 84 | .Ar path |
84 | .Ar mode | 85 | to |
85 | .It Ic CHOWN Ar own Ar path | 86 | .Ar mode . |
87 | .It Ic chown Ar own Ar path | ||
86 | Change owner of file | 88 | Change owner of file |
87 | .Ar path to | 89 | .Ar path |
90 | to | ||
88 | .Ar own . | 91 | .Ar own . |
89 | .Ar own | 92 | .Ar own |
90 | must be a numeric UID. | 93 | must be a numeric UID. |
91 | .It Ic HELP | 94 | .It Ic help |
92 | Display help text | 95 | Display help text. |
93 | .It Ic GET Ar remote-file Op Ar local-file | 96 | .It Ic get Ar remote-path Op Ar local-path |
94 | Retrieve the | 97 | Retrieve the |
95 | .Ar remote-file | 98 | .Ar remote-path |
96 | and store it on the local machine. | 99 | and store it on the local machine. |
97 | If the local | 100 | If the local |
98 | file name is not specified, it is given the same name it has on the | 101 | path name is not specified, it is given the same name it has on the |
99 | remote machine. | 102 | remote machine. |
100 | .It Ic LLS Op Ar ls-options Op Ar path | 103 | .It Ic lls Op Ar ls-options Op Ar path |
101 | Display local directory listing of either | 104 | Display local directory listing of either |
102 | .Ar path | 105 | .Ar path |
103 | or current directory if | 106 | or current directory if |
104 | .Ar path | 107 | .Ar path |
105 | was not specified. | 108 | is not specified. |
106 | .It Ic LMKDIR Ar path | 109 | .It Ic lmkdir Ar path |
107 | Create local directory specified by | 110 | Create local directory specified by |
108 | .Ar path | 111 | .Ar path . |
109 | .It Ic LPWD | 112 | .It Ic lpwd |
110 | Print local working directory | 113 | Print local working directory. |
111 | .It Ic LS Op Ar path | 114 | .It Ic ls Op Ar path |
112 | Display remote directory listing of either | 115 | Display remote directory listing of either |
113 | .Ar path | 116 | .Ar path |
114 | or current directory, is | 117 | or current directory if |
115 | .Ar path not specified. | 118 | .Ar path |
116 | .It Ic LUMASK Ar umask | 119 | is not specified. |
120 | .It Ic lumask Ar umask | ||
117 | Set local umask to | 121 | Set local umask to |
118 | .Ar umask | 122 | .Ar umask . |
119 | .It Ic MKDIR Ar path | 123 | .It Ic mkdir Ar path |
120 | Create remote directory specified by | 124 | Create remote directory specified by |
121 | .Ar path | 125 | .Ar path . |
122 | .It Ic PUT local-file Op Ar remote-file | 126 | .It Ic put Ar local-path Op Ar remote-path |
123 | Upload | 127 | Upload |
124 | .Ar local-file | 128 | .Ar local-path |
125 | and store it on the remote machine. If the local file name is not specified, | 129 | and store it on the remote machine. If the remote path name is not specified, |
126 | it is given the same name it has on the local machine. | 130 | it is given the same name it has on the local machine. |
127 | .It Ic PWD | 131 | .It Ic pwd |
128 | Display remote working directory | 132 | Display remote working directory. |
129 | .It Ic EXIT | 133 | .It Ic exit |
130 | Quit sftp | 134 | Quit sftp. |
131 | .It Ic QUIT | 135 | .It Ic quit |
132 | Quit sftp | 136 | Quit sftp. |
133 | .It Ic RENAME Ar oldpath Ar newpath | 137 | .It Ic rename Ar oldpath Ar newpath |
134 | Rename remote file from | 138 | Rename remote file from |
135 | .Ar oldpath | 139 | .Ar oldpath |
136 | to | 140 | to |
137 | .Ar newpath | 141 | .Ar newpath . |
138 | .It Ic RMDIR Ar path | 142 | .It Ic rmdir Ar path |
139 | Remove remote directory specified by | 143 | Remove remote directory specified by |
140 | .Ar path | 144 | .Ar path . |
141 | .It Ic RM Ar path | 145 | .It Ic rm Ar path |
142 | Delete remote file specified by | 146 | Delete remote file specified by |
143 | .Ar path | 147 | .Ar path . |
144 | .It Ic ! Ar command | 148 | .It Ic ! Ar command |
145 | Execute | 149 | Execute |
146 | .Ar command | 150 | .Ar command |
147 | in local shell | 151 | in local shell. |
148 | .It Ic ! | 152 | .It Ic ! |
149 | Escape to local shell | 153 | Escape to local shell. |
154 | .It Ic ? | ||
155 | Synonym for help. | ||
156 | .El | ||
150 | .Sh AUTHORS | 157 | .Sh AUTHORS |
151 | Damien Miller <djm@mindrot.org> | 158 | Damien Miller <djm@mindrot.org> |
152 | .Sh SEE ALSO | 159 | .Sh SEE ALSO |
153 | .Xr ssh 1 , | 160 | .Xr ssh 1 , |
154 | .Xr ssh-add 1 , | 161 | .Xr ssh-add 1 , |
155 | .Xr ssh-keygen 1 , | 162 | .Xr ssh-keygen 1 , |
156 | .Xr sshd 8 | 163 | .Xr sshd 8 , |
164 | .Xr scp 1 | ||
165 | |||
@@ -24,7 +24,7 @@ | |||
24 | 24 | ||
25 | #include "includes.h" | 25 | #include "includes.h" |
26 | 26 | ||
27 | RCSID("$OpenBSD: sftp.c,v 1.2 2001/02/04 15:32:25 stevesk Exp $"); | 27 | RCSID("$OpenBSD: sftp.c,v 1.7 2001/02/08 00:04:52 markus Exp $"); |
28 | 28 | ||
29 | /* XXX: commandline mode */ | 29 | /* XXX: commandline mode */ |
30 | /* XXX: copy between two remote hosts (commandline) */ | 30 | /* XXX: copy between two remote hosts (commandline) */ |
@@ -40,6 +40,10 @@ RCSID("$OpenBSD: sftp.c,v 1.2 2001/02/04 15:32:25 stevesk Exp $"); | |||
40 | #include "sftp-client.h" | 40 | #include "sftp-client.h" |
41 | #include "sftp-int.h" | 41 | #include "sftp-int.h" |
42 | 42 | ||
43 | int use_ssh1 = 0; | ||
44 | char *ssh_program = _PATH_SSH_PROGRAM; | ||
45 | char *sftp_server = NULL; | ||
46 | |||
43 | void | 47 | void |
44 | connect_to_server(char **args, int *in, int *out, pid_t *sshpid) | 48 | connect_to_server(char **args, int *in, int *out, pid_t *sshpid) |
45 | { | 49 | { |
@@ -72,8 +76,8 @@ connect_to_server(char **args, int *in, int *out, pid_t *sshpid) | |||
72 | close(*out); | 76 | close(*out); |
73 | close(c_in); | 77 | close(c_in); |
74 | close(c_out); | 78 | close(c_out); |
75 | execv(_PATH_SSH_PROGRAM, args); | 79 | execv(ssh_program, args); |
76 | fprintf(stderr, "exec: %s", strerror(errno)); | 80 | fprintf(stderr, "exec: %s: %s\n", ssh_program, strerror(errno)); |
77 | exit(1); | 81 | exit(1); |
78 | } | 82 | } |
79 | 83 | ||
@@ -87,16 +91,24 @@ make_ssh_args(char *add_arg) | |||
87 | static char **args = NULL; | 91 | static char **args = NULL; |
88 | static int nargs = 0; | 92 | static int nargs = 0; |
89 | char debug_buf[4096]; | 93 | char debug_buf[4096]; |
90 | int i; | 94 | int i, use_subsystem = 1; |
95 | |||
96 | /* no subsystem if protocol 1 or the server-spec contains a '/' */ | ||
97 | if (use_ssh1 || | ||
98 | (sftp_server != NULL && strchr(sftp_server, '/') != NULL)) | ||
99 | use_subsystem = 0; | ||
91 | 100 | ||
92 | /* Init args array */ | 101 | /* Init args array */ |
93 | if (args == NULL) { | 102 | if (args == NULL) { |
94 | nargs = 4; | 103 | nargs = use_subsystem ? 6 : 5; |
95 | i = 0; | 104 | i = 0; |
96 | args = xmalloc(sizeof(*args) * nargs); | 105 | args = xmalloc(sizeof(*args) * nargs); |
97 | args[i++] = "ssh"; | 106 | args[i++] = "ssh"; |
98 | args[i++] = "-oProtocol=2"; | 107 | args[i++] = use_ssh1 ? "-oProtocol=1" : "-oProtocol=2"; |
99 | args[i++] = "-s"; | 108 | if (use_subsystem) |
109 | args[i++] = "-s"; | ||
110 | args[i++] = "-oForwardAgent=no"; | ||
111 | args[i++] = "-oForwardX11=no"; | ||
100 | args[i++] = NULL; | 112 | args[i++] = NULL; |
101 | } | 113 | } |
102 | 114 | ||
@@ -110,7 +122,10 @@ make_ssh_args(char *add_arg) | |||
110 | } | 122 | } |
111 | 123 | ||
112 | /* Otherwise finish up and return the arg array */ | 124 | /* Otherwise finish up and return the arg array */ |
113 | make_ssh_args("sftp"); | 125 | if (sftp_server != NULL) |
126 | make_ssh_args(sftp_server); | ||
127 | else | ||
128 | make_ssh_args("sftp"); | ||
114 | 129 | ||
115 | /* XXX: overflow - doesn't grow debug_buf */ | 130 | /* XXX: overflow - doesn't grow debug_buf */ |
116 | debug_buf[0] = '\0'; | 131 | debug_buf[0] = '\0'; |
@@ -128,49 +143,70 @@ make_ssh_args(char *add_arg) | |||
128 | void | 143 | void |
129 | usage(void) | 144 | usage(void) |
130 | { | 145 | { |
131 | fprintf(stderr, "usage: sftp [-vC] [-osshopt=value] [user@]host\n"); | 146 | fprintf(stderr, "usage: sftp [-1vC] [-osshopt=value] [user@]host\n"); |
132 | exit(1); | 147 | exit(1); |
133 | } | 148 | } |
134 | 149 | ||
135 | int | 150 | int |
136 | main(int argc, char **argv) | 151 | main(int argc, char **argv) |
137 | { | 152 | { |
138 | int in, out, i, debug_level, compress_flag; | 153 | int in, out, ch, debug_level, compress_flag; |
139 | pid_t sshpid; | 154 | pid_t sshpid; |
140 | char *cp; | 155 | char *host, *userhost; |
141 | LogLevel ll; | 156 | LogLevel ll; |
157 | extern int optind; | ||
158 | extern char *optarg; | ||
142 | 159 | ||
143 | debug_level = compress_flag = 0; | 160 | debug_level = compress_flag = 0; |
144 | for(i = 1; i < argc && argv[i][0] == '-'; i++) { | 161 | |
145 | if (!strcmp(argv[i], "-v")) | 162 | while ((ch = getopt(argc, argv, "1hvCo:s:S:")) != -1) { |
146 | debug_level = MIN(3, debug_level + 1); | 163 | switch (ch) { |
147 | else if (!strcmp(argv[i], "-C")) | 164 | case 'C': |
148 | compress_flag = 1; | 165 | compress_flag = 1; |
149 | else if (!strncmp(argv[i], "-o", 2)) { | 166 | break; |
150 | make_ssh_args(argv[i]); | 167 | case 'v': |
151 | } else { | 168 | debug_level = MIN(3, debug_level + 1); |
152 | fprintf(stderr, "Unknown option \"%s\"\n", argv[i]); | 169 | break; |
170 | case 'o': | ||
171 | make_ssh_args("-o"); | ||
172 | make_ssh_args(optarg); | ||
173 | break; | ||
174 | case '1': | ||
175 | use_ssh1 = 1; | ||
176 | if (sftp_server == NULL) | ||
177 | sftp_server = _PATH_SFTP_SERVER; | ||
178 | break; | ||
179 | case 's': | ||
180 | sftp_server = optarg; | ||
181 | break; | ||
182 | case 'S': | ||
183 | ssh_program = optarg; | ||
184 | break; | ||
185 | case 'h': | ||
186 | default: | ||
153 | usage(); | 187 | usage(); |
154 | } | 188 | } |
155 | } | 189 | } |
156 | 190 | ||
157 | if (i == argc || argc > (i + 1)) | 191 | if (optind == argc || argc > (optind + 1)) |
158 | usage(); | 192 | usage(); |
159 | 193 | ||
160 | if ((cp = strchr(argv[i], '@')) == NULL) | 194 | userhost = argv[optind]; |
161 | cp = argv[i]; | 195 | |
196 | if ((host = strchr(userhost, '@')) == NULL) | ||
197 | host = userhost; | ||
162 | else { | 198 | else { |
163 | *cp = '\0'; | 199 | *host = '\0'; |
164 | if (!argv[i][0]) { | 200 | if (!userhost[0]) { |
165 | fprintf(stderr, "Missing username\n"); | 201 | fprintf(stderr, "Missing username\n"); |
166 | usage(); | 202 | usage(); |
167 | } | 203 | } |
168 | make_ssh_args("-l"); | 204 | make_ssh_args("-l"); |
169 | make_ssh_args(argv[i]); | 205 | make_ssh_args(userhost); |
170 | cp++; | 206 | host++; |
171 | } | 207 | } |
172 | 208 | ||
173 | if (!*cp) { | 209 | if (!*host) { |
174 | fprintf(stderr, "Missing hostname\n"); | 210 | fprintf(stderr, "Missing hostname\n"); |
175 | usage(); | 211 | usage(); |
176 | } | 212 | } |
@@ -200,9 +236,9 @@ main(int argc, char **argv) | |||
200 | 236 | ||
201 | log_init(argv[0], ll, SYSLOG_FACILITY_USER, 1); | 237 | log_init(argv[0], ll, SYSLOG_FACILITY_USER, 1); |
202 | 238 | ||
203 | make_ssh_args(cp); | 239 | make_ssh_args(host); |
204 | 240 | ||
205 | fprintf(stderr, "Connecting to %s...\n", cp); | 241 | fprintf(stderr, "Connecting to %s...\n", host); |
206 | 242 | ||
207 | connect_to_server(make_ssh_args(NULL), &in, &out, &sshpid); | 243 | connect_to_server(make_ssh_args(NULL), &in, &out, &sshpid); |
208 | 244 | ||
@@ -216,7 +252,8 @@ main(int argc, char **argv) | |||
216 | if (kill(sshpid, SIGHUP) == -1) | 252 | if (kill(sshpid, SIGHUP) == -1) |
217 | fatal("Couldn't terminate ssh process: %s", strerror(errno)); | 253 | fatal("Couldn't terminate ssh process: %s", strerror(errno)); |
218 | 254 | ||
219 | /* XXX: wait? */ | 255 | if (waitpid(sshpid, NULL, 0) == -1) |
256 | fatal("Couldn't wait for ssh process: %s", strerror(errno)); | ||
220 | 257 | ||
221 | exit(0); | 258 | exit(0); |
222 | } | 259 | } |