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 @@ +20010210 + - (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 + + + + 20010209 - (bal) patch to vis.c to deal with HAVE_VIS right by Robert Mooney <rjmooney@mediaone.net> @@ -3703,4 +3767,4 @@ - Wrote replacements for strlcpy and mkdtemp - Released 1.0pre1 -$Id: ChangeLog,v 1.709 2001/02/09 11:55:16 djm Exp $ +$Id: ChangeLog,v 1.710 2001/02/09 13:40:03 djm Exp $ diff --git a/Makefile.in b/Makefile.in index af82ea15..f64e2550 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1,4 +1,4 @@ -# $Id: Makefile.in,v 1.149 2001/02/07 23:07:09 djm Exp $ +# $Id: Makefile.in,v 1.150 2001/02/09 13:40:03 djm Exp $ prefix=@prefix@ exec_prefix=@exec_prefix@ @@ -16,10 +16,15 @@ DESTDIR= VPATH=@srcdir@ SSH_PROGRAM=@bindir@/ssh ASKPASS_PROGRAM=$(libexecdir)/ssh-askpass +SFTP_SERVER=$(libexecdir)/sftp-server + +PATHS= -DETCDIR=\"$(sysconfdir)\" \ + -D_PATH_SSH_PROGRAM=\"$(SSH_PROGRAM)\" \ + -D_PATH_SSH_ASKPASS_DEFAULT=\"$(ASKPASS_PROGRAM)\" \ + -D_PATH_SFTP_SERVER=\"$(SFTP_SERVER)\" CC=@CC@ LD=@LD@ -PATHS=-DETCDIR=\"$(sysconfdir)\" -D_PATH_SSH_PROGRAM=\"$(SSH_PROGRAM)\" -D_PATH_SSH_ASKPASS_DEFAULT=\"$(ASKPASS_PROGRAM)\" CFLAGS=@CFLAGS@ CPPFLAGS=@CPPFLAGS@ -I. -I$(srcdir)/openbsd-compat -I$(srcdir) $(PATHS) @DEFS@ LIBS=@LIBS@ @@ -162,7 +167,7 @@ install-files: $(INSTALL) -m 0775 -s ssh-keyscan $(DESTDIR)$(bindir)/ssh-keyscan $(INSTALL) -m 0755 -s sshd $(DESTDIR)$(sbindir)/sshd @NO_SFTP@$(INSTALL) -m 0755 -s sftp $(DESTDIR)$(bindir)/sftp - @NO_SFTP@$(INSTALL) -m 0755 -s sftp-server $(DESTDIR)$(libexecdir)/sftp-server + @NO_SFTP@$(INSTALL) -m 0755 -s sftp-server $(DESTDIR)$(SFTP_SERVER) $(INSTALL) -m 644 ssh.[01].out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1 $(INSTALL) -m 644 scp.[01].out $(DESTDIR)$(mandir)/$(mansubdir)1/scp.1 $(INSTALL) -m 644 ssh-add.[01].out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-add.1 @@ -250,7 +255,7 @@ uninstall: -rm -f $(DESTDIR)$(bindir)/ssh-keyscan$(EXEEXT) -rm -f $(DESTDIR)$(bindir)/sftp$(EXEEXT) -rm -f $(DESTDIR)$(sbindir)/sshd$(EXEEXT) - -rm -r $(DESTDIR)$(libexecdir)/sftp-server$(EXEEXT) + -rm -r $(DESTDIR)$(SFTP_SERVER)$(EXEEXT) -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1 -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/scp.1 -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-add.1 diff --git a/pathnames.h b/pathnames.h index 85d8a1fe..3f116bdb 100644 --- a/pathnames.h +++ b/pathnames.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pathnames.h,v 1.2 2001/01/29 01:58:17 niklas Exp $ */ +/* $OpenBSD: pathnames.h,v 1.4 2001/02/08 22:28:07 stevesk Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> @@ -116,6 +116,12 @@ #define _PATH_CP "cp" #endif +/* for sftp */ +#ifndef _PATH_SFTP_SERVER +#define _PATH_SFTP_SERVER "/usr/libexec/sftp-server" +#endif +#define _PATH_LS "ls" + /* path to login program */ #ifndef LOGIN_PROGRAM # ifdef LOGIN_PROGRAM_FALLBACK diff --git a/sftp-client.c b/sftp-client.c index e8b9007f..490c00bd 100644 --- a/sftp-client.c +++ b/sftp-client.c @@ -29,7 +29,7 @@ /* XXX: copy between two remote sites */ #include "includes.h" -RCSID("$OpenBSD: sftp-client.c,v 1.4 2001/02/06 23:30:28 djm Exp $"); +RCSID("$OpenBSD: sftp-client.c,v 1.8 2001/02/08 17:11:23 stevesk Exp $"); #include "ssh.h" #include "buffer.h" @@ -338,7 +338,9 @@ do_ls(int fd_in, int fd_out, char *path) SSH2_FXP_NAME, type); count = buffer_get_int(&msg); - debug3("Received %i SSH2_FXP_NAME responses", count); + if (count == 0) + break; + debug3("Received %d SSH2_FXP_NAME responses", count); for(i = 0; i < count; i++) { char *filename, *longname; Attrib *a; @@ -556,6 +558,7 @@ do_download(int fd_in, int fd_out, char *remote_path, char *local_path, char *handle; Buffer msg; Attrib junk, *a; + int status; a = do_stat(fd_in, fd_out, remote_path); if (a == NULL) @@ -635,7 +638,7 @@ do_download(int fd_in, int fd_out, char *remote_path, char *local_path, if (id != expected_id) fatal("ID mismatch (%d != %d)", id, expected_id); if (type == SSH2_FXP_STATUS) { - int status = buffer_get_int(&msg); + status = buffer_get_int(&msg); if (status == SSH2_FX_EOF) break; @@ -644,10 +647,7 @@ do_download(int fd_in, int fd_out, char *remote_path, char *local_path, "file \"%s\" : %s", remote_path, fx2txt(status)); do_close(fd_in, fd_out, handle, handle_len); - xfree(handle); - close(local_fd); - buffer_free(&msg); - return(status); + goto done; } } else if (type != SSH2_FXP_DATA) { 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, fatal("Received more data than asked for %d > %d", len, COPY_SIZE); - debug3("In read loop, got %d offset %lld", len, + debug3("In read loop, got %d offset %llu", len, (unsigned long long)offset); if (atomicio(write, local_fd, data, len) != len) { error("Couldn't write to \"%s\": %s", local_path, strerror(errno)); do_close(fd_in, fd_out, handle, handle_len); - xfree(handle); - close(local_fd); + status = -1; xfree(data); - buffer_free(&msg); - return(-1); + goto done; } offset += len; xfree(data); } - xfree(handle); - buffer_free(&msg); - close(local_fd); + status = do_close(fd_in, fd_out, handle, handle_len); - return(do_close(fd_in, fd_out, handle, handle_len)); +done: + close(local_fd); + buffer_free(&msg); + xfree(handle); + return status; } int @@ -693,6 +693,7 @@ do_upload(int fd_in, int fd_out, char *local_path, char *remote_path, Buffer msg; struct stat sb; Attrib a; + int status; if ((local_fd = open(local_path, O_RDONLY, 0)) == -1) { 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, for(;;) { int len; char data[COPY_SIZE]; - u_int status; /* * 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, error("Couldn't write to remote file \"%s\": %s", remote_path, fx2txt(status)); do_close(fd_in, fd_out, handle, handle_len); - xfree(handle); close(local_fd); - return(-1); + goto done; } debug3("In write loop, got %d offset %llu", len, (unsigned long long)offset); offset += len; } - xfree(handle); - buffer_free(&msg); if (close(local_fd) == -1) { error("Couldn't close local file \"%s\": %s", local_path, strerror(errno)); do_close(fd_in, fd_out, handle, handle_len); - return(-1); + status = -1; + goto done; } - return(do_close(fd_in, fd_out, handle, handle_len)); + status = do_close(fd_in, fd_out, handle, handle_len); + +done: + xfree(handle); + buffer_free(&msg); + return status; } + + diff --git a/sftp-common.c b/sftp-common.c index aed9b339..3310eaba 100644 --- a/sftp-common.c +++ b/sftp-common.c @@ -24,7 +24,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: sftp-common.c,v 1.1 2001/02/04 11:11:54 djm Exp $"); +RCSID("$OpenBSD: sftp-common.c,v 1.2 2001/02/06 23:50:10 markus Exp $"); #include "buffer.h" #include "bufaux.h" @@ -121,13 +121,13 @@ fx2txt(int status) { switch (status) { case SSH2_FX_OK: - return("No Error"); + return("No error"); case SSH2_FX_EOF: - return("End of File"); + return("End of file"); case SSH2_FX_NO_SUCH_FILE: - return("No Such File"); + return("No such file or directory"); case SSH2_FX_PERMISSION_DENIED: - return("Permission Denied"); + return("Permission denied"); case SSH2_FX_FAILURE: return("Failure"); case SSH2_FX_BAD_MESSAGE: @@ -24,10 +24,11 @@ /* XXX: finish implementation of all commands */ /* XXX: do fnmatch() instead of using raw pathname */ +/* XXX: globbed ls */ /* XXX: recursive operations */ #include "includes.h" -RCSID("$OpenBSD: sftp-int.c,v 1.7 2001/02/05 00:02:32 deraadt Exp $"); +RCSID("$OpenBSD: sftp-int.c,v 1.19 2001/02/09 11:46:24 djm Exp $"); #include "buffer.h" #include "xmalloc.h" @@ -70,28 +71,29 @@ struct CMD { }; const struct CMD cmds[] = { - { "CD", I_CHDIR }, - { "CHDIR", I_CHDIR }, - { "CHGRP", I_CHGRP }, - { "CHMOD", I_CHMOD }, - { "CHOWN", I_CHOWN }, - { "EXIT", I_QUIT }, - { "GET", I_GET }, - { "HELP", I_HELP }, - { "LCD", I_LCHDIR }, - { "LCHDIR", I_LCHDIR }, - { "LLS", I_LLS }, - { "LMKDIR", I_LMKDIR }, - { "LPWD", I_LPWD }, - { "LS", I_LS }, - { "LUMASK", I_LUMASK }, - { "MKDIR", I_MKDIR }, - { "PUT", I_PUT }, - { "PWD", I_PWD }, - { "QUIT", I_QUIT }, - { "RENAME", I_RENAME }, - { "RM", I_RM }, - { "RMDIR", I_RMDIR }, + { "cd", I_CHDIR }, + { "chdir", I_CHDIR }, + { "chgrp", I_CHGRP }, + { "chmod", I_CHMOD }, + { "chown", I_CHOWN }, + { "dir", I_LS }, + { "exit", I_QUIT }, + { "get", I_GET }, + { "help", I_HELP }, + { "lcd", I_LCHDIR }, + { "lchdir", I_LCHDIR }, + { "lls", I_LLS }, + { "lmkdir", I_LMKDIR }, + { "lpwd", I_LPWD }, + { "ls", I_LS }, + { "lumask", I_LUMASK }, + { "mkdir", I_MKDIR }, + { "put", I_PUT }, + { "pwd", I_PWD }, + { "quit", I_QUIT }, + { "rename", I_RENAME }, + { "rm", I_RM }, + { "rmdir", I_RMDIR }, { "!", I_SHELL }, { "?", I_HELP }, { NULL, -1} @@ -101,28 +103,29 @@ void help(void) { printf("Available commands:\n"); - printf("CD path Change remote directory to 'path'\n"); - printf("LCD path Change local directory to 'path'\n"); - printf("CHGRP grp path Change group of file 'path' to 'grp'\n"); - printf("CHMOD mode path Change permissions of file 'path' to 'mode'\n"); - printf("CHOWN own path Change owner of file 'path' to 'own'\n"); - printf("HELP Display this help text\n"); - printf("GET remote-path [local-path] Download file\n"); - printf("LLS [ls options] [path] Display local directory listing\n"); - printf("LMKDIR path Create local directory\n"); - printf("LPWD Print local working directory\n"); - printf("LS [path] Display remote directory listing\n"); - printf("LUMASK umask Set local umask to 'umask'\n"); - printf("MKDIR path Create remote directory\n"); - printf("PUT local-path [remote-path] Upload file\n"); - printf("PWD Display remote working directory\n"); - printf("EXIT Quit sftp\n"); - printf("QUIT Quit sftp\n"); - printf("RENAME oldpath newpath Rename remote file\n"); - printf("RMDIR path Remove remote directory\n"); - printf("RM path Delete remote file\n"); + printf("cd path Change remote directory to 'path'\n"); + printf("lcd path Change local directory to 'path'\n"); + printf("chgrp grp path Change group of file 'path' to 'grp'\n"); + printf("chmod mode path Change permissions of file 'path' to 'mode'\n"); + printf("chown own path Change owner of file 'path' to 'own'\n"); + printf("help Display this help text\n"); + printf("get remote-path [local-path] Download file\n"); + printf("lls [ls-options [path]] Display local directory listing\n"); + printf("lmkdir path Create local directory\n"); + printf("lpwd Print local working directory\n"); + printf("ls [path] Display remote directory listing\n"); + printf("lumask umask Set local umask to 'umask'\n"); + printf("mkdir path Create remote directory\n"); + printf("put local-path [remote-path] Upload file\n"); + printf("pwd Display remote working directory\n"); + printf("exit Quit sftp\n"); + printf("quit Quit sftp\n"); + printf("rename oldpath newpath Rename remote file\n"); + printf("rmdir path Remove remote directory\n"); + printf("rm path Delete remote file\n"); printf("!command Execute 'command' in local shell\n"); printf("! Escape to local shell\n"); + printf("? Synonym for help\n"); } void @@ -166,13 +169,15 @@ void local_do_ls(const char *args) { if (!args || !*args) - local_do_shell("ls"); + local_do_shell(_PATH_LS); else { - char *buf = xmalloc(8 + strlen(args) + 1); + int len = strlen(_PATH_LS " ") + strlen(args) + 1; + char *buf = xmalloc(len); /* XXX: quoting - rip quoting code from ftp? */ - sprintf(buf, "/bin/ls %s", args); + snprintf(buf, len, _PATH_LS " %s", args); local_do_shell(buf); + xfree(buf); } } @@ -198,7 +203,7 @@ parse_getput_flags(const char **cpp, int *pflag) /* Check for flags */ if (cp[0] == '-' && cp[1] && strchr(WHITESPACE, cp[2])) { - switch (*cp) { + switch (cp[1]) { case 'P': *pflag = 1; break; @@ -216,50 +221,49 @@ parse_getput_flags(const char **cpp, int *pflag) int get_pathname(const char **cpp, char **path) { - const char *quot, *cp = *cpp; + const char *cp = *cpp, *end; + char quot; int i; cp += strspn(cp, WHITESPACE); if (!*cp) { *cpp = cp; *path = NULL; - return(0); + return (0); } /* Check for quoted filenames */ if (*cp == '\"' || *cp == '\'') { - quot = cp++; - for(i = 0; cp[i] && cp[i] != *quot; i++) - ; - if (!cp[i]) { + quot = *cp++; + + end = strchr(cp, quot); + if (end == NULL) { error("Unterminated quote"); - *path = NULL; - return(-1); + goto fail; } - if (i == 0) { + if (cp == end) { error("Empty quotes"); - *path = NULL; - return(-1); + goto fail; } - *path = xmalloc(i + 1); - memcpy(*path, cp, i); - (*path)[i] = '\0'; - cp += i + 1; - *cpp = cp + strspn(cp, WHITESPACE); - return(0); + *cpp = end + 1 + strspn(end + 1, WHITESPACE); + } else { + /* Read to end of filename */ + end = strpbrk(cp, WHITESPACE); + if (end == NULL) + end = strchr(cp, '\0'); + *cpp = end + strspn(end, WHITESPACE); } - /* Read to end of filename */ - for(i = 0; cp[i] && cp[i] != ' '; i++) - ; + i = end - cp; *path = xmalloc(i + 1); memcpy(*path, cp, i); (*path)[i] = '\0'; - cp += i; - *cpp = cp + strspn(cp, WHITESPACE); - return(0); + + fail: + *path = NULL; + return (-1); } int @@ -270,7 +274,6 @@ infer_path(const char *p, char **ifp) debug("XXX: P = \"%s\"", p); cp = strrchr(p, '/'); - if (cp == NULL) { *ifp = xstrdup(p); return(0); @@ -421,14 +424,13 @@ parse_args(const char **cpp, int *pflag, unsigned long *n_arg, } *cpp = cp; - return(cmdnum); } int parse_dispatch_command(int in, int out, const char *cmd, char **pwd) { - char *path1, *path2; + char *path1, *path2, *tmp; int pflag, cmdnum; unsigned long n_arg; Attrib a, *aa; @@ -471,12 +473,44 @@ parse_dispatch_command(int in, int out, const char *cmd, char **pwd) break; case I_CHDIR: path1 = make_absolute(path1, *pwd); + if ((tmp = do_realpath(in, out, path1)) == NULL) + break; + if ((aa = do_stat(in, out, tmp)) == NULL) { + xfree(tmp); + break; + } + if (!(aa->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)) { + error("Can't change directory: Can't check target"); + xfree(tmp); + break; + } + if (!S_ISDIR(aa->perm)) { + error("Can't change directory: \"%s\" is not " + "a directory", tmp); + xfree(tmp); + break; + } xfree(*pwd); - *pwd = do_realpath(in, out, path1); + *pwd = tmp; break; case I_LS: + if (!path1) { + do_ls(in, out, *pwd); + break; + } path1 = make_absolute(path1, *pwd); - do_ls(in, out, path1?path1:*pwd); + if ((tmp = do_realpath(in, out, path1)) == NULL) + break; + xfree(path1); + path1 = tmp; + if ((aa = do_stat(in, out, path1)) == NULL) + break; + if ((aa->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) && + !S_ISDIR(aa->perm)) { + error("Can't ls: \"%s\" is not a directory", path1); + break; + } + do_ls(in, out, path1); break; case I_LCHDIR: if (chdir(path1) == -1) @@ -485,7 +519,7 @@ parse_dispatch_command(int in, int out, const char *cmd, char **pwd) break; case I_LMKDIR: if (mkdir(path1, 0777) == -1) - error("Couldn't create local directory to " + error("Couldn't create local directory " "\"%s\": %s", path1, strerror(errno)); break; case I_LLS: @@ -506,23 +540,27 @@ parse_dispatch_command(int in, int out, const char *cmd, char **pwd) break; case I_CHOWN: path1 = make_absolute(path1, *pwd); - aa = do_stat(in, out, path1); + if (!(aa = do_stat(in, out, path1))) + break; if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) { error("Can't get current ownership of " "remote file \"%s\"", path1); break; } + aa->flags &= SSH2_FILEXFER_ATTR_UIDGID; aa->uid = n_arg; do_setstat(in, out, path1, aa); break; case I_CHGRP: path1 = make_absolute(path1, *pwd); - aa = do_stat(in, out, path1); + if (!(aa = do_stat(in, out, path1))) + break; if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) { error("Can't get current ownership of " "remote file \"%s\"", path1); break; } + aa->flags &= SSH2_FILEXFER_ATTR_UIDGID; aa->gid = n_arg; do_setstat(in, out, path1, aa); break; @@ -550,7 +588,6 @@ parse_dispatch_command(int in, int out, const char *cmd, char **pwd) xfree(path1); if (path2) xfree(path2); - return(0); } @@ -564,8 +601,8 @@ interactive_loop(int fd_in, int fd_out) if (pwd == NULL) fatal("Need cwd"); - setvbuf(stdout, (char *)NULL, _IOLBF, 0); - setvbuf(stdin, (char *)NULL, _IOLBF, 0); + setvbuf(stdout, NULL, _IOLBF, 0); + setvbuf(stdin, NULL, _IOLBF, 0); for(;;) { char *cp; @@ -1,4 +1,4 @@ -.\" $OpenBSD: sftp.1,v 1.1 2001/02/04 11:11:54 djm Exp $ +.\" $OpenBSD: sftp.1,v 1.5 2001/02/07 18:10:39 stevesk Exp $ .\" .\" Copyright (c) 2001 Damien Miller. All rights reserved. .\" @@ -30,7 +30,7 @@ .Nd Secure file tranfer program .Sh SYNOPSIS .Nm sftp -.Op Fl v Li | Fl C +.Op Fl vC .Op Fl o Ar ssh_option .Op Ar hostname | user@hostname .Sh DESCRIPTION @@ -44,113 +44,122 @@ It may also use many features of ssh, such as public key authentication and compression. .Nm connects and logs into the specified -.Ar hostname +.Ar hostname , then enters an interactive command mode. .Pp The options are as follows: .Bl -tag -width Ds +.It Fl v +Raise logging level. This option is also passed to ssh. .It Fl C Enables compression (via ssh's .Fl C flag) -.It Fl v -Raise logging level. This option is also passed to ssh. .It Fl o Ar ssh_option Specify an option to be directly passed to .Xr ssh 1 . .El .Sh INTERACTIVE COMMANDS -Once in interactive mode -.Nm , +Once in interactive mode, +.Nm understands a set of commands similar to those of .Xr ftp 1 . Commands are case insensitive. .Bl -tag -width Ds -.It Ic CD Ar path +.It Ic cd Ar path Change remote directory to -.Ar path -.It Ic LCD Ar path +.Ar path . +.It Ic lcd Ar path Change local directory to -.Ar path -.It Ic CHGRP Ar grp Ar path +.Ar path . +.It Ic chgrp Ar grp Ar path Change group of file -.Ar path to +.Ar path +to .Ar grp . .Ar grp -must be numeric. -.It Ic CHMOD Ar mode Ar path +must be a numeric GID. +.It Ic chmod Ar mode Ar path Change permissions of file -.Ar path to -.Ar mode -.It Ic CHOWN Ar own Ar path +.Ar path +to +.Ar mode . +.It Ic chown Ar own Ar path Change owner of file -.Ar path to +.Ar path +to .Ar own . .Ar own must be a numeric UID. -.It Ic HELP -Display help text -.It Ic GET Ar remote-file Op Ar local-file +.It Ic help +Display help text. +.It Ic get Ar remote-path Op Ar local-path Retrieve the -.Ar remote-file +.Ar remote-path and store it on the local machine. If the local -file name is not specified, it is given the same name it has on the +path name is not specified, it is given the same name it has on the remote machine. -.It Ic LLS Op Ar ls-options Op Ar path +.It Ic lls Op Ar ls-options Op Ar path Display local directory listing of either .Ar path or current directory if .Ar path -was not specified. -.It Ic LMKDIR Ar path +is not specified. +.It Ic lmkdir Ar path Create local directory specified by -.Ar path -.It Ic LPWD -Print local working directory -.It Ic LS Op Ar path +.Ar path . +.It Ic lpwd +Print local working directory. +.It Ic ls Op Ar path Display remote directory listing of either .Ar path -or current directory, is -.Ar path not specified. -.It Ic LUMASK Ar umask +or current directory if +.Ar path +is not specified. +.It Ic lumask Ar umask Set local umask to -.Ar umask -.It Ic MKDIR Ar path +.Ar umask . +.It Ic mkdir Ar path Create remote directory specified by -.Ar path -.It Ic PUT local-file Op Ar remote-file +.Ar path . +.It Ic put Ar local-path Op Ar remote-path Upload -.Ar local-file -and store it on the remote machine. If the local file name is not specified, +.Ar local-path +and store it on the remote machine. If the remote path name is not specified, it is given the same name it has on the local machine. -.It Ic PWD -Display remote working directory -.It Ic EXIT -Quit sftp -.It Ic QUIT -Quit sftp -.It Ic RENAME Ar oldpath Ar newpath +.It Ic pwd +Display remote working directory. +.It Ic exit +Quit sftp. +.It Ic quit +Quit sftp. +.It Ic rename Ar oldpath Ar newpath Rename remote file from .Ar oldpath to -.Ar newpath -.It Ic RMDIR Ar path +.Ar newpath . +.It Ic rmdir Ar path Remove remote directory specified by -.Ar path -.It Ic RM Ar path +.Ar path . +.It Ic rm Ar path Delete remote file specified by -.Ar path +.Ar path . .It Ic ! Ar command Execute .Ar command -in local shell +in local shell. .It Ic ! -Escape to local shell +Escape to local shell. +.It Ic ? +Synonym for help. +.El .Sh AUTHORS Damien Miller <djm@mindrot.org> .Sh SEE ALSO .Xr ssh 1 , .Xr ssh-add 1 , .Xr ssh-keygen 1 , -.Xr sshd 8 +.Xr sshd 8 , +.Xr scp 1 + @@ -24,7 +24,7 @@ #include "includes.h" -RCSID("$OpenBSD: sftp.c,v 1.2 2001/02/04 15:32:25 stevesk Exp $"); +RCSID("$OpenBSD: sftp.c,v 1.7 2001/02/08 00:04:52 markus Exp $"); /* XXX: commandline mode */ /* 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 $"); #include "sftp-client.h" #include "sftp-int.h" +int use_ssh1 = 0; +char *ssh_program = _PATH_SSH_PROGRAM; +char *sftp_server = NULL; + void connect_to_server(char **args, int *in, int *out, pid_t *sshpid) { @@ -72,8 +76,8 @@ connect_to_server(char **args, int *in, int *out, pid_t *sshpid) close(*out); close(c_in); close(c_out); - execv(_PATH_SSH_PROGRAM, args); - fprintf(stderr, "exec: %s", strerror(errno)); + execv(ssh_program, args); + fprintf(stderr, "exec: %s: %s\n", ssh_program, strerror(errno)); exit(1); } @@ -87,16 +91,24 @@ make_ssh_args(char *add_arg) static char **args = NULL; static int nargs = 0; char debug_buf[4096]; - int i; + int i, use_subsystem = 1; + + /* no subsystem if protocol 1 or the server-spec contains a '/' */ + if (use_ssh1 || + (sftp_server != NULL && strchr(sftp_server, '/') != NULL)) + use_subsystem = 0; /* Init args array */ if (args == NULL) { - nargs = 4; + nargs = use_subsystem ? 6 : 5; i = 0; args = xmalloc(sizeof(*args) * nargs); args[i++] = "ssh"; - args[i++] = "-oProtocol=2"; - args[i++] = "-s"; + args[i++] = use_ssh1 ? "-oProtocol=1" : "-oProtocol=2"; + if (use_subsystem) + args[i++] = "-s"; + args[i++] = "-oForwardAgent=no"; + args[i++] = "-oForwardX11=no"; args[i++] = NULL; } @@ -110,7 +122,10 @@ make_ssh_args(char *add_arg) } /* Otherwise finish up and return the arg array */ - make_ssh_args("sftp"); + if (sftp_server != NULL) + make_ssh_args(sftp_server); + else + make_ssh_args("sftp"); /* XXX: overflow - doesn't grow debug_buf */ debug_buf[0] = '\0'; @@ -128,49 +143,70 @@ make_ssh_args(char *add_arg) void usage(void) { - fprintf(stderr, "usage: sftp [-vC] [-osshopt=value] [user@]host\n"); + fprintf(stderr, "usage: sftp [-1vC] [-osshopt=value] [user@]host\n"); exit(1); } int main(int argc, char **argv) { - int in, out, i, debug_level, compress_flag; + int in, out, ch, debug_level, compress_flag; pid_t sshpid; - char *cp; + char *host, *userhost; LogLevel ll; + extern int optind; + extern char *optarg; debug_level = compress_flag = 0; - for(i = 1; i < argc && argv[i][0] == '-'; i++) { - if (!strcmp(argv[i], "-v")) - debug_level = MIN(3, debug_level + 1); - else if (!strcmp(argv[i], "-C")) + + while ((ch = getopt(argc, argv, "1hvCo:s:S:")) != -1) { + switch (ch) { + case 'C': compress_flag = 1; - else if (!strncmp(argv[i], "-o", 2)) { - make_ssh_args(argv[i]); - } else { - fprintf(stderr, "Unknown option \"%s\"\n", argv[i]); + break; + case 'v': + debug_level = MIN(3, debug_level + 1); + break; + case 'o': + make_ssh_args("-o"); + make_ssh_args(optarg); + break; + case '1': + use_ssh1 = 1; + if (sftp_server == NULL) + sftp_server = _PATH_SFTP_SERVER; + break; + case 's': + sftp_server = optarg; + break; + case 'S': + ssh_program = optarg; + break; + case 'h': + default: usage(); } } - if (i == argc || argc > (i + 1)) + if (optind == argc || argc > (optind + 1)) usage(); - if ((cp = strchr(argv[i], '@')) == NULL) - cp = argv[i]; + userhost = argv[optind]; + + if ((host = strchr(userhost, '@')) == NULL) + host = userhost; else { - *cp = '\0'; - if (!argv[i][0]) { + *host = '\0'; + if (!userhost[0]) { fprintf(stderr, "Missing username\n"); usage(); } make_ssh_args("-l"); - make_ssh_args(argv[i]); - cp++; + make_ssh_args(userhost); + host++; } - if (!*cp) { + if (!*host) { fprintf(stderr, "Missing hostname\n"); usage(); } @@ -200,9 +236,9 @@ main(int argc, char **argv) log_init(argv[0], ll, SYSLOG_FACILITY_USER, 1); - make_ssh_args(cp); + make_ssh_args(host); - fprintf(stderr, "Connecting to %s...\n", cp); + fprintf(stderr, "Connecting to %s...\n", host); connect_to_server(make_ssh_args(NULL), &in, &out, &sshpid); @@ -216,7 +252,8 @@ main(int argc, char **argv) if (kill(sshpid, SIGHUP) == -1) fatal("Couldn't terminate ssh process: %s", strerror(errno)); - /* XXX: wait? */ + if (waitpid(sshpid, NULL, 0) == -1) + fatal("Couldn't wait for ssh process: %s", strerror(errno)); exit(0); } |