summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien Miller <djm@mindrot.org>2001-02-10 00:40:03 +1100
committerDamien Miller <djm@mindrot.org>2001-02-10 00:40:03 +1100
commitd7686fd1fbe842baa8ce77f018c040d5e1d3438a (patch)
treea5d6ad5b4b232e06185a49b1b5aabe4761a3d8ed
parent4192c467916f96668fad5b53d90d83dfbfdcacb5 (diff)
- (djm) Sync sftp and scp stuff from OpenBSD:
- djm@cvs.openbsd.org 2001/02/07 03:55:13 [sftp-client.c] Don't free handles before we are done with them. Based on work from Corinna Vinschen <vinschen@redhat.com>. ok markus@ - djm@cvs.openbsd.org 2001/02/06 22:32:53 [sftp.1] Punctuation fix from Pekka Savola <pekkas@netcore.fi> - deraadt@cvs.openbsd.org 2001/02/07 04:07:29 [sftp.1] pretty up significantly - itojun@cvs.openbsd.org 2001/02/07 06:49:42 [sftp.1] .Bl-.El mismatch. markus ok - djm@cvs.openbsd.org 2001/02/07 06:12:30 [sftp-int.c] Check that target is a directory before doing ls; ok markus@ - itojun@cvs.openbsd.org 2001/02/07 11:01:18 [scp.c sftp-client.c sftp-server.c] unsigned long long -> %llu, not %qu. markus ok - stevesk@cvs.openbsd.org 2001/02/07 11:10:39 [sftp.1 sftp-int.c] more man page cleanup and sync of help text with man page; ok markus@ - markus@cvs.openbsd.org 2001/02/07 14:58:34 [sftp-client.c] older servers reply with SSH2_FXP_NAME + count==0 instead of EOF - djm@cvs.openbsd.org 2001/02/07 15:27:19 [sftp.c] Don't forward agent and X11 in sftp. Suggestion from Roumen Petrov <roumen.petrov@skalasoft.com> - stevesk@cvs.openbsd.org 2001/02/07 15:36:04 [sftp-int.c] portable; ok markus@ - stevesk@cvs.openbsd.org 2001/02/07 15:55:47 [sftp-int.c] lowercase cmds[].c also; ok markus@ - markus@cvs.openbsd.org 2001/02/07 17:04:52 [pathnames.h sftp.c] allow sftp over ssh protocol 1; ok djm@ - deraadt@cvs.openbsd.org 2001/02/08 07:38:55 [scp.c] memory leak fix, and snprintf throughout - deraadt@cvs.openbsd.org 2001/02/08 08:02:02 [sftp-int.c] plug a memory leak - stevesk@cvs.openbsd.org 2001/02/08 10:11:23 [session.c sftp-client.c] %i -> %d - stevesk@cvs.openbsd.org 2001/02/08 10:57:59 [sftp-int.c] typo - stevesk@cvs.openbsd.org 2001/02/08 15:28:07 [sftp-int.c pathnames.h] _PATH_LS; ok markus@ - djm@cvs.openbsd.org 2001/02/09 04:46:25 [sftp-int.c] Check for NULL attribs for chown, chmod & chgrp operations, only send relevant attribs back to server; ok markus@ - (djm) Update makefile.in for _PATH_SFTP_SERVER
-rw-r--r--ChangeLog66
-rw-r--r--Makefile.in13
-rw-r--r--pathnames.h8
-rw-r--r--sftp-client.c51
-rw-r--r--sftp-common.c10
-rw-r--r--sftp-int.c199
-rw-r--r--sftp.1119
-rw-r--r--sftp.c97
8 files changed, 363 insertions, 200 deletions
diff --git a/ChangeLog b/ChangeLog
index 601f30176..966b073cb 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,67 @@
120010210
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
120010209 6520010209
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
3prefix=@prefix@ 3prefix=@prefix@
4exec_prefix=@exec_prefix@ 4exec_prefix=@exec_prefix@
@@ -16,10 +16,15 @@ DESTDIR=
16VPATH=@srcdir@ 16VPATH=@srcdir@
17SSH_PROGRAM=@bindir@/ssh 17SSH_PROGRAM=@bindir@/ssh
18ASKPASS_PROGRAM=$(libexecdir)/ssh-askpass 18ASKPASS_PROGRAM=$(libexecdir)/ssh-askpass
19SFTP_SERVER=$(libexecdir)/sftp-server
20
21PATHS= -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
20CC=@CC@ 26CC=@CC@
21LD=@LD@ 27LD=@LD@
22PATHS=-DETCDIR=\"$(sysconfdir)\" -D_PATH_SSH_PROGRAM=\"$(SSH_PROGRAM)\" -D_PATH_SSH_ASKPASS_DEFAULT=\"$(ASKPASS_PROGRAM)\"
23CFLAGS=@CFLAGS@ 28CFLAGS=@CFLAGS@
24CPPFLAGS=@CPPFLAGS@ -I. -I$(srcdir)/openbsd-compat -I$(srcdir) $(PATHS) @DEFS@ 29CPPFLAGS=@CPPFLAGS@ -I. -I$(srcdir)/openbsd-compat -I$(srcdir) $(PATHS) @DEFS@
25LIBS=@LIBS@ 30LIBS=@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"
32RCSID("$OpenBSD: sftp-client.c,v 1.4 2001/02/06 23:30:28 djm Exp $"); 32RCSID("$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)); 678done:
679 close(local_fd);
680 buffer_free(&msg);
681 xfree(handle);
682 return status;
683} 683}
684 684
685int 685int
@@ -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
796done:
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"
27RCSID("$OpenBSD: sftp-common.c,v 1.1 2001/02/04 11:11:54 djm Exp $"); 27RCSID("$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"
30RCSID("$OpenBSD: sftp-int.c,v 1.7 2001/02/05 00:02:32 deraadt Exp $"); 31RCSID("$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
72const struct CMD cmds[] = { 73const 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
101help(void) 103help(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
128void 131void
@@ -166,13 +169,15 @@ void
166local_do_ls(const char *args) 169local_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)
216int 221int
217get_pathname(const char **cpp, char **path) 222get_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
265int 269int
@@ -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
428int 430int
429parse_dispatch_command(int in, int out, const char *cmd, char **pwd) 431parse_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;
diff --git a/sftp.1 b/sftp.1
index 59206b654..84edc4d67 100644
--- a/sftp.1
+++ b/sftp.1
@@ -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
44compression. 44compression.
45.Nm 45.Nm
46connects and logs into the specified 46connects and logs into the specified
47.Ar hostname 47.Ar hostname ,
48then enters an interactive command mode. 48then enters an interactive command mode.
49.Pp 49.Pp
50The options are as follows: 50The options are as follows:
51.Bl -tag -width Ds 51.Bl -tag -width Ds
52.It Fl v
53Raise logging level. This option is also passed to ssh.
52.It Fl C 54.It Fl C
53Enables compression (via ssh's 55Enables compression (via ssh's
54.Fl C 56.Fl C
55flag) 57flag)
56.It Fl v
57Raise logging level. This option is also passed to ssh.
58.It Fl o Ar ssh_option 58.It Fl o Ar ssh_option
59Specify an option to be directly passed to 59Specify 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
63Once in interactive mode 63Once in interactive mode,
64.Nm , 64.Nm
65understands a set of commands similar to those of 65understands a set of commands similar to those of
66.Xr ftp 1 . 66.Xr ftp 1 .
67Commands are case insensitive. 67Commands 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
70Change remote directory to 70Change remote directory to
71.Ar path 71.Ar path .
72.It Ic LCD Ar path 72.It Ic lcd Ar path
73Change local directory to 73Change 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
76Change group of file 76Change group of file
77.Ar path to 77.Ar path
78to
78.Ar grp . 79.Ar grp .
79.Ar grp 80.Ar grp
80must be numeric. 81must be a numeric GID.
81.It Ic CHMOD Ar mode Ar path 82.It Ic chmod Ar mode Ar path
82Change permissions of file 83Change permissions of file
83.Ar path to 84.Ar path
84.Ar mode 85to
85.It Ic CHOWN Ar own Ar path 86.Ar mode .
87.It Ic chown Ar own Ar path
86Change owner of file 88Change owner of file
87.Ar path to 89.Ar path
90to
88.Ar own . 91.Ar own .
89.Ar own 92.Ar own
90must be a numeric UID. 93must be a numeric UID.
91.It Ic HELP 94.It Ic help
92Display help text 95Display help text.
93.It Ic GET Ar remote-file Op Ar local-file 96.It Ic get Ar remote-path Op Ar local-path
94Retrieve the 97Retrieve the
95.Ar remote-file 98.Ar remote-path
96and store it on the local machine. 99and store it on the local machine.
97If the local 100If the local
98file name is not specified, it is given the same name it has on the 101path name is not specified, it is given the same name it has on the
99remote machine. 102remote machine.
100.It Ic LLS Op Ar ls-options Op Ar path 103.It Ic lls Op Ar ls-options Op Ar path
101Display local directory listing of either 104Display local directory listing of either
102.Ar path 105.Ar path
103or current directory if 106or current directory if
104.Ar path 107.Ar path
105was not specified. 108is not specified.
106.It Ic LMKDIR Ar path 109.It Ic lmkdir Ar path
107Create local directory specified by 110Create local directory specified by
108.Ar path 111.Ar path .
109.It Ic LPWD 112.It Ic lpwd
110Print local working directory 113Print local working directory.
111.It Ic LS Op Ar path 114.It Ic ls Op Ar path
112Display remote directory listing of either 115Display remote directory listing of either
113.Ar path 116.Ar path
114or current directory, is 117or current directory if
115.Ar path not specified. 118.Ar path
116.It Ic LUMASK Ar umask 119is not specified.
120.It Ic lumask Ar umask
117Set local umask to 121Set local umask to
118.Ar umask 122.Ar umask .
119.It Ic MKDIR Ar path 123.It Ic mkdir Ar path
120Create remote directory specified by 124Create 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
123Upload 127Upload
124.Ar local-file 128.Ar local-path
125and store it on the remote machine. If the local file name is not specified, 129and store it on the remote machine. If the remote path name is not specified,
126it is given the same name it has on the local machine. 130it is given the same name it has on the local machine.
127.It Ic PWD 131.It Ic pwd
128Display remote working directory 132Display remote working directory.
129.It Ic EXIT 133.It Ic exit
130Quit sftp 134Quit sftp.
131.It Ic QUIT 135.It Ic quit
132Quit sftp 136Quit sftp.
133.It Ic RENAME Ar oldpath Ar newpath 137.It Ic rename Ar oldpath Ar newpath
134Rename remote file from 138Rename remote file from
135.Ar oldpath 139.Ar oldpath
136to 140to
137.Ar newpath 141.Ar newpath .
138.It Ic RMDIR Ar path 142.It Ic rmdir Ar path
139Remove remote directory specified by 143Remove remote directory specified by
140.Ar path 144.Ar path .
141.It Ic RM Ar path 145.It Ic rm Ar path
142Delete remote file specified by 146Delete remote file specified by
143.Ar path 147.Ar path .
144.It Ic ! Ar command 148.It Ic ! Ar command
145Execute 149Execute
146.Ar command 150.Ar command
147in local shell 151in local shell.
148.It Ic ! 152.It Ic !
149Escape to local shell 153Escape to local shell.
154.It Ic ?
155Synonym for help.
156.El
150.Sh AUTHORS 157.Sh AUTHORS
151Damien Miller <djm@mindrot.org> 158Damien 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
diff --git a/sftp.c b/sftp.c
index 27873d034..b4775c02f 100644
--- a/sftp.c
+++ b/sftp.c
@@ -24,7 +24,7 @@
24 24
25#include "includes.h" 25#include "includes.h"
26 26
27RCSID("$OpenBSD: sftp.c,v 1.2 2001/02/04 15:32:25 stevesk Exp $"); 27RCSID("$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
43int use_ssh1 = 0;
44char *ssh_program = _PATH_SSH_PROGRAM;
45char *sftp_server = NULL;
46
43void 47void
44connect_to_server(char **args, int *in, int *out, pid_t *sshpid) 48connect_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)
128void 143void
129usage(void) 144usage(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
135int 150int
136main(int argc, char **argv) 151main(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}