- djm@cvs.openbsd.org 2010/12/04 00:18:01

[sftp-server.c sftp.1 sftp-client.h sftp.c PROTOCOL sftp-client.c]
     add a protocol extension to support a hard link operation. It is
     available through the "ln" command in the client. The old "ln"
     behaviour of creating a symlink is available using its "-s" option
     or through the preexisting "symlink" command; based on a patch from
     miklos AT szeredi.hu in bz#1555; ok markus@
This commit is contained in:
Darren Tucker 2010-12-05 09:02:47 +11:00
parent adab6f1299
commit af1f909254
7 changed files with 151 additions and 20 deletions

View File

@ -11,6 +11,13 @@
[auth-rsa.c]
move check for revoked keys to run earlier (in auth_rsa_key_allowed)
bz#1829; patch from ldv AT altlinux.org; ok markus@
- djm@cvs.openbsd.org 2010/12/04 00:18:01
[sftp-server.c sftp.1 sftp-client.h sftp.c PROTOCOL sftp-client.c]
add a protocol extension to support a hard link operation. It is
available through the "ln" command in the client. The old "ln"
behaviour of creating a symlink is available using its "-s" option
or through the preexisting "symlink" command; based on a patch from
miklos AT szeredi.hu in bz#1555; ok markus@
20101204
- (djm) [openbsd-compat/bindresvport.c] Use arc4random_uniform(range)

View File

@ -275,4 +275,20 @@ The values of the f_flag bitmask are as follows:
Both the "statvfs@openssh.com" and "fstatvfs@openssh.com" extensions are
advertised in the SSH_FXP_VERSION hello with version "2".
$OpenBSD: PROTOCOL,v 1.16 2010/08/31 11:54:45 djm Exp $
10. sftp: Extension request "hardlink@openssh.com"
This request is for creating a hard link to a regular file. This
request is implemented as a SSH_FXP_EXTENDED request with the
following format:
uint32 id
string "hardlink@openssh.com"
string oldpath
string newpath
On receiving this request the server will perform the operation
link(oldpath, newpath) and will respond with a SSH_FXP_STATUS message.
This extension is advertised in the SSH_FXP_VERSION hello with version
"1".
$OpenBSD: PROTOCOL,v 1.17 2010/12/04 00:18:01 djm Exp $

View File

@ -1,4 +1,4 @@
/* $OpenBSD: sftp-client.c,v 1.93 2010/09/22 22:58:51 djm Exp $ */
/* $OpenBSD: sftp-client.c,v 1.94 2010/12/04 00:18:01 djm Exp $ */
/*
* Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
*
@ -75,6 +75,7 @@ struct sftp_conn {
#define SFTP_EXT_POSIX_RENAME 0x00000001
#define SFTP_EXT_STATVFS 0x00000002
#define SFTP_EXT_FSTATVFS 0x00000004
#define SFTP_EXT_HARDLINK 0x00000008
u_int exts;
u_int64_t limit_kbps;
struct bwlimit bwlimit_in, bwlimit_out;
@ -378,10 +379,14 @@ do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests,
strcmp(value, "2") == 0) {
ret->exts |= SFTP_EXT_STATVFS;
known = 1;
} if (strcmp(name, "fstatvfs@openssh.com") == 0 &&
} else if (strcmp(name, "fstatvfs@openssh.com") == 0 &&
strcmp(value, "2") == 0) {
ret->exts |= SFTP_EXT_FSTATVFS;
known = 1;
} else if (strcmp(name, "hardlink@openssh.com") == 0 &&
strcmp(value, "1") == 0) {
ret->exts |= SFTP_EXT_HARDLINK;
known = 1;
}
if (known) {
debug2("Server supports extension \"%s\" revision %s",
@ -794,6 +799,39 @@ do_rename(struct sftp_conn *conn, char *oldpath, char *newpath)
return(status);
}
int
do_hardlink(struct sftp_conn *conn, char *oldpath, char *newpath)
{
Buffer msg;
u_int status, id;
buffer_init(&msg);
/* Send link request */
id = conn->msg_id++;
if ((conn->exts & SFTP_EXT_HARDLINK) == 0) {
error("Server does not support hardlink@openssh.com extension");
return -1;
}
buffer_put_char(&msg, SSH2_FXP_EXTENDED);
buffer_put_int(&msg, id);
buffer_put_cstring(&msg, "hardlink@openssh.com");
buffer_put_cstring(&msg, oldpath);
buffer_put_cstring(&msg, newpath);
send_msg(conn, &msg);
debug3("Sent message hardlink@openssh.com \"%s\" -> \"%s\"",
oldpath, newpath);
buffer_free(&msg);
status = get_status(conn, id);
if (status != SSH2_FX_OK)
error("Couldn't link file \"%s\" to \"%s\": %s", oldpath,
newpath, fx2txt(status));
return(status);
}
int
do_symlink(struct sftp_conn *conn, char *oldpath, char *newpath)
{

View File

@ -1,4 +1,4 @@
/* $OpenBSD: sftp-client.h,v 1.19 2010/09/22 22:58:51 djm Exp $ */
/* $OpenBSD: sftp-client.h,v 1.20 2010/12/04 00:18:01 djm Exp $ */
/*
* Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
@ -94,6 +94,9 @@ int do_statvfs(struct sftp_conn *, const char *, struct sftp_statvfs *, int);
/* Rename 'oldpath' to 'newpath' */
int do_rename(struct sftp_conn *, char *, char *);
/* Link 'oldpath' to 'newpath' */
int do_hardlink(struct sftp_conn *, char *, char *);
/* Rename 'oldpath' to 'newpath' */
int do_symlink(struct sftp_conn *, char *, char *);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: sftp-server.c,v 1.92 2010/11/04 02:45:34 djm Exp $ */
/* $OpenBSD: sftp-server.c,v 1.93 2010/12/04 00:18:01 djm Exp $ */
/*
* Copyright (c) 2000-2004 Markus Friedl. All rights reserved.
*
@ -535,6 +535,9 @@ process_init(void)
/* fstatvfs extension */
buffer_put_cstring(&msg, "fstatvfs@openssh.com");
buffer_put_cstring(&msg, "2"); /* version */
/* hardlink extension */
buffer_put_cstring(&msg, "hardlink@openssh.com");
buffer_put_cstring(&msg, "1"); /* version */
send_msg(&msg);
buffer_free(&msg);
}
@ -1222,6 +1225,27 @@ process_extended_fstatvfs(u_int32_t id)
send_statvfs(id, &st);
}
static void
process_extended_hardlink(u_int32_t id)
{
char *oldpath, *newpath;
int ret, status;
oldpath = get_string(NULL);
newpath = get_string(NULL);
debug3("request %u: hardlink", id);
logit("hardlink old \"%s\" new \"%s\"", oldpath, newpath);
if (readonly)
status = SSH2_FX_PERMISSION_DENIED;
else {
ret = link(oldpath, newpath);
status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
}
send_status(id, status);
xfree(oldpath);
xfree(newpath);
}
static void
process_extended(void)
{
@ -1236,6 +1260,8 @@ process_extended(void)
process_extended_statvfs(id);
else if (strcmp(request, "fstatvfs@openssh.com") == 0)
process_extended_fstatvfs(id);
else if (strcmp(request, "hardlink@openssh.com") == 0)
process_extended_hardlink(id);
else
send_status(id, SSH2_FX_OP_UNSUPPORTED); /* MUST */
xfree(request);

18
sftp.1
View File

@ -1,4 +1,4 @@
.\" $OpenBSD: sftp.1,v 1.87 2010/11/18 15:01:00 jmc Exp $
.\" $OpenBSD: sftp.1,v 1.88 2010/12/04 00:18:01 djm Exp $
.\"
.\" Copyright (c) 2001 Damien Miller. All rights reserved.
.\"
@ -22,7 +22,7 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd $Mdocdate: November 18 2010 $
.Dd $Mdocdate: December 4 2010 $
.Dt SFTP 1
.Os
.Sh NAME
@ -128,7 +128,7 @@ commands fail:
.Ic get , put , rename , ln ,
.Ic rm , mkdir , chdir , ls ,
.Ic lchdir , chmod , chown ,
.Ic chgrp , lpwd , df ,
.Ic chgrp , lpwd , df , symlink ,
and
.Ic lmkdir .
Termination on error can be suppressed on a command by command basis by
@ -392,11 +392,19 @@ characters and may match multiple files.
.It Ic lmkdir Ar path
Create local directory specified by
.Ar path .
.It Ic ln Ar oldpath Ar newpath
Create a symbolic link from
.It Xo Ic ln
.Op Fl s
.Ar oldpath
.Ar newpath
.Xc
Create a link from
.Ar oldpath
to
.Ar newpath .
If the
.Fl s
flag is specified the created link is a symbolic link, otherwise it is
a hard link.
.It Ic lpwd
Print local working directory.
.It Xo Ic ls

53
sftp.c
View File

@ -1,4 +1,4 @@
/* $OpenBSD: sftp.c,v 1.131 2010/10/23 22:06:12 sthen Exp $ */
/* $OpenBSD: sftp.c,v 1.132 2010/12/04 00:18:01 djm Exp $ */
/*
* Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
*
@ -132,6 +132,7 @@ extern char *__progname;
#define I_GET 5
#define I_HELP 6
#define I_LCHDIR 7
#define I_LINK 25
#define I_LLS 8
#define I_LMKDIR 9
#define I_LPWD 10
@ -176,7 +177,7 @@ static const struct CMD cmds[] = {
{ "lchdir", I_LCHDIR, LOCAL },
{ "lls", I_LLS, LOCAL },
{ "lmkdir", I_LMKDIR, LOCAL },
{ "ln", I_SYMLINK, REMOTE },
{ "ln", I_LINK, REMOTE },
{ "lpwd", I_LPWD, LOCAL },
{ "ls", I_LS, REMOTE },
{ "lumask", I_LUMASK, NOARGS },
@ -240,7 +241,7 @@ help(void)
"lcd path Change local directory to 'path'\n"
"lls [ls-options [path]] Display local directory listing\n"
"lmkdir path Create local directory\n"
"ln oldpath newpath Symlink remote file\n"
"ln [-s] oldpath newpath Link remote file (-s for symlink)\n"
"lpwd Print local working directory\n"
"ls [-1afhlnrSt] [path] Display remote directory listing\n"
"lumask umask Set local umask to 'umask'\n"
@ -376,6 +377,30 @@ parse_getput_flags(const char *cmd, char **argv, int argc, int *pflag,
return optind;
}
static int
parse_link_flags(const char *cmd, char **argv, int argc, int *sflag)
{
extern int opterr, optind, optopt, optreset;
int ch;
optind = optreset = 1;
opterr = 0;
*sflag = 0;
while ((ch = getopt(argc, argv, "s")) != -1) {
switch (ch) {
case 's':
*sflag = 1;
break;
default:
error("%s: Invalid flag -%c", cmd, optopt);
return -1;
}
}
return optind;
}
static int
parse_ls_flags(char **argv, int argc, int *lflag)
{
@ -1088,7 +1113,7 @@ makeargv(const char *arg, int *argcp, int sloppy, char *lastquote,
static int
parse_args(const char **cpp, int *pflag, int *rflag, int *lflag, int *iflag,
int *hflag, unsigned long *n_arg, char **path1, char **path2)
int *hflag, int *sflag, unsigned long *n_arg, char **path1, char **path2)
{
const char *cmd, *cp = *cpp;
char *cp2, **argv;
@ -1138,7 +1163,8 @@ parse_args(const char **cpp, int *pflag, int *rflag, int *lflag, int *iflag,
switch (cmdnum) {
case I_GET:
case I_PUT:
if ((optidx = parse_getput_flags(cmd, argv, argc, pflag, rflag)) == -1)
if ((optidx = parse_getput_flags(cmd, argv, argc,
pflag, rflag)) == -1)
return -1;
/* Get first pathname (mandatory) */
if (argc - optidx < 1) {
@ -1154,8 +1180,11 @@ parse_args(const char **cpp, int *pflag, int *rflag, int *lflag, int *iflag,
undo_glob_escape(*path2);
}
break;
case I_RENAME:
case I_LINK:
if ((optidx = parse_link_flags(cmd, argv, argc, sflag)) == -1)
return -1;
case I_SYMLINK:
case I_RENAME:
if (argc - optidx < 2) {
error("You must specify two paths after a %s "
"command.", cmd);
@ -1258,7 +1287,8 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
int err_abort)
{
char *path1, *path2, *tmp;
int pflag = 0, rflag = 0, lflag = 0, iflag = 0, hflag = 0, cmdnum, i;
int pflag = 0, rflag = 0, lflag = 0, iflag = 0, hflag = 0, sflag = 0;
int cmdnum, i;
unsigned long n_arg = 0;
Attrib a, *aa;
char path_buf[MAXPATHLEN];
@ -1266,8 +1296,8 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
glob_t g;
path1 = path2 = NULL;
cmdnum = parse_args(&cmd, &pflag, &rflag, &lflag, &iflag, &hflag, &n_arg,
&path1, &path2);
cmdnum = parse_args(&cmd, &pflag, &rflag, &lflag, &iflag, &hflag,
&sflag, &n_arg, &path1, &path2);
if (iflag != 0)
err_abort = 0;
@ -1295,8 +1325,11 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
err = do_rename(conn, path1, path2);
break;
case I_SYMLINK:
sflag = 1;
case I_LINK:
path1 = make_absolute(path1, *pwd);
path2 = make_absolute(path2, *pwd);
err = do_symlink(conn, path1, path2);
err = (sflag ? do_symlink : do_hardlink)(conn, path1, path2);
break;
case I_RM:
path1 = make_absolute(path1, *pwd);