summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDamien Miller <djm@mindrot.org>2001-03-08 10:08:49 +1100
committerDamien Miller <djm@mindrot.org>2001-03-08 10:08:49 +1100
commit058316f0f1811ac716c1cb799f50adae4af7928e (patch)
treec25e9fee7be4720a39d405984e7fec473dfeea13
parent8ac0a7ec448764036e1a1657013a9fd9179be860 (diff)
- OpenBSD CVS Sync
- djm@cvs.openbsd.org 2001/03/07 10:11:23 [sftp-client.c sftp-client.h sftp-int.c sftp-server.c sftp.1 sftp.c sftp.h] Support for new draft (draft-ietf-secsh-filexfer-01). New symlink handling functions and small protocol change.
-rw-r--r--ChangeLog9
-rw-r--r--sftp-client.c81
-rw-r--r--sftp-client.h13
-rw-r--r--sftp-int.c29
-rw-r--r--sftp-server.c75
-rw-r--r--sftp.118
-rw-r--r--sftp.c4
-rw-r--r--sftp.h9
8 files changed, 216 insertions, 22 deletions
diff --git a/ChangeLog b/ChangeLog
index 38d6be3d..a8a1a94e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+20010308
+ - OpenBSD CVS Sync
+ - djm@cvs.openbsd.org 2001/03/07 10:11:23
+ [sftp-client.c sftp-client.h sftp-int.c sftp-server.c sftp.1 sftp.c sftp.h]
+ Support for new draft (draft-ietf-secsh-filexfer-01). New symlink handling
+ functions and small protocol change.
+
20010307
- (bal) OpenBSD CVS Sync
- deraadt@cvs.openbsd.org 2001/03/06 06:11:18
@@ -4430,4 +4437,4 @@
- Wrote replacements for strlcpy and mkdtemp
- Released 1.0pre1
-$Id: ChangeLog,v 1.924 2001/03/07 10:38:19 djm Exp $
+$Id: ChangeLog,v 1.925 2001/03/07 23:08:49 djm Exp $
diff --git a/sftp-client.c b/sftp-client.c
index 5242cab0..d1e4ebac 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.10 2001/02/14 09:46:03 djm Exp $");
+RCSID("$OpenBSD: sftp-client.c,v 1.11 2001/03/07 10:11:22 djm Exp $");
#include "ssh.h"
#include "buffer.h"
@@ -247,7 +247,8 @@ do_init(int fd_in, int fd_out)
}
buffer_free(&msg);
- return(0);
+
+ return(version);
}
int
@@ -483,8 +484,7 @@ do_realpath(int fd_in, int fd_out, char *path)
Attrib *a;
expected_id = id = msg_id++;
- send_string_request(fd_out, id, SSH2_FXP_REALPATH, path,
- strlen(path));
+ send_string_request(fd_out, id, SSH2_FXP_REALPATH, path, strlen(path));
buffer_init(&msg);
@@ -549,6 +549,79 @@ do_rename(int fd_in, int fd_out, char *oldpath, char *newpath)
}
int
+do_symlink(int fd_in, int fd_out, char *oldpath, char *newpath)
+{
+ Buffer msg;
+ u_int status, id;
+
+ buffer_init(&msg);
+
+ /* Send rename request */
+ id = msg_id++;
+ buffer_put_char(&msg, SSH2_FXP_SYMLINK);
+ buffer_put_int(&msg, id);
+ buffer_put_cstring(&msg, oldpath);
+ buffer_put_cstring(&msg, newpath);
+ send_msg(fd_out, &msg);
+ debug3("Sent message SSH2_FXP_SYMLINK \"%s\" -> \"%s\"", oldpath,
+ newpath);
+ buffer_free(&msg);
+
+ status = get_status(fd_in, id);
+ if (status != SSH2_FX_OK)
+ error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath, newpath,
+ fx2txt(status));
+
+ return(status);
+}
+
+char *
+do_readlink(int fd_in, int fd_out, char *path)
+{
+ Buffer msg;
+ u_int type, expected_id, count, id;
+ char *filename, *longname;
+ Attrib *a;
+
+ expected_id = id = msg_id++;
+ send_string_request(fd_out, id, SSH2_FXP_READLINK, path, strlen(path));
+
+ buffer_init(&msg);
+
+ get_msg(fd_in, &msg);
+ type = buffer_get_char(&msg);
+ id = buffer_get_int(&msg);
+
+ if (id != expected_id)
+ fatal("ID mismatch (%d != %d)", id, expected_id);
+
+ if (type == SSH2_FXP_STATUS) {
+ u_int status = buffer_get_int(&msg);
+
+ error("Couldn't readlink: %s", fx2txt(status));
+ return(NULL);
+ } else if (type != SSH2_FXP_NAME)
+ fatal("Expected SSH2_FXP_NAME(%d) packet, got %d",
+ SSH2_FXP_NAME, type);
+
+ count = buffer_get_int(&msg);
+ if (count != 1)
+ fatal("Got multiple names (%d) from SSH_FXP_READLINK", count);
+
+ filename = buffer_get_string(&msg, NULL);
+ longname = buffer_get_string(&msg, NULL);
+ a = decode_attrib(&msg);
+
+ debug3("SSH_FXP_READLINK %s -> %s", path, filename);
+
+ xfree(longname);
+
+ buffer_free(&msg);
+
+ return(filename);
+}
+
+int
do_download(int fd_in, int fd_out, char *remote_path, char *local_path,
int pflag)
{
diff --git a/sftp-client.h b/sftp-client.h
index 838b46b0..e836c0d6 100644
--- a/sftp-client.h
+++ b/sftp-client.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: sftp-client.h,v 1.1 2001/02/04 11:11:54 djm Exp $ */
+/* $OpenBSD: sftp-client.h,v 1.2 2001/03/07 10:11:23 djm Exp $ */
/*
* Copyright (c) 2001 Damien Miller. All rights reserved.
@@ -26,7 +26,10 @@
/* Client side of SSH2 filexfer protocol */
-/* Initialiase a SSH filexfer connection */
+/*
+ * Initialiase a SSH filexfer connection. Returns -1 on error or
+ * protocol version on success.
+ */
int do_init(int fd_in, int fd_out);
/* Close file referred to by 'handle' */
@@ -67,6 +70,12 @@ char *do_realpath(int fd_in, int fd_out, char *path);
/* Rename 'oldpath' to 'newpath' */
int do_rename(int fd_in, int fd_out, char *oldpath, char *newpath);
+/* Rename 'oldpath' to 'newpath' */
+int do_symlink(int fd_in, int fd_out, char *oldpath, char *newpath);
+
+/* Return target of symlink 'path' - caller must free result */
+char *do_readlink(int fd_in, int fd_out, char *path);
+
/* XXX: add callbacks to do_download/do_upload so we can do progress meter */
/*
diff --git a/sftp-int.c b/sftp-int.c
index 7aa7abdb..6f5b3677 100644
--- a/sftp-int.c
+++ b/sftp-int.c
@@ -28,7 +28,7 @@
/* XXX: recursive operations */
#include "includes.h"
-RCSID("$OpenBSD: sftp-int.c,v 1.25 2001/03/06 06:11:44 deraadt Exp $");
+RCSID("$OpenBSD: sftp-int.c,v 1.26 2001/03/07 10:11:23 djm Exp $");
#include "buffer.h"
#include "xmalloc.h"
@@ -40,7 +40,11 @@ RCSID("$OpenBSD: sftp-int.c,v 1.25 2001/03/06 06:11:44 deraadt Exp $");
#include "sftp-client.h"
#include "sftp-int.h"
-extern FILE* infile;
+/* File to read commands from */
+extern FILE *infile;
+
+/* Version of server we are speaking to */
+int version;
/* Seperators for interactive commands */
#define WHITESPACE " \t\r\n"
@@ -66,6 +70,7 @@ extern FILE* infile;
#define I_RM 18
#define I_RMDIR 19
#define I_SHELL 20
+#define I_SYMLINK 21
struct CMD {
const char *c;
@@ -86,6 +91,7 @@ const struct CMD cmds[] = {
{ "lchdir", I_LCHDIR },
{ "lls", I_LLS },
{ "lmkdir", I_LMKDIR },
+ { "ln", I_SYMLINK },
{ "lpwd", I_LPWD },
{ "ls", I_LS },
{ "lumask", I_LUMASK },
@@ -96,6 +102,7 @@ const struct CMD cmds[] = {
{ "rename", I_RENAME },
{ "rm", I_RM },
{ "rmdir", I_RMDIR },
+ { "symlink", I_SYMLINK },
{ "!", I_SHELL },
{ "?", I_HELP },
{ NULL, -1}
@@ -113,6 +120,7 @@ help(void)
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("ln oldpath newpath Symlink remote file\n");
printf("lmkdir path Create local directory\n");
printf("lpwd Print local working directory\n");
printf("ls [path] Display remote directory listing\n");
@@ -125,6 +133,7 @@ help(void)
printf("rename oldpath newpath Rename remote file\n");
printf("rmdir path Remove remote directory\n");
printf("rm path Delete remote file\n");
+ printf("symlink oldpath newpath Symlink remote file\n");
printf("!command Execute 'command' in local shell\n");
printf("! Escape to local shell\n");
printf("? Synonym for help\n");
@@ -356,7 +365,7 @@ parse_args(const char **cpp, int *pflag, unsigned long *n_arg,
return(-1);
break;
case I_RENAME:
- /* Get first pathname (mandatory) */
+ case I_SYMLINK:
if (get_pathname(&cp, path1))
return(-1);
if (get_pathname(&cp, path2))
@@ -468,6 +477,16 @@ parse_dispatch_command(int in, int out, const char *cmd, char **pwd)
path2 = make_absolute(path2, *pwd);
err = do_rename(in, out, path1, path2);
break;
+ case I_SYMLINK:
+ if (version < 3) {
+ error("The server (version %d) does not support "
+ "this operation", version);
+ err = -1;
+ } else {
+ path2 = make_absolute(path2, *pwd);
+ err = do_symlink(in, out, path1, path2);
+ }
+ break;
case I_RM:
path1 = make_absolute(path1, *pwd);
err = do_rm(in, out, path1);
@@ -624,6 +643,10 @@ interactive_loop(int fd_in, int fd_out)
char *pwd;
char cmd[2048];
+ version = do_init(fd_in, fd_out);
+ if (version == -1)
+ fatal("Couldn't initialise connection to server");
+
pwd = do_realpath(fd_in, fd_out, ".");
if (pwd == NULL)
fatal("Need cwd");
diff --git a/sftp-server.c b/sftp-server.c
index 6575eb94..17808457 100644
--- a/sftp-server.c
+++ b/sftp-server.c
@@ -22,7 +22,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
-RCSID("$OpenBSD: sftp-server.c,v 1.22 2001/03/03 22:07:50 deraadt Exp $");
+RCSID("$OpenBSD: sftp-server.c,v 1.23 2001/03/07 10:11:23 djm Exp $");
#include "buffer.h"
#include "bufaux.h"
@@ -49,6 +49,9 @@ char *__progname;
Buffer iqueue;
Buffer oqueue;
+/* Version of client */
+int version;
+
/* portable attibutes, etc. */
typedef struct Stat Stat;
@@ -266,12 +269,29 @@ void
send_status(u_int32_t id, u_int32_t error)
{
Buffer msg;
+ const char *status_messages[] = {
+ "Success", /* SSH_FX_OK */
+ "End of file", /* SSH_FX_EOF */
+ "No such file", /* SSH_FX_NO_SUCH_FILE */
+ "Permission denied", /* SSH_FX_PERMISSION_DENIED */
+ "Failure", /* SSH_FX_FAILURE */
+ "Bad message", /* SSH_FX_BAD_MESSAGE */
+ "No connection", /* SSH_FX_NO_CONNECTION */
+ "Connection lost", /* SSH_FX_CONNECTION_LOST */
+ "Operation unsupported", /* SSH_FX_OP_UNSUPPORTED */
+ "Unknown error" /* Others */
+ };
TRACE("sent status id %d error %d", id, error);
buffer_init(&msg);
buffer_put_char(&msg, SSH2_FXP_STATUS);
buffer_put_int(&msg, id);
buffer_put_int(&msg, error);
+ if (version >= 3) {
+ buffer_put_cstring(&msg,
+ status_messages[MIN(error,SSH2_FX_MAX)]);
+ buffer_put_cstring(&msg, "");
+ }
send_msg(&msg);
buffer_free(&msg);
}
@@ -347,8 +367,8 @@ void
process_init(void)
{
Buffer msg;
- int version = buffer_get_int(&iqueue);
+ version = buffer_get_int(&iqueue);
TRACE("client version %d", version);
buffer_init(&msg);
buffer_put_char(&msg, SSH2_FXP_VERSION);
@@ -860,6 +880,51 @@ process_rename(void)
}
void
+process_readlink(void)
+{
+ u_int32_t id;
+ char link[MAXPATHLEN];
+ char *path;
+
+ id = get_int();
+ path = get_string(NULL);
+ TRACE("readlink id %d path %s", id, path);
+ if (readlink(path, link, sizeof(link) - 1) == -1)
+ send_status(id, errno_to_portable(errno));
+ else {
+ Stat s;
+
+ link[sizeof(link) - 1] = '\0';
+ attrib_clear(&s.attrib);
+ s.name = s.long_name = link;
+ send_names(id, 1, &s);
+ }
+ xfree(path);
+}
+
+void
+process_symlink(void)
+{
+ u_int32_t id;
+ struct stat st;
+ char *oldpath, *newpath;
+ int ret, status = SSH2_FX_FAILURE;
+
+ id = get_int();
+ oldpath = get_string(NULL);
+ newpath = get_string(NULL);
+ TRACE("symlink id %d old %s new %s", id, oldpath, newpath);
+ /* fail if 'newpath' exists */
+ if (stat(newpath, &st) == -1) {
+ ret = symlink(oldpath, newpath);
+ status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
+ }
+ send_status(id, status);
+ xfree(oldpath);
+ xfree(newpath);
+}
+
+void
process_extended(void)
{
u_int32_t id;
@@ -944,6 +1009,12 @@ process(void)
case SSH2_FXP_RENAME:
process_rename();
break;
+ case SSH2_FXP_READLINK:
+ process_readlink();
+ break;
+ case SSH2_FXP_SYMLINK:
+ process_symlink();
+ break;
case SSH2_FXP_EXTENDED:
process_extended();
break;
diff --git a/sftp.1 b/sftp.1
index 7792283e..826a0ddf 100644
--- a/sftp.1
+++ b/sftp.1
@@ -1,4 +1,4 @@
-.\" $OpenBSD: sftp.1,v 1.11 2001/03/06 15:10:42 deraadt Exp $
+.\" $OpenBSD: sftp.1,v 1.12 2001/03/07 10:11:23 djm Exp $
.\"
.\" Copyright (c) 2001 Damien Miller. All rights reserved.
.\"
@@ -58,7 +58,7 @@ instead of
Since it lacks user interaction it should be used in conjuction with a
non-interactive authentication. Sftp will abort if any of the following
commands fail:
-.Pa get, put, rename, rm, mkdir, chdir, lchdir
+.Pa get, put, rename, ln, rm, mkdir, chdir, lchdir
and
.Pa lmkdir.
.It Fl C
@@ -131,6 +131,11 @@ is not specified.
.It Ic lmkdir Ar path
Create local directory specified by
.Ar path .
+.It Ic ln Ar oldpath Ar newpath
+Create a symbolic link from
+.Ar oldpath
+to
+.Ar newpath .
.It Ic lpwd
Print local working directory.
.It Ic ls Op Ar path
@@ -152,8 +157,8 @@ Create remote directory specified by
.Xc
Upload
.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. If the
+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. If the
.Fl P
flag is specified, then the file's full permission and access time are
copied too.
@@ -172,6 +177,11 @@ Remove remote directory specified by
.It Ic rm Ar path
Delete remote file specified by
.Ar path .
+.It Ic symlink Ar oldpath Ar newpath
+Create a symbolic link from
+.Ar oldpath
+to
+.Ar newpath .
.It Ic ! Ar command
Execute
.Ar command
diff --git a/sftp.c b/sftp.c
index c2282509..4569dacc 100644
--- a/sftp.c
+++ b/sftp.c
@@ -24,7 +24,7 @@
#include "includes.h"
-RCSID("$OpenBSD: sftp.c,v 1.10 2001/03/06 06:11:44 deraadt Exp $");
+RCSID("$OpenBSD: sftp.c,v 1.11 2001/03/07 10:11:23 djm Exp $");
/* XXX: commandline mode */
/* XXX: copy between two remote hosts (commandline) */
@@ -256,8 +256,6 @@ main(int argc, char **argv)
connect_to_server(make_ssh_args(NULL), &in, &out, &sshpid);
- do_init(in, out);
-
interactive_loop(in, out);
#if !defined(USE_PIPES)
diff --git a/sftp.h b/sftp.h
index 763056f5..2ad95864 100644
--- a/sftp.h
+++ b/sftp.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: sftp.h,v 1.2 2001/01/29 01:58:18 niklas Exp $ */
+/* $OpenBSD: sftp.h,v 1.3 2001/03/07 10:11:23 djm Exp $ */
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
@@ -25,11 +25,11 @@
*/
/*
- * draft-ietf-secsh-filexfer-00.txt
+ * draft-ietf-secsh-filexfer-01.txt
*/
/* version */
-#define SSH2_FILEXFER_VERSION 2
+#define SSH2_FILEXFER_VERSION 3
/* client to server */
#define SSH2_FXP_INIT 1
@@ -49,6 +49,8 @@
#define SSH2_FXP_REALPATH 16
#define SSH2_FXP_STAT 17
#define SSH2_FXP_RENAME 18
+#define SSH2_FXP_READLINK 19
+#define SSH2_FXP_SYMLINK 20
/* server to client */
#define SSH2_FXP_VERSION 2
@@ -86,3 +88,4 @@
#define SSH2_FX_NO_CONNECTION 6
#define SSH2_FX_CONNECTION_LOST 7
#define SSH2_FX_OP_UNSUPPORTED 8
+#define SSH2_FX_MAX 8