2001-02-23 18:21:44 +00:00
|
|
|
/*
|
2004-04-27 12:31:57 +00:00
|
|
|
* psftp.c: (platform-independent) front end for PSFTP.
|
2001-02-23 18:21:44 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
2001-02-24 12:02:35 +00:00
|
|
|
#include <stdarg.h>
|
2001-02-23 18:21:44 +00:00
|
|
|
#include <assert.h>
|
2001-08-26 11:35:11 +00:00
|
|
|
#include <limits.h>
|
2001-02-23 18:21:44 +00:00
|
|
|
|
2001-02-24 16:08:56 +00:00
|
|
|
#define PUTTY_DO_GLOBALS
|
|
|
|
#include "putty.h"
|
2003-08-24 12:47:46 +00:00
|
|
|
#include "psftp.h"
|
2001-02-24 16:08:56 +00:00
|
|
|
#include "storage.h"
|
|
|
|
#include "ssh.h"
|
2001-02-23 18:21:44 +00:00
|
|
|
#include "sftp.h"
|
|
|
|
|
2009-04-23 17:39:36 +00:00
|
|
|
const char *const appname = "PSFTP";
|
|
|
|
|
2001-08-25 17:09:23 +00:00
|
|
|
/*
|
|
|
|
* Since SFTP is a request-response oriented protocol, it requires
|
|
|
|
* no buffer management: when we send data, we stop and wait for an
|
|
|
|
* acknowledgement _anyway_, and so we can't possibly overfill our
|
|
|
|
* send buffer.
|
|
|
|
*/
|
|
|
|
|
2001-12-13 18:42:34 +00:00
|
|
|
static int psftp_connect(char *userhost, char *user, int portnumber);
|
2002-02-27 22:30:57 +00:00
|
|
|
static int do_sftp_init(void);
|
2003-12-19 12:44:46 +00:00
|
|
|
void do_sftp_cleanup();
|
2001-12-13 18:42:34 +00:00
|
|
|
|
2001-02-23 18:21:44 +00:00
|
|
|
/* ----------------------------------------------------------------------
|
|
|
|
* sftp client state.
|
|
|
|
*/
|
|
|
|
|
|
|
|
char *pwd, *homedir;
|
2018-09-11 15:23:38 +00:00
|
|
|
static Backend *backend;
|
Post-release destabilisation! Completely remove the struct type
'Config' in putty.h, which stores all PuTTY's settings and includes an
arbitrary length limit on every single one of those settings which is
stored in string form. In place of it is 'Conf', an opaque data type
everywhere outside the new file conf.c, which stores a list of (key,
value) pairs in which every key contains an integer identifying a
configuration setting, and for some of those integers the key also
contains extra parts (so that, for instance, CONF_environmt is a
string-to-string mapping). Everywhere that a Config was previously
used, a Conf is now; everywhere there was a Config structure copy,
conf_copy() is called; every lookup, adjustment, load and save
operation on a Config has been rewritten; and there's a mechanism for
serialising a Conf into a binary blob and back for use with Duplicate
Session.
User-visible effects of this change _should_ be minimal, though I
don't doubt I've introduced one or two bugs here and there which will
eventually be found. The _intended_ visible effects of this change are
that all arbitrary limits on configuration strings and lists (e.g.
limit on number of port forwardings) should now disappear; that list
boxes in the configuration will now be displayed in a sorted order
rather than the arbitrary order in which they were added to the list
(since the underlying data structure is now a sorted tree234 rather
than an ad-hoc comma-separated string); and one more specific change,
which is that local and dynamic port forwardings on the same port
number are now mutually exclusive in the configuration (putting 'D' in
the key rather than the value was a mistake in the first place).
One other reorganisation as a result of this is that I've moved all
the dialog.c standard handlers (dlg_stdeditbox_handler and friends)
out into config.c, because I can't really justify calling them generic
any more. When they took a pointer to an arbitrary structure type and
the offset of a field within that structure, they were independent of
whether that structure was a Config or something completely different,
but now they really do expect to talk to a Conf, which can _only_ be
used for PuTTY configuration, so I've renamed them all things like
conf_editbox_handler and moved them out of the nominally independent
dialog-box management module into the PuTTY-specific config.c.
[originally from svn r9214]
2011-07-14 18:52:21 +00:00
|
|
|
static Conf *conf;
|
2011-09-13 11:44:03 +00:00
|
|
|
int sent_eof = FALSE;
|
2001-02-23 18:21:44 +00:00
|
|
|
|
New abstraction 'Seat', to pass to backends.
This is a new vtable-based abstraction which is passed to a backend in
place of Frontend, and it implements only the subset of the Frontend
functions needed by a backend. (Many other Frontend functions still
exist, notably the wide range of things called by terminal.c providing
platform-independent operations on the GUI terminal window.)
The purpose of making it a vtable is that this opens up the
possibility of creating a backend as an internal implementation detail
of some other activity, by providing just that one backend with a
custom Seat that implements the methods differently.
For example, this refactoring should make it feasible to directly
implement an SSH proxy type, aka the 'jump host' feature supported by
OpenSSH, aka 'open a secondary SSH session in MAINCHAN_DIRECT_TCP
mode, and then expose the main channel of that as the Socket for the
primary connection'. (Which of course you can already do by spawning
'plink -nc' as a separate proxy process, but this would permit it in
the _same_ process without anything getting confused.)
I've centralised a full set of stub methods in misc.c for the new
abstraction, which allows me to get rid of several annoying stubs in
the previous code. Also, while I'm here, I've moved a lot of
duplicated modalfatalbox() type functions from application main
program files into wincons.c / uxcons.c, which I think saves
duplication overall. (A minor visible effect is that the prefixes on
those console-based fatal error messages will now be more consistent
between applications.)
2018-10-11 18:58:42 +00:00
|
|
|
/* ------------------------------------------------------------
|
|
|
|
* Seat vtable.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int psftp_output(Seat *, int is_stderr, const void *, int);
|
|
|
|
static int psftp_eof(Seat *);
|
|
|
|
|
|
|
|
static const SeatVtable psftp_seat_vt = {
|
|
|
|
psftp_output,
|
|
|
|
psftp_eof,
|
|
|
|
filexfer_get_userpass_input,
|
|
|
|
nullseat_notify_remote_exit,
|
|
|
|
console_connection_fatal,
|
|
|
|
nullseat_update_specials_menu,
|
|
|
|
nullseat_get_ttymode,
|
|
|
|
nullseat_set_busy_status,
|
|
|
|
console_verify_ssh_host_key,
|
|
|
|
console_confirm_weak_crypto_primitive,
|
|
|
|
console_confirm_weak_cached_hostkey,
|
|
|
|
nullseat_is_never_utf8,
|
|
|
|
nullseat_echoedit_update,
|
|
|
|
nullseat_get_x_display,
|
|
|
|
nullseat_get_windowid,
|
2018-10-13 06:37:24 +00:00
|
|
|
nullseat_get_window_pixel_size,
|
New abstraction 'Seat', to pass to backends.
This is a new vtable-based abstraction which is passed to a backend in
place of Frontend, and it implements only the subset of the Frontend
functions needed by a backend. (Many other Frontend functions still
exist, notably the wide range of things called by terminal.c providing
platform-independent operations on the GUI terminal window.)
The purpose of making it a vtable is that this opens up the
possibility of creating a backend as an internal implementation detail
of some other activity, by providing just that one backend with a
custom Seat that implements the methods differently.
For example, this refactoring should make it feasible to directly
implement an SSH proxy type, aka the 'jump host' feature supported by
OpenSSH, aka 'open a secondary SSH session in MAINCHAN_DIRECT_TCP
mode, and then expose the main channel of that as the Socket for the
primary connection'. (Which of course you can already do by spawning
'plink -nc' as a separate proxy process, but this would permit it in
the _same_ process without anything getting confused.)
I've centralised a full set of stub methods in misc.c for the new
abstraction, which allows me to get rid of several annoying stubs in
the previous code. Also, while I'm here, I've moved a lot of
duplicated modalfatalbox() type functions from application main
program files into wincons.c / uxcons.c, which I think saves
duplication overall. (A minor visible effect is that the prefixes on
those console-based fatal error messages will now be more consistent
between applications.)
2018-10-11 18:58:42 +00:00
|
|
|
};
|
|
|
|
static Seat psftp_seat[1] = {{ &psftp_seat_vt }};
|
|
|
|
|
Clean up handling of the return value from sftp_find_request. In many
places we simply enforce by assertion that it will match the request
we sent out a moment ago: in fact it can also return NULL, so it makes
more sense to report a proper error message if it doesn't return the
expected value, and while we're at it, have that error message
whatever message was helpfully left in fxp_error() by
sftp_find_request when it failed.
To do this, I've written a centralised function in psftp.c called
sftp_wait_for_reply, which is handed a request that's just been sent
out and deals with the mechanics of waiting for its reply, returning
the reply when it arrives, and aborting with a sensible error if
anything else arrives instead. The numerous sites in psftp.c which
called sftp_find_request have all been rewritten to do this instead,
and as a side effect they now look more sensible. The only other uses
of sftp_find_request were in xfer_*load_gotpkt, which had to be
tweaked in its own way.
While I'm here, also fix memory management in sftp_find_request, which
was freeing its input packet on some but not all error return paths.
[originally from svn r9894]
2013-07-06 20:43:21 +00:00
|
|
|
/* ----------------------------------------------------------------------
|
|
|
|
* Manage sending requests and waiting for replies.
|
|
|
|
*/
|
|
|
|
struct sftp_packet *sftp_wait_for_reply(struct sftp_request *req)
|
|
|
|
{
|
|
|
|
struct sftp_packet *pktin;
|
|
|
|
struct sftp_request *rreq;
|
|
|
|
|
|
|
|
sftp_register(req);
|
|
|
|
pktin = sftp_recv();
|
New abstraction 'Seat', to pass to backends.
This is a new vtable-based abstraction which is passed to a backend in
place of Frontend, and it implements only the subset of the Frontend
functions needed by a backend. (Many other Frontend functions still
exist, notably the wide range of things called by terminal.c providing
platform-independent operations on the GUI terminal window.)
The purpose of making it a vtable is that this opens up the
possibility of creating a backend as an internal implementation detail
of some other activity, by providing just that one backend with a
custom Seat that implements the methods differently.
For example, this refactoring should make it feasible to directly
implement an SSH proxy type, aka the 'jump host' feature supported by
OpenSSH, aka 'open a secondary SSH session in MAINCHAN_DIRECT_TCP
mode, and then expose the main channel of that as the Socket for the
primary connection'. (Which of course you can already do by spawning
'plink -nc' as a separate proxy process, but this would permit it in
the _same_ process without anything getting confused.)
I've centralised a full set of stub methods in misc.c for the new
abstraction, which allows me to get rid of several annoying stubs in
the previous code. Also, while I'm here, I've moved a lot of
duplicated modalfatalbox() type functions from application main
program files into wincons.c / uxcons.c, which I think saves
duplication overall. (A minor visible effect is that the prefixes on
those console-based fatal error messages will now be more consistent
between applications.)
2018-10-11 18:58:42 +00:00
|
|
|
if (pktin == NULL) {
|
|
|
|
seat_connection_fatal(
|
|
|
|
psftp_seat, "did not receive SFTP response packet from server");
|
|
|
|
}
|
Clean up handling of the return value from sftp_find_request. In many
places we simply enforce by assertion that it will match the request
we sent out a moment ago: in fact it can also return NULL, so it makes
more sense to report a proper error message if it doesn't return the
expected value, and while we're at it, have that error message
whatever message was helpfully left in fxp_error() by
sftp_find_request when it failed.
To do this, I've written a centralised function in psftp.c called
sftp_wait_for_reply, which is handed a request that's just been sent
out and deals with the mechanics of waiting for its reply, returning
the reply when it arrives, and aborting with a sensible error if
anything else arrives instead. The numerous sites in psftp.c which
called sftp_find_request have all been rewritten to do this instead,
and as a side effect they now look more sensible. The only other uses
of sftp_find_request were in xfer_*load_gotpkt, which had to be
tweaked in its own way.
While I'm here, also fix memory management in sftp_find_request, which
was freeing its input packet on some but not all error return paths.
[originally from svn r9894]
2013-07-06 20:43:21 +00:00
|
|
|
rreq = sftp_find_request(pktin);
|
New abstraction 'Seat', to pass to backends.
This is a new vtable-based abstraction which is passed to a backend in
place of Frontend, and it implements only the subset of the Frontend
functions needed by a backend. (Many other Frontend functions still
exist, notably the wide range of things called by terminal.c providing
platform-independent operations on the GUI terminal window.)
The purpose of making it a vtable is that this opens up the
possibility of creating a backend as an internal implementation detail
of some other activity, by providing just that one backend with a
custom Seat that implements the methods differently.
For example, this refactoring should make it feasible to directly
implement an SSH proxy type, aka the 'jump host' feature supported by
OpenSSH, aka 'open a secondary SSH session in MAINCHAN_DIRECT_TCP
mode, and then expose the main channel of that as the Socket for the
primary connection'. (Which of course you can already do by spawning
'plink -nc' as a separate proxy process, but this would permit it in
the _same_ process without anything getting confused.)
I've centralised a full set of stub methods in misc.c for the new
abstraction, which allows me to get rid of several annoying stubs in
the previous code. Also, while I'm here, I've moved a lot of
duplicated modalfatalbox() type functions from application main
program files into wincons.c / uxcons.c, which I think saves
duplication overall. (A minor visible effect is that the prefixes on
those console-based fatal error messages will now be more consistent
between applications.)
2018-10-11 18:58:42 +00:00
|
|
|
if (rreq != req) {
|
|
|
|
seat_connection_fatal(
|
|
|
|
psftp_seat,
|
|
|
|
"unable to understand SFTP response packet from server: %s",
|
|
|
|
fxp_error());
|
|
|
|
}
|
Clean up handling of the return value from sftp_find_request. In many
places we simply enforce by assertion that it will match the request
we sent out a moment ago: in fact it can also return NULL, so it makes
more sense to report a proper error message if it doesn't return the
expected value, and while we're at it, have that error message
whatever message was helpfully left in fxp_error() by
sftp_find_request when it failed.
To do this, I've written a centralised function in psftp.c called
sftp_wait_for_reply, which is handed a request that's just been sent
out and deals with the mechanics of waiting for its reply, returning
the reply when it arrives, and aborting with a sensible error if
anything else arrives instead. The numerous sites in psftp.c which
called sftp_find_request have all been rewritten to do this instead,
and as a side effect they now look more sensible. The only other uses
of sftp_find_request were in xfer_*load_gotpkt, which had to be
tweaked in its own way.
While I'm here, also fix memory management in sftp_find_request, which
was freeing its input packet on some but not all error return paths.
[originally from svn r9894]
2013-07-06 20:43:21 +00:00
|
|
|
return pktin;
|
|
|
|
}
|
|
|
|
|
2001-02-23 18:21:44 +00:00
|
|
|
/* ----------------------------------------------------------------------
|
|
|
|
* Higher-level helper functions used in commands.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2001-02-24 12:02:35 +00:00
|
|
|
* Attempt to canonify a pathname starting from the pwd. If
|
|
|
|
* canonification fails, at least fall back to returning a _valid_
|
|
|
|
* pathname (though it may be ugly, eg /home/simon/../foobar).
|
2001-02-23 18:21:44 +00:00
|
|
|
*/
|
2015-05-15 10:15:42 +00:00
|
|
|
char *canonify(const char *name)
|
2001-05-06 14:35:20 +00:00
|
|
|
{
|
2001-02-24 12:02:35 +00:00
|
|
|
char *fullname, *canonname;
|
2003-06-29 14:26:09 +00:00
|
|
|
struct sftp_packet *pktin;
|
Clean up handling of the return value from sftp_find_request. In many
places we simply enforce by assertion that it will match the request
we sent out a moment ago: in fact it can also return NULL, so it makes
more sense to report a proper error message if it doesn't return the
expected value, and while we're at it, have that error message
whatever message was helpfully left in fxp_error() by
sftp_find_request when it failed.
To do this, I've written a centralised function in psftp.c called
sftp_wait_for_reply, which is handed a request that's just been sent
out and deals with the mechanics of waiting for its reply, returning
the reply when it arrives, and aborting with a sensible error if
anything else arrives instead. The numerous sites in psftp.c which
called sftp_find_request have all been rewritten to do this instead,
and as a side effect they now look more sensible. The only other uses
of sftp_find_request were in xfer_*load_gotpkt, which had to be
tweaked in its own way.
While I'm here, also fix memory management in sftp_find_request, which
was freeing its input packet on some but not all error return paths.
[originally from svn r9894]
2013-07-06 20:43:21 +00:00
|
|
|
struct sftp_request *req;
|
2001-02-24 16:08:56 +00:00
|
|
|
|
2001-02-24 12:02:35 +00:00
|
|
|
if (name[0] == '/') {
|
|
|
|
fullname = dupstr(name);
|
|
|
|
} else {
|
2015-05-15 10:15:42 +00:00
|
|
|
const char *slash;
|
2001-05-06 14:35:20 +00:00
|
|
|
if (pwd[strlen(pwd) - 1] == '/')
|
2001-02-24 16:08:56 +00:00
|
|
|
slash = "";
|
|
|
|
else
|
|
|
|
slash = "/";
|
|
|
|
fullname = dupcat(pwd, slash, name, NULL);
|
2001-02-24 12:02:35 +00:00
|
|
|
}
|
2001-02-24 16:08:56 +00:00
|
|
|
|
Clean up handling of the return value from sftp_find_request. In many
places we simply enforce by assertion that it will match the request
we sent out a moment ago: in fact it can also return NULL, so it makes
more sense to report a proper error message if it doesn't return the
expected value, and while we're at it, have that error message
whatever message was helpfully left in fxp_error() by
sftp_find_request when it failed.
To do this, I've written a centralised function in psftp.c called
sftp_wait_for_reply, which is handed a request that's just been sent
out and deals with the mechanics of waiting for its reply, returning
the reply when it arrives, and aborting with a sensible error if
anything else arrives instead. The numerous sites in psftp.c which
called sftp_find_request have all been rewritten to do this instead,
and as a side effect they now look more sensible. The only other uses
of sftp_find_request were in xfer_*load_gotpkt, which had to be
tweaked in its own way.
While I'm here, also fix memory management in sftp_find_request, which
was freeing its input packet on some but not all error return paths.
[originally from svn r9894]
2013-07-06 20:43:21 +00:00
|
|
|
req = fxp_realpath_send(fullname);
|
|
|
|
pktin = sftp_wait_for_reply(req);
|
|
|
|
canonname = fxp_realpath_recv(pktin, req);
|
2001-02-24 16:08:56 +00:00
|
|
|
|
2001-02-24 12:02:35 +00:00
|
|
|
if (canonname) {
|
|
|
|
sfree(fullname);
|
|
|
|
return canonname;
|
2001-02-26 16:39:15 +00:00
|
|
|
} else {
|
2001-05-06 14:35:20 +00:00
|
|
|
/*
|
|
|
|
* Attempt number 2. Some FXP_REALPATH implementations
|
|
|
|
* (glibc-based ones, in particular) require the _whole_
|
|
|
|
* path to point to something that exists, whereas others
|
|
|
|
* (BSD-based) only require all but the last component to
|
|
|
|
* exist. So if the first call failed, we should strip off
|
|
|
|
* everything from the last slash onwards and try again,
|
|
|
|
* then put the final component back on.
|
|
|
|
*
|
|
|
|
* Special cases:
|
|
|
|
*
|
|
|
|
* - if the last component is "/." or "/..", then we don't
|
|
|
|
* bother trying this because there's no way it can work.
|
|
|
|
*
|
|
|
|
* - if the thing actually ends with a "/", we remove it
|
|
|
|
* before we start. Except if the string is "/" itself
|
|
|
|
* (although I can't see why we'd have got here if so,
|
|
|
|
* because surely "/" would have worked the first
|
|
|
|
* time?), in which case we don't bother.
|
|
|
|
*
|
|
|
|
* - if there's no slash in the string at all, give up in
|
|
|
|
* confusion (we expect at least one because of the way
|
|
|
|
* we constructed the string).
|
|
|
|
*/
|
|
|
|
|
|
|
|
int i;
|
|
|
|
char *returnname;
|
|
|
|
|
|
|
|
i = strlen(fullname);
|
|
|
|
if (i > 2 && fullname[i - 1] == '/')
|
|
|
|
fullname[--i] = '\0'; /* strip trailing / unless at pos 0 */
|
|
|
|
while (i > 0 && fullname[--i] != '/');
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Give up on special cases.
|
|
|
|
*/
|
|
|
|
if (fullname[i] != '/' || /* no slash at all */
|
|
|
|
!strcmp(fullname + i, "/.") || /* ends in /. */
|
|
|
|
!strcmp(fullname + i, "/..") || /* ends in /.. */
|
|
|
|
!strcmp(fullname, "/")) {
|
|
|
|
return fullname;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Now i points at the slash. Deal with the final special
|
|
|
|
* case i==0 (ie the whole path was "/nonexistentfile").
|
|
|
|
*/
|
|
|
|
fullname[i] = '\0'; /* separate the string */
|
|
|
|
if (i == 0) {
|
Clean up handling of the return value from sftp_find_request. In many
places we simply enforce by assertion that it will match the request
we sent out a moment ago: in fact it can also return NULL, so it makes
more sense to report a proper error message if it doesn't return the
expected value, and while we're at it, have that error message
whatever message was helpfully left in fxp_error() by
sftp_find_request when it failed.
To do this, I've written a centralised function in psftp.c called
sftp_wait_for_reply, which is handed a request that's just been sent
out and deals with the mechanics of waiting for its reply, returning
the reply when it arrives, and aborting with a sensible error if
anything else arrives instead. The numerous sites in psftp.c which
called sftp_find_request have all been rewritten to do this instead,
and as a side effect they now look more sensible. The only other uses
of sftp_find_request were in xfer_*load_gotpkt, which had to be
tweaked in its own way.
While I'm here, also fix memory management in sftp_find_request, which
was freeing its input packet on some but not all error return paths.
[originally from svn r9894]
2013-07-06 20:43:21 +00:00
|
|
|
req = fxp_realpath_send("/");
|
2001-05-06 14:35:20 +00:00
|
|
|
} else {
|
Clean up handling of the return value from sftp_find_request. In many
places we simply enforce by assertion that it will match the request
we sent out a moment ago: in fact it can also return NULL, so it makes
more sense to report a proper error message if it doesn't return the
expected value, and while we're at it, have that error message
whatever message was helpfully left in fxp_error() by
sftp_find_request when it failed.
To do this, I've written a centralised function in psftp.c called
sftp_wait_for_reply, which is handed a request that's just been sent
out and deals with the mechanics of waiting for its reply, returning
the reply when it arrives, and aborting with a sensible error if
anything else arrives instead. The numerous sites in psftp.c which
called sftp_find_request have all been rewritten to do this instead,
and as a side effect they now look more sensible. The only other uses
of sftp_find_request were in xfer_*load_gotpkt, which had to be
tweaked in its own way.
While I'm here, also fix memory management in sftp_find_request, which
was freeing its input packet on some but not all error return paths.
[originally from svn r9894]
2013-07-06 20:43:21 +00:00
|
|
|
req = fxp_realpath_send(fullname);
|
2001-05-06 14:35:20 +00:00
|
|
|
}
|
Clean up handling of the return value from sftp_find_request. In many
places we simply enforce by assertion that it will match the request
we sent out a moment ago: in fact it can also return NULL, so it makes
more sense to report a proper error message if it doesn't return the
expected value, and while we're at it, have that error message
whatever message was helpfully left in fxp_error() by
sftp_find_request when it failed.
To do this, I've written a centralised function in psftp.c called
sftp_wait_for_reply, which is handed a request that's just been sent
out and deals with the mechanics of waiting for its reply, returning
the reply when it arrives, and aborting with a sensible error if
anything else arrives instead. The numerous sites in psftp.c which
called sftp_find_request have all been rewritten to do this instead,
and as a side effect they now look more sensible. The only other uses
of sftp_find_request were in xfer_*load_gotpkt, which had to be
tweaked in its own way.
While I'm here, also fix memory management in sftp_find_request, which
was freeing its input packet on some but not all error return paths.
[originally from svn r9894]
2013-07-06 20:43:21 +00:00
|
|
|
pktin = sftp_wait_for_reply(req);
|
|
|
|
canonname = fxp_realpath_recv(pktin, req);
|
2001-05-06 14:35:20 +00:00
|
|
|
|
2006-10-22 20:19:55 +00:00
|
|
|
if (!canonname) {
|
|
|
|
/* Even that failed. Restore our best guess at the
|
|
|
|
* constructed filename and give up */
|
|
|
|
fullname[i] = '/'; /* restore slash and last component */
|
|
|
|
return fullname;
|
|
|
|
}
|
2001-05-06 14:35:20 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* We have a canonical name for all but the last path
|
|
|
|
* component. Concatenate the last component and return.
|
|
|
|
*/
|
|
|
|
returnname = dupcat(canonname,
|
|
|
|
canonname[strlen(canonname) - 1] ==
|
|
|
|
'/' ? "" : "/", fullname + i + 1, NULL);
|
|
|
|
sfree(fullname);
|
|
|
|
sfree(canonname);
|
|
|
|
return returnname;
|
2001-02-26 16:39:15 +00:00
|
|
|
}
|
2001-02-23 18:21:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2004-12-16 16:37:37 +00:00
|
|
|
* qsort comparison routine for fxp_name structures. Sorts by real
|
|
|
|
* file name.
|
2001-02-23 18:21:44 +00:00
|
|
|
*/
|
2004-12-16 16:37:37 +00:00
|
|
|
static int sftp_name_compare(const void *av, const void *bv)
|
2001-05-06 14:35:20 +00:00
|
|
|
{
|
2002-03-31 16:26:13 +00:00
|
|
|
const struct fxp_name *const *a = (const struct fxp_name *const *) av;
|
|
|
|
const struct fxp_name *const *b = (const struct fxp_name *const *) bv;
|
|
|
|
return strcmp((*a)->filename, (*b)->filename);
|
2001-02-23 18:21:44 +00:00
|
|
|
}
|
|
|
|
|
2001-09-09 16:31:26 +00:00
|
|
|
/*
|
2004-12-16 16:37:37 +00:00
|
|
|
* Likewise, but for a bare char *.
|
2001-09-09 16:31:26 +00:00
|
|
|
*/
|
2004-12-16 16:37:37 +00:00
|
|
|
static int bare_name_compare(const void *av, const void *bv)
|
2001-09-09 16:31:26 +00:00
|
|
|
{
|
2004-12-16 16:37:37 +00:00
|
|
|
const char **a = (const char **) av;
|
|
|
|
const char **b = (const char **) bv;
|
|
|
|
return strcmp(*a, *b);
|
2001-09-09 16:31:26 +00:00
|
|
|
}
|
|
|
|
|
2005-01-01 16:43:19 +00:00
|
|
|
static void not_connected(void)
|
|
|
|
{
|
|
|
|
printf("psftp: not connected to a host; use \"open host.name\"\n");
|
|
|
|
}
|
|
|
|
|
2004-12-16 16:37:37 +00:00
|
|
|
/* ----------------------------------------------------------------------
|
|
|
|
* The meat of the `get' and `put' commands.
|
2001-02-23 18:21:44 +00:00
|
|
|
*/
|
2004-12-30 13:51:37 +00:00
|
|
|
int sftp_get_file(char *fname, char *outfname, int recurse, int restart)
|
2001-05-06 14:35:20 +00:00
|
|
|
{
|
2001-02-23 18:21:44 +00:00
|
|
|
struct fxp_handle *fh;
|
2003-06-29 14:26:09 +00:00
|
|
|
struct sftp_packet *pktin;
|
Clean up handling of the return value from sftp_find_request. In many
places we simply enforce by assertion that it will match the request
we sent out a moment ago: in fact it can also return NULL, so it makes
more sense to report a proper error message if it doesn't return the
expected value, and while we're at it, have that error message
whatever message was helpfully left in fxp_error() by
sftp_find_request when it failed.
To do this, I've written a centralised function in psftp.c called
sftp_wait_for_reply, which is handed a request that's just been sent
out and deals with the mechanics of waiting for its reply, returning
the reply when it arrives, and aborting with a sensible error if
anything else arrives instead. The numerous sites in psftp.c which
called sftp_find_request have all been rewritten to do this instead,
and as a side effect they now look more sensible. The only other uses
of sftp_find_request were in xfer_*load_gotpkt, which had to be
tweaked in its own way.
While I'm here, also fix memory management in sftp_find_request, which
was freeing its input packet on some but not all error return paths.
[originally from svn r9894]
2013-07-06 20:43:21 +00:00
|
|
|
struct sftp_request *req;
|
2003-09-27 17:52:34 +00:00
|
|
|
struct fxp_xfer *xfer;
|
2018-10-26 22:08:58 +00:00
|
|
|
uint64_t offset;
|
2006-08-12 15:20:19 +00:00
|
|
|
WFile *file;
|
2004-12-17 13:39:41 +00:00
|
|
|
int ret, shown_err = FALSE;
|
2011-08-11 17:59:30 +00:00
|
|
|
struct fxp_attrs attrs;
|
2001-02-23 18:21:44 +00:00
|
|
|
|
2004-12-16 16:37:37 +00:00
|
|
|
/*
|
|
|
|
* In recursive mode, see if we're dealing with a directory.
|
|
|
|
* (If we're not in recursive mode, we need not even check: the
|
|
|
|
* subsequent FXP_OPEN will return a usable error message.)
|
|
|
|
*/
|
2004-12-30 13:51:37 +00:00
|
|
|
if (recurse) {
|
2004-12-16 16:37:37 +00:00
|
|
|
int result;
|
2001-12-13 18:42:34 +00:00
|
|
|
|
Clean up handling of the return value from sftp_find_request. In many
places we simply enforce by assertion that it will match the request
we sent out a moment ago: in fact it can also return NULL, so it makes
more sense to report a proper error message if it doesn't return the
expected value, and while we're at it, have that error message
whatever message was helpfully left in fxp_error() by
sftp_find_request when it failed.
To do this, I've written a centralised function in psftp.c called
sftp_wait_for_reply, which is handed a request that's just been sent
out and deals with the mechanics of waiting for its reply, returning
the reply when it arrives, and aborting with a sensible error if
anything else arrives instead. The numerous sites in psftp.c which
called sftp_find_request have all been rewritten to do this instead,
and as a side effect they now look more sensible. The only other uses
of sftp_find_request were in xfer_*load_gotpkt, which had to be
tweaked in its own way.
While I'm here, also fix memory management in sftp_find_request, which
was freeing its input packet on some but not all error return paths.
[originally from svn r9894]
2013-07-06 20:43:21 +00:00
|
|
|
req = fxp_stat_send(fname);
|
|
|
|
pktin = sftp_wait_for_reply(req);
|
|
|
|
result = fxp_stat_recv(pktin, req, &attrs);
|
2004-12-16 17:35:20 +00:00
|
|
|
|
2004-12-30 13:51:37 +00:00
|
|
|
if (result &&
|
|
|
|
(attrs.flags & SSH_FILEXFER_ATTR_PERMISSIONS) &&
|
|
|
|
(attrs.permissions & 0040000)) {
|
2004-12-16 16:37:37 +00:00
|
|
|
|
|
|
|
struct fxp_handle *dirhandle;
|
|
|
|
int nnames, namesize;
|
|
|
|
struct fxp_name **ournames;
|
|
|
|
struct fxp_names *names;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* First, attempt to create the destination directory,
|
2004-12-30 13:51:37 +00:00
|
|
|
* unless it already exists.
|
2004-12-16 16:37:37 +00:00
|
|
|
*/
|
2004-12-30 13:51:37 +00:00
|
|
|
if (file_type(outfname) != FILE_TYPE_DIRECTORY &&
|
2004-12-16 16:37:37 +00:00
|
|
|
!create_directory(outfname)) {
|
|
|
|
printf("%s: Cannot create directory\n", outfname);
|
|
|
|
return 0;
|
|
|
|
}
|
2001-02-23 18:21:44 +00:00
|
|
|
|
2004-12-16 16:37:37 +00:00
|
|
|
/*
|
|
|
|
* Now get the list of filenames in the remote
|
|
|
|
* directory.
|
|
|
|
*/
|
Clean up handling of the return value from sftp_find_request. In many
places we simply enforce by assertion that it will match the request
we sent out a moment ago: in fact it can also return NULL, so it makes
more sense to report a proper error message if it doesn't return the
expected value, and while we're at it, have that error message
whatever message was helpfully left in fxp_error() by
sftp_find_request when it failed.
To do this, I've written a centralised function in psftp.c called
sftp_wait_for_reply, which is handed a request that's just been sent
out and deals with the mechanics of waiting for its reply, returning
the reply when it arrives, and aborting with a sensible error if
anything else arrives instead. The numerous sites in psftp.c which
called sftp_find_request have all been rewritten to do this instead,
and as a side effect they now look more sensible. The only other uses
of sftp_find_request were in xfer_*load_gotpkt, which had to be
tweaked in its own way.
While I'm here, also fix memory management in sftp_find_request, which
was freeing its input packet on some but not all error return paths.
[originally from svn r9894]
2013-07-06 20:43:21 +00:00
|
|
|
req = fxp_opendir_send(fname);
|
|
|
|
pktin = sftp_wait_for_reply(req);
|
|
|
|
dirhandle = fxp_opendir_recv(pktin, req);
|
2004-12-16 16:37:37 +00:00
|
|
|
|
|
|
|
if (!dirhandle) {
|
|
|
|
printf("%s: unable to open directory: %s\n",
|
|
|
|
fname, fxp_error());
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
nnames = namesize = 0;
|
|
|
|
ournames = NULL;
|
|
|
|
while (1) {
|
|
|
|
int i;
|
|
|
|
|
Clean up handling of the return value from sftp_find_request. In many
places we simply enforce by assertion that it will match the request
we sent out a moment ago: in fact it can also return NULL, so it makes
more sense to report a proper error message if it doesn't return the
expected value, and while we're at it, have that error message
whatever message was helpfully left in fxp_error() by
sftp_find_request when it failed.
To do this, I've written a centralised function in psftp.c called
sftp_wait_for_reply, which is handed a request that's just been sent
out and deals with the mechanics of waiting for its reply, returning
the reply when it arrives, and aborting with a sensible error if
anything else arrives instead. The numerous sites in psftp.c which
called sftp_find_request have all been rewritten to do this instead,
and as a side effect they now look more sensible. The only other uses
of sftp_find_request were in xfer_*load_gotpkt, which had to be
tweaked in its own way.
While I'm here, also fix memory management in sftp_find_request, which
was freeing its input packet on some but not all error return paths.
[originally from svn r9894]
2013-07-06 20:43:21 +00:00
|
|
|
req = fxp_readdir_send(dirhandle);
|
|
|
|
pktin = sftp_wait_for_reply(req);
|
|
|
|
names = fxp_readdir_recv(pktin, req);
|
2004-12-16 16:37:37 +00:00
|
|
|
|
|
|
|
if (names == NULL) {
|
|
|
|
if (fxp_error_type() == SSH_FX_EOF)
|
|
|
|
break;
|
|
|
|
printf("%s: reading directory: %s\n", fname, fxp_error());
|
2013-07-11 17:24:44 +00:00
|
|
|
|
|
|
|
req = fxp_close_send(dirhandle);
|
|
|
|
pktin = sftp_wait_for_reply(req);
|
|
|
|
fxp_close_recv(pktin, req);
|
|
|
|
|
2004-12-16 16:37:37 +00:00
|
|
|
sfree(ournames);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (names->nnames == 0) {
|
|
|
|
fxp_free_names(names);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (nnames + names->nnames >= namesize) {
|
|
|
|
namesize += names->nnames + 128;
|
|
|
|
ournames = sresize(ournames, namesize, struct fxp_name *);
|
|
|
|
}
|
|
|
|
for (i = 0; i < names->nnames; i++)
|
2004-12-16 19:36:47 +00:00
|
|
|
if (strcmp(names->names[i].filename, ".") &&
|
2004-12-30 13:51:37 +00:00
|
|
|
strcmp(names->names[i].filename, "..")) {
|
2004-12-16 19:36:47 +00:00
|
|
|
if (!vet_filename(names->names[i].filename)) {
|
|
|
|
printf("ignoring potentially dangerous server-"
|
|
|
|
"supplied filename '%s'\n",
|
|
|
|
names->names[i].filename);
|
|
|
|
} else {
|
|
|
|
ournames[nnames++] =
|
|
|
|
fxp_dup_name(&names->names[i]);
|
|
|
|
}
|
|
|
|
}
|
2004-12-16 16:37:37 +00:00
|
|
|
fxp_free_names(names);
|
|
|
|
}
|
Clean up handling of the return value from sftp_find_request. In many
places we simply enforce by assertion that it will match the request
we sent out a moment ago: in fact it can also return NULL, so it makes
more sense to report a proper error message if it doesn't return the
expected value, and while we're at it, have that error message
whatever message was helpfully left in fxp_error() by
sftp_find_request when it failed.
To do this, I've written a centralised function in psftp.c called
sftp_wait_for_reply, which is handed a request that's just been sent
out and deals with the mechanics of waiting for its reply, returning
the reply when it arrives, and aborting with a sensible error if
anything else arrives instead. The numerous sites in psftp.c which
called sftp_find_request have all been rewritten to do this instead,
and as a side effect they now look more sensible. The only other uses
of sftp_find_request were in xfer_*load_gotpkt, which had to be
tweaked in its own way.
While I'm here, also fix memory management in sftp_find_request, which
was freeing its input packet on some but not all error return paths.
[originally from svn r9894]
2013-07-06 20:43:21 +00:00
|
|
|
req = fxp_close_send(dirhandle);
|
|
|
|
pktin = sftp_wait_for_reply(req);
|
|
|
|
fxp_close_recv(pktin, req);
|
2004-12-16 16:37:37 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Sort the names into a clear order. This ought to
|
|
|
|
* make things more predictable when we're doing a
|
|
|
|
* reget of the same directory, just in case two
|
|
|
|
* readdirs on the same remote directory return a
|
|
|
|
* different order.
|
|
|
|
*/
|
2013-07-11 17:24:39 +00:00
|
|
|
if (nnames > 0)
|
|
|
|
qsort(ournames, nnames, sizeof(*ournames), sftp_name_compare);
|
2004-12-16 16:37:37 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If we're in restart mode, find the last filename on
|
|
|
|
* this list that already exists. We may have to do a
|
|
|
|
* reget on _that_ file, but shouldn't have to do
|
|
|
|
* anything on the previous files.
|
|
|
|
*
|
|
|
|
* If none of them exists, of course, we start at 0.
|
|
|
|
*/
|
|
|
|
i = 0;
|
2007-04-02 08:44:00 +00:00
|
|
|
if (restart) {
|
|
|
|
while (i < nnames) {
|
|
|
|
char *nextoutfname;
|
|
|
|
int ret;
|
2013-07-11 17:24:10 +00:00
|
|
|
nextoutfname = dir_file_cat(outfname,
|
|
|
|
ournames[i]->filename);
|
2007-04-02 08:44:00 +00:00
|
|
|
ret = (file_type(nextoutfname) == FILE_TYPE_NONEXISTENT);
|
|
|
|
sfree(nextoutfname);
|
|
|
|
if (ret)
|
|
|
|
break;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
if (i > 0)
|
|
|
|
i--;
|
|
|
|
}
|
2004-12-16 16:37:37 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Now we're ready to recurse. Starting at ournames[i]
|
|
|
|
* and continuing on to the end of the list, we
|
|
|
|
* construct a new source and target file name, and
|
|
|
|
* call sftp_get_file again.
|
|
|
|
*/
|
|
|
|
for (; i < nnames; i++) {
|
|
|
|
char *nextfname, *nextoutfname;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
nextfname = dupcat(fname, "/", ournames[i]->filename, NULL);
|
2013-07-11 17:24:10 +00:00
|
|
|
nextoutfname = dir_file_cat(outfname, ournames[i]->filename);
|
2004-12-30 13:51:37 +00:00
|
|
|
ret = sftp_get_file(nextfname, nextoutfname, recurse, restart);
|
2004-12-16 16:37:37 +00:00
|
|
|
restart = FALSE; /* after first partial file, do full */
|
|
|
|
sfree(nextoutfname);
|
|
|
|
sfree(nextfname);
|
|
|
|
if (!ret) {
|
|
|
|
for (i = 0; i < nnames; i++) {
|
|
|
|
fxp_free_name(ournames[i]);
|
|
|
|
}
|
|
|
|
sfree(ournames);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Done this recursion level. Free everything.
|
|
|
|
*/
|
|
|
|
for (i = 0; i < nnames; i++) {
|
|
|
|
fxp_free_name(ournames[i]);
|
|
|
|
}
|
|
|
|
sfree(ournames);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
2001-02-23 18:21:44 +00:00
|
|
|
}
|
|
|
|
|
Clean up handling of the return value from sftp_find_request. In many
places we simply enforce by assertion that it will match the request
we sent out a moment ago: in fact it can also return NULL, so it makes
more sense to report a proper error message if it doesn't return the
expected value, and while we're at it, have that error message
whatever message was helpfully left in fxp_error() by
sftp_find_request when it failed.
To do this, I've written a centralised function in psftp.c called
sftp_wait_for_reply, which is handed a request that's just been sent
out and deals with the mechanics of waiting for its reply, returning
the reply when it arrives, and aborting with a sensible error if
anything else arrives instead. The numerous sites in psftp.c which
called sftp_find_request have all been rewritten to do this instead,
and as a side effect they now look more sensible. The only other uses
of sftp_find_request were in xfer_*load_gotpkt, which had to be
tweaked in its own way.
While I'm here, also fix memory management in sftp_find_request, which
was freeing its input packet on some but not all error return paths.
[originally from svn r9894]
2013-07-06 20:43:21 +00:00
|
|
|
req = fxp_stat_send(fname);
|
|
|
|
pktin = sftp_wait_for_reply(req);
|
|
|
|
if (!fxp_stat_recv(pktin, req, &attrs))
|
2011-08-11 17:59:30 +00:00
|
|
|
attrs.flags = 0;
|
|
|
|
|
Clean up handling of the return value from sftp_find_request. In many
places we simply enforce by assertion that it will match the request
we sent out a moment ago: in fact it can also return NULL, so it makes
more sense to report a proper error message if it doesn't return the
expected value, and while we're at it, have that error message
whatever message was helpfully left in fxp_error() by
sftp_find_request when it failed.
To do this, I've written a centralised function in psftp.c called
sftp_wait_for_reply, which is handed a request that's just been sent
out and deals with the mechanics of waiting for its reply, returning
the reply when it arrives, and aborting with a sensible error if
anything else arrives instead. The numerous sites in psftp.c which
called sftp_find_request have all been rewritten to do this instead,
and as a side effect they now look more sensible. The only other uses
of sftp_find_request were in xfer_*load_gotpkt, which had to be
tweaked in its own way.
While I'm here, also fix memory management in sftp_find_request, which
was freeing its input packet on some but not all error return paths.
[originally from svn r9894]
2013-07-06 20:43:21 +00:00
|
|
|
req = fxp_open_send(fname, SSH_FXF_READ, NULL);
|
|
|
|
pktin = sftp_wait_for_reply(req);
|
|
|
|
fh = fxp_open_recv(pktin, req);
|
2003-06-29 14:26:09 +00:00
|
|
|
|
2001-02-23 18:21:44 +00:00
|
|
|
if (!fh) {
|
2006-04-13 21:18:09 +00:00
|
|
|
printf("%s: open for read: %s\n", fname, fxp_error());
|
2001-02-23 18:21:44 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2001-08-26 11:35:11 +00:00
|
|
|
|
|
|
|
if (restart) {
|
2006-08-12 15:20:19 +00:00
|
|
|
file = open_existing_wfile(outfname, NULL);
|
2001-08-26 11:35:11 +00:00
|
|
|
} else {
|
Add an SFTP server to the SSH server code.
Unlike the traditional Unix SSH server organisation, the SFTP server
is built into the same process as all the rest of the code. sesschan.c
spots a subsystem request for "sftp", and responds to it by
instantiating an SftpServer object and swapping out its own vtable for
one that talks to it.
(I rather like the idea of an object swapping its own vtable for a
different one in the middle of its lifetime! This is one of those
tricks that would be absurdly hard to implement in a 'proper' OO
language, but when you're doing vtables by hand in C, it's no more
difficult than any other piece of ordinary pointer manipulation. As
long as the methods in both vtables expect the same physical structure
layout, it doesn't cause a problem.)
The SftpServer object doesn't deal directly with SFTP packet formats;
it implements the SFTP server logic in a more abstract way, by having
a vtable method for each SFTP request type with an appropriate
parameter list. It sends its replies by calling methods in another
vtable called SftpReplyBuilder, which in the normal case will write an
SFTP reply packet to send back to the client. So SftpServer can focus
more or less completely on the details of a particular filesystem API
- and hence, the implementation I've got lives in the unix source
directory, and works directly with file descriptors and struct stat
and the like.
(One purpose of this abstraction layer is that I may well want to
write a second dummy implementation, for test-suite purposes, with
completely controllable behaviour, and now I have a handy place to
plug it in in place of the live filesystem.)
In between sesschan's parsing of the byte stream into SFTP packets and
the SftpServer object, there's a layer in the new file sftpserver.c
which does the actual packet decoding and encoding: each request
packet is passed to that, which pulls the fields out of the request
packet and calls the appropriate method of SftpServer. It also
provides the default SftpReplyBuilder which makes the output packet.
I've moved some code out of the previous SFTP client implementation -
basic packet construction code, and in particular the BinarySink/
BinarySource marshalling fuinction for fxp_attrs - into sftpcommon.c,
so that the two directions can share as much as possible.
2018-10-20 21:10:32 +00:00
|
|
|
file = open_new_file(outfname, GET_PERMISSIONS(attrs, -1));
|
2001-08-26 11:35:11 +00:00
|
|
|
}
|
|
|
|
|
2006-08-12 15:20:19 +00:00
|
|
|
if (!file) {
|
2001-02-23 18:21:44 +00:00
|
|
|
printf("local: unable to open %s\n", outfname);
|
2003-06-29 14:26:09 +00:00
|
|
|
|
Clean up handling of the return value from sftp_find_request. In many
places we simply enforce by assertion that it will match the request
we sent out a moment ago: in fact it can also return NULL, so it makes
more sense to report a proper error message if it doesn't return the
expected value, and while we're at it, have that error message
whatever message was helpfully left in fxp_error() by
sftp_find_request when it failed.
To do this, I've written a centralised function in psftp.c called
sftp_wait_for_reply, which is handed a request that's just been sent
out and deals with the mechanics of waiting for its reply, returning
the reply when it arrives, and aborting with a sensible error if
anything else arrives instead. The numerous sites in psftp.c which
called sftp_find_request have all been rewritten to do this instead,
and as a side effect they now look more sensible. The only other uses
of sftp_find_request were in xfer_*load_gotpkt, which had to be
tweaked in its own way.
While I'm here, also fix memory management in sftp_find_request, which
was freeing its input packet on some but not all error return paths.
[originally from svn r9894]
2013-07-06 20:43:21 +00:00
|
|
|
req = fxp_close_send(fh);
|
|
|
|
pktin = sftp_wait_for_reply(req);
|
|
|
|
fxp_close_recv(pktin, req);
|
2003-06-29 14:26:09 +00:00
|
|
|
|
2001-02-23 18:21:44 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2001-08-26 11:35:11 +00:00
|
|
|
if (restart) {
|
2018-10-26 22:08:58 +00:00
|
|
|
if (seek_file(file, 0, FROM_END) == -1) {
|
2008-07-06 12:11:34 +00:00
|
|
|
close_wfile(file);
|
2006-08-12 15:20:19 +00:00
|
|
|
printf("reget: cannot restart %s - file too large\n",
|
|
|
|
outfname);
|
Clean up handling of the return value from sftp_find_request. In many
places we simply enforce by assertion that it will match the request
we sent out a moment ago: in fact it can also return NULL, so it makes
more sense to report a proper error message if it doesn't return the
expected value, and while we're at it, have that error message
whatever message was helpfully left in fxp_error() by
sftp_find_request when it failed.
To do this, I've written a centralised function in psftp.c called
sftp_wait_for_reply, which is handed a request that's just been sent
out and deals with the mechanics of waiting for its reply, returning
the reply when it arrives, and aborting with a sensible error if
anything else arrives instead. The numerous sites in psftp.c which
called sftp_find_request have all been rewritten to do this instead,
and as a side effect they now look more sensible. The only other uses
of sftp_find_request were in xfer_*load_gotpkt, which had to be
tweaked in its own way.
While I'm here, also fix memory management in sftp_find_request, which
was freeing its input packet on some but not all error return paths.
[originally from svn r9894]
2013-07-06 20:43:21 +00:00
|
|
|
req = fxp_close_send(fh);
|
|
|
|
pktin = sftp_wait_for_reply(req);
|
|
|
|
fxp_close_recv(pktin, req);
|
2006-08-12 15:20:19 +00:00
|
|
|
|
2008-07-06 12:11:34 +00:00
|
|
|
return 0;
|
2006-08-12 15:20:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
offset = get_file_posn(file);
|
2018-10-26 22:08:58 +00:00
|
|
|
printf("reget: restarting at file position %"PRIu64"\n", offset);
|
2001-08-26 11:35:11 +00:00
|
|
|
} else {
|
2018-10-26 22:08:58 +00:00
|
|
|
offset = 0;
|
2001-08-26 11:35:11 +00:00
|
|
|
}
|
2001-02-23 18:21:44 +00:00
|
|
|
|
2001-08-26 11:35:11 +00:00
|
|
|
printf("remote:%s => local:%s\n", fname, outfname);
|
2001-02-23 18:21:44 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* FIXME: we can use FXP_FSTAT here to get the file size, and
|
|
|
|
* thus put up a progress bar.
|
|
|
|
*/
|
2001-12-13 19:26:51 +00:00
|
|
|
ret = 1;
|
2003-09-27 17:52:34 +00:00
|
|
|
xfer = xfer_download_init(fh, offset);
|
2003-09-28 14:24:01 +00:00
|
|
|
while (!xfer_done(xfer)) {
|
2003-09-27 17:52:34 +00:00
|
|
|
void *vbuf;
|
2016-12-28 13:59:49 +00:00
|
|
|
int len;
|
2001-02-23 18:21:44 +00:00
|
|
|
int wpos, wlen;
|
|
|
|
|
2003-09-27 17:52:34 +00:00
|
|
|
xfer_download_queue(xfer);
|
|
|
|
pktin = sftp_recv();
|
|
|
|
ret = xfer_download_gotpkt(xfer, pktin);
|
Clean up handling of the return value from sftp_find_request. In many
places we simply enforce by assertion that it will match the request
we sent out a moment ago: in fact it can also return NULL, so it makes
more sense to report a proper error message if it doesn't return the
expected value, and while we're at it, have that error message
whatever message was helpfully left in fxp_error() by
sftp_find_request when it failed.
To do this, I've written a centralised function in psftp.c called
sftp_wait_for_reply, which is handed a request that's just been sent
out and deals with the mechanics of waiting for its reply, returning
the reply when it arrives, and aborting with a sensible error if
anything else arrives instead. The numerous sites in psftp.c which
called sftp_find_request have all been rewritten to do this instead,
and as a side effect they now look more sensible. The only other uses
of sftp_find_request were in xfer_*load_gotpkt, which had to be
tweaked in its own way.
While I'm here, also fix memory management in sftp_find_request, which
was freeing its input packet on some but not all error return paths.
[originally from svn r9894]
2013-07-06 20:43:21 +00:00
|
|
|
if (ret <= 0) {
|
2004-12-17 13:39:41 +00:00
|
|
|
if (!shown_err) {
|
|
|
|
printf("error while reading: %s\n", fxp_error());
|
|
|
|
shown_err = TRUE;
|
|
|
|
}
|
2013-07-11 17:24:53 +00:00
|
|
|
if (ret == INT_MIN) /* pktin not even freed */
|
|
|
|
sfree(pktin);
|
2003-09-27 17:52:34 +00:00
|
|
|
ret = 0;
|
2001-02-23 18:21:44 +00:00
|
|
|
}
|
2001-05-06 14:35:20 +00:00
|
|
|
|
2003-09-27 17:52:34 +00:00
|
|
|
while (xfer_download_data(xfer, &vbuf, &len)) {
|
|
|
|
unsigned char *buf = (unsigned char *)vbuf;
|
|
|
|
|
|
|
|
wpos = 0;
|
|
|
|
while (wpos < len) {
|
2006-08-12 15:20:19 +00:00
|
|
|
wlen = write_to_file(file, buf + wpos, len - wpos);
|
2003-09-27 17:52:34 +00:00
|
|
|
if (wlen <= 0) {
|
|
|
|
printf("error while writing local file\n");
|
|
|
|
ret = 0;
|
|
|
|
xfer_set_error(xfer);
|
2007-04-10 21:46:44 +00:00
|
|
|
break;
|
2003-09-27 17:52:34 +00:00
|
|
|
}
|
|
|
|
wpos += wlen;
|
|
|
|
}
|
|
|
|
if (wpos < len) { /* we had an error */
|
2001-12-13 19:26:51 +00:00
|
|
|
ret = 0;
|
2003-09-27 17:52:34 +00:00
|
|
|
xfer_set_error(xfer);
|
2001-02-23 18:21:44 +00:00
|
|
|
}
|
2003-09-29 15:39:36 +00:00
|
|
|
|
|
|
|
sfree(vbuf);
|
2001-12-13 19:26:51 +00:00
|
|
|
}
|
2001-02-23 18:21:44 +00:00
|
|
|
}
|
|
|
|
|
2003-09-27 17:52:34 +00:00
|
|
|
xfer_cleanup(xfer);
|
|
|
|
|
2006-08-12 15:20:19 +00:00
|
|
|
close_wfile(file);
|
2003-06-29 14:26:09 +00:00
|
|
|
|
Clean up handling of the return value from sftp_find_request. In many
places we simply enforce by assertion that it will match the request
we sent out a moment ago: in fact it can also return NULL, so it makes
more sense to report a proper error message if it doesn't return the
expected value, and while we're at it, have that error message
whatever message was helpfully left in fxp_error() by
sftp_find_request when it failed.
To do this, I've written a centralised function in psftp.c called
sftp_wait_for_reply, which is handed a request that's just been sent
out and deals with the mechanics of waiting for its reply, returning
the reply when it arrives, and aborting with a sensible error if
anything else arrives instead. The numerous sites in psftp.c which
called sftp_find_request have all been rewritten to do this instead,
and as a side effect they now look more sensible. The only other uses
of sftp_find_request were in xfer_*load_gotpkt, which had to be
tweaked in its own way.
While I'm here, also fix memory management in sftp_find_request, which
was freeing its input packet on some but not all error return paths.
[originally from svn r9894]
2013-07-06 20:43:21 +00:00
|
|
|
req = fxp_close_send(fh);
|
|
|
|
pktin = sftp_wait_for_reply(req);
|
|
|
|
fxp_close_recv(pktin, req);
|
2003-06-29 14:26:09 +00:00
|
|
|
|
2001-12-13 19:26:51 +00:00
|
|
|
return ret;
|
2001-02-23 18:21:44 +00:00
|
|
|
}
|
|
|
|
|
2004-12-30 13:51:37 +00:00
|
|
|
int sftp_put_file(char *fname, char *outfname, int recurse, int restart)
|
2001-05-06 14:35:20 +00:00
|
|
|
{
|
2001-02-23 18:21:44 +00:00
|
|
|
struct fxp_handle *fh;
|
2003-09-28 14:24:01 +00:00
|
|
|
struct fxp_xfer *xfer;
|
2003-06-29 14:26:09 +00:00
|
|
|
struct sftp_packet *pktin;
|
Clean up handling of the return value from sftp_find_request. In many
places we simply enforce by assertion that it will match the request
we sent out a moment ago: in fact it can also return NULL, so it makes
more sense to report a proper error message if it doesn't return the
expected value, and while we're at it, have that error message
whatever message was helpfully left in fxp_error() by
sftp_find_request when it failed.
To do this, I've written a centralised function in psftp.c called
sftp_wait_for_reply, which is handed a request that's just been sent
out and deals with the mechanics of waiting for its reply, returning
the reply when it arrives, and aborting with a sensible error if
anything else arrives instead. The numerous sites in psftp.c which
called sftp_find_request have all been rewritten to do this instead,
and as a side effect they now look more sensible. The only other uses
of sftp_find_request were in xfer_*load_gotpkt, which had to be
tweaked in its own way.
While I'm here, also fix memory management in sftp_find_request, which
was freeing its input packet on some but not all error return paths.
[originally from svn r9894]
2013-07-06 20:43:21 +00:00
|
|
|
struct sftp_request *req;
|
2018-10-26 22:08:58 +00:00
|
|
|
uint64_t offset;
|
2006-08-12 15:20:19 +00:00
|
|
|
RFile *file;
|
2016-12-29 11:25:34 +00:00
|
|
|
int err = 0, eof;
|
2011-08-11 17:59:30 +00:00
|
|
|
struct fxp_attrs attrs;
|
|
|
|
long permissions;
|
2001-02-23 18:21:44 +00:00
|
|
|
|
2004-12-16 16:37:37 +00:00
|
|
|
/*
|
|
|
|
* In recursive mode, see if we're dealing with a directory.
|
|
|
|
* (If we're not in recursive mode, we need not even check: the
|
|
|
|
* subsequent fopen will return an error message.)
|
|
|
|
*/
|
2004-12-30 13:51:37 +00:00
|
|
|
if (recurse && file_type(fname) == FILE_TYPE_DIRECTORY) {
|
2004-12-16 16:37:37 +00:00
|
|
|
int result;
|
|
|
|
int nnames, namesize;
|
|
|
|
char *name, **ournames;
|
|
|
|
DirHandle *dh;
|
|
|
|
int i;
|
2001-02-23 18:21:44 +00:00
|
|
|
|
2004-12-30 13:51:37 +00:00
|
|
|
/*
|
|
|
|
* First, attempt to create the destination directory,
|
|
|
|
* unless it already exists.
|
|
|
|
*/
|
Clean up handling of the return value from sftp_find_request. In many
places we simply enforce by assertion that it will match the request
we sent out a moment ago: in fact it can also return NULL, so it makes
more sense to report a proper error message if it doesn't return the
expected value, and while we're at it, have that error message
whatever message was helpfully left in fxp_error() by
sftp_find_request when it failed.
To do this, I've written a centralised function in psftp.c called
sftp_wait_for_reply, which is handed a request that's just been sent
out and deals with the mechanics of waiting for its reply, returning
the reply when it arrives, and aborting with a sensible error if
anything else arrives instead. The numerous sites in psftp.c which
called sftp_find_request have all been rewritten to do this instead,
and as a side effect they now look more sensible. The only other uses
of sftp_find_request were in xfer_*load_gotpkt, which had to be
tweaked in its own way.
While I'm here, also fix memory management in sftp_find_request, which
was freeing its input packet on some but not all error return paths.
[originally from svn r9894]
2013-07-06 20:43:21 +00:00
|
|
|
req = fxp_stat_send(outfname);
|
|
|
|
pktin = sftp_wait_for_reply(req);
|
|
|
|
result = fxp_stat_recv(pktin, req, &attrs);
|
2004-12-30 13:51:37 +00:00
|
|
|
if (!result ||
|
|
|
|
!(attrs.flags & SSH_FILEXFER_ATTR_PERMISSIONS) ||
|
|
|
|
!(attrs.permissions & 0040000)) {
|
2018-10-06 10:52:04 +00:00
|
|
|
req = fxp_mkdir_send(outfname, NULL);
|
Clean up handling of the return value from sftp_find_request. In many
places we simply enforce by assertion that it will match the request
we sent out a moment ago: in fact it can also return NULL, so it makes
more sense to report a proper error message if it doesn't return the
expected value, and while we're at it, have that error message
whatever message was helpfully left in fxp_error() by
sftp_find_request when it failed.
To do this, I've written a centralised function in psftp.c called
sftp_wait_for_reply, which is handed a request that's just been sent
out and deals with the mechanics of waiting for its reply, returning
the reply when it arrives, and aborting with a sensible error if
anything else arrives instead. The numerous sites in psftp.c which
called sftp_find_request have all been rewritten to do this instead,
and as a side effect they now look more sensible. The only other uses
of sftp_find_request were in xfer_*load_gotpkt, which had to be
tweaked in its own way.
While I'm here, also fix memory management in sftp_find_request, which
was freeing its input packet on some but not all error return paths.
[originally from svn r9894]
2013-07-06 20:43:21 +00:00
|
|
|
pktin = sftp_wait_for_reply(req);
|
|
|
|
result = fxp_mkdir_recv(pktin, req);
|
2004-12-16 16:37:37 +00:00
|
|
|
|
2004-12-30 13:51:37 +00:00
|
|
|
if (!result) {
|
|
|
|
printf("%s: create directory: %s\n",
|
|
|
|
outfname, fxp_error());
|
|
|
|
return 0;
|
2004-12-16 16:37:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Now get the list of filenames in the local directory.
|
|
|
|
*/
|
|
|
|
nnames = namesize = 0;
|
|
|
|
ournames = NULL;
|
2004-12-16 17:35:20 +00:00
|
|
|
|
2004-12-30 13:51:37 +00:00
|
|
|
dh = open_directory(fname);
|
|
|
|
if (!dh) {
|
|
|
|
printf("%s: unable to open directory\n", fname);
|
|
|
|
return 0;
|
2004-12-16 17:35:20 +00:00
|
|
|
}
|
2004-12-30 13:51:37 +00:00
|
|
|
while ((name = read_filename(dh)) != NULL) {
|
|
|
|
if (nnames >= namesize) {
|
|
|
|
namesize += 128;
|
|
|
|
ournames = sresize(ournames, namesize, char *);
|
|
|
|
}
|
|
|
|
ournames[nnames++] = name;
|
2004-12-16 16:37:37 +00:00
|
|
|
}
|
2004-12-30 13:51:37 +00:00
|
|
|
close_directory(dh);
|
2004-12-16 16:37:37 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Sort the names into a clear order. This ought to make
|
|
|
|
* things more predictable when we're doing a reput of the
|
|
|
|
* same directory, just in case two readdirs on the same
|
|
|
|
* local directory return a different order.
|
|
|
|
*/
|
2013-07-11 17:24:39 +00:00
|
|
|
if (nnames > 0)
|
|
|
|
qsort(ournames, nnames, sizeof(*ournames), bare_name_compare);
|
2004-12-16 16:37:37 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If we're in restart mode, find the last filename on this
|
|
|
|
* list that already exists. We may have to do a reput on
|
|
|
|
* _that_ file, but shouldn't have to do anything on the
|
|
|
|
* previous files.
|
|
|
|
*
|
|
|
|
* If none of them exists, of course, we start at 0.
|
|
|
|
*/
|
|
|
|
i = 0;
|
2007-04-02 08:44:00 +00:00
|
|
|
if (restart) {
|
|
|
|
while (i < nnames) {
|
|
|
|
char *nextoutfname;
|
|
|
|
nextoutfname = dupcat(outfname, "/", ournames[i], NULL);
|
Clean up handling of the return value from sftp_find_request. In many
places we simply enforce by assertion that it will match the request
we sent out a moment ago: in fact it can also return NULL, so it makes
more sense to report a proper error message if it doesn't return the
expected value, and while we're at it, have that error message
whatever message was helpfully left in fxp_error() by
sftp_find_request when it failed.
To do this, I've written a centralised function in psftp.c called
sftp_wait_for_reply, which is handed a request that's just been sent
out and deals with the mechanics of waiting for its reply, returning
the reply when it arrives, and aborting with a sensible error if
anything else arrives instead. The numerous sites in psftp.c which
called sftp_find_request have all been rewritten to do this instead,
and as a side effect they now look more sensible. The only other uses
of sftp_find_request were in xfer_*load_gotpkt, which had to be
tweaked in its own way.
While I'm here, also fix memory management in sftp_find_request, which
was freeing its input packet on some but not all error return paths.
[originally from svn r9894]
2013-07-06 20:43:21 +00:00
|
|
|
req = fxp_stat_send(nextoutfname);
|
|
|
|
pktin = sftp_wait_for_reply(req);
|
|
|
|
result = fxp_stat_recv(pktin, req, &attrs);
|
2007-04-02 08:44:00 +00:00
|
|
|
sfree(nextoutfname);
|
|
|
|
if (!result)
|
|
|
|
break;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
if (i > 0)
|
|
|
|
i--;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Now we're ready to recurse. Starting at ournames[i]
|
2004-12-16 16:37:37 +00:00
|
|
|
* and continuing on to the end of the list, we
|
|
|
|
* construct a new source and target file name, and
|
|
|
|
* call sftp_put_file again.
|
|
|
|
*/
|
|
|
|
for (; i < nnames; i++) {
|
|
|
|
char *nextfname, *nextoutfname;
|
|
|
|
int ret;
|
|
|
|
|
2013-07-11 17:24:10 +00:00
|
|
|
nextfname = dir_file_cat(fname, ournames[i]);
|
2004-12-16 16:37:37 +00:00
|
|
|
nextoutfname = dupcat(outfname, "/", ournames[i], NULL);
|
2004-12-30 13:51:37 +00:00
|
|
|
ret = sftp_put_file(nextfname, nextoutfname, recurse, restart);
|
2004-12-16 16:37:37 +00:00
|
|
|
restart = FALSE; /* after first partial file, do full */
|
|
|
|
sfree(nextoutfname);
|
|
|
|
sfree(nextfname);
|
|
|
|
if (!ret) {
|
|
|
|
for (i = 0; i < nnames; i++) {
|
|
|
|
sfree(ournames[i]);
|
|
|
|
}
|
|
|
|
sfree(ournames);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Done this recursion level. Free everything.
|
|
|
|
*/
|
|
|
|
for (i = 0; i < nnames; i++) {
|
|
|
|
sfree(ournames[i]);
|
|
|
|
}
|
|
|
|
sfree(ournames);
|
|
|
|
|
|
|
|
return 1;
|
2001-02-23 18:21:44 +00:00
|
|
|
}
|
|
|
|
|
2011-08-11 17:59:30 +00:00
|
|
|
file = open_existing_file(fname, NULL, NULL, NULL, &permissions);
|
2006-08-12 15:20:19 +00:00
|
|
|
if (!file) {
|
2001-02-23 18:21:44 +00:00
|
|
|
printf("local: unable to open %s\n", fname);
|
|
|
|
return 0;
|
|
|
|
}
|
2011-08-11 17:59:30 +00:00
|
|
|
attrs.flags = 0;
|
|
|
|
PUT_PERMISSIONS(attrs, permissions);
|
2001-08-26 11:35:11 +00:00
|
|
|
if (restart) {
|
Clean up handling of the return value from sftp_find_request. In many
places we simply enforce by assertion that it will match the request
we sent out a moment ago: in fact it can also return NULL, so it makes
more sense to report a proper error message if it doesn't return the
expected value, and while we're at it, have that error message
whatever message was helpfully left in fxp_error() by
sftp_find_request when it failed.
To do this, I've written a centralised function in psftp.c called
sftp_wait_for_reply, which is handed a request that's just been sent
out and deals with the mechanics of waiting for its reply, returning
the reply when it arrives, and aborting with a sensible error if
anything else arrives instead. The numerous sites in psftp.c which
called sftp_find_request have all been rewritten to do this instead,
and as a side effect they now look more sensible. The only other uses
of sftp_find_request were in xfer_*load_gotpkt, which had to be
tweaked in its own way.
While I'm here, also fix memory management in sftp_find_request, which
was freeing its input packet on some but not all error return paths.
[originally from svn r9894]
2013-07-06 20:43:21 +00:00
|
|
|
req = fxp_open_send(outfname, SSH_FXF_WRITE, &attrs);
|
2001-08-26 11:35:11 +00:00
|
|
|
} else {
|
Clean up handling of the return value from sftp_find_request. In many
places we simply enforce by assertion that it will match the request
we sent out a moment ago: in fact it can also return NULL, so it makes
more sense to report a proper error message if it doesn't return the
expected value, and while we're at it, have that error message
whatever message was helpfully left in fxp_error() by
sftp_find_request when it failed.
To do this, I've written a centralised function in psftp.c called
sftp_wait_for_reply, which is handed a request that's just been sent
out and deals with the mechanics of waiting for its reply, returning
the reply when it arrives, and aborting with a sensible error if
anything else arrives instead. The numerous sites in psftp.c which
called sftp_find_request have all been rewritten to do this instead,
and as a side effect they now look more sensible. The only other uses
of sftp_find_request were in xfer_*load_gotpkt, which had to be
tweaked in its own way.
While I'm here, also fix memory management in sftp_find_request, which
was freeing its input packet on some but not all error return paths.
[originally from svn r9894]
2013-07-06 20:43:21 +00:00
|
|
|
req = fxp_open_send(outfname,
|
|
|
|
SSH_FXF_WRITE | SSH_FXF_CREAT | SSH_FXF_TRUNC,
|
|
|
|
&attrs);
|
2001-08-26 11:35:11 +00:00
|
|
|
}
|
Clean up handling of the return value from sftp_find_request. In many
places we simply enforce by assertion that it will match the request
we sent out a moment ago: in fact it can also return NULL, so it makes
more sense to report a proper error message if it doesn't return the
expected value, and while we're at it, have that error message
whatever message was helpfully left in fxp_error() by
sftp_find_request when it failed.
To do this, I've written a centralised function in psftp.c called
sftp_wait_for_reply, which is handed a request that's just been sent
out and deals with the mechanics of waiting for its reply, returning
the reply when it arrives, and aborting with a sensible error if
anything else arrives instead. The numerous sites in psftp.c which
called sftp_find_request have all been rewritten to do this instead,
and as a side effect they now look more sensible. The only other uses
of sftp_find_request were in xfer_*load_gotpkt, which had to be
tweaked in its own way.
While I'm here, also fix memory management in sftp_find_request, which
was freeing its input packet on some but not all error return paths.
[originally from svn r9894]
2013-07-06 20:43:21 +00:00
|
|
|
pktin = sftp_wait_for_reply(req);
|
|
|
|
fh = fxp_open_recv(pktin, req);
|
2003-06-29 14:26:09 +00:00
|
|
|
|
2001-02-23 18:21:44 +00:00
|
|
|
if (!fh) {
|
2008-07-06 12:11:34 +00:00
|
|
|
close_rfile(file);
|
2006-04-13 21:18:09 +00:00
|
|
|
printf("%s: open for write: %s\n", outfname, fxp_error());
|
2001-02-23 18:21:44 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2001-08-26 11:35:11 +00:00
|
|
|
if (restart) {
|
|
|
|
struct fxp_attrs attrs;
|
2016-12-29 11:25:34 +00:00
|
|
|
int ret;
|
2003-06-29 14:26:09 +00:00
|
|
|
|
Clean up handling of the return value from sftp_find_request. In many
places we simply enforce by assertion that it will match the request
we sent out a moment ago: in fact it can also return NULL, so it makes
more sense to report a proper error message if it doesn't return the
expected value, and while we're at it, have that error message
whatever message was helpfully left in fxp_error() by
sftp_find_request when it failed.
To do this, I've written a centralised function in psftp.c called
sftp_wait_for_reply, which is handed a request that's just been sent
out and deals with the mechanics of waiting for its reply, returning
the reply when it arrives, and aborting with a sensible error if
anything else arrives instead. The numerous sites in psftp.c which
called sftp_find_request have all been rewritten to do this instead,
and as a side effect they now look more sensible. The only other uses
of sftp_find_request were in xfer_*load_gotpkt, which had to be
tweaked in its own way.
While I'm here, also fix memory management in sftp_find_request, which
was freeing its input packet on some but not all error return paths.
[originally from svn r9894]
2013-07-06 20:43:21 +00:00
|
|
|
req = fxp_fstat_send(fh);
|
|
|
|
pktin = sftp_wait_for_reply(req);
|
|
|
|
ret = fxp_fstat_recv(pktin, req, &attrs);
|
2003-06-29 14:26:09 +00:00
|
|
|
|
|
|
|
if (!ret) {
|
2001-08-26 11:35:11 +00:00
|
|
|
printf("read size of %s: %s\n", outfname, fxp_error());
|
2016-12-28 14:27:47 +00:00
|
|
|
err = 1;
|
2014-12-20 16:53:01 +00:00
|
|
|
goto cleanup;
|
2001-08-26 11:35:11 +00:00
|
|
|
}
|
|
|
|
if (!(attrs.flags & SSH_FILEXFER_ATTR_SIZE)) {
|
|
|
|
printf("read size of %s: size was not given\n", outfname);
|
2016-12-28 14:27:47 +00:00
|
|
|
err = 1;
|
2014-12-20 16:53:01 +00:00
|
|
|
goto cleanup;
|
2001-08-26 11:35:11 +00:00
|
|
|
}
|
|
|
|
offset = attrs.size;
|
2018-10-26 22:08:58 +00:00
|
|
|
printf("reput: restarting at file position %"PRIu64"\n", offset);
|
2006-08-12 15:20:19 +00:00
|
|
|
|
|
|
|
if (seek_file((WFile *)file, offset, FROM_START) != 0)
|
2018-10-26 22:08:58 +00:00
|
|
|
seek_file((WFile *)file, 0, FROM_END); /* *shrug* */
|
2001-08-26 11:35:11 +00:00
|
|
|
} else {
|
2018-10-26 22:08:58 +00:00
|
|
|
offset = 0;
|
2001-08-26 11:35:11 +00:00
|
|
|
}
|
2001-02-23 18:21:44 +00:00
|
|
|
|
2001-08-26 11:35:11 +00:00
|
|
|
printf("local:%s => remote:%s\n", fname, outfname);
|
2001-02-23 18:21:44 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* FIXME: we can use FXP_FSTAT here to get the file size, and
|
|
|
|
* thus put up a progress bar.
|
|
|
|
*/
|
2003-09-28 14:24:01 +00:00
|
|
|
xfer = xfer_upload_init(fh, offset);
|
2016-12-28 14:27:47 +00:00
|
|
|
eof = 0;
|
2003-09-28 14:24:01 +00:00
|
|
|
while ((!err && !eof) || !xfer_done(xfer)) {
|
2001-02-23 18:21:44 +00:00
|
|
|
char buffer[4096];
|
2003-06-29 14:26:09 +00:00
|
|
|
int len, ret;
|
2001-02-23 18:21:44 +00:00
|
|
|
|
2003-09-28 14:24:01 +00:00
|
|
|
while (xfer_upload_ready(xfer) && !err && !eof) {
|
2006-08-12 15:20:19 +00:00
|
|
|
len = read_from_file(file, buffer, sizeof(buffer));
|
2003-09-28 14:24:01 +00:00
|
|
|
if (len == -1) {
|
|
|
|
printf("error while reading local file\n");
|
|
|
|
err = 1;
|
|
|
|
} else if (len == 0) {
|
|
|
|
eof = 1;
|
|
|
|
} else {
|
|
|
|
xfer_upload_data(xfer, buffer, len);
|
|
|
|
}
|
2001-02-23 18:21:44 +00:00
|
|
|
}
|
2003-06-29 14:26:09 +00:00
|
|
|
|
2003-12-03 23:25:48 +00:00
|
|
|
if (!xfer_done(xfer)) {
|
|
|
|
pktin = sftp_recv();
|
|
|
|
ret = xfer_upload_gotpkt(xfer, pktin);
|
2013-07-11 17:24:53 +00:00
|
|
|
if (ret <= 0) {
|
|
|
|
if (ret == INT_MIN) /* pktin not even freed */
|
|
|
|
sfree(pktin);
|
|
|
|
if (!err) {
|
|
|
|
printf("error while writing: %s\n", fxp_error());
|
|
|
|
err = 1;
|
|
|
|
}
|
2003-12-03 23:25:48 +00:00
|
|
|
}
|
2001-02-23 18:21:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-09-28 14:24:01 +00:00
|
|
|
xfer_cleanup(xfer);
|
|
|
|
|
2014-12-20 16:53:01 +00:00
|
|
|
cleanup:
|
Clean up handling of the return value from sftp_find_request. In many
places we simply enforce by assertion that it will match the request
we sent out a moment ago: in fact it can also return NULL, so it makes
more sense to report a proper error message if it doesn't return the
expected value, and while we're at it, have that error message
whatever message was helpfully left in fxp_error() by
sftp_find_request when it failed.
To do this, I've written a centralised function in psftp.c called
sftp_wait_for_reply, which is handed a request that's just been sent
out and deals with the mechanics of waiting for its reply, returning
the reply when it arrives, and aborting with a sensible error if
anything else arrives instead. The numerous sites in psftp.c which
called sftp_find_request have all been rewritten to do this instead,
and as a side effect they now look more sensible. The only other uses
of sftp_find_request were in xfer_*load_gotpkt, which had to be
tweaked in its own way.
While I'm here, also fix memory management in sftp_find_request, which
was freeing its input packet on some but not all error return paths.
[originally from svn r9894]
2013-07-06 20:43:21 +00:00
|
|
|
req = fxp_close_send(fh);
|
|
|
|
pktin = sftp_wait_for_reply(req);
|
2016-12-29 11:25:34 +00:00
|
|
|
if (!fxp_close_recv(pktin, req)) {
|
2016-12-28 14:34:53 +00:00
|
|
|
if (!err) {
|
|
|
|
printf("error while closing: %s", fxp_error());
|
|
|
|
err = 1;
|
|
|
|
}
|
|
|
|
}
|
2003-06-29 14:26:09 +00:00
|
|
|
|
2006-08-12 15:20:19 +00:00
|
|
|
close_rfile(file);
|
2004-12-16 16:37:37 +00:00
|
|
|
|
2016-12-28 14:27:47 +00:00
|
|
|
return (err == 0) ? 1 : 0;
|
2004-12-16 16:37:37 +00:00
|
|
|
}
|
|
|
|
|
2004-12-30 13:51:37 +00:00
|
|
|
/* ----------------------------------------------------------------------
|
|
|
|
* A remote wildcard matcher, providing a similar interface to the
|
|
|
|
* local one in psftp.h.
|
|
|
|
*/
|
|
|
|
|
|
|
|
typedef struct SftpWildcardMatcher {
|
|
|
|
struct fxp_handle *dirh;
|
|
|
|
struct fxp_names *names;
|
|
|
|
int namepos;
|
|
|
|
char *wildcard, *prefix;
|
|
|
|
} SftpWildcardMatcher;
|
|
|
|
|
|
|
|
SftpWildcardMatcher *sftp_begin_wildcard_matching(char *name)
|
|
|
|
{
|
|
|
|
struct sftp_packet *pktin;
|
Clean up handling of the return value from sftp_find_request. In many
places we simply enforce by assertion that it will match the request
we sent out a moment ago: in fact it can also return NULL, so it makes
more sense to report a proper error message if it doesn't return the
expected value, and while we're at it, have that error message
whatever message was helpfully left in fxp_error() by
sftp_find_request when it failed.
To do this, I've written a centralised function in psftp.c called
sftp_wait_for_reply, which is handed a request that's just been sent
out and deals with the mechanics of waiting for its reply, returning
the reply when it arrives, and aborting with a sensible error if
anything else arrives instead. The numerous sites in psftp.c which
called sftp_find_request have all been rewritten to do this instead,
and as a side effect they now look more sensible. The only other uses
of sftp_find_request were in xfer_*load_gotpkt, which had to be
tweaked in its own way.
While I'm here, also fix memory management in sftp_find_request, which
was freeing its input packet on some but not all error return paths.
[originally from svn r9894]
2013-07-06 20:43:21 +00:00
|
|
|
struct sftp_request *req;
|
2004-12-30 13:51:37 +00:00
|
|
|
char *wildcard;
|
|
|
|
char *unwcdir, *tmpdir, *cdir;
|
|
|
|
int len, check;
|
|
|
|
SftpWildcardMatcher *swcm;
|
|
|
|
struct fxp_handle *dirh;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We don't handle multi-level wildcards; so we expect to find
|
|
|
|
* a fully specified directory part, followed by a wildcard
|
|
|
|
* after that.
|
|
|
|
*/
|
|
|
|
wildcard = stripslashes(name, 0);
|
|
|
|
|
|
|
|
unwcdir = dupstr(name);
|
|
|
|
len = wildcard - name;
|
|
|
|
unwcdir[len] = '\0';
|
|
|
|
if (len > 0 && unwcdir[len-1] == '/')
|
|
|
|
unwcdir[len-1] = '\0';
|
|
|
|
tmpdir = snewn(1 + len, char);
|
|
|
|
check = wc_unescape(tmpdir, unwcdir);
|
|
|
|
sfree(tmpdir);
|
|
|
|
|
|
|
|
if (!check) {
|
|
|
|
printf("Multiple-level wildcards are not supported\n");
|
|
|
|
sfree(unwcdir);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
cdir = canonify(unwcdir);
|
|
|
|
|
Clean up handling of the return value from sftp_find_request. In many
places we simply enforce by assertion that it will match the request
we sent out a moment ago: in fact it can also return NULL, so it makes
more sense to report a proper error message if it doesn't return the
expected value, and while we're at it, have that error message
whatever message was helpfully left in fxp_error() by
sftp_find_request when it failed.
To do this, I've written a centralised function in psftp.c called
sftp_wait_for_reply, which is handed a request that's just been sent
out and deals with the mechanics of waiting for its reply, returning
the reply when it arrives, and aborting with a sensible error if
anything else arrives instead. The numerous sites in psftp.c which
called sftp_find_request have all been rewritten to do this instead,
and as a side effect they now look more sensible. The only other uses
of sftp_find_request were in xfer_*load_gotpkt, which had to be
tweaked in its own way.
While I'm here, also fix memory management in sftp_find_request, which
was freeing its input packet on some but not all error return paths.
[originally from svn r9894]
2013-07-06 20:43:21 +00:00
|
|
|
req = fxp_opendir_send(cdir);
|
|
|
|
pktin = sftp_wait_for_reply(req);
|
|
|
|
dirh = fxp_opendir_recv(pktin, req);
|
2004-12-30 13:51:37 +00:00
|
|
|
|
|
|
|
if (dirh) {
|
|
|
|
swcm = snew(SftpWildcardMatcher);
|
|
|
|
swcm->dirh = dirh;
|
|
|
|
swcm->names = NULL;
|
|
|
|
swcm->wildcard = dupstr(wildcard);
|
|
|
|
swcm->prefix = unwcdir;
|
|
|
|
} else {
|
|
|
|
printf("Unable to open %s: %s\n", cdir, fxp_error());
|
|
|
|
swcm = NULL;
|
|
|
|
sfree(unwcdir);
|
|
|
|
}
|
|
|
|
|
|
|
|
sfree(cdir);
|
|
|
|
|
|
|
|
return swcm;
|
|
|
|
}
|
|
|
|
|
|
|
|
char *sftp_wildcard_get_filename(SftpWildcardMatcher *swcm)
|
|
|
|
{
|
|
|
|
struct fxp_name *name;
|
|
|
|
struct sftp_packet *pktin;
|
Clean up handling of the return value from sftp_find_request. In many
places we simply enforce by assertion that it will match the request
we sent out a moment ago: in fact it can also return NULL, so it makes
more sense to report a proper error message if it doesn't return the
expected value, and while we're at it, have that error message
whatever message was helpfully left in fxp_error() by
sftp_find_request when it failed.
To do this, I've written a centralised function in psftp.c called
sftp_wait_for_reply, which is handed a request that's just been sent
out and deals with the mechanics of waiting for its reply, returning
the reply when it arrives, and aborting with a sensible error if
anything else arrives instead. The numerous sites in psftp.c which
called sftp_find_request have all been rewritten to do this instead,
and as a side effect they now look more sensible. The only other uses
of sftp_find_request were in xfer_*load_gotpkt, which had to be
tweaked in its own way.
While I'm here, also fix memory management in sftp_find_request, which
was freeing its input packet on some but not all error return paths.
[originally from svn r9894]
2013-07-06 20:43:21 +00:00
|
|
|
struct sftp_request *req;
|
2004-12-30 13:51:37 +00:00
|
|
|
|
|
|
|
while (1) {
|
|
|
|
if (swcm->names && swcm->namepos >= swcm->names->nnames) {
|
|
|
|
fxp_free_names(swcm->names);
|
|
|
|
swcm->names = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!swcm->names) {
|
Clean up handling of the return value from sftp_find_request. In many
places we simply enforce by assertion that it will match the request
we sent out a moment ago: in fact it can also return NULL, so it makes
more sense to report a proper error message if it doesn't return the
expected value, and while we're at it, have that error message
whatever message was helpfully left in fxp_error() by
sftp_find_request when it failed.
To do this, I've written a centralised function in psftp.c called
sftp_wait_for_reply, which is handed a request that's just been sent
out and deals with the mechanics of waiting for its reply, returning
the reply when it arrives, and aborting with a sensible error if
anything else arrives instead. The numerous sites in psftp.c which
called sftp_find_request have all been rewritten to do this instead,
and as a side effect they now look more sensible. The only other uses
of sftp_find_request were in xfer_*load_gotpkt, which had to be
tweaked in its own way.
While I'm here, also fix memory management in sftp_find_request, which
was freeing its input packet on some but not all error return paths.
[originally from svn r9894]
2013-07-06 20:43:21 +00:00
|
|
|
req = fxp_readdir_send(swcm->dirh);
|
|
|
|
pktin = sftp_wait_for_reply(req);
|
|
|
|
swcm->names = fxp_readdir_recv(pktin, req);
|
2004-12-30 13:51:37 +00:00
|
|
|
|
|
|
|
if (!swcm->names) {
|
|
|
|
if (fxp_error_type() != SSH_FX_EOF)
|
|
|
|
printf("%s: reading directory: %s\n", swcm->prefix,
|
|
|
|
fxp_error());
|
|
|
|
return NULL;
|
2012-06-20 17:39:32 +00:00
|
|
|
} else if (swcm->names->nnames == 0) {
|
|
|
|
/*
|
|
|
|
* Another failure mode which we treat as EOF is if
|
|
|
|
* the server reports success from FXP_READDIR but
|
|
|
|
* returns no actual names. This is unusual, since
|
|
|
|
* from most servers you'd expect at least "." and
|
|
|
|
* "..", but there's nothing forbidding a server from
|
|
|
|
* omitting those if it wants to.
|
|
|
|
*/
|
|
|
|
return NULL;
|
|
|
|
}
|
2004-12-30 13:51:37 +00:00
|
|
|
|
|
|
|
swcm->namepos = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(swcm->names && swcm->namepos < swcm->names->nnames);
|
|
|
|
|
|
|
|
name = &swcm->names->names[swcm->namepos++];
|
|
|
|
|
|
|
|
if (!strcmp(name->filename, ".") || !strcmp(name->filename, ".."))
|
|
|
|
continue; /* expected bad filenames */
|
|
|
|
|
|
|
|
if (!vet_filename(name->filename)) {
|
|
|
|
printf("ignoring potentially dangerous server-"
|
|
|
|
"supplied filename '%s'\n", name->filename);
|
|
|
|
continue; /* unexpected bad filename */
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!wc_match(swcm->wildcard, name->filename))
|
|
|
|
continue; /* doesn't match the wildcard */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We have a working filename. Return it.
|
|
|
|
*/
|
|
|
|
return dupprintf("%s%s%s", swcm->prefix,
|
2005-01-01 12:34:32 +00:00
|
|
|
(!swcm->prefix[0] ||
|
|
|
|
swcm->prefix[strlen(swcm->prefix)-1]=='/' ?
|
|
|
|
"" : "/"),
|
2004-12-30 13:51:37 +00:00
|
|
|
name->filename);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void sftp_finish_wildcard_matching(SftpWildcardMatcher *swcm)
|
|
|
|
{
|
|
|
|
struct sftp_packet *pktin;
|
Clean up handling of the return value from sftp_find_request. In many
places we simply enforce by assertion that it will match the request
we sent out a moment ago: in fact it can also return NULL, so it makes
more sense to report a proper error message if it doesn't return the
expected value, and while we're at it, have that error message
whatever message was helpfully left in fxp_error() by
sftp_find_request when it failed.
To do this, I've written a centralised function in psftp.c called
sftp_wait_for_reply, which is handed a request that's just been sent
out and deals with the mechanics of waiting for its reply, returning
the reply when it arrives, and aborting with a sensible error if
anything else arrives instead. The numerous sites in psftp.c which
called sftp_find_request have all been rewritten to do this instead,
and as a side effect they now look more sensible. The only other uses
of sftp_find_request were in xfer_*load_gotpkt, which had to be
tweaked in its own way.
While I'm here, also fix memory management in sftp_find_request, which
was freeing its input packet on some but not all error return paths.
[originally from svn r9894]
2013-07-06 20:43:21 +00:00
|
|
|
struct sftp_request *req;
|
2004-12-30 13:51:37 +00:00
|
|
|
|
Clean up handling of the return value from sftp_find_request. In many
places we simply enforce by assertion that it will match the request
we sent out a moment ago: in fact it can also return NULL, so it makes
more sense to report a proper error message if it doesn't return the
expected value, and while we're at it, have that error message
whatever message was helpfully left in fxp_error() by
sftp_find_request when it failed.
To do this, I've written a centralised function in psftp.c called
sftp_wait_for_reply, which is handed a request that's just been sent
out and deals with the mechanics of waiting for its reply, returning
the reply when it arrives, and aborting with a sensible error if
anything else arrives instead. The numerous sites in psftp.c which
called sftp_find_request have all been rewritten to do this instead,
and as a side effect they now look more sensible. The only other uses
of sftp_find_request were in xfer_*load_gotpkt, which had to be
tweaked in its own way.
While I'm here, also fix memory management in sftp_find_request, which
was freeing its input packet on some but not all error return paths.
[originally from svn r9894]
2013-07-06 20:43:21 +00:00
|
|
|
req = fxp_close_send(swcm->dirh);
|
|
|
|
pktin = sftp_wait_for_reply(req);
|
|
|
|
fxp_close_recv(pktin, req);
|
2004-12-30 13:51:37 +00:00
|
|
|
|
|
|
|
if (swcm->names)
|
|
|
|
fxp_free_names(swcm->names);
|
|
|
|
|
|
|
|
sfree(swcm->prefix);
|
|
|
|
sfree(swcm->wildcard);
|
|
|
|
|
|
|
|
sfree(swcm);
|
|
|
|
}
|
|
|
|
|
2005-01-01 12:34:32 +00:00
|
|
|
/*
|
|
|
|
* General function to match a potential wildcard in a filename
|
|
|
|
* argument and iterate over every matching file. Used in several
|
|
|
|
* PSFTP commands (rmdir, rm, chmod, mv).
|
|
|
|
*/
|
|
|
|
int wildcard_iterate(char *filename, int (*func)(void *, char *), void *ctx)
|
|
|
|
{
|
|
|
|
char *unwcfname, *newname, *cname;
|
|
|
|
int is_wc, ret;
|
|
|
|
|
|
|
|
unwcfname = snewn(strlen(filename)+1, char);
|
|
|
|
is_wc = !wc_unescape(unwcfname, filename);
|
|
|
|
|
|
|
|
if (is_wc) {
|
|
|
|
SftpWildcardMatcher *swcm = sftp_begin_wildcard_matching(filename);
|
|
|
|
int matched = FALSE;
|
|
|
|
sfree(unwcfname);
|
|
|
|
|
|
|
|
if (!swcm)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
ret = 1;
|
|
|
|
|
|
|
|
while ( (newname = sftp_wildcard_get_filename(swcm)) != NULL ) {
|
|
|
|
cname = canonify(newname);
|
|
|
|
if (!cname) {
|
2006-04-13 21:18:09 +00:00
|
|
|
printf("%s: canonify: %s\n", newname, fxp_error());
|
2005-01-01 12:34:32 +00:00
|
|
|
ret = 0;
|
|
|
|
}
|
2013-07-11 17:43:41 +00:00
|
|
|
sfree(newname);
|
2005-01-01 12:34:32 +00:00
|
|
|
matched = TRUE;
|
|
|
|
ret &= func(ctx, cname);
|
|
|
|
sfree(cname);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!matched) {
|
|
|
|
/* Politely warn the user that nothing matched. */
|
|
|
|
printf("%s: nothing matched\n", filename);
|
|
|
|
}
|
|
|
|
|
|
|
|
sftp_finish_wildcard_matching(swcm);
|
|
|
|
} else {
|
|
|
|
cname = canonify(unwcfname);
|
|
|
|
if (!cname) {
|
2006-04-13 21:18:09 +00:00
|
|
|
printf("%s: canonify: %s\n", filename, fxp_error());
|
2005-01-01 12:34:32 +00:00
|
|
|
ret = 0;
|
|
|
|
}
|
|
|
|
ret = func(ctx, cname);
|
|
|
|
sfree(cname);
|
|
|
|
sfree(unwcfname);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Handy helper function.
|
|
|
|
*/
|
|
|
|
int is_wildcard(char *name)
|
|
|
|
{
|
|
|
|
char *unwcfname = snewn(strlen(name)+1, char);
|
|
|
|
int is_wc = !wc_unescape(unwcfname, name);
|
|
|
|
sfree(unwcfname);
|
|
|
|
return is_wc;
|
|
|
|
}
|
|
|
|
|
2004-12-16 16:37:37 +00:00
|
|
|
/* ----------------------------------------------------------------------
|
|
|
|
* Actual sftp commands.
|
|
|
|
*/
|
|
|
|
struct sftp_command {
|
|
|
|
char **words;
|
|
|
|
int nwords, wordssize;
|
|
|
|
int (*obey) (struct sftp_command *); /* returns <0 to quit */
|
|
|
|
};
|
|
|
|
|
|
|
|
int sftp_cmd_null(struct sftp_command *cmd)
|
|
|
|
{
|
|
|
|
return 1; /* success */
|
|
|
|
}
|
|
|
|
|
|
|
|
int sftp_cmd_unknown(struct sftp_command *cmd)
|
|
|
|
{
|
|
|
|
printf("psftp: unknown command \"%s\"\n", cmd->words[0]);
|
|
|
|
return 0; /* failure */
|
|
|
|
}
|
|
|
|
|
|
|
|
int sftp_cmd_quit(struct sftp_command *cmd)
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2004-12-16 19:19:59 +00:00
|
|
|
int sftp_cmd_close(struct sftp_command *cmd)
|
|
|
|
{
|
2018-09-11 15:23:38 +00:00
|
|
|
if (!backend) {
|
2005-01-01 16:43:19 +00:00
|
|
|
not_connected();
|
2004-12-16 19:19:59 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-09-11 15:23:38 +00:00
|
|
|
if (backend_connected(backend)) {
|
2004-12-16 19:19:59 +00:00
|
|
|
char ch;
|
Rework special-commands system to add an integer argument.
In order to list cross-certifiable host keys in the GUI specials menu,
the SSH backend has been inventing new values on the end of the
Telnet_Special enumeration, starting from the value TS_LOCALSTART.
This is inelegant, and also makes it awkward to break up special
handlers (e.g. to dispatch different specials to different SSH
layers), since if all you know about a special is that it's somewhere
in the TS_LOCALSTART+n space, you can't tell what _general kind_ of
thing it is. Also, if I ever need another open-ended set of specials
in future, I'll have to remember which TS_LOCALSTART+n codes are in
which set.
So here's a revamp that causes every special to take an extra integer
argument. For all previously numbered specials, this argument is
passed as zero and ignored, but there's a new main special code for
SSH host key cross-certification, in which the integer argument is an
index into the backend's list of available keys. TS_LOCALSTART is now
a thing of the past: if I need any other open-ended sets of specials
in future, I can add a new top-level code with a nicely separated
space of arguments.
While I'm at it, I've removed the legacy misnomer 'Telnet_Special'
from the code completely; the enum is now SessionSpecialCode, the
struct containing full details of a menu entry is SessionSpecial, and
the enum values now start SS_ rather than TS_.
2018-09-24 08:35:52 +00:00
|
|
|
backend_special(backend, SS_EOF, 0);
|
2011-09-13 11:44:03 +00:00
|
|
|
sent_eof = TRUE;
|
2004-12-16 19:19:59 +00:00
|
|
|
sftp_recvdata(&ch, 1);
|
|
|
|
}
|
|
|
|
do_sftp_cleanup();
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2004-12-16 16:37:37 +00:00
|
|
|
/*
|
|
|
|
* List a directory. If no arguments are given, list pwd; otherwise
|
|
|
|
* list the directory given in words[1].
|
|
|
|
*/
|
|
|
|
int sftp_cmd_ls(struct sftp_command *cmd)
|
|
|
|
{
|
|
|
|
struct fxp_handle *dirh;
|
|
|
|
struct fxp_names *names;
|
|
|
|
struct fxp_name **ournames;
|
|
|
|
int nnames, namesize;
|
2015-05-15 10:15:42 +00:00
|
|
|
const char *dir;
|
|
|
|
char *cdir, *unwcdir, *wildcard;
|
2004-12-16 16:37:37 +00:00
|
|
|
struct sftp_packet *pktin;
|
Clean up handling of the return value from sftp_find_request. In many
places we simply enforce by assertion that it will match the request
we sent out a moment ago: in fact it can also return NULL, so it makes
more sense to report a proper error message if it doesn't return the
expected value, and while we're at it, have that error message
whatever message was helpfully left in fxp_error() by
sftp_find_request when it failed.
To do this, I've written a centralised function in psftp.c called
sftp_wait_for_reply, which is handed a request that's just been sent
out and deals with the mechanics of waiting for its reply, returning
the reply when it arrives, and aborting with a sensible error if
anything else arrives instead. The numerous sites in psftp.c which
called sftp_find_request have all been rewritten to do this instead,
and as a side effect they now look more sensible. The only other uses
of sftp_find_request were in xfer_*load_gotpkt, which had to be
tweaked in its own way.
While I'm here, also fix memory management in sftp_find_request, which
was freeing its input packet on some but not all error return paths.
[originally from svn r9894]
2013-07-06 20:43:21 +00:00
|
|
|
struct sftp_request *req;
|
2004-12-16 16:37:37 +00:00
|
|
|
int i;
|
|
|
|
|
2018-09-11 15:23:38 +00:00
|
|
|
if (!backend) {
|
2005-01-01 16:43:19 +00:00
|
|
|
not_connected();
|
2004-12-16 16:37:37 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cmd->nwords < 2)
|
|
|
|
dir = ".";
|
|
|
|
else
|
|
|
|
dir = cmd->words[1];
|
|
|
|
|
2004-12-16 17:45:29 +00:00
|
|
|
unwcdir = snewn(1 + strlen(dir), char);
|
|
|
|
if (wc_unescape(unwcdir, dir)) {
|
|
|
|
dir = unwcdir;
|
|
|
|
wildcard = NULL;
|
|
|
|
} else {
|
|
|
|
char *tmpdir;
|
|
|
|
int len, check;
|
|
|
|
|
2013-07-14 10:46:07 +00:00
|
|
|
sfree(unwcdir);
|
2004-12-16 17:45:29 +00:00
|
|
|
wildcard = stripslashes(dir, 0);
|
|
|
|
unwcdir = dupstr(dir);
|
|
|
|
len = wildcard - dir;
|
|
|
|
unwcdir[len] = '\0';
|
|
|
|
if (len > 0 && unwcdir[len-1] == '/')
|
|
|
|
unwcdir[len-1] = '\0';
|
|
|
|
tmpdir = snewn(1 + len, char);
|
|
|
|
check = wc_unescape(tmpdir, unwcdir);
|
|
|
|
sfree(tmpdir);
|
|
|
|
if (!check) {
|
|
|
|
printf("Multiple-level wildcards are not supported\n");
|
|
|
|
sfree(unwcdir);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
dir = unwcdir;
|
|
|
|
}
|
|
|
|
|
2004-12-16 16:37:37 +00:00
|
|
|
cdir = canonify(dir);
|
|
|
|
if (!cdir) {
|
2006-04-13 21:18:09 +00:00
|
|
|
printf("%s: canonify: %s\n", dir, fxp_error());
|
2004-12-16 17:45:29 +00:00
|
|
|
sfree(unwcdir);
|
2004-12-16 16:37:37 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
printf("Listing directory %s\n", cdir);
|
|
|
|
|
Clean up handling of the return value from sftp_find_request. In many
places we simply enforce by assertion that it will match the request
we sent out a moment ago: in fact it can also return NULL, so it makes
more sense to report a proper error message if it doesn't return the
expected value, and while we're at it, have that error message
whatever message was helpfully left in fxp_error() by
sftp_find_request when it failed.
To do this, I've written a centralised function in psftp.c called
sftp_wait_for_reply, which is handed a request that's just been sent
out and deals with the mechanics of waiting for its reply, returning
the reply when it arrives, and aborting with a sensible error if
anything else arrives instead. The numerous sites in psftp.c which
called sftp_find_request have all been rewritten to do this instead,
and as a side effect they now look more sensible. The only other uses
of sftp_find_request were in xfer_*load_gotpkt, which had to be
tweaked in its own way.
While I'm here, also fix memory management in sftp_find_request, which
was freeing its input packet on some but not all error return paths.
[originally from svn r9894]
2013-07-06 20:43:21 +00:00
|
|
|
req = fxp_opendir_send(cdir);
|
|
|
|
pktin = sftp_wait_for_reply(req);
|
|
|
|
dirh = fxp_opendir_recv(pktin, req);
|
2004-12-16 16:37:37 +00:00
|
|
|
|
|
|
|
if (dirh == NULL) {
|
|
|
|
printf("Unable to open %s: %s\n", dir, fxp_error());
|
2017-06-20 20:17:43 +00:00
|
|
|
sfree(cdir);
|
|
|
|
sfree(unwcdir);
|
2017-02-18 22:46:38 +00:00
|
|
|
return 0;
|
2004-12-16 16:37:37 +00:00
|
|
|
} else {
|
|
|
|
nnames = namesize = 0;
|
|
|
|
ournames = NULL;
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
|
Clean up handling of the return value from sftp_find_request. In many
places we simply enforce by assertion that it will match the request
we sent out a moment ago: in fact it can also return NULL, so it makes
more sense to report a proper error message if it doesn't return the
expected value, and while we're at it, have that error message
whatever message was helpfully left in fxp_error() by
sftp_find_request when it failed.
To do this, I've written a centralised function in psftp.c called
sftp_wait_for_reply, which is handed a request that's just been sent
out and deals with the mechanics of waiting for its reply, returning
the reply when it arrives, and aborting with a sensible error if
anything else arrives instead. The numerous sites in psftp.c which
called sftp_find_request have all been rewritten to do this instead,
and as a side effect they now look more sensible. The only other uses
of sftp_find_request were in xfer_*load_gotpkt, which had to be
tweaked in its own way.
While I'm here, also fix memory management in sftp_find_request, which
was freeing its input packet on some but not all error return paths.
[originally from svn r9894]
2013-07-06 20:43:21 +00:00
|
|
|
req = fxp_readdir_send(dirh);
|
|
|
|
pktin = sftp_wait_for_reply(req);
|
|
|
|
names = fxp_readdir_recv(pktin, req);
|
2004-12-16 16:37:37 +00:00
|
|
|
|
|
|
|
if (names == NULL) {
|
|
|
|
if (fxp_error_type() == SSH_FX_EOF)
|
|
|
|
break;
|
|
|
|
printf("Reading directory %s: %s\n", dir, fxp_error());
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (names->nnames == 0) {
|
|
|
|
fxp_free_names(names);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nnames + names->nnames >= namesize) {
|
|
|
|
namesize += names->nnames + 128;
|
|
|
|
ournames = sresize(ournames, namesize, struct fxp_name *);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < names->nnames; i++)
|
2004-12-16 17:45:29 +00:00
|
|
|
if (!wildcard || wc_match(wildcard, names->names[i].filename))
|
|
|
|
ournames[nnames++] = fxp_dup_name(&names->names[i]);
|
2004-12-16 16:37:37 +00:00
|
|
|
|
|
|
|
fxp_free_names(names);
|
|
|
|
}
|
Clean up handling of the return value from sftp_find_request. In many
places we simply enforce by assertion that it will match the request
we sent out a moment ago: in fact it can also return NULL, so it makes
more sense to report a proper error message if it doesn't return the
expected value, and while we're at it, have that error message
whatever message was helpfully left in fxp_error() by
sftp_find_request when it failed.
To do this, I've written a centralised function in psftp.c called
sftp_wait_for_reply, which is handed a request that's just been sent
out and deals with the mechanics of waiting for its reply, returning
the reply when it arrives, and aborting with a sensible error if
anything else arrives instead. The numerous sites in psftp.c which
called sftp_find_request have all been rewritten to do this instead,
and as a side effect they now look more sensible. The only other uses
of sftp_find_request were in xfer_*load_gotpkt, which had to be
tweaked in its own way.
While I'm here, also fix memory management in sftp_find_request, which
was freeing its input packet on some but not all error return paths.
[originally from svn r9894]
2013-07-06 20:43:21 +00:00
|
|
|
req = fxp_close_send(dirh);
|
|
|
|
pktin = sftp_wait_for_reply(req);
|
|
|
|
fxp_close_recv(pktin, req);
|
2004-12-16 16:37:37 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Now we have our filenames. Sort them by actual file
|
|
|
|
* name, and then output the longname parts.
|
|
|
|
*/
|
2013-07-11 17:24:39 +00:00
|
|
|
if (nnames > 0)
|
|
|
|
qsort(ournames, nnames, sizeof(*ournames), sftp_name_compare);
|
2004-12-16 16:37:37 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* And print them.
|
|
|
|
*/
|
|
|
|
for (i = 0; i < nnames; i++) {
|
|
|
|
printf("%s\n", ournames[i]->longname);
|
|
|
|
fxp_free_name(ournames[i]);
|
|
|
|
}
|
|
|
|
sfree(ournames);
|
|
|
|
}
|
|
|
|
|
|
|
|
sfree(cdir);
|
2004-12-16 17:45:29 +00:00
|
|
|
sfree(unwcdir);
|
2004-12-16 16:37:37 +00:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Change directories. We do this by canonifying the new name, then
|
|
|
|
* trying to OPENDIR it. Only if that succeeds do we set the new pwd.
|
|
|
|
*/
|
|
|
|
int sftp_cmd_cd(struct sftp_command *cmd)
|
|
|
|
{
|
|
|
|
struct fxp_handle *dirh;
|
|
|
|
struct sftp_packet *pktin;
|
Clean up handling of the return value from sftp_find_request. In many
places we simply enforce by assertion that it will match the request
we sent out a moment ago: in fact it can also return NULL, so it makes
more sense to report a proper error message if it doesn't return the
expected value, and while we're at it, have that error message
whatever message was helpfully left in fxp_error() by
sftp_find_request when it failed.
To do this, I've written a centralised function in psftp.c called
sftp_wait_for_reply, which is handed a request that's just been sent
out and deals with the mechanics of waiting for its reply, returning
the reply when it arrives, and aborting with a sensible error if
anything else arrives instead. The numerous sites in psftp.c which
called sftp_find_request have all been rewritten to do this instead,
and as a side effect they now look more sensible. The only other uses
of sftp_find_request were in xfer_*load_gotpkt, which had to be
tweaked in its own way.
While I'm here, also fix memory management in sftp_find_request, which
was freeing its input packet on some but not all error return paths.
[originally from svn r9894]
2013-07-06 20:43:21 +00:00
|
|
|
struct sftp_request *req;
|
2004-12-16 16:37:37 +00:00
|
|
|
char *dir;
|
|
|
|
|
2018-09-11 15:23:38 +00:00
|
|
|
if (!backend) {
|
2005-01-01 16:43:19 +00:00
|
|
|
not_connected();
|
2004-12-16 16:37:37 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cmd->nwords < 2)
|
|
|
|
dir = dupstr(homedir);
|
2017-06-19 16:39:32 +00:00
|
|
|
else {
|
2004-12-16 16:37:37 +00:00
|
|
|
dir = canonify(cmd->words[1]);
|
2017-06-19 16:39:32 +00:00
|
|
|
if (!dir) {
|
|
|
|
printf("%s: canonify: %s\n", cmd->words[1], fxp_error());
|
|
|
|
return 0;
|
|
|
|
}
|
2004-12-16 16:37:37 +00:00
|
|
|
}
|
|
|
|
|
Clean up handling of the return value from sftp_find_request. In many
places we simply enforce by assertion that it will match the request
we sent out a moment ago: in fact it can also return NULL, so it makes
more sense to report a proper error message if it doesn't return the
expected value, and while we're at it, have that error message
whatever message was helpfully left in fxp_error() by
sftp_find_request when it failed.
To do this, I've written a centralised function in psftp.c called
sftp_wait_for_reply, which is handed a request that's just been sent
out and deals with the mechanics of waiting for its reply, returning
the reply when it arrives, and aborting with a sensible error if
anything else arrives instead. The numerous sites in psftp.c which
called sftp_find_request have all been rewritten to do this instead,
and as a side effect they now look more sensible. The only other uses
of sftp_find_request were in xfer_*load_gotpkt, which had to be
tweaked in its own way.
While I'm here, also fix memory management in sftp_find_request, which
was freeing its input packet on some but not all error return paths.
[originally from svn r9894]
2013-07-06 20:43:21 +00:00
|
|
|
req = fxp_opendir_send(dir);
|
|
|
|
pktin = sftp_wait_for_reply(req);
|
|
|
|
dirh = fxp_opendir_recv(pktin, req);
|
2004-12-16 16:37:37 +00:00
|
|
|
|
|
|
|
if (!dirh) {
|
|
|
|
printf("Directory %s: %s\n", dir, fxp_error());
|
|
|
|
sfree(dir);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
Clean up handling of the return value from sftp_find_request. In many
places we simply enforce by assertion that it will match the request
we sent out a moment ago: in fact it can also return NULL, so it makes
more sense to report a proper error message if it doesn't return the
expected value, and while we're at it, have that error message
whatever message was helpfully left in fxp_error() by
sftp_find_request when it failed.
To do this, I've written a centralised function in psftp.c called
sftp_wait_for_reply, which is handed a request that's just been sent
out and deals with the mechanics of waiting for its reply, returning
the reply when it arrives, and aborting with a sensible error if
anything else arrives instead. The numerous sites in psftp.c which
called sftp_find_request have all been rewritten to do this instead,
and as a side effect they now look more sensible. The only other uses
of sftp_find_request were in xfer_*load_gotpkt, which had to be
tweaked in its own way.
While I'm here, also fix memory management in sftp_find_request, which
was freeing its input packet on some but not all error return paths.
[originally from svn r9894]
2013-07-06 20:43:21 +00:00
|
|
|
req = fxp_close_send(dirh);
|
|
|
|
pktin = sftp_wait_for_reply(req);
|
|
|
|
fxp_close_recv(pktin, req);
|
2004-12-16 16:37:37 +00:00
|
|
|
|
|
|
|
sfree(pwd);
|
|
|
|
pwd = dir;
|
|
|
|
printf("Remote directory is now %s\n", pwd);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Print current directory. Easy as pie.
|
|
|
|
*/
|
|
|
|
int sftp_cmd_pwd(struct sftp_command *cmd)
|
|
|
|
{
|
2018-09-11 15:23:38 +00:00
|
|
|
if (!backend) {
|
2005-01-01 16:43:19 +00:00
|
|
|
not_connected();
|
2004-12-16 16:37:37 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
printf("Remote directory is %s\n", pwd);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2004-12-16 17:35:20 +00:00
|
|
|
* Get a file and save it at the local end. We have three very
|
|
|
|
* similar commands here. The basic one is `get'; `reget' differs
|
|
|
|
* in that it checks for the existence of the destination file and
|
|
|
|
* starts from where a previous aborted transfer left off; `mget'
|
|
|
|
* differs in that it interprets all its arguments as files to
|
|
|
|
* transfer (never as a different local name for a remote file) and
|
|
|
|
* can handle wildcards.
|
2004-12-16 16:37:37 +00:00
|
|
|
*/
|
2004-12-16 17:35:20 +00:00
|
|
|
int sftp_general_get(struct sftp_command *cmd, int restart, int multiple)
|
2004-12-16 16:37:37 +00:00
|
|
|
{
|
2004-12-30 13:51:37 +00:00
|
|
|
char *fname, *unwcfname, *origfname, *origwfname, *outfname;
|
2004-12-16 16:37:37 +00:00
|
|
|
int i, ret;
|
|
|
|
int recurse = FALSE;
|
|
|
|
|
2018-09-11 15:23:38 +00:00
|
|
|
if (!backend) {
|
2005-01-01 16:43:19 +00:00
|
|
|
not_connected();
|
2004-12-16 16:37:37 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
i = 1;
|
|
|
|
while (i < cmd->nwords && cmd->words[i][0] == '-') {
|
|
|
|
if (!strcmp(cmd->words[i], "--")) {
|
|
|
|
/* finish processing options */
|
|
|
|
i++;
|
|
|
|
break;
|
|
|
|
} else if (!strcmp(cmd->words[i], "-r")) {
|
|
|
|
recurse = TRUE;
|
|
|
|
} else {
|
2004-12-17 12:15:17 +00:00
|
|
|
printf("%s: unrecognised option '%s'\n", cmd->words[0], cmd->words[i]);
|
2004-12-16 16:37:37 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i >= cmd->nwords) {
|
2004-12-17 12:15:17 +00:00
|
|
|
printf("%s: expects a filename\n", cmd->words[0]);
|
2004-12-16 16:37:37 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2004-12-30 13:51:37 +00:00
|
|
|
ret = 1;
|
2004-12-16 17:35:20 +00:00
|
|
|
do {
|
2004-12-30 13:51:37 +00:00
|
|
|
SftpWildcardMatcher *swcm;
|
|
|
|
|
2004-12-16 17:35:20 +00:00
|
|
|
origfname = cmd->words[i++];
|
2004-12-30 13:51:37 +00:00
|
|
|
unwcfname = snewn(strlen(origfname)+1, char);
|
2004-12-16 16:37:37 +00:00
|
|
|
|
2004-12-30 13:51:37 +00:00
|
|
|
if (multiple && !wc_unescape(unwcfname, origfname)) {
|
|
|
|
swcm = sftp_begin_wildcard_matching(origfname);
|
|
|
|
if (!swcm) {
|
|
|
|
sfree(unwcfname);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
origwfname = sftp_wildcard_get_filename(swcm);
|
|
|
|
if (!origwfname) {
|
|
|
|
/* Politely warn the user that nothing matched. */
|
|
|
|
printf("%s: nothing matched\n", origfname);
|
|
|
|
sftp_finish_wildcard_matching(swcm);
|
|
|
|
sfree(unwcfname);
|
|
|
|
continue;
|
|
|
|
}
|
2004-12-16 17:35:20 +00:00
|
|
|
} else {
|
2004-12-30 13:51:37 +00:00
|
|
|
origwfname = origfname;
|
|
|
|
swcm = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (origwfname) {
|
|
|
|
fname = canonify(origwfname);
|
|
|
|
|
2004-12-16 17:35:20 +00:00
|
|
|
if (!fname) {
|
2013-07-22 19:55:55 +00:00
|
|
|
sftp_finish_wildcard_matching(swcm);
|
2006-04-13 21:18:09 +00:00
|
|
|
printf("%s: canonify: %s\n", origwfname, fxp_error());
|
2013-07-22 19:55:55 +00:00
|
|
|
sfree(origwfname);
|
2004-12-16 17:35:20 +00:00
|
|
|
sfree(unwcfname);
|
|
|
|
return 0;
|
|
|
|
}
|
2004-12-16 16:37:37 +00:00
|
|
|
|
2004-12-16 17:35:20 +00:00
|
|
|
if (!multiple && i < cmd->nwords)
|
|
|
|
outfname = cmd->words[i++];
|
|
|
|
else
|
2004-12-30 13:51:37 +00:00
|
|
|
outfname = stripslashes(origwfname, 0);
|
2004-12-16 16:37:37 +00:00
|
|
|
|
2004-12-30 13:51:37 +00:00
|
|
|
ret = sftp_get_file(fname, outfname, recurse, restart);
|
2004-12-16 17:35:20 +00:00
|
|
|
|
|
|
|
sfree(fname);
|
2004-12-30 13:51:37 +00:00
|
|
|
|
|
|
|
if (swcm) {
|
|
|
|
sfree(origwfname);
|
|
|
|
origwfname = sftp_wildcard_get_filename(swcm);
|
|
|
|
} else {
|
|
|
|
origwfname = NULL;
|
|
|
|
}
|
2004-12-16 17:35:20 +00:00
|
|
|
}
|
|
|
|
sfree(unwcfname);
|
2004-12-30 13:51:37 +00:00
|
|
|
if (swcm)
|
|
|
|
sftp_finish_wildcard_matching(swcm);
|
2004-12-16 17:35:20 +00:00
|
|
|
if (!ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
} while (multiple && i < cmd->nwords);
|
2004-12-16 16:37:37 +00:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
int sftp_cmd_get(struct sftp_command *cmd)
|
|
|
|
{
|
2004-12-16 17:35:20 +00:00
|
|
|
return sftp_general_get(cmd, 0, 0);
|
|
|
|
}
|
|
|
|
int sftp_cmd_mget(struct sftp_command *cmd)
|
|
|
|
{
|
|
|
|
return sftp_general_get(cmd, 0, 1);
|
2004-12-16 16:37:37 +00:00
|
|
|
}
|
|
|
|
int sftp_cmd_reget(struct sftp_command *cmd)
|
|
|
|
{
|
2004-12-16 17:35:20 +00:00
|
|
|
return sftp_general_get(cmd, 1, 0);
|
2004-12-16 16:37:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2004-12-16 17:35:20 +00:00
|
|
|
* Send a file and store it at the remote end. We have three very
|
|
|
|
* similar commands here. The basic one is `put'; `reput' differs
|
|
|
|
* in that it checks for the existence of the destination file and
|
|
|
|
* starts from where a previous aborted transfer left off; `mput'
|
|
|
|
* differs in that it interprets all its arguments as files to
|
|
|
|
* transfer (never as a different remote name for a local file) and
|
|
|
|
* can handle wildcards.
|
2004-12-16 16:37:37 +00:00
|
|
|
*/
|
2004-12-16 17:35:20 +00:00
|
|
|
int sftp_general_put(struct sftp_command *cmd, int restart, int multiple)
|
2004-12-16 16:37:37 +00:00
|
|
|
{
|
2004-12-30 13:51:37 +00:00
|
|
|
char *fname, *wfname, *origoutfname, *outfname;
|
2004-12-16 16:37:37 +00:00
|
|
|
int i, ret;
|
|
|
|
int recurse = FALSE;
|
|
|
|
|
2018-09-11 15:23:38 +00:00
|
|
|
if (!backend) {
|
2005-01-01 16:43:19 +00:00
|
|
|
not_connected();
|
2004-12-16 16:37:37 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
i = 1;
|
|
|
|
while (i < cmd->nwords && cmd->words[i][0] == '-') {
|
|
|
|
if (!strcmp(cmd->words[i], "--")) {
|
|
|
|
/* finish processing options */
|
|
|
|
i++;
|
|
|
|
break;
|
|
|
|
} else if (!strcmp(cmd->words[i], "-r")) {
|
|
|
|
recurse = TRUE;
|
|
|
|
} else {
|
2004-12-17 12:15:17 +00:00
|
|
|
printf("%s: unrecognised option '%s'\n", cmd->words[0], cmd->words[i]);
|
2004-12-16 16:37:37 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i >= cmd->nwords) {
|
2004-12-17 12:15:17 +00:00
|
|
|
printf("%s: expects a filename\n", cmd->words[0]);
|
2004-12-16 16:37:37 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2004-12-30 13:51:37 +00:00
|
|
|
ret = 1;
|
2004-12-16 17:35:20 +00:00
|
|
|
do {
|
2004-12-30 13:51:37 +00:00
|
|
|
WildcardMatcher *wcm;
|
2004-12-16 17:35:20 +00:00
|
|
|
fname = cmd->words[i++];
|
2004-12-16 16:37:37 +00:00
|
|
|
|
2004-12-16 17:35:20 +00:00
|
|
|
if (multiple && test_wildcard(fname, FALSE) == WCTYPE_WILDCARD) {
|
2004-12-30 13:51:37 +00:00
|
|
|
wcm = begin_wildcard_matching(fname);
|
|
|
|
wfname = wildcard_get_filename(wcm);
|
|
|
|
if (!wfname) {
|
|
|
|
/* Politely warn the user that nothing matched. */
|
|
|
|
printf("%s: nothing matched\n", fname);
|
|
|
|
finish_wildcard_matching(wcm);
|
|
|
|
continue;
|
|
|
|
}
|
2004-12-16 17:35:20 +00:00
|
|
|
} else {
|
2004-12-30 13:51:37 +00:00
|
|
|
wfname = fname;
|
|
|
|
wcm = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (wfname) {
|
2004-12-16 17:35:20 +00:00
|
|
|
if (!multiple && i < cmd->nwords)
|
|
|
|
origoutfname = cmd->words[i++];
|
|
|
|
else
|
2004-12-30 13:51:37 +00:00
|
|
|
origoutfname = stripslashes(wfname, 1);
|
2004-12-16 17:35:20 +00:00
|
|
|
|
|
|
|
outfname = canonify(origoutfname);
|
|
|
|
if (!outfname) {
|
2006-04-13 21:18:09 +00:00
|
|
|
printf("%s: canonify: %s\n", origoutfname, fxp_error());
|
2004-12-30 13:51:37 +00:00
|
|
|
if (wcm) {
|
|
|
|
sfree(wfname);
|
|
|
|
finish_wildcard_matching(wcm);
|
|
|
|
}
|
2004-12-16 17:35:20 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2004-12-30 13:51:37 +00:00
|
|
|
ret = sftp_put_file(wfname, outfname, recurse, restart);
|
2004-12-16 17:35:20 +00:00
|
|
|
sfree(outfname);
|
2004-12-30 13:51:37 +00:00
|
|
|
|
|
|
|
if (wcm) {
|
|
|
|
sfree(wfname);
|
|
|
|
wfname = wildcard_get_filename(wcm);
|
|
|
|
} else {
|
|
|
|
wfname = NULL;
|
|
|
|
}
|
2004-12-16 17:35:20 +00:00
|
|
|
}
|
2004-12-30 13:51:37 +00:00
|
|
|
|
|
|
|
if (wcm)
|
|
|
|
finish_wildcard_matching(wcm);
|
|
|
|
|
2004-12-16 17:35:20 +00:00
|
|
|
if (!ret)
|
|
|
|
return ret;
|
2004-12-16 16:37:37 +00:00
|
|
|
|
2004-12-16 17:35:20 +00:00
|
|
|
} while (multiple && i < cmd->nwords);
|
2001-02-23 18:21:44 +00:00
|
|
|
|
2001-12-13 19:26:51 +00:00
|
|
|
return ret;
|
2001-02-23 18:21:44 +00:00
|
|
|
}
|
2001-08-26 11:35:11 +00:00
|
|
|
int sftp_cmd_put(struct sftp_command *cmd)
|
|
|
|
{
|
2004-12-16 17:35:20 +00:00
|
|
|
return sftp_general_put(cmd, 0, 0);
|
|
|
|
}
|
|
|
|
int sftp_cmd_mput(struct sftp_command *cmd)
|
|
|
|
{
|
|
|
|
return sftp_general_put(cmd, 0, 1);
|
2001-08-26 11:35:11 +00:00
|
|
|
}
|
|
|
|
int sftp_cmd_reput(struct sftp_command *cmd)
|
|
|
|
{
|
2004-12-16 17:35:20 +00:00
|
|
|
return sftp_general_put(cmd, 1, 0);
|
2001-08-26 11:35:11 +00:00
|
|
|
}
|
2001-02-23 18:21:44 +00:00
|
|
|
|
2001-08-04 14:19:51 +00:00
|
|
|
int sftp_cmd_mkdir(struct sftp_command *cmd)
|
|
|
|
{
|
|
|
|
char *dir;
|
2003-06-29 14:26:09 +00:00
|
|
|
struct sftp_packet *pktin;
|
Clean up handling of the return value from sftp_find_request. In many
places we simply enforce by assertion that it will match the request
we sent out a moment ago: in fact it can also return NULL, so it makes
more sense to report a proper error message if it doesn't return the
expected value, and while we're at it, have that error message
whatever message was helpfully left in fxp_error() by
sftp_find_request when it failed.
To do this, I've written a centralised function in psftp.c called
sftp_wait_for_reply, which is handed a request that's just been sent
out and deals with the mechanics of waiting for its reply, returning
the reply when it arrives, and aborting with a sensible error if
anything else arrives instead. The numerous sites in psftp.c which
called sftp_find_request have all been rewritten to do this instead,
and as a side effect they now look more sensible. The only other uses
of sftp_find_request were in xfer_*load_gotpkt, which had to be
tweaked in its own way.
While I'm here, also fix memory management in sftp_find_request, which
was freeing its input packet on some but not all error return paths.
[originally from svn r9894]
2013-07-06 20:43:21 +00:00
|
|
|
struct sftp_request *req;
|
2001-08-04 14:19:51 +00:00
|
|
|
int result;
|
2005-01-01 12:34:32 +00:00
|
|
|
int i, ret;
|
2001-08-04 14:19:51 +00:00
|
|
|
|
2018-09-11 15:23:38 +00:00
|
|
|
if (!backend) {
|
2005-01-01 16:43:19 +00:00
|
|
|
not_connected();
|
2001-12-13 18:42:34 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2001-08-04 14:19:51 +00:00
|
|
|
|
|
|
|
if (cmd->nwords < 2) {
|
|
|
|
printf("mkdir: expects a directory\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-01-01 12:34:32 +00:00
|
|
|
ret = 1;
|
|
|
|
for (i = 1; i < cmd->nwords; i++) {
|
|
|
|
dir = canonify(cmd->words[i]);
|
|
|
|
if (!dir) {
|
2017-06-19 16:39:32 +00:00
|
|
|
printf("%s: canonify: %s\n", cmd->words[i], fxp_error());
|
2005-01-01 12:34:32 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-10-06 10:52:04 +00:00
|
|
|
req = fxp_mkdir_send(dir, NULL);
|
Clean up handling of the return value from sftp_find_request. In many
places we simply enforce by assertion that it will match the request
we sent out a moment ago: in fact it can also return NULL, so it makes
more sense to report a proper error message if it doesn't return the
expected value, and while we're at it, have that error message
whatever message was helpfully left in fxp_error() by
sftp_find_request when it failed.
To do this, I've written a centralised function in psftp.c called
sftp_wait_for_reply, which is handed a request that's just been sent
out and deals with the mechanics of waiting for its reply, returning
the reply when it arrives, and aborting with a sensible error if
anything else arrives instead. The numerous sites in psftp.c which
called sftp_find_request have all been rewritten to do this instead,
and as a side effect they now look more sensible. The only other uses
of sftp_find_request were in xfer_*load_gotpkt, which had to be
tweaked in its own way.
While I'm here, also fix memory management in sftp_find_request, which
was freeing its input packet on some but not all error return paths.
[originally from svn r9894]
2013-07-06 20:43:21 +00:00
|
|
|
pktin = sftp_wait_for_reply(req);
|
|
|
|
result = fxp_mkdir_recv(pktin, req);
|
2005-01-01 12:34:32 +00:00
|
|
|
|
|
|
|
if (!result) {
|
|
|
|
printf("mkdir %s: %s\n", dir, fxp_error());
|
|
|
|
ret = 0;
|
2005-01-01 16:35:57 +00:00
|
|
|
} else
|
|
|
|
printf("mkdir %s: OK\n", dir);
|
2005-01-01 12:34:32 +00:00
|
|
|
|
|
|
|
sfree(dir);
|
2001-08-04 14:19:51 +00:00
|
|
|
}
|
|
|
|
|
2005-01-01 12:34:32 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int sftp_action_rmdir(void *vctx, char *dir)
|
|
|
|
{
|
|
|
|
struct sftp_packet *pktin;
|
Clean up handling of the return value from sftp_find_request. In many
places we simply enforce by assertion that it will match the request
we sent out a moment ago: in fact it can also return NULL, so it makes
more sense to report a proper error message if it doesn't return the
expected value, and while we're at it, have that error message
whatever message was helpfully left in fxp_error() by
sftp_find_request when it failed.
To do this, I've written a centralised function in psftp.c called
sftp_wait_for_reply, which is handed a request that's just been sent
out and deals with the mechanics of waiting for its reply, returning
the reply when it arrives, and aborting with a sensible error if
anything else arrives instead. The numerous sites in psftp.c which
called sftp_find_request have all been rewritten to do this instead,
and as a side effect they now look more sensible. The only other uses
of sftp_find_request were in xfer_*load_gotpkt, which had to be
tweaked in its own way.
While I'm here, also fix memory management in sftp_find_request, which
was freeing its input packet on some but not all error return paths.
[originally from svn r9894]
2013-07-06 20:43:21 +00:00
|
|
|
struct sftp_request *req;
|
2005-01-01 12:34:32 +00:00
|
|
|
int result;
|
|
|
|
|
Clean up handling of the return value from sftp_find_request. In many
places we simply enforce by assertion that it will match the request
we sent out a moment ago: in fact it can also return NULL, so it makes
more sense to report a proper error message if it doesn't return the
expected value, and while we're at it, have that error message
whatever message was helpfully left in fxp_error() by
sftp_find_request when it failed.
To do this, I've written a centralised function in psftp.c called
sftp_wait_for_reply, which is handed a request that's just been sent
out and deals with the mechanics of waiting for its reply, returning
the reply when it arrives, and aborting with a sensible error if
anything else arrives instead. The numerous sites in psftp.c which
called sftp_find_request have all been rewritten to do this instead,
and as a side effect they now look more sensible. The only other uses
of sftp_find_request were in xfer_*load_gotpkt, which had to be
tweaked in its own way.
While I'm here, also fix memory management in sftp_find_request, which
was freeing its input packet on some but not all error return paths.
[originally from svn r9894]
2013-07-06 20:43:21 +00:00
|
|
|
req = fxp_rmdir_send(dir);
|
|
|
|
pktin = sftp_wait_for_reply(req);
|
|
|
|
result = fxp_rmdir_recv(pktin, req);
|
2003-06-29 14:26:09 +00:00
|
|
|
|
2001-08-04 14:19:51 +00:00
|
|
|
if (!result) {
|
2005-01-01 12:34:32 +00:00
|
|
|
printf("rmdir %s: %s\n", dir, fxp_error());
|
2001-08-04 14:19:51 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-01-01 16:35:57 +00:00
|
|
|
printf("rmdir %s: OK\n", dir);
|
|
|
|
|
2001-12-13 19:26:51 +00:00
|
|
|
return 1;
|
2001-08-04 14:19:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int sftp_cmd_rmdir(struct sftp_command *cmd)
|
|
|
|
{
|
2005-01-01 12:34:32 +00:00
|
|
|
int i, ret;
|
2001-08-04 14:19:51 +00:00
|
|
|
|
2018-09-11 15:23:38 +00:00
|
|
|
if (!backend) {
|
2005-01-01 16:43:19 +00:00
|
|
|
not_connected();
|
2001-12-13 18:42:34 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2001-08-04 14:19:51 +00:00
|
|
|
|
|
|
|
if (cmd->nwords < 2) {
|
|
|
|
printf("rmdir: expects a directory\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-01-01 12:34:32 +00:00
|
|
|
ret = 1;
|
|
|
|
for (i = 1; i < cmd->nwords; i++)
|
|
|
|
ret &= wildcard_iterate(cmd->words[i], sftp_action_rmdir, NULL);
|
2001-08-04 14:19:51 +00:00
|
|
|
|
2005-01-01 12:34:32 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int sftp_action_rm(void *vctx, char *fname)
|
|
|
|
{
|
|
|
|
struct sftp_packet *pktin;
|
Clean up handling of the return value from sftp_find_request. In many
places we simply enforce by assertion that it will match the request
we sent out a moment ago: in fact it can also return NULL, so it makes
more sense to report a proper error message if it doesn't return the
expected value, and while we're at it, have that error message
whatever message was helpfully left in fxp_error() by
sftp_find_request when it failed.
To do this, I've written a centralised function in psftp.c called
sftp_wait_for_reply, which is handed a request that's just been sent
out and deals with the mechanics of waiting for its reply, returning
the reply when it arrives, and aborting with a sensible error if
anything else arrives instead. The numerous sites in psftp.c which
called sftp_find_request have all been rewritten to do this instead,
and as a side effect they now look more sensible. The only other uses
of sftp_find_request were in xfer_*load_gotpkt, which had to be
tweaked in its own way.
While I'm here, also fix memory management in sftp_find_request, which
was freeing its input packet on some but not all error return paths.
[originally from svn r9894]
2013-07-06 20:43:21 +00:00
|
|
|
struct sftp_request *req;
|
2005-01-01 12:34:32 +00:00
|
|
|
int result;
|
|
|
|
|
Clean up handling of the return value from sftp_find_request. In many
places we simply enforce by assertion that it will match the request
we sent out a moment ago: in fact it can also return NULL, so it makes
more sense to report a proper error message if it doesn't return the
expected value, and while we're at it, have that error message
whatever message was helpfully left in fxp_error() by
sftp_find_request when it failed.
To do this, I've written a centralised function in psftp.c called
sftp_wait_for_reply, which is handed a request that's just been sent
out and deals with the mechanics of waiting for its reply, returning
the reply when it arrives, and aborting with a sensible error if
anything else arrives instead. The numerous sites in psftp.c which
called sftp_find_request have all been rewritten to do this instead,
and as a side effect they now look more sensible. The only other uses
of sftp_find_request were in xfer_*load_gotpkt, which had to be
tweaked in its own way.
While I'm here, also fix memory management in sftp_find_request, which
was freeing its input packet on some but not all error return paths.
[originally from svn r9894]
2013-07-06 20:43:21 +00:00
|
|
|
req = fxp_remove_send(fname);
|
|
|
|
pktin = sftp_wait_for_reply(req);
|
|
|
|
result = fxp_remove_recv(pktin, req);
|
2003-06-29 14:26:09 +00:00
|
|
|
|
2001-08-04 14:19:51 +00:00
|
|
|
if (!result) {
|
2005-01-01 12:34:32 +00:00
|
|
|
printf("rm %s: %s\n", fname, fxp_error());
|
2001-08-04 14:19:51 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-01-01 16:35:57 +00:00
|
|
|
printf("rm %s: OK\n", fname);
|
|
|
|
|
2001-12-13 19:26:51 +00:00
|
|
|
return 1;
|
2001-08-04 14:19:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int sftp_cmd_rm(struct sftp_command *cmd)
|
|
|
|
{
|
2005-01-01 12:34:32 +00:00
|
|
|
int i, ret;
|
2001-08-04 14:19:51 +00:00
|
|
|
|
2018-09-11 15:23:38 +00:00
|
|
|
if (!backend) {
|
2005-01-01 16:43:19 +00:00
|
|
|
not_connected();
|
2001-12-13 18:42:34 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2001-08-04 14:19:51 +00:00
|
|
|
if (cmd->nwords < 2) {
|
|
|
|
printf("rm: expects a filename\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-01-01 12:34:32 +00:00
|
|
|
ret = 1;
|
|
|
|
for (i = 1; i < cmd->nwords; i++)
|
|
|
|
ret &= wildcard_iterate(cmd->words[i], sftp_action_rm, NULL);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int check_is_dir(char *dstfname)
|
|
|
|
{
|
|
|
|
struct sftp_packet *pktin;
|
Clean up handling of the return value from sftp_find_request. In many
places we simply enforce by assertion that it will match the request
we sent out a moment ago: in fact it can also return NULL, so it makes
more sense to report a proper error message if it doesn't return the
expected value, and while we're at it, have that error message
whatever message was helpfully left in fxp_error() by
sftp_find_request when it failed.
To do this, I've written a centralised function in psftp.c called
sftp_wait_for_reply, which is handed a request that's just been sent
out and deals with the mechanics of waiting for its reply, returning
the reply when it arrives, and aborting with a sensible error if
anything else arrives instead. The numerous sites in psftp.c which
called sftp_find_request have all been rewritten to do this instead,
and as a side effect they now look more sensible. The only other uses
of sftp_find_request were in xfer_*load_gotpkt, which had to be
tweaked in its own way.
While I'm here, also fix memory management in sftp_find_request, which
was freeing its input packet on some but not all error return paths.
[originally from svn r9894]
2013-07-06 20:43:21 +00:00
|
|
|
struct sftp_request *req;
|
2005-01-01 12:34:32 +00:00
|
|
|
struct fxp_attrs attrs;
|
|
|
|
int result;
|
|
|
|
|
Clean up handling of the return value from sftp_find_request. In many
places we simply enforce by assertion that it will match the request
we sent out a moment ago: in fact it can also return NULL, so it makes
more sense to report a proper error message if it doesn't return the
expected value, and while we're at it, have that error message
whatever message was helpfully left in fxp_error() by
sftp_find_request when it failed.
To do this, I've written a centralised function in psftp.c called
sftp_wait_for_reply, which is handed a request that's just been sent
out and deals with the mechanics of waiting for its reply, returning
the reply when it arrives, and aborting with a sensible error if
anything else arrives instead. The numerous sites in psftp.c which
called sftp_find_request have all been rewritten to do this instead,
and as a side effect they now look more sensible. The only other uses
of sftp_find_request were in xfer_*load_gotpkt, which had to be
tweaked in its own way.
While I'm here, also fix memory management in sftp_find_request, which
was freeing its input packet on some but not all error return paths.
[originally from svn r9894]
2013-07-06 20:43:21 +00:00
|
|
|
req = fxp_stat_send(dstfname);
|
|
|
|
pktin = sftp_wait_for_reply(req);
|
|
|
|
result = fxp_stat_recv(pktin, req, &attrs);
|
2005-01-01 12:34:32 +00:00
|
|
|
|
|
|
|
if (result &&
|
|
|
|
(attrs.flags & SSH_FILEXFER_ATTR_PERMISSIONS) &&
|
|
|
|
(attrs.permissions & 0040000))
|
|
|
|
return TRUE;
|
|
|
|
else
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct sftp_context_mv {
|
|
|
|
char *dstfname;
|
|
|
|
int dest_is_dir;
|
|
|
|
};
|
|
|
|
|
|
|
|
static int sftp_action_mv(void *vctx, char *srcfname)
|
|
|
|
{
|
|
|
|
struct sftp_context_mv *ctx = (struct sftp_context_mv *)vctx;
|
|
|
|
struct sftp_packet *pktin;
|
Clean up handling of the return value from sftp_find_request. In many
places we simply enforce by assertion that it will match the request
we sent out a moment ago: in fact it can also return NULL, so it makes
more sense to report a proper error message if it doesn't return the
expected value, and while we're at it, have that error message
whatever message was helpfully left in fxp_error() by
sftp_find_request when it failed.
To do this, I've written a centralised function in psftp.c called
sftp_wait_for_reply, which is handed a request that's just been sent
out and deals with the mechanics of waiting for its reply, returning
the reply when it arrives, and aborting with a sensible error if
anything else arrives instead. The numerous sites in psftp.c which
called sftp_find_request have all been rewritten to do this instead,
and as a side effect they now look more sensible. The only other uses
of sftp_find_request were in xfer_*load_gotpkt, which had to be
tweaked in its own way.
While I'm here, also fix memory management in sftp_find_request, which
was freeing its input packet on some but not all error return paths.
[originally from svn r9894]
2013-07-06 20:43:21 +00:00
|
|
|
struct sftp_request *req;
|
2005-01-01 12:34:32 +00:00
|
|
|
const char *error;
|
|
|
|
char *finalfname, *newcanon = NULL;
|
|
|
|
int ret, result;
|
|
|
|
|
|
|
|
if (ctx->dest_is_dir) {
|
|
|
|
char *p;
|
|
|
|
char *newname;
|
|
|
|
|
|
|
|
p = srcfname + strlen(srcfname);
|
|
|
|
while (p > srcfname && p[-1] != '/') p--;
|
|
|
|
newname = dupcat(ctx->dstfname, "/", p, NULL);
|
|
|
|
newcanon = canonify(newname);
|
|
|
|
if (!newcanon) {
|
2006-04-13 21:18:09 +00:00
|
|
|
printf("%s: canonify: %s\n", newname, fxp_error());
|
2005-01-01 12:34:32 +00:00
|
|
|
sfree(newname);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
sfree(newname);
|
|
|
|
|
|
|
|
finalfname = newcanon;
|
|
|
|
} else {
|
|
|
|
finalfname = ctx->dstfname;
|
2001-08-04 14:19:51 +00:00
|
|
|
}
|
|
|
|
|
Clean up handling of the return value from sftp_find_request. In many
places we simply enforce by assertion that it will match the request
we sent out a moment ago: in fact it can also return NULL, so it makes
more sense to report a proper error message if it doesn't return the
expected value, and while we're at it, have that error message
whatever message was helpfully left in fxp_error() by
sftp_find_request when it failed.
To do this, I've written a centralised function in psftp.c called
sftp_wait_for_reply, which is handed a request that's just been sent
out and deals with the mechanics of waiting for its reply, returning
the reply when it arrives, and aborting with a sensible error if
anything else arrives instead. The numerous sites in psftp.c which
called sftp_find_request have all been rewritten to do this instead,
and as a side effect they now look more sensible. The only other uses
of sftp_find_request were in xfer_*load_gotpkt, which had to be
tweaked in its own way.
While I'm here, also fix memory management in sftp_find_request, which
was freeing its input packet on some but not all error return paths.
[originally from svn r9894]
2013-07-06 20:43:21 +00:00
|
|
|
req = fxp_rename_send(srcfname, finalfname);
|
|
|
|
pktin = sftp_wait_for_reply(req);
|
|
|
|
result = fxp_rename_recv(pktin, req);
|
2003-06-29 14:26:09 +00:00
|
|
|
|
2005-01-01 12:34:32 +00:00
|
|
|
error = result ? NULL : fxp_error();
|
|
|
|
|
|
|
|
if (error) {
|
|
|
|
printf("mv %s %s: %s\n", srcfname, finalfname, error);
|
|
|
|
ret = 0;
|
|
|
|
} else {
|
|
|
|
printf("%s -> %s\n", srcfname, finalfname);
|
|
|
|
ret = 1;
|
2001-08-04 14:19:51 +00:00
|
|
|
}
|
|
|
|
|
2005-01-01 12:34:32 +00:00
|
|
|
sfree(newcanon);
|
|
|
|
return ret;
|
2001-08-26 11:35:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int sftp_cmd_mv(struct sftp_command *cmd)
|
|
|
|
{
|
2005-01-01 12:34:32 +00:00
|
|
|
struct sftp_context_mv actx, *ctx = &actx;
|
|
|
|
int i, ret;
|
2001-08-26 11:35:11 +00:00
|
|
|
|
2018-09-11 15:23:38 +00:00
|
|
|
if (!backend) {
|
2005-01-01 16:43:19 +00:00
|
|
|
not_connected();
|
2001-12-13 18:42:34 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2001-08-26 11:35:11 +00:00
|
|
|
if (cmd->nwords < 3) {
|
|
|
|
printf("mv: expects two filenames\n");
|
2001-08-04 14:19:51 +00:00
|
|
|
return 0;
|
2001-08-26 11:35:11 +00:00
|
|
|
}
|
2005-01-01 12:34:32 +00:00
|
|
|
|
|
|
|
ctx->dstfname = canonify(cmd->words[cmd->nwords-1]);
|
|
|
|
if (!ctx->dstfname) {
|
2006-04-13 21:18:09 +00:00
|
|
|
printf("%s: canonify: %s\n", ctx->dstfname, fxp_error());
|
2001-08-26 11:35:11 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-01-01 12:34:32 +00:00
|
|
|
/*
|
|
|
|
* If there's more than one source argument, or one source
|
|
|
|
* argument which is a wildcard, we _require_ that the
|
|
|
|
* destination is a directory.
|
|
|
|
*/
|
|
|
|
ctx->dest_is_dir = check_is_dir(ctx->dstfname);
|
|
|
|
if ((cmd->nwords > 3 || is_wildcard(cmd->words[1])) && !ctx->dest_is_dir) {
|
|
|
|
printf("mv: multiple or wildcard arguments require the destination"
|
|
|
|
" to be a directory\n");
|
2005-01-01 13:01:13 +00:00
|
|
|
sfree(ctx->dstfname);
|
2001-08-26 11:35:11 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2001-08-04 14:19:51 +00:00
|
|
|
|
2005-01-01 12:34:32 +00:00
|
|
|
/*
|
|
|
|
* Now iterate over the source arguments.
|
|
|
|
*/
|
|
|
|
ret = 1;
|
|
|
|
for (i = 1; i < cmd->nwords-1; i++)
|
|
|
|
ret &= wildcard_iterate(cmd->words[i], sftp_action_mv, ctx);
|
|
|
|
|
2005-01-01 13:01:13 +00:00
|
|
|
sfree(ctx->dstfname);
|
2005-01-01 12:34:32 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct sftp_context_chmod {
|
|
|
|
unsigned attrs_clr, attrs_xor;
|
|
|
|
};
|
|
|
|
|
|
|
|
static int sftp_action_chmod(void *vctx, char *fname)
|
|
|
|
{
|
|
|
|
struct fxp_attrs attrs;
|
|
|
|
struct sftp_packet *pktin;
|
Clean up handling of the return value from sftp_find_request. In many
places we simply enforce by assertion that it will match the request
we sent out a moment ago: in fact it can also return NULL, so it makes
more sense to report a proper error message if it doesn't return the
expected value, and while we're at it, have that error message
whatever message was helpfully left in fxp_error() by
sftp_find_request when it failed.
To do this, I've written a centralised function in psftp.c called
sftp_wait_for_reply, which is handed a request that's just been sent
out and deals with the mechanics of waiting for its reply, returning
the reply when it arrives, and aborting with a sensible error if
anything else arrives instead. The numerous sites in psftp.c which
called sftp_find_request have all been rewritten to do this instead,
and as a side effect they now look more sensible. The only other uses
of sftp_find_request were in xfer_*load_gotpkt, which had to be
tweaked in its own way.
While I'm here, also fix memory management in sftp_find_request, which
was freeing its input packet on some but not all error return paths.
[originally from svn r9894]
2013-07-06 20:43:21 +00:00
|
|
|
struct sftp_request *req;
|
2005-01-01 12:34:32 +00:00
|
|
|
int result;
|
|
|
|
unsigned oldperms, newperms;
|
|
|
|
struct sftp_context_chmod *ctx = (struct sftp_context_chmod *)vctx;
|
|
|
|
|
Clean up handling of the return value from sftp_find_request. In many
places we simply enforce by assertion that it will match the request
we sent out a moment ago: in fact it can also return NULL, so it makes
more sense to report a proper error message if it doesn't return the
expected value, and while we're at it, have that error message
whatever message was helpfully left in fxp_error() by
sftp_find_request when it failed.
To do this, I've written a centralised function in psftp.c called
sftp_wait_for_reply, which is handed a request that's just been sent
out and deals with the mechanics of waiting for its reply, returning
the reply when it arrives, and aborting with a sensible error if
anything else arrives instead. The numerous sites in psftp.c which
called sftp_find_request have all been rewritten to do this instead,
and as a side effect they now look more sensible. The only other uses
of sftp_find_request were in xfer_*load_gotpkt, which had to be
tweaked in its own way.
While I'm here, also fix memory management in sftp_find_request, which
was freeing its input packet on some but not all error return paths.
[originally from svn r9894]
2013-07-06 20:43:21 +00:00
|
|
|
req = fxp_stat_send(fname);
|
|
|
|
pktin = sftp_wait_for_reply(req);
|
|
|
|
result = fxp_stat_recv(pktin, req, &attrs);
|
2003-06-29 14:26:09 +00:00
|
|
|
|
2005-01-01 12:34:32 +00:00
|
|
|
if (!result || !(attrs.flags & SSH_FILEXFER_ATTR_PERMISSIONS)) {
|
|
|
|
printf("get attrs for %s: %s\n", fname,
|
|
|
|
result ? "file permissions not provided" : fxp_error());
|
|
|
|
return 0;
|
|
|
|
}
|
2001-08-26 11:35:11 +00:00
|
|
|
|
2005-01-01 12:34:32 +00:00
|
|
|
attrs.flags = SSH_FILEXFER_ATTR_PERMISSIONS; /* perms _only_ */
|
|
|
|
oldperms = attrs.permissions & 07777;
|
|
|
|
attrs.permissions &= ~ctx->attrs_clr;
|
|
|
|
attrs.permissions ^= ctx->attrs_xor;
|
|
|
|
newperms = attrs.permissions & 07777;
|
2003-06-29 14:26:09 +00:00
|
|
|
|
2005-01-01 12:34:32 +00:00
|
|
|
if (oldperms == newperms)
|
|
|
|
return 1; /* no need to do anything! */
|
2003-06-29 14:26:09 +00:00
|
|
|
|
Clean up handling of the return value from sftp_find_request. In many
places we simply enforce by assertion that it will match the request
we sent out a moment ago: in fact it can also return NULL, so it makes
more sense to report a proper error message if it doesn't return the
expected value, and while we're at it, have that error message
whatever message was helpfully left in fxp_error() by
sftp_find_request when it failed.
To do this, I've written a centralised function in psftp.c called
sftp_wait_for_reply, which is handed a request that's just been sent
out and deals with the mechanics of waiting for its reply, returning
the reply when it arrives, and aborting with a sensible error if
anything else arrives instead. The numerous sites in psftp.c which
called sftp_find_request have all been rewritten to do this instead,
and as a side effect they now look more sensible. The only other uses
of sftp_find_request were in xfer_*load_gotpkt, which had to be
tweaked in its own way.
While I'm here, also fix memory management in sftp_find_request, which
was freeing its input packet on some but not all error return paths.
[originally from svn r9894]
2013-07-06 20:43:21 +00:00
|
|
|
req = fxp_setstat_send(fname, attrs);
|
|
|
|
pktin = sftp_wait_for_reply(req);
|
|
|
|
result = fxp_setstat_recv(pktin, req);
|
2003-06-29 14:26:09 +00:00
|
|
|
|
2005-01-01 12:34:32 +00:00
|
|
|
if (!result) {
|
|
|
|
printf("set attrs for %s: %s\n", fname, fxp_error());
|
|
|
|
return 0;
|
2001-08-26 11:35:11 +00:00
|
|
|
}
|
|
|
|
|
2005-01-01 12:34:32 +00:00
|
|
|
printf("%s: %04o -> %04o\n", fname, oldperms, newperms);
|
|
|
|
|
2001-12-13 19:26:51 +00:00
|
|
|
return 1;
|
2001-08-04 14:19:51 +00:00
|
|
|
}
|
|
|
|
|
2001-08-26 11:35:11 +00:00
|
|
|
int sftp_cmd_chmod(struct sftp_command *cmd)
|
|
|
|
{
|
2005-01-01 12:34:32 +00:00
|
|
|
char *mode;
|
|
|
|
int i, ret;
|
|
|
|
struct sftp_context_chmod actx, *ctx = &actx;
|
2001-08-26 11:35:11 +00:00
|
|
|
|
2018-09-11 15:23:38 +00:00
|
|
|
if (!backend) {
|
2005-01-01 16:43:19 +00:00
|
|
|
not_connected();
|
2001-12-13 18:42:34 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2001-08-26 11:35:11 +00:00
|
|
|
if (cmd->nwords < 3) {
|
|
|
|
printf("chmod: expects a mode specifier and a filename\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Attempt to parse the mode specifier in cmd->words[1]. We
|
|
|
|
* don't support the full horror of Unix chmod; instead we
|
|
|
|
* support a much simpler syntax in which the user can either
|
|
|
|
* specify an octal number, or a comma-separated sequence of
|
|
|
|
* [ugoa]*[-+=][rwxst]+. (The initial [ugoa] sequence may
|
|
|
|
* _only_ be omitted if the only attribute mentioned is t,
|
|
|
|
* since all others require a user/group/other specification.
|
|
|
|
* Additionally, the s attribute may not be specified for any
|
|
|
|
* [ugoa] specifications other than exactly u or exactly g.
|
|
|
|
*/
|
2005-01-01 12:34:32 +00:00
|
|
|
ctx->attrs_clr = ctx->attrs_xor = 0;
|
2001-08-26 11:35:11 +00:00
|
|
|
mode = cmd->words[1];
|
|
|
|
if (mode[0] >= '0' && mode[0] <= '9') {
|
|
|
|
if (mode[strspn(mode, "01234567")]) {
|
|
|
|
printf("chmod: numeric file modes should"
|
|
|
|
" contain digits 0-7 only\n");
|
|
|
|
return 0;
|
|
|
|
}
|
2005-01-01 12:34:32 +00:00
|
|
|
ctx->attrs_clr = 07777;
|
|
|
|
sscanf(mode, "%o", &ctx->attrs_xor);
|
|
|
|
ctx->attrs_xor &= ctx->attrs_clr;
|
2001-08-26 11:35:11 +00:00
|
|
|
} else {
|
|
|
|
while (*mode) {
|
|
|
|
char *modebegin = mode;
|
|
|
|
unsigned subset, perms;
|
|
|
|
int action;
|
|
|
|
|
|
|
|
subset = 0;
|
|
|
|
while (*mode && *mode != ',' &&
|
|
|
|
*mode != '+' && *mode != '-' && *mode != '=') {
|
|
|
|
switch (*mode) {
|
|
|
|
case 'u': subset |= 04700; break; /* setuid, user perms */
|
|
|
|
case 'g': subset |= 02070; break; /* setgid, group perms */
|
|
|
|
case 'o': subset |= 00007; break; /* just other perms */
|
|
|
|
case 'a': subset |= 06777; break; /* all of the above */
|
|
|
|
default:
|
|
|
|
printf("chmod: file mode '%.*s' contains unrecognised"
|
|
|
|
" user/group/other specifier '%c'\n",
|
2003-08-24 13:22:17 +00:00
|
|
|
(int)strcspn(modebegin, ","), modebegin, *mode);
|
2001-08-26 11:35:11 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
mode++;
|
|
|
|
}
|
|
|
|
if (!*mode || *mode == ',') {
|
|
|
|
printf("chmod: file mode '%.*s' is incomplete\n",
|
2003-08-24 13:22:17 +00:00
|
|
|
(int)strcspn(modebegin, ","), modebegin);
|
2001-08-26 11:35:11 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
action = *mode++;
|
|
|
|
if (!*mode || *mode == ',') {
|
|
|
|
printf("chmod: file mode '%.*s' is incomplete\n",
|
2003-08-24 13:22:17 +00:00
|
|
|
(int)strcspn(modebegin, ","), modebegin);
|
2001-08-26 11:35:11 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
perms = 0;
|
|
|
|
while (*mode && *mode != ',') {
|
|
|
|
switch (*mode) {
|
|
|
|
case 'r': perms |= 00444; break;
|
|
|
|
case 'w': perms |= 00222; break;
|
|
|
|
case 'x': perms |= 00111; break;
|
|
|
|
case 't': perms |= 01000; subset |= 01000; break;
|
|
|
|
case 's':
|
|
|
|
if ((subset & 06777) != 04700 &&
|
|
|
|
(subset & 06777) != 02070) {
|
|
|
|
printf("chmod: file mode '%.*s': set[ug]id bit should"
|
|
|
|
" be used with exactly one of u or g only\n",
|
2003-08-24 13:22:17 +00:00
|
|
|
(int)strcspn(modebegin, ","), modebegin);
|
2001-08-26 11:35:11 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
perms |= 06000;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
printf("chmod: file mode '%.*s' contains unrecognised"
|
|
|
|
" permission specifier '%c'\n",
|
2003-08-24 13:22:17 +00:00
|
|
|
(int)strcspn(modebegin, ","), modebegin, *mode);
|
2001-08-26 11:35:11 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
mode++;
|
|
|
|
}
|
|
|
|
if (!(subset & 06777) && (perms &~ subset)) {
|
|
|
|
printf("chmod: file mode '%.*s' contains no user/group/other"
|
|
|
|
" specifier and permissions other than 't' \n",
|
2003-08-24 13:22:17 +00:00
|
|
|
(int)strcspn(modebegin, ","), modebegin);
|
2001-08-26 11:35:11 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
perms &= subset;
|
|
|
|
switch (action) {
|
|
|
|
case '+':
|
2005-01-01 12:34:32 +00:00
|
|
|
ctx->attrs_clr |= perms;
|
|
|
|
ctx->attrs_xor |= perms;
|
2001-08-26 11:35:11 +00:00
|
|
|
break;
|
|
|
|
case '-':
|
2005-01-01 12:34:32 +00:00
|
|
|
ctx->attrs_clr |= perms;
|
|
|
|
ctx->attrs_xor &= ~perms;
|
2001-08-26 11:35:11 +00:00
|
|
|
break;
|
|
|
|
case '=':
|
2005-01-01 12:34:32 +00:00
|
|
|
ctx->attrs_clr |= subset;
|
|
|
|
ctx->attrs_xor |= perms;
|
2001-08-26 11:35:11 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (*mode) mode++; /* eat comma */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-01-01 12:34:32 +00:00
|
|
|
ret = 1;
|
|
|
|
for (i = 2; i < cmd->nwords; i++)
|
|
|
|
ret &= wildcard_iterate(cmd->words[i], sftp_action_chmod, ctx);
|
2001-08-26 11:35:11 +00:00
|
|
|
|
2005-01-01 12:34:32 +00:00
|
|
|
return ret;
|
2001-08-26 11:35:11 +00:00
|
|
|
}
|
2001-08-04 14:19:51 +00:00
|
|
|
|
2001-12-13 18:42:34 +00:00
|
|
|
static int sftp_cmd_open(struct sftp_command *cmd)
|
|
|
|
{
|
2004-01-21 19:56:08 +00:00
|
|
|
int portnumber;
|
|
|
|
|
2018-09-11 15:23:38 +00:00
|
|
|
if (backend) {
|
2001-12-13 18:42:34 +00:00
|
|
|
printf("psftp: already connected\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cmd->nwords < 2) {
|
|
|
|
printf("open: expects a host name\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2004-01-21 19:56:08 +00:00
|
|
|
if (cmd->nwords > 2) {
|
|
|
|
portnumber = atoi(cmd->words[2]);
|
|
|
|
if (portnumber == 0) {
|
|
|
|
printf("open: invalid port number\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
portnumber = 0;
|
|
|
|
|
|
|
|
if (psftp_connect(cmd->words[1], NULL, portnumber)) {
|
2018-09-11 15:23:38 +00:00
|
|
|
backend = NULL; /* connection is already closed */
|
2001-12-13 18:42:34 +00:00
|
|
|
return -1; /* this is fatal */
|
|
|
|
}
|
|
|
|
do_sftp_init();
|
2001-12-13 19:26:51 +00:00
|
|
|
return 1;
|
2001-12-13 18:42:34 +00:00
|
|
|
}
|
|
|
|
|
2001-12-16 13:33:04 +00:00
|
|
|
static int sftp_cmd_lcd(struct sftp_command *cmd)
|
|
|
|
{
|
2003-08-24 12:47:46 +00:00
|
|
|
char *currdir, *errmsg;
|
2001-12-16 13:33:04 +00:00
|
|
|
|
|
|
|
if (cmd->nwords < 2) {
|
|
|
|
printf("lcd: expects a local directory name\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2003-08-24 12:47:46 +00:00
|
|
|
errmsg = psftp_lcd(cmd->words[1]);
|
|
|
|
if (errmsg) {
|
|
|
|
printf("lcd: unable to change directory: %s\n", errmsg);
|
|
|
|
sfree(errmsg);
|
2001-12-16 13:33:04 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2003-08-24 12:47:46 +00:00
|
|
|
currdir = psftp_getcwd();
|
2001-12-16 13:33:04 +00:00
|
|
|
printf("New local directory is %s\n", currdir);
|
|
|
|
sfree(currdir);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int sftp_cmd_lpwd(struct sftp_command *cmd)
|
|
|
|
{
|
|
|
|
char *currdir;
|
|
|
|
|
2003-08-24 12:47:46 +00:00
|
|
|
currdir = psftp_getcwd();
|
2001-12-16 13:33:04 +00:00
|
|
|
printf("Current local directory is %s\n", currdir);
|
|
|
|
sfree(currdir);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int sftp_cmd_pling(struct sftp_command *cmd)
|
|
|
|
{
|
|
|
|
int exitcode;
|
|
|
|
|
|
|
|
exitcode = system(cmd->words[1]);
|
|
|
|
return (exitcode == 0);
|
|
|
|
}
|
|
|
|
|
2001-09-09 16:29:51 +00:00
|
|
|
static int sftp_cmd_help(struct sftp_command *cmd);
|
|
|
|
|
2001-02-23 18:21:44 +00:00
|
|
|
static struct sftp_cmd_lookup {
|
2015-05-15 10:15:42 +00:00
|
|
|
const char *name;
|
2001-09-09 16:29:51 +00:00
|
|
|
/*
|
|
|
|
* For help purposes, there are two kinds of command:
|
|
|
|
*
|
|
|
|
* - primary commands, in which `longhelp' is non-NULL. In
|
|
|
|
* this case `shorthelp' is descriptive text, and `longhelp'
|
|
|
|
* is longer descriptive text intended to be printed after
|
|
|
|
* the command name.
|
|
|
|
*
|
|
|
|
* - alias commands, in which `longhelp' is NULL. In this case
|
|
|
|
* `shorthelp' is the name of a primary command, which
|
|
|
|
* contains the help that should double up for this command.
|
|
|
|
*/
|
2001-12-16 13:33:04 +00:00
|
|
|
int listed; /* do we list this in primary help? */
|
2015-05-15 10:15:42 +00:00
|
|
|
const char *shorthelp;
|
|
|
|
const char *longhelp;
|
2001-05-06 14:35:20 +00:00
|
|
|
int (*obey) (struct sftp_command *);
|
2001-02-23 18:21:44 +00:00
|
|
|
} sftp_lookup[] = {
|
|
|
|
/*
|
|
|
|
* List of sftp commands. This is binary-searched so it MUST be
|
|
|
|
* in ASCII order.
|
|
|
|
*/
|
2001-05-06 14:35:20 +00:00
|
|
|
{
|
2003-08-24 12:47:46 +00:00
|
|
|
"!", TRUE, "run a local command",
|
2001-12-16 13:33:04 +00:00
|
|
|
"<command>\n"
|
2003-08-24 12:47:46 +00:00
|
|
|
/* FIXME: this example is crap for non-Windows. */
|
|
|
|
" Runs a local command. For example, \"!del myfile\".\n",
|
2001-12-16 13:33:04 +00:00
|
|
|
sftp_cmd_pling
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"bye", TRUE, "finish your SFTP session",
|
2001-09-09 16:29:51 +00:00
|
|
|
"\n"
|
|
|
|
" Terminates your SFTP session and quits the PSFTP program.\n",
|
|
|
|
sftp_cmd_quit
|
|
|
|
},
|
|
|
|
{
|
2001-12-16 13:33:04 +00:00
|
|
|
"cd", TRUE, "change your remote working directory",
|
2005-01-01 16:16:13 +00:00
|
|
|
" [ <new working directory> ]\n"
|
2001-09-09 16:29:51 +00:00
|
|
|
" Change the remote working directory for your SFTP session.\n"
|
|
|
|
" If a new working directory is not supplied, you will be\n"
|
|
|
|
" returned to your home directory.\n",
|
|
|
|
sftp_cmd_cd
|
|
|
|
},
|
|
|
|
{
|
2001-12-16 13:33:04 +00:00
|
|
|
"chmod", TRUE, "change file permissions and modes",
|
2005-01-01 16:16:13 +00:00
|
|
|
" <modes> <filename-or-wildcard> [ <filename-or-wildcard>... ]\n"
|
|
|
|
" Change the file permissions on one or more remote files or\n"
|
|
|
|
" directories.\n"
|
|
|
|
" <modes> can be any octal Unix permission specifier.\n"
|
|
|
|
" Alternatively, <modes> can include the following modifiers:\n"
|
2001-09-09 16:29:51 +00:00
|
|
|
" u+r make file readable by owning user\n"
|
|
|
|
" u+w make file writable by owning user\n"
|
|
|
|
" u+x make file executable by owning user\n"
|
|
|
|
" u-r make file not readable by owning user\n"
|
|
|
|
" [also u-w, u-x]\n"
|
|
|
|
" g+r make file readable by members of owning group\n"
|
|
|
|
" [also g+w, g+x, g-r, g-w, g-x]\n"
|
|
|
|
" o+r make file readable by all other users\n"
|
|
|
|
" [also o+w, o+x, o-r, o-w, o-x]\n"
|
|
|
|
" a+r make file readable by absolutely everybody\n"
|
|
|
|
" [also a+w, a+x, a-r, a-w, a-x]\n"
|
|
|
|
" u+s enable the Unix set-user-ID bit\n"
|
|
|
|
" u-s disable the Unix set-user-ID bit\n"
|
|
|
|
" g+s enable the Unix set-group-ID bit\n"
|
|
|
|
" g-s disable the Unix set-group-ID bit\n"
|
|
|
|
" +t enable the Unix \"sticky bit\"\n"
|
|
|
|
" You can give more than one modifier for the same user (\"g-rwx\"), and\n"
|
|
|
|
" more than one user for the same modifier (\"ug+w\"). You can\n"
|
|
|
|
" use commas to separate different modifiers (\"u+rwx,g+s\").\n",
|
|
|
|
sftp_cmd_chmod
|
|
|
|
},
|
2004-12-16 19:19:59 +00:00
|
|
|
{
|
|
|
|
"close", TRUE, "finish your SFTP session but do not quit PSFTP",
|
|
|
|
"\n"
|
|
|
|
" Terminates your SFTP session, but does not quit the PSFTP\n"
|
|
|
|
" program. You can then use \"open\" to start another SFTP\n"
|
|
|
|
" session, to the same server or to a different one.\n",
|
|
|
|
sftp_cmd_close
|
|
|
|
},
|
2001-09-09 16:29:51 +00:00
|
|
|
{
|
2005-01-01 16:16:13 +00:00
|
|
|
"del", TRUE, "delete files on the remote server",
|
|
|
|
" <filename-or-wildcard> [ <filename-or-wildcard>... ]\n"
|
|
|
|
" Delete a file or files from the server.\n",
|
2001-09-09 16:29:51 +00:00
|
|
|
sftp_cmd_rm
|
|
|
|
},
|
|
|
|
{
|
2001-12-16 13:33:04 +00:00
|
|
|
"delete", FALSE, "del", NULL, sftp_cmd_rm
|
2001-09-09 16:29:51 +00:00
|
|
|
},
|
|
|
|
{
|
2005-01-01 16:16:13 +00:00
|
|
|
"dir", TRUE, "list remote files",
|
2004-12-17 12:15:17 +00:00
|
|
|
" [ <directory-name> ]/[ <wildcard> ]\n"
|
2001-09-09 16:29:51 +00:00
|
|
|
" List the contents of a specified directory on the server.\n"
|
|
|
|
" If <directory-name> is not given, the current working directory\n"
|
2004-12-17 12:15:17 +00:00
|
|
|
" is assumed.\n"
|
|
|
|
" If <wildcard> is given, it is treated as a set of files to\n"
|
|
|
|
" list; otherwise, all files are listed.\n",
|
2001-09-09 16:29:51 +00:00
|
|
|
sftp_cmd_ls
|
|
|
|
},
|
|
|
|
{
|
2001-12-16 13:33:04 +00:00
|
|
|
"exit", TRUE, "bye", NULL, sftp_cmd_quit
|
2001-09-09 16:29:51 +00:00
|
|
|
},
|
|
|
|
{
|
2001-12-16 13:33:04 +00:00
|
|
|
"get", TRUE, "download a file from the server to your local machine",
|
2004-12-17 12:15:17 +00:00
|
|
|
" [ -r ] [ -- ] <filename> [ <local-filename> ]\n"
|
2001-09-09 16:29:51 +00:00
|
|
|
" Downloads a file on the server and stores it locally under\n"
|
|
|
|
" the same name, or under a different one if you supply the\n"
|
2004-12-17 12:15:17 +00:00
|
|
|
" argument <local-filename>.\n"
|
|
|
|
" If -r specified, recursively fetch a directory.\n",
|
2001-09-09 16:29:51 +00:00
|
|
|
sftp_cmd_get
|
|
|
|
},
|
|
|
|
{
|
2001-12-16 13:33:04 +00:00
|
|
|
"help", TRUE, "give help",
|
2001-09-09 16:29:51 +00:00
|
|
|
" [ <command> [ <command> ... ] ]\n"
|
|
|
|
" Give general help if no commands are specified.\n"
|
|
|
|
" If one or more commands are specified, give specific help on\n"
|
|
|
|
" those particular commands.\n",
|
|
|
|
sftp_cmd_help
|
|
|
|
},
|
|
|
|
{
|
2001-12-16 13:33:04 +00:00
|
|
|
"lcd", TRUE, "change local working directory",
|
|
|
|
" <local-directory-name>\n"
|
|
|
|
" Change the local working directory of the PSFTP program (the\n"
|
|
|
|
" default location where the \"get\" command will save files).\n",
|
|
|
|
sftp_cmd_lcd
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"lpwd", TRUE, "print local working directory",
|
|
|
|
"\n"
|
|
|
|
" Print the local working directory of the PSFTP program (the\n"
|
|
|
|
" default location where the \"get\" command will save files).\n",
|
|
|
|
sftp_cmd_lpwd
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"ls", TRUE, "dir", NULL,
|
2001-09-09 16:29:51 +00:00
|
|
|
sftp_cmd_ls
|
|
|
|
},
|
2004-12-16 17:35:20 +00:00
|
|
|
{
|
|
|
|
"mget", TRUE, "download multiple files at once",
|
2004-12-17 12:15:17 +00:00
|
|
|
" [ -r ] [ -- ] <filename-or-wildcard> [ <filename-or-wildcard>... ]\n"
|
2004-12-16 17:35:20 +00:00
|
|
|
" Downloads many files from the server, storing each one under\n"
|
|
|
|
" the same name it has on the server side. You can use wildcards\n"
|
2004-12-17 12:15:17 +00:00
|
|
|
" such as \"*.c\" to specify lots of files at once.\n"
|
|
|
|
" If -r specified, recursively fetch files and directories.\n",
|
2004-12-16 17:35:20 +00:00
|
|
|
sftp_cmd_mget
|
|
|
|
},
|
2001-09-09 16:29:51 +00:00
|
|
|
{
|
2005-01-01 16:16:13 +00:00
|
|
|
"mkdir", TRUE, "create directories on the remote server",
|
|
|
|
" <directory-name> [ <directory-name>... ]\n"
|
|
|
|
" Creates directories with the given names on the server.\n",
|
2001-09-09 16:29:51 +00:00
|
|
|
sftp_cmd_mkdir
|
|
|
|
},
|
2004-12-16 17:35:20 +00:00
|
|
|
{
|
|
|
|
"mput", TRUE, "upload multiple files at once",
|
2004-12-18 10:46:21 +00:00
|
|
|
" [ -r ] [ -- ] <filename-or-wildcard> [ <filename-or-wildcard>... ]\n"
|
2004-12-16 17:35:20 +00:00
|
|
|
" Uploads many files to the server, storing each one under the\n"
|
|
|
|
" same name it has on the client side. You can use wildcards\n"
|
2004-12-17 12:15:17 +00:00
|
|
|
" such as \"*.c\" to specify lots of files at once.\n"
|
|
|
|
" If -r specified, recursively store files and directories.\n",
|
2004-12-16 17:35:20 +00:00
|
|
|
sftp_cmd_mput
|
|
|
|
},
|
2001-09-09 16:29:51 +00:00
|
|
|
{
|
2005-01-01 16:16:13 +00:00
|
|
|
"mv", TRUE, "move or rename file(s) on the remote server",
|
|
|
|
" <source> [ <source>... ] <destination>\n"
|
|
|
|
" Moves or renames <source>(s) on the server to <destination>,\n"
|
|
|
|
" also on the server.\n"
|
|
|
|
" If <destination> specifies an existing directory, then <source>\n"
|
|
|
|
" may be a wildcard, and multiple <source>s may be given; all\n"
|
|
|
|
" source files are moved into <destination>.\n"
|
|
|
|
" Otherwise, <source> must specify a single file, which is moved\n"
|
|
|
|
" or renamed so that it is accessible under the name <destination>.\n",
|
2001-09-09 16:29:51 +00:00
|
|
|
sftp_cmd_mv
|
|
|
|
},
|
2001-12-13 18:42:34 +00:00
|
|
|
{
|
2001-12-16 13:33:04 +00:00
|
|
|
"open", TRUE, "connect to a host",
|
2004-01-21 19:56:08 +00:00
|
|
|
" [<user>@]<hostname> [<port>]\n"
|
2001-12-13 18:42:34 +00:00
|
|
|
" Establishes an SFTP connection to a given host. Only usable\n"
|
2005-01-01 16:16:13 +00:00
|
|
|
" when you are not already connected to a server.\n",
|
2001-12-13 18:42:34 +00:00
|
|
|
sftp_cmd_open
|
|
|
|
},
|
2001-12-19 18:49:32 +00:00
|
|
|
{
|
|
|
|
"put", TRUE, "upload a file from your local machine to the server",
|
2004-12-17 12:15:17 +00:00
|
|
|
" [ -r ] [ -- ] <filename> [ <remote-filename> ]\n"
|
2001-12-19 18:49:32 +00:00
|
|
|
" Uploads a file to the server and stores it there under\n"
|
|
|
|
" the same name, or under a different one if you supply the\n"
|
2004-12-17 12:15:17 +00:00
|
|
|
" argument <remote-filename>.\n"
|
|
|
|
" If -r specified, recursively store a directory.\n",
|
2001-12-19 18:49:32 +00:00
|
|
|
sftp_cmd_put
|
|
|
|
},
|
2001-09-09 16:31:26 +00:00
|
|
|
{
|
2001-12-16 13:33:04 +00:00
|
|
|
"pwd", TRUE, "print your remote working directory",
|
2001-09-09 16:31:26 +00:00
|
|
|
"\n"
|
|
|
|
" Print the current remote working directory for your SFTP session.\n",
|
|
|
|
sftp_cmd_pwd
|
|
|
|
},
|
2001-09-09 16:29:51 +00:00
|
|
|
{
|
2001-12-16 13:33:04 +00:00
|
|
|
"quit", TRUE, "bye", NULL,
|
2001-09-09 16:29:51 +00:00
|
|
|
sftp_cmd_quit
|
|
|
|
},
|
|
|
|
{
|
2005-01-01 16:16:13 +00:00
|
|
|
"reget", TRUE, "continue downloading files",
|
2004-12-17 12:15:17 +00:00
|
|
|
" [ -r ] [ -- ] <filename> [ <local-filename> ]\n"
|
2001-09-09 16:29:51 +00:00
|
|
|
" Works exactly like the \"get\" command, but the local file\n"
|
|
|
|
" must already exist. The download will begin at the end of the\n"
|
2004-12-17 12:15:17 +00:00
|
|
|
" file. This is for resuming a download that was interrupted.\n"
|
|
|
|
" If -r specified, resume interrupted \"get -r\".\n",
|
2001-09-09 16:29:51 +00:00
|
|
|
sftp_cmd_reget
|
|
|
|
},
|
|
|
|
{
|
2001-12-16 13:33:04 +00:00
|
|
|
"ren", TRUE, "mv", NULL,
|
2001-09-09 16:29:51 +00:00
|
|
|
sftp_cmd_mv
|
|
|
|
},
|
|
|
|
{
|
2001-12-16 13:33:04 +00:00
|
|
|
"rename", FALSE, "mv", NULL,
|
2001-09-09 16:29:51 +00:00
|
|
|
sftp_cmd_mv
|
|
|
|
},
|
|
|
|
{
|
2005-01-01 16:16:13 +00:00
|
|
|
"reput", TRUE, "continue uploading files",
|
2004-12-17 12:15:17 +00:00
|
|
|
" [ -r ] [ -- ] <filename> [ <remote-filename> ]\n"
|
2001-09-09 16:29:51 +00:00
|
|
|
" Works exactly like the \"put\" command, but the remote file\n"
|
|
|
|
" must already exist. The upload will begin at the end of the\n"
|
2004-12-17 12:15:17 +00:00
|
|
|
" file. This is for resuming an upload that was interrupted.\n"
|
|
|
|
" If -r specified, resume interrupted \"put -r\".\n",
|
2001-09-09 16:29:51 +00:00
|
|
|
sftp_cmd_reput
|
|
|
|
},
|
|
|
|
{
|
2001-12-16 13:33:04 +00:00
|
|
|
"rm", TRUE, "del", NULL,
|
2001-09-09 16:29:51 +00:00
|
|
|
sftp_cmd_rm
|
|
|
|
},
|
|
|
|
{
|
2005-01-01 16:16:13 +00:00
|
|
|
"rmdir", TRUE, "remove directories on the remote server",
|
|
|
|
" <directory-name> [ <directory-name>... ]\n"
|
2001-09-09 16:29:51 +00:00
|
|
|
" Removes the directory with the given name on the server.\n"
|
2005-01-01 16:16:13 +00:00
|
|
|
" The directory will not be removed unless it is empty.\n"
|
|
|
|
" Wildcards may be used to specify multiple directories.\n",
|
2001-09-09 16:29:51 +00:00
|
|
|
sftp_cmd_rmdir
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2015-05-15 10:15:42 +00:00
|
|
|
const struct sftp_cmd_lookup *lookup_command(const char *name)
|
2001-09-09 16:29:51 +00:00
|
|
|
{
|
|
|
|
int i, j, k, cmp;
|
|
|
|
|
|
|
|
i = -1;
|
|
|
|
j = sizeof(sftp_lookup) / sizeof(*sftp_lookup);
|
|
|
|
while (j - i > 1) {
|
|
|
|
k = (j + i) / 2;
|
|
|
|
cmp = strcmp(name, sftp_lookup[k].name);
|
|
|
|
if (cmp < 0)
|
|
|
|
j = k;
|
|
|
|
else if (cmp > 0)
|
|
|
|
i = k;
|
|
|
|
else {
|
|
|
|
return &sftp_lookup[k];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int sftp_cmd_help(struct sftp_command *cmd)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
if (cmd->nwords == 1) {
|
|
|
|
/*
|
|
|
|
* Give short help on each command.
|
|
|
|
*/
|
|
|
|
int maxlen;
|
|
|
|
maxlen = 0;
|
|
|
|
for (i = 0; i < sizeof(sftp_lookup) / sizeof(*sftp_lookup); i++) {
|
2001-12-16 13:33:04 +00:00
|
|
|
int len;
|
|
|
|
if (!sftp_lookup[i].listed)
|
|
|
|
continue;
|
|
|
|
len = strlen(sftp_lookup[i].name);
|
2001-09-09 16:29:51 +00:00
|
|
|
if (maxlen < len)
|
|
|
|
maxlen = len;
|
|
|
|
}
|
|
|
|
for (i = 0; i < sizeof(sftp_lookup) / sizeof(*sftp_lookup); i++) {
|
|
|
|
const struct sftp_cmd_lookup *lookup;
|
2001-12-16 13:33:04 +00:00
|
|
|
if (!sftp_lookup[i].listed)
|
|
|
|
continue;
|
2001-09-09 16:29:51 +00:00
|
|
|
lookup = &sftp_lookup[i];
|
|
|
|
printf("%-*s", maxlen+2, lookup->name);
|
|
|
|
if (lookup->longhelp == NULL)
|
|
|
|
lookup = lookup_command(lookup->shorthelp);
|
|
|
|
printf("%s\n", lookup->shorthelp);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* Give long help on specific commands.
|
|
|
|
*/
|
|
|
|
for (i = 1; i < cmd->nwords; i++) {
|
|
|
|
const struct sftp_cmd_lookup *lookup;
|
|
|
|
lookup = lookup_command(cmd->words[i]);
|
|
|
|
if (!lookup) {
|
|
|
|
printf("help: %s: command not found\n", cmd->words[i]);
|
|
|
|
} else {
|
|
|
|
printf("%s", lookup->name);
|
|
|
|
if (lookup->longhelp == NULL)
|
|
|
|
lookup = lookup_command(lookup->shorthelp);
|
|
|
|
printf("%s", lookup->longhelp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2001-12-13 19:26:51 +00:00
|
|
|
return 1;
|
2001-09-09 16:29:51 +00:00
|
|
|
}
|
2001-02-23 18:21:44 +00:00
|
|
|
|
|
|
|
/* ----------------------------------------------------------------------
|
|
|
|
* Command line reading and parsing.
|
|
|
|
*/
|
2001-08-04 14:19:51 +00:00
|
|
|
struct sftp_command *sftp_getcmd(FILE *fp, int mode, int modeflags)
|
2001-05-06 14:35:20 +00:00
|
|
|
{
|
2001-02-23 18:21:44 +00:00
|
|
|
char *line;
|
|
|
|
struct sftp_command *cmd;
|
|
|
|
char *p, *q, *r;
|
|
|
|
int quoting;
|
|
|
|
|
2003-03-29 16:14:26 +00:00
|
|
|
cmd = snew(struct sftp_command);
|
2001-02-23 18:21:44 +00:00
|
|
|
cmd->words = NULL;
|
|
|
|
cmd->nwords = 0;
|
|
|
|
cmd->wordssize = 0;
|
|
|
|
|
|
|
|
line = NULL;
|
2004-11-27 13:20:21 +00:00
|
|
|
|
|
|
|
if (fp) {
|
|
|
|
if (modeflags & 1)
|
|
|
|
printf("psftp> ");
|
|
|
|
line = fgetline(fp);
|
|
|
|
} else {
|
2018-09-11 15:23:38 +00:00
|
|
|
line = ssh_sftp_get_cmdline("psftp> ", !backend);
|
2001-02-23 18:21:44 +00:00
|
|
|
}
|
2004-11-27 13:20:21 +00:00
|
|
|
|
|
|
|
if (!line || !*line) {
|
|
|
|
cmd->obey = sftp_cmd_quit;
|
|
|
|
if ((mode == 0) || (modeflags & 1))
|
|
|
|
printf("quit\n");
|
2013-07-14 10:46:07 +00:00
|
|
|
sfree(line);
|
2004-11-27 13:20:21 +00:00
|
|
|
return cmd; /* eof */
|
|
|
|
}
|
|
|
|
|
|
|
|
line[strcspn(line, "\r\n")] = '\0';
|
|
|
|
|
2001-12-13 19:26:51 +00:00
|
|
|
if (modeflags & 1) {
|
|
|
|
printf("%s\n", line);
|
|
|
|
}
|
2001-02-23 18:21:44 +00:00
|
|
|
|
|
|
|
p = line;
|
2001-12-16 13:33:04 +00:00
|
|
|
while (*p && (*p == ' ' || *p == '\t'))
|
|
|
|
p++;
|
|
|
|
|
|
|
|
if (*p == '!') {
|
|
|
|
/*
|
|
|
|
* Special case: the ! command. This is always parsed as
|
|
|
|
* exactly two words: one containing the !, and the second
|
|
|
|
* containing everything else on the line.
|
|
|
|
*/
|
|
|
|
cmd->nwords = cmd->wordssize = 2;
|
2003-03-29 16:14:26 +00:00
|
|
|
cmd->words = sresize(cmd->words, cmd->wordssize, char *);
|
2003-12-19 12:44:46 +00:00
|
|
|
cmd->words[0] = dupstr("!");
|
|
|
|
cmd->words[1] = dupstr(p+1);
|
2008-11-24 18:19:55 +00:00
|
|
|
} else if (*p == '#') {
|
|
|
|
/*
|
|
|
|
* Special case: comment. Entire line is ignored.
|
|
|
|
*/
|
|
|
|
cmd->nwords = cmd->wordssize = 0;
|
2001-12-16 13:33:04 +00:00
|
|
|
} else {
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Parse the command line into words. The syntax is:
|
|
|
|
* - double quotes are removed, but cause spaces within to be
|
|
|
|
* treated as non-separating.
|
|
|
|
* - a double-doublequote pair is a literal double quote, inside
|
|
|
|
* _or_ outside quotes. Like this:
|
|
|
|
*
|
|
|
|
* firstword "second word" "this has ""quotes"" in" and""this""
|
|
|
|
*
|
|
|
|
* becomes
|
|
|
|
*
|
|
|
|
* >firstword<
|
|
|
|
* >second word<
|
|
|
|
* >this has "quotes" in<
|
|
|
|
* >and"this"<
|
|
|
|
*/
|
2012-08-22 18:36:44 +00:00
|
|
|
while (1) {
|
2001-12-16 13:33:04 +00:00
|
|
|
/* skip whitespace */
|
|
|
|
while (*p && (*p == ' ' || *p == '\t'))
|
|
|
|
p++;
|
2012-08-22 18:36:44 +00:00
|
|
|
/* terminate loop */
|
|
|
|
if (!*p)
|
|
|
|
break;
|
2001-12-16 13:33:04 +00:00
|
|
|
/* mark start of word */
|
|
|
|
q = r = p; /* q sits at start, r writes word */
|
|
|
|
quoting = 0;
|
|
|
|
while (*p) {
|
|
|
|
if (!quoting && (*p == ' ' || *p == '\t'))
|
|
|
|
break; /* reached end of word */
|
|
|
|
else if (*p == '"' && p[1] == '"')
|
|
|
|
p += 2, *r++ = '"'; /* a literal quote */
|
|
|
|
else if (*p == '"')
|
|
|
|
p++, quoting = !quoting;
|
|
|
|
else
|
|
|
|
*r++ = *p++;
|
|
|
|
}
|
|
|
|
if (*p)
|
|
|
|
p++; /* skip over the whitespace */
|
|
|
|
*r = '\0';
|
|
|
|
if (cmd->nwords >= cmd->wordssize) {
|
|
|
|
cmd->wordssize = cmd->nwords + 16;
|
2003-03-29 16:14:26 +00:00
|
|
|
cmd->words = sresize(cmd->words, cmd->wordssize, char *);
|
2001-12-16 13:33:04 +00:00
|
|
|
}
|
2003-12-19 12:44:46 +00:00
|
|
|
cmd->words[cmd->nwords++] = dupstr(q);
|
2001-02-23 18:21:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-11-27 13:20:21 +00:00
|
|
|
sfree(line);
|
|
|
|
|
2001-02-23 18:21:44 +00:00
|
|
|
/*
|
|
|
|
* Now parse the first word and assign a function.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (cmd->nwords == 0)
|
|
|
|
cmd->obey = sftp_cmd_null;
|
|
|
|
else {
|
2001-09-09 16:29:51 +00:00
|
|
|
const struct sftp_cmd_lookup *lookup;
|
|
|
|
lookup = lookup_command(cmd->words[0]);
|
|
|
|
if (!lookup)
|
|
|
|
cmd->obey = sftp_cmd_unknown;
|
|
|
|
else
|
|
|
|
cmd->obey = lookup->obey;
|
2001-02-23 18:21:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return cmd;
|
|
|
|
}
|
|
|
|
|
2002-02-27 22:20:30 +00:00
|
|
|
static int do_sftp_init(void)
|
2001-05-06 14:35:20 +00:00
|
|
|
{
|
2003-06-29 14:26:09 +00:00
|
|
|
struct sftp_packet *pktin;
|
Clean up handling of the return value from sftp_find_request. In many
places we simply enforce by assertion that it will match the request
we sent out a moment ago: in fact it can also return NULL, so it makes
more sense to report a proper error message if it doesn't return the
expected value, and while we're at it, have that error message
whatever message was helpfully left in fxp_error() by
sftp_find_request when it failed.
To do this, I've written a centralised function in psftp.c called
sftp_wait_for_reply, which is handed a request that's just been sent
out and deals with the mechanics of waiting for its reply, returning
the reply when it arrives, and aborting with a sensible error if
anything else arrives instead. The numerous sites in psftp.c which
called sftp_find_request have all been rewritten to do this instead,
and as a side effect they now look more sensible. The only other uses
of sftp_find_request were in xfer_*load_gotpkt, which had to be
tweaked in its own way.
While I'm here, also fix memory management in sftp_find_request, which
was freeing its input packet on some but not all error return paths.
[originally from svn r9894]
2013-07-06 20:43:21 +00:00
|
|
|
struct sftp_request *req;
|
2003-06-29 14:26:09 +00:00
|
|
|
|
2001-02-23 18:21:44 +00:00
|
|
|
/*
|
|
|
|
* Do protocol initialisation.
|
|
|
|
*/
|
|
|
|
if (!fxp_init()) {
|
|
|
|
fprintf(stderr,
|
2001-05-06 14:35:20 +00:00
|
|
|
"Fatal: unable to initialise SFTP: %s\n", fxp_error());
|
2002-02-27 22:20:30 +00:00
|
|
|
return 1; /* failure */
|
2001-02-23 18:21:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Find out where our home directory is.
|
|
|
|
*/
|
Clean up handling of the return value from sftp_find_request. In many
places we simply enforce by assertion that it will match the request
we sent out a moment ago: in fact it can also return NULL, so it makes
more sense to report a proper error message if it doesn't return the
expected value, and while we're at it, have that error message
whatever message was helpfully left in fxp_error() by
sftp_find_request when it failed.
To do this, I've written a centralised function in psftp.c called
sftp_wait_for_reply, which is handed a request that's just been sent
out and deals with the mechanics of waiting for its reply, returning
the reply when it arrives, and aborting with a sensible error if
anything else arrives instead. The numerous sites in psftp.c which
called sftp_find_request have all been rewritten to do this instead,
and as a side effect they now look more sensible. The only other uses
of sftp_find_request were in xfer_*load_gotpkt, which had to be
tweaked in its own way.
While I'm here, also fix memory management in sftp_find_request, which
was freeing its input packet on some but not all error return paths.
[originally from svn r9894]
2013-07-06 20:43:21 +00:00
|
|
|
req = fxp_realpath_send(".");
|
|
|
|
pktin = sftp_wait_for_reply(req);
|
|
|
|
homedir = fxp_realpath_recv(pktin, req);
|
2003-06-29 14:26:09 +00:00
|
|
|
|
2001-02-23 18:21:44 +00:00
|
|
|
if (!homedir) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"Warning: failed to resolve home directory: %s\n",
|
|
|
|
fxp_error());
|
|
|
|
homedir = dupstr(".");
|
|
|
|
} else {
|
|
|
|
printf("Remote working directory is %s\n", homedir);
|
|
|
|
}
|
|
|
|
pwd = dupstr(homedir);
|
2002-02-27 22:20:30 +00:00
|
|
|
return 0;
|
2001-12-13 18:42:34 +00:00
|
|
|
}
|
|
|
|
|
2003-12-19 12:44:46 +00:00
|
|
|
void do_sftp_cleanup()
|
|
|
|
{
|
|
|
|
char ch;
|
2018-09-11 15:23:38 +00:00
|
|
|
if (backend) {
|
Rework special-commands system to add an integer argument.
In order to list cross-certifiable host keys in the GUI specials menu,
the SSH backend has been inventing new values on the end of the
Telnet_Special enumeration, starting from the value TS_LOCALSTART.
This is inelegant, and also makes it awkward to break up special
handlers (e.g. to dispatch different specials to different SSH
layers), since if all you know about a special is that it's somewhere
in the TS_LOCALSTART+n space, you can't tell what _general kind_ of
thing it is. Also, if I ever need another open-ended set of specials
in future, I'll have to remember which TS_LOCALSTART+n codes are in
which set.
So here's a revamp that causes every special to take an extra integer
argument. For all previously numbered specials, this argument is
passed as zero and ignored, but there's a new main special code for
SSH host key cross-certification, in which the integer argument is an
index into the backend's list of available keys. TS_LOCALSTART is now
a thing of the past: if I need any other open-ended sets of specials
in future, I can add a new top-level code with a nicely separated
space of arguments.
While I'm at it, I've removed the legacy misnomer 'Telnet_Special'
from the code completely; the enum is now SessionSpecialCode, the
struct containing full details of a menu entry is SessionSpecial, and
the enum values now start SS_ rather than TS_.
2018-09-24 08:35:52 +00:00
|
|
|
backend_special(backend, SS_EOF, 0);
|
2011-09-13 11:44:03 +00:00
|
|
|
sent_eof = TRUE;
|
2004-01-21 19:56:08 +00:00
|
|
|
sftp_recvdata(&ch, 1);
|
2018-09-11 15:23:38 +00:00
|
|
|
backend_free(backend);
|
2004-01-21 19:56:08 +00:00
|
|
|
sftp_cleanup_request();
|
2018-09-11 15:23:38 +00:00
|
|
|
backend = NULL;
|
2004-01-21 19:56:08 +00:00
|
|
|
}
|
2003-12-19 12:44:46 +00:00
|
|
|
if (pwd) {
|
|
|
|
sfree(pwd);
|
|
|
|
pwd = NULL;
|
|
|
|
}
|
|
|
|
if (homedir) {
|
|
|
|
sfree(homedir);
|
|
|
|
homedir = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-25 22:27:16 +00:00
|
|
|
int do_sftp(int mode, int modeflags, char *batchfile)
|
2001-12-13 18:42:34 +00:00
|
|
|
{
|
|
|
|
FILE *fp;
|
2001-12-13 19:26:51 +00:00
|
|
|
int ret;
|
2001-02-23 18:21:44 +00:00
|
|
|
|
2001-08-04 14:19:51 +00:00
|
|
|
/*
|
|
|
|
* Batch mode?
|
2001-02-23 18:21:44 +00:00
|
|
|
*/
|
2001-08-04 14:19:51 +00:00
|
|
|
if (mode == 0) {
|
|
|
|
|
|
|
|
/* ------------------------------------------------------------------
|
|
|
|
* Now we're ready to do Real Stuff.
|
|
|
|
*/
|
|
|
|
while (1) {
|
2001-12-13 19:26:51 +00:00
|
|
|
struct sftp_command *cmd;
|
2004-11-27 13:20:21 +00:00
|
|
|
cmd = sftp_getcmd(NULL, 0, 0);
|
2001-12-13 19:26:51 +00:00
|
|
|
if (!cmd)
|
|
|
|
break;
|
2003-12-19 12:44:46 +00:00
|
|
|
ret = cmd->obey(cmd);
|
|
|
|
if (cmd->words) {
|
|
|
|
int i;
|
|
|
|
for(i = 0; i < cmd->nwords; i++)
|
|
|
|
sfree(cmd->words[i]);
|
|
|
|
sfree(cmd->words);
|
|
|
|
}
|
|
|
|
sfree(cmd);
|
|
|
|
if (ret < 0)
|
2001-12-13 19:26:51 +00:00
|
|
|
break;
|
2001-09-09 16:29:51 +00:00
|
|
|
}
|
2001-08-04 14:19:51 +00:00
|
|
|
} else {
|
|
|
|
fp = fopen(batchfile, "r");
|
|
|
|
if (!fp) {
|
2001-09-09 16:29:51 +00:00
|
|
|
printf("Fatal: unable to open %s\n", batchfile);
|
2015-06-25 22:27:16 +00:00
|
|
|
return 1;
|
2001-08-04 14:19:51 +00:00
|
|
|
}
|
2015-06-25 22:27:16 +00:00
|
|
|
ret = 0;
|
2001-08-04 14:19:51 +00:00
|
|
|
while (1) {
|
2001-09-09 16:29:51 +00:00
|
|
|
struct sftp_command *cmd;
|
|
|
|
cmd = sftp_getcmd(fp, mode, modeflags);
|
|
|
|
if (!cmd)
|
|
|
|
break;
|
2001-12-13 19:26:51 +00:00
|
|
|
ret = cmd->obey(cmd);
|
|
|
|
if (ret < 0)
|
2001-09-09 16:29:51 +00:00
|
|
|
break;
|
2001-12-13 19:26:51 +00:00
|
|
|
if (ret == 0) {
|
2001-09-09 16:29:51 +00:00
|
|
|
if (!(modeflags & 2))
|
2001-08-04 14:19:51 +00:00
|
|
|
break;
|
2001-09-09 16:29:51 +00:00
|
|
|
}
|
2001-08-04 14:19:51 +00:00
|
|
|
}
|
2001-09-09 16:29:51 +00:00
|
|
|
fclose(fp);
|
2015-06-25 22:27:16 +00:00
|
|
|
/*
|
|
|
|
* In batch mode, and if exit on command failure is enabled,
|
|
|
|
* any command failure causes the whole of PSFTP to fail.
|
|
|
|
*/
|
|
|
|
if (ret == 0 && !(modeflags & 2)) return 2;
|
2001-02-23 18:21:44 +00:00
|
|
|
}
|
2015-06-25 22:27:16 +00:00
|
|
|
return 0;
|
2001-02-24 16:08:56 +00:00
|
|
|
}
|
2001-02-23 18:21:44 +00:00
|
|
|
|
2001-02-24 16:08:56 +00:00
|
|
|
/* ----------------------------------------------------------------------
|
|
|
|
* Dirty bits: integration with PuTTY.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int verbose = 0;
|
|
|
|
|
2018-09-11 14:02:59 +00:00
|
|
|
void ldisc_echoedit_update(Ldisc *ldisc) { }
|
2001-02-24 16:08:56 +00:00
|
|
|
|
2003-04-28 13:59:32 +00:00
|
|
|
/*
|
|
|
|
* In psftp, all agent requests should be synchronous, so this is a
|
|
|
|
* never-called stub.
|
|
|
|
*/
|
|
|
|
void agent_schedule_callback(void (*callback)(void *, void *, int),
|
|
|
|
void *callback_ctx, void *data, int len)
|
|
|
|
{
|
|
|
|
assert(!"We shouldn't be here");
|
|
|
|
}
|
|
|
|
|
2001-02-24 16:08:56 +00:00
|
|
|
/*
|
|
|
|
* Receive a block of data from the SSH link. Block until all data
|
|
|
|
* is available.
|
|
|
|
*
|
|
|
|
* To do this, we repeatedly call the SSH protocol module, with our
|
New abstraction 'Seat', to pass to backends.
This is a new vtable-based abstraction which is passed to a backend in
place of Frontend, and it implements only the subset of the Frontend
functions needed by a backend. (Many other Frontend functions still
exist, notably the wide range of things called by terminal.c providing
platform-independent operations on the GUI terminal window.)
The purpose of making it a vtable is that this opens up the
possibility of creating a backend as an internal implementation detail
of some other activity, by providing just that one backend with a
custom Seat that implements the methods differently.
For example, this refactoring should make it feasible to directly
implement an SSH proxy type, aka the 'jump host' feature supported by
OpenSSH, aka 'open a secondary SSH session in MAINCHAN_DIRECT_TCP
mode, and then expose the main channel of that as the Socket for the
primary connection'. (Which of course you can already do by spawning
'plink -nc' as a separate proxy process, but this would permit it in
the _same_ process without anything getting confused.)
I've centralised a full set of stub methods in misc.c for the new
abstraction, which allows me to get rid of several annoying stubs in
the previous code. Also, while I'm here, I've moved a lot of
duplicated modalfatalbox() type functions from application main
program files into wincons.c / uxcons.c, which I think saves
duplication overall. (A minor visible effect is that the prefixes on
those console-based fatal error messages will now be more consistent
between applications.)
2018-10-11 18:58:42 +00:00
|
|
|
* own psftp_output() function to catch the data that comes back. We
|
2001-02-24 16:08:56 +00:00
|
|
|
* do this until we have enough data.
|
|
|
|
*/
|
|
|
|
|
2001-05-06 14:35:20 +00:00
|
|
|
static unsigned char *outptr; /* where to put the data */
|
|
|
|
static unsigned outlen; /* how much data required */
|
2001-02-24 16:08:56 +00:00
|
|
|
static unsigned char *pending = NULL; /* any spare data */
|
2001-05-06 14:35:20 +00:00
|
|
|
static unsigned pendlen = 0, pendsize = 0; /* length and phys. size of buffer */
|
New abstraction 'Seat', to pass to backends.
This is a new vtable-based abstraction which is passed to a backend in
place of Frontend, and it implements only the subset of the Frontend
functions needed by a backend. (Many other Frontend functions still
exist, notably the wide range of things called by terminal.c providing
platform-independent operations on the GUI terminal window.)
The purpose of making it a vtable is that this opens up the
possibility of creating a backend as an internal implementation detail
of some other activity, by providing just that one backend with a
custom Seat that implements the methods differently.
For example, this refactoring should make it feasible to directly
implement an SSH proxy type, aka the 'jump host' feature supported by
OpenSSH, aka 'open a secondary SSH session in MAINCHAN_DIRECT_TCP
mode, and then expose the main channel of that as the Socket for the
primary connection'. (Which of course you can already do by spawning
'plink -nc' as a separate proxy process, but this would permit it in
the _same_ process without anything getting confused.)
I've centralised a full set of stub methods in misc.c for the new
abstraction, which allows me to get rid of several annoying stubs in
the previous code. Also, while I'm here, I've moved a lot of
duplicated modalfatalbox() type functions from application main
program files into wincons.c / uxcons.c, which I think saves
duplication overall. (A minor visible effect is that the prefixes on
those console-based fatal error messages will now be more consistent
between applications.)
2018-10-11 18:58:42 +00:00
|
|
|
static int psftp_output(Seat *seat, int is_stderr,
|
|
|
|
const void *data, int datalen)
|
2001-05-06 14:35:20 +00:00
|
|
|
{
|
|
|
|
unsigned char *p = (unsigned char *) data;
|
|
|
|
unsigned len = (unsigned) datalen;
|
2001-02-24 16:08:56 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* stderr data is just spouted to local stderr and otherwise
|
|
|
|
* ignored.
|
|
|
|
*/
|
|
|
|
if (is_stderr) {
|
2003-10-12 13:16:39 +00:00
|
|
|
if (len > 0)
|
2009-08-07 00:19:04 +00:00
|
|
|
if (fwrite(data, 1, len, stderr) < len)
|
|
|
|
/* oh well */;
|
2001-08-25 17:09:23 +00:00
|
|
|
return 0;
|
2001-02-24 16:08:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If this is before the real session begins, just return.
|
|
|
|
*/
|
|
|
|
if (!outptr)
|
2001-08-25 17:09:23 +00:00
|
|
|
return 0;
|
2001-02-24 16:08:56 +00:00
|
|
|
|
2003-10-12 13:16:39 +00:00
|
|
|
if ((outlen > 0) && (len > 0)) {
|
2001-05-06 14:35:20 +00:00
|
|
|
unsigned used = outlen;
|
|
|
|
if (used > len)
|
|
|
|
used = len;
|
|
|
|
memcpy(outptr, p, used);
|
|
|
|
outptr += used;
|
|
|
|
outlen -= used;
|
|
|
|
p += used;
|
|
|
|
len -= used;
|
2001-02-24 16:08:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (len > 0) {
|
2001-05-06 14:35:20 +00:00
|
|
|
if (pendsize < pendlen + len) {
|
|
|
|
pendsize = pendlen + len + 4096;
|
2003-03-29 16:14:26 +00:00
|
|
|
pending = sresize(pending, pendsize, unsigned char);
|
2001-05-06 14:35:20 +00:00
|
|
|
}
|
|
|
|
memcpy(pending + pendlen, p, len);
|
|
|
|
pendlen += len;
|
2001-02-24 16:08:56 +00:00
|
|
|
}
|
2001-08-25 17:09:23 +00:00
|
|
|
|
|
|
|
return 0;
|
2001-02-24 16:08:56 +00:00
|
|
|
}
|
New abstraction 'Seat', to pass to backends.
This is a new vtable-based abstraction which is passed to a backend in
place of Frontend, and it implements only the subset of the Frontend
functions needed by a backend. (Many other Frontend functions still
exist, notably the wide range of things called by terminal.c providing
platform-independent operations on the GUI terminal window.)
The purpose of making it a vtable is that this opens up the
possibility of creating a backend as an internal implementation detail
of some other activity, by providing just that one backend with a
custom Seat that implements the methods differently.
For example, this refactoring should make it feasible to directly
implement an SSH proxy type, aka the 'jump host' feature supported by
OpenSSH, aka 'open a secondary SSH session in MAINCHAN_DIRECT_TCP
mode, and then expose the main channel of that as the Socket for the
primary connection'. (Which of course you can already do by spawning
'plink -nc' as a separate proxy process, but this would permit it in
the _same_ process without anything getting confused.)
I've centralised a full set of stub methods in misc.c for the new
abstraction, which allows me to get rid of several annoying stubs in
the previous code. Also, while I'm here, I've moved a lot of
duplicated modalfatalbox() type functions from application main
program files into wincons.c / uxcons.c, which I think saves
duplication overall. (A minor visible effect is that the prefixes on
those console-based fatal error messages will now be more consistent
between applications.)
2018-10-11 18:58:42 +00:00
|
|
|
|
|
|
|
static int psftp_eof(Seat *seat)
|
2011-09-13 11:44:03 +00:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* We expect to be the party deciding when to close the
|
|
|
|
* connection, so if we see EOF before we sent it ourselves, we
|
|
|
|
* should panic.
|
|
|
|
*/
|
|
|
|
if (!sent_eof) {
|
New abstraction 'Seat', to pass to backends.
This is a new vtable-based abstraction which is passed to a backend in
place of Frontend, and it implements only the subset of the Frontend
functions needed by a backend. (Many other Frontend functions still
exist, notably the wide range of things called by terminal.c providing
platform-independent operations on the GUI terminal window.)
The purpose of making it a vtable is that this opens up the
possibility of creating a backend as an internal implementation detail
of some other activity, by providing just that one backend with a
custom Seat that implements the methods differently.
For example, this refactoring should make it feasible to directly
implement an SSH proxy type, aka the 'jump host' feature supported by
OpenSSH, aka 'open a secondary SSH session in MAINCHAN_DIRECT_TCP
mode, and then expose the main channel of that as the Socket for the
primary connection'. (Which of course you can already do by spawning
'plink -nc' as a separate proxy process, but this would permit it in
the _same_ process without anything getting confused.)
I've centralised a full set of stub methods in misc.c for the new
abstraction, which allows me to get rid of several annoying stubs in
the previous code. Also, while I'm here, I've moved a lot of
duplicated modalfatalbox() type functions from application main
program files into wincons.c / uxcons.c, which I think saves
duplication overall. (A minor visible effect is that the prefixes on
those console-based fatal error messages will now be more consistent
between applications.)
2018-10-11 18:58:42 +00:00
|
|
|
seat_connection_fatal(
|
|
|
|
psftp_seat, "Received unexpected end-of-file from SFTP server");
|
2011-09-13 11:44:03 +00:00
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
New abstraction 'Seat', to pass to backends.
This is a new vtable-based abstraction which is passed to a backend in
place of Frontend, and it implements only the subset of the Frontend
functions needed by a backend. (Many other Frontend functions still
exist, notably the wide range of things called by terminal.c providing
platform-independent operations on the GUI terminal window.)
The purpose of making it a vtable is that this opens up the
possibility of creating a backend as an internal implementation detail
of some other activity, by providing just that one backend with a
custom Seat that implements the methods differently.
For example, this refactoring should make it feasible to directly
implement an SSH proxy type, aka the 'jump host' feature supported by
OpenSSH, aka 'open a secondary SSH session in MAINCHAN_DIRECT_TCP
mode, and then expose the main channel of that as the Socket for the
primary connection'. (Which of course you can already do by spawning
'plink -nc' as a separate proxy process, but this would permit it in
the _same_ process without anything getting confused.)
I've centralised a full set of stub methods in misc.c for the new
abstraction, which allows me to get rid of several annoying stubs in
the previous code. Also, while I'm here, I've moved a lot of
duplicated modalfatalbox() type functions from application main
program files into wincons.c / uxcons.c, which I think saves
duplication overall. (A minor visible effect is that the prefixes on
those console-based fatal error messages will now be more consistent
between applications.)
2018-10-11 18:58:42 +00:00
|
|
|
|
2001-05-06 14:35:20 +00:00
|
|
|
int sftp_recvdata(char *buf, int len)
|
|
|
|
{
|
|
|
|
outptr = (unsigned char *) buf;
|
2001-02-24 16:08:56 +00:00
|
|
|
outlen = len;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* See if the pending-input block contains some of what we
|
|
|
|
* need.
|
|
|
|
*/
|
|
|
|
if (pendlen > 0) {
|
2001-05-06 14:35:20 +00:00
|
|
|
unsigned pendused = pendlen;
|
|
|
|
if (pendused > outlen)
|
|
|
|
pendused = outlen;
|
2001-02-24 16:08:56 +00:00
|
|
|
memcpy(outptr, pending, pendused);
|
2001-05-06 14:35:20 +00:00
|
|
|
memmove(pending, pending + pendused, pendlen - pendused);
|
2001-02-24 16:08:56 +00:00
|
|
|
outptr += pendused;
|
|
|
|
outlen -= pendused;
|
2001-05-06 14:35:20 +00:00
|
|
|
pendlen -= pendused;
|
|
|
|
if (pendlen == 0) {
|
|
|
|
pendsize = 0;
|
|
|
|
sfree(pending);
|
|
|
|
pending = NULL;
|
|
|
|
}
|
|
|
|
if (outlen == 0)
|
|
|
|
return 1;
|
2001-02-24 16:08:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
while (outlen > 0) {
|
2018-09-11 15:23:38 +00:00
|
|
|
if (backend_exitcode(backend) >= 0 || ssh_sftp_loop_iteration() < 0)
|
2001-05-06 14:35:20 +00:00
|
|
|
return 0; /* doom */
|
2001-02-24 16:08:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
2001-05-06 14:35:20 +00:00
|
|
|
int sftp_senddata(char *buf, int len)
|
|
|
|
{
|
2018-09-11 15:23:38 +00:00
|
|
|
backend_send(backend, buf, len);
|
2001-02-24 16:08:56 +00:00
|
|
|
return 1;
|
|
|
|
}
|
2016-04-08 23:24:12 +00:00
|
|
|
int sftp_sendbuffer(void)
|
|
|
|
{
|
2018-09-11 15:23:38 +00:00
|
|
|
return backend_sendbuffer(backend);
|
2016-04-08 23:24:12 +00:00
|
|
|
}
|
2001-02-24 16:08:56 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Short description of parameters.
|
|
|
|
*/
|
|
|
|
static void usage(void)
|
|
|
|
{
|
|
|
|
printf("PuTTY Secure File Transfer (SFTP) client\n");
|
|
|
|
printf("%s\n", ver);
|
2004-02-22 14:57:40 +00:00
|
|
|
printf("Usage: psftp [options] [user@]host\n");
|
2001-02-24 16:08:56 +00:00
|
|
|
printf("Options:\n");
|
2005-03-19 02:26:58 +00:00
|
|
|
printf(" -V print version information and exit\n");
|
|
|
|
printf(" -pgpfp print PGP key fingerprints and exit\n");
|
2001-08-04 14:19:51 +00:00
|
|
|
printf(" -b file use specified batchfile\n");
|
|
|
|
printf(" -bc output batchfile commands\n");
|
|
|
|
printf(" -be don't stop batchfile processing if errors\n");
|
2001-02-24 16:08:56 +00:00
|
|
|
printf(" -v show verbose messages\n");
|
2002-09-11 17:30:36 +00:00
|
|
|
printf(" -load sessname Load settings from saved session\n");
|
|
|
|
printf(" -l user connect with specified username\n");
|
2001-02-24 16:08:56 +00:00
|
|
|
printf(" -P port connect to specified port\n");
|
|
|
|
printf(" -pw passw login with specified password\n");
|
2002-09-11 17:30:36 +00:00
|
|
|
printf(" -1 -2 force use of particular SSH protocol version\n");
|
2004-12-30 16:45:11 +00:00
|
|
|
printf(" -4 -6 force use of IPv4 or IPv6\n");
|
2002-09-11 17:30:36 +00:00
|
|
|
printf(" -C enable compression\n");
|
2014-09-20 22:49:47 +00:00
|
|
|
printf(" -i key private key file for user authentication\n");
|
2006-02-19 12:52:28 +00:00
|
|
|
printf(" -noagent disable use of Pageant\n");
|
|
|
|
printf(" -agent enable use of Pageant\n");
|
2014-09-20 22:49:47 +00:00
|
|
|
printf(" -hostkey aa:bb:cc:...\n");
|
|
|
|
printf(" manually specify a host key (may be repeated)\n");
|
2002-09-11 17:30:36 +00:00
|
|
|
printf(" -batch disable all interactive prompts\n");
|
2017-02-11 23:03:46 +00:00
|
|
|
printf(" -proxycmd command\n");
|
|
|
|
printf(" use 'command' as local proxy\n");
|
2015-11-08 11:57:39 +00:00
|
|
|
printf(" -sshlog file\n");
|
|
|
|
printf(" -sshrawlog file\n");
|
|
|
|
printf(" log protocol details to a file\n");
|
2002-03-06 20:13:22 +00:00
|
|
|
cleanup_exit(1);
|
2001-02-24 16:08:56 +00:00
|
|
|
}
|
|
|
|
|
2004-04-17 20:25:09 +00:00
|
|
|
static void version(void)
|
|
|
|
{
|
2017-01-21 14:55:53 +00:00
|
|
|
char *buildinfo_text = buildinfo("\n");
|
|
|
|
printf("psftp: %s\n%s\n", ver, buildinfo_text);
|
|
|
|
sfree(buildinfo_text);
|
2017-02-15 19:50:14 +00:00
|
|
|
exit(0);
|
2004-04-17 20:25:09 +00:00
|
|
|
}
|
|
|
|
|
2001-02-24 16:08:56 +00:00
|
|
|
/*
|
2001-12-13 18:42:34 +00:00
|
|
|
* Connect to a host.
|
2001-02-24 16:08:56 +00:00
|
|
|
*/
|
2001-12-13 18:42:34 +00:00
|
|
|
static int psftp_connect(char *userhost, char *user, int portnumber)
|
2001-02-24 16:08:56 +00:00
|
|
|
{
|
2001-12-13 18:42:34 +00:00
|
|
|
char *host, *realhost;
|
2003-05-04 14:18:18 +00:00
|
|
|
const char *err;
|
2018-09-11 14:17:16 +00:00
|
|
|
LogContext *logctx;
|
2001-02-24 16:08:56 +00:00
|
|
|
|
|
|
|
/* Separate host and username */
|
|
|
|
host = userhost;
|
|
|
|
host = strrchr(host, '@');
|
|
|
|
if (host == NULL) {
|
|
|
|
host = userhost;
|
|
|
|
} else {
|
|
|
|
*host++ = '\0';
|
|
|
|
if (user) {
|
2001-05-06 14:35:20 +00:00
|
|
|
printf("psftp: multiple usernames specified; using \"%s\"\n",
|
|
|
|
user);
|
2001-02-24 16:08:56 +00:00
|
|
|
} else
|
|
|
|
user = userhost;
|
|
|
|
}
|
|
|
|
|
2004-07-25 14:00:26 +00:00
|
|
|
/*
|
|
|
|
* If we haven't loaded session details already (e.g., from -load),
|
|
|
|
* try looking for a session called "host".
|
|
|
|
*/
|
|
|
|
if (!loaded_session) {
|
|
|
|
/* Try to load settings for `host' into a temporary config */
|
Post-release destabilisation! Completely remove the struct type
'Config' in putty.h, which stores all PuTTY's settings and includes an
arbitrary length limit on every single one of those settings which is
stored in string form. In place of it is 'Conf', an opaque data type
everywhere outside the new file conf.c, which stores a list of (key,
value) pairs in which every key contains an integer identifying a
configuration setting, and for some of those integers the key also
contains extra parts (so that, for instance, CONF_environmt is a
string-to-string mapping). Everywhere that a Config was previously
used, a Conf is now; everywhere there was a Config structure copy,
conf_copy() is called; every lookup, adjustment, load and save
operation on a Config has been rewritten; and there's a mechanism for
serialising a Conf into a binary blob and back for use with Duplicate
Session.
User-visible effects of this change _should_ be minimal, though I
don't doubt I've introduced one or two bugs here and there which will
eventually be found. The _intended_ visible effects of this change are
that all arbitrary limits on configuration strings and lists (e.g.
limit on number of port forwardings) should now disappear; that list
boxes in the configuration will now be displayed in a sorted order
rather than the arbitrary order in which they were added to the list
(since the underlying data structure is now a sorted tree234 rather
than an ad-hoc comma-separated string); and one more specific change,
which is that local and dynamic port forwardings on the same port
number are now mutually exclusive in the configuration (putting 'D' in
the key rather than the value was a mistake in the first place).
One other reorganisation as a result of this is that I've moved all
the dialog.c standard handlers (dlg_stdeditbox_handler and friends)
out into config.c, because I can't really justify calling them generic
any more. When they took a pointer to an arbitrary structure type and
the offset of a field within that structure, they were independent of
whether that structure was a Config or something completely different,
but now they really do expect to talk to a Conf, which can _only_ be
used for PuTTY configuration, so I've renamed them all things like
conf_editbox_handler and moved them out of the nominally independent
dialog-box management module into the PuTTY-specific config.c.
[originally from svn r9214]
2011-07-14 18:52:21 +00:00
|
|
|
Conf *conf2 = conf_new();
|
|
|
|
conf_set_str(conf2, CONF_host, "");
|
|
|
|
do_defaults(host, conf2);
|
|
|
|
if (conf_get_str(conf2, CONF_host)[0] != '\0') {
|
2004-07-25 14:00:26 +00:00
|
|
|
/* Settings present and include hostname */
|
|
|
|
/* Re-load data into the real config. */
|
Post-release destabilisation! Completely remove the struct type
'Config' in putty.h, which stores all PuTTY's settings and includes an
arbitrary length limit on every single one of those settings which is
stored in string form. In place of it is 'Conf', an opaque data type
everywhere outside the new file conf.c, which stores a list of (key,
value) pairs in which every key contains an integer identifying a
configuration setting, and for some of those integers the key also
contains extra parts (so that, for instance, CONF_environmt is a
string-to-string mapping). Everywhere that a Config was previously
used, a Conf is now; everywhere there was a Config structure copy,
conf_copy() is called; every lookup, adjustment, load and save
operation on a Config has been rewritten; and there's a mechanism for
serialising a Conf into a binary blob and back for use with Duplicate
Session.
User-visible effects of this change _should_ be minimal, though I
don't doubt I've introduced one or two bugs here and there which will
eventually be found. The _intended_ visible effects of this change are
that all arbitrary limits on configuration strings and lists (e.g.
limit on number of port forwardings) should now disappear; that list
boxes in the configuration will now be displayed in a sorted order
rather than the arbitrary order in which they were added to the list
(since the underlying data structure is now a sorted tree234 rather
than an ad-hoc comma-separated string); and one more specific change,
which is that local and dynamic port forwardings on the same port
number are now mutually exclusive in the configuration (putting 'D' in
the key rather than the value was a mistake in the first place).
One other reorganisation as a result of this is that I've moved all
the dialog.c standard handlers (dlg_stdeditbox_handler and friends)
out into config.c, because I can't really justify calling them generic
any more. When they took a pointer to an arbitrary structure type and
the offset of a field within that structure, they were independent of
whether that structure was a Config or something completely different,
but now they really do expect to talk to a Conf, which can _only_ be
used for PuTTY configuration, so I've renamed them all things like
conf_editbox_handler and moved them out of the nominally independent
dialog-box management module into the PuTTY-specific config.c.
[originally from svn r9214]
2011-07-14 18:52:21 +00:00
|
|
|
do_defaults(host, conf);
|
2004-07-25 14:00:26 +00:00
|
|
|
} else {
|
|
|
|
/* Session doesn't exist or mention a hostname. */
|
|
|
|
/* Use `host' as a bare hostname. */
|
Post-release destabilisation! Completely remove the struct type
'Config' in putty.h, which stores all PuTTY's settings and includes an
arbitrary length limit on every single one of those settings which is
stored in string form. In place of it is 'Conf', an opaque data type
everywhere outside the new file conf.c, which stores a list of (key,
value) pairs in which every key contains an integer identifying a
configuration setting, and for some of those integers the key also
contains extra parts (so that, for instance, CONF_environmt is a
string-to-string mapping). Everywhere that a Config was previously
used, a Conf is now; everywhere there was a Config structure copy,
conf_copy() is called; every lookup, adjustment, load and save
operation on a Config has been rewritten; and there's a mechanism for
serialising a Conf into a binary blob and back for use with Duplicate
Session.
User-visible effects of this change _should_ be minimal, though I
don't doubt I've introduced one or two bugs here and there which will
eventually be found. The _intended_ visible effects of this change are
that all arbitrary limits on configuration strings and lists (e.g.
limit on number of port forwardings) should now disappear; that list
boxes in the configuration will now be displayed in a sorted order
rather than the arbitrary order in which they were added to the list
(since the underlying data structure is now a sorted tree234 rather
than an ad-hoc comma-separated string); and one more specific change,
which is that local and dynamic port forwardings on the same port
number are now mutually exclusive in the configuration (putting 'D' in
the key rather than the value was a mistake in the first place).
One other reorganisation as a result of this is that I've moved all
the dialog.c standard handlers (dlg_stdeditbox_handler and friends)
out into config.c, because I can't really justify calling them generic
any more. When they took a pointer to an arbitrary structure type and
the offset of a field within that structure, they were independent of
whether that structure was a Config or something completely different,
but now they really do expect to talk to a Conf, which can _only_ be
used for PuTTY configuration, so I've renamed them all things like
conf_editbox_handler and moved them out of the nominally independent
dialog-box management module into the PuTTY-specific config.c.
[originally from svn r9214]
2011-07-14 18:52:21 +00:00
|
|
|
conf_set_str(conf, CONF_host, host);
|
2004-07-25 14:00:26 +00:00
|
|
|
}
|
2013-07-22 19:55:55 +00:00
|
|
|
conf_free(conf2);
|
2004-07-25 14:00:26 +00:00
|
|
|
} else {
|
|
|
|
/* Patch in hostname `host' to session details. */
|
Post-release destabilisation! Completely remove the struct type
'Config' in putty.h, which stores all PuTTY's settings and includes an
arbitrary length limit on every single one of those settings which is
stored in string form. In place of it is 'Conf', an opaque data type
everywhere outside the new file conf.c, which stores a list of (key,
value) pairs in which every key contains an integer identifying a
configuration setting, and for some of those integers the key also
contains extra parts (so that, for instance, CONF_environmt is a
string-to-string mapping). Everywhere that a Config was previously
used, a Conf is now; everywhere there was a Config structure copy,
conf_copy() is called; every lookup, adjustment, load and save
operation on a Config has been rewritten; and there's a mechanism for
serialising a Conf into a binary blob and back for use with Duplicate
Session.
User-visible effects of this change _should_ be minimal, though I
don't doubt I've introduced one or two bugs here and there which will
eventually be found. The _intended_ visible effects of this change are
that all arbitrary limits on configuration strings and lists (e.g.
limit on number of port forwardings) should now disappear; that list
boxes in the configuration will now be displayed in a sorted order
rather than the arbitrary order in which they were added to the list
(since the underlying data structure is now a sorted tree234 rather
than an ad-hoc comma-separated string); and one more specific change,
which is that local and dynamic port forwardings on the same port
number are now mutually exclusive in the configuration (putting 'D' in
the key rather than the value was a mistake in the first place).
One other reorganisation as a result of this is that I've moved all
the dialog.c standard handlers (dlg_stdeditbox_handler and friends)
out into config.c, because I can't really justify calling them generic
any more. When they took a pointer to an arbitrary structure type and
the offset of a field within that structure, they were independent of
whether that structure was a Config or something completely different,
but now they really do expect to talk to a Conf, which can _only_ be
used for PuTTY configuration, so I've renamed them all things like
conf_editbox_handler and moved them out of the nominally independent
dialog-box management module into the PuTTY-specific config.c.
[originally from svn r9214]
2011-07-14 18:52:21 +00:00
|
|
|
conf_set_str(conf, CONF_host, host);
|
2002-10-07 17:31:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Force use of SSH. (If they got the protocol wrong we assume the
|
|
|
|
* port is useless too.)
|
|
|
|
*/
|
Post-release destabilisation! Completely remove the struct type
'Config' in putty.h, which stores all PuTTY's settings and includes an
arbitrary length limit on every single one of those settings which is
stored in string form. In place of it is 'Conf', an opaque data type
everywhere outside the new file conf.c, which stores a list of (key,
value) pairs in which every key contains an integer identifying a
configuration setting, and for some of those integers the key also
contains extra parts (so that, for instance, CONF_environmt is a
string-to-string mapping). Everywhere that a Config was previously
used, a Conf is now; everywhere there was a Config structure copy,
conf_copy() is called; every lookup, adjustment, load and save
operation on a Config has been rewritten; and there's a mechanism for
serialising a Conf into a binary blob and back for use with Duplicate
Session.
User-visible effects of this change _should_ be minimal, though I
don't doubt I've introduced one or two bugs here and there which will
eventually be found. The _intended_ visible effects of this change are
that all arbitrary limits on configuration strings and lists (e.g.
limit on number of port forwardings) should now disappear; that list
boxes in the configuration will now be displayed in a sorted order
rather than the arbitrary order in which they were added to the list
(since the underlying data structure is now a sorted tree234 rather
than an ad-hoc comma-separated string); and one more specific change,
which is that local and dynamic port forwardings on the same port
number are now mutually exclusive in the configuration (putting 'D' in
the key rather than the value was a mistake in the first place).
One other reorganisation as a result of this is that I've moved all
the dialog.c standard handlers (dlg_stdeditbox_handler and friends)
out into config.c, because I can't really justify calling them generic
any more. When they took a pointer to an arbitrary structure type and
the offset of a field within that structure, they were independent of
whether that structure was a Config or something completely different,
but now they really do expect to talk to a Conf, which can _only_ be
used for PuTTY configuration, so I've renamed them all things like
conf_editbox_handler and moved them out of the nominally independent
dialog-box management module into the PuTTY-specific config.c.
[originally from svn r9214]
2011-07-14 18:52:21 +00:00
|
|
|
if (conf_get_int(conf, CONF_protocol) != PROT_SSH) {
|
|
|
|
conf_set_int(conf, CONF_protocol, PROT_SSH);
|
|
|
|
conf_set_int(conf, CONF_port, 22);
|
2001-02-24 16:08:56 +00:00
|
|
|
}
|
|
|
|
|
2004-07-25 16:10:48 +00:00
|
|
|
/*
|
|
|
|
* If saved session / Default Settings says SSH-1 (`1 only' or `1'),
|
|
|
|
* then change it to SSH-2, on the grounds that that's more likely to
|
|
|
|
* work for SFTP. (Can be overridden with `-1' option.)
|
|
|
|
* But if it says `2 only' or `2', respect which.
|
|
|
|
*/
|
Post-release destabilisation! Completely remove the struct type
'Config' in putty.h, which stores all PuTTY's settings and includes an
arbitrary length limit on every single one of those settings which is
stored in string form. In place of it is 'Conf', an opaque data type
everywhere outside the new file conf.c, which stores a list of (key,
value) pairs in which every key contains an integer identifying a
configuration setting, and for some of those integers the key also
contains extra parts (so that, for instance, CONF_environmt is a
string-to-string mapping). Everywhere that a Config was previously
used, a Conf is now; everywhere there was a Config structure copy,
conf_copy() is called; every lookup, adjustment, load and save
operation on a Config has been rewritten; and there's a mechanism for
serialising a Conf into a binary blob and back for use with Duplicate
Session.
User-visible effects of this change _should_ be minimal, though I
don't doubt I've introduced one or two bugs here and there which will
eventually be found. The _intended_ visible effects of this change are
that all arbitrary limits on configuration strings and lists (e.g.
limit on number of port forwardings) should now disappear; that list
boxes in the configuration will now be displayed in a sorted order
rather than the arbitrary order in which they were added to the list
(since the underlying data structure is now a sorted tree234 rather
than an ad-hoc comma-separated string); and one more specific change,
which is that local and dynamic port forwardings on the same port
number are now mutually exclusive in the configuration (putting 'D' in
the key rather than the value was a mistake in the first place).
One other reorganisation as a result of this is that I've moved all
the dialog.c standard handlers (dlg_stdeditbox_handler and friends)
out into config.c, because I can't really justify calling them generic
any more. When they took a pointer to an arbitrary structure type and
the offset of a field within that structure, they were independent of
whether that structure was a Config or something completely different,
but now they really do expect to talk to a Conf, which can _only_ be
used for PuTTY configuration, so I've renamed them all things like
conf_editbox_handler and moved them out of the nominally independent
dialog-box management module into the PuTTY-specific config.c.
[originally from svn r9214]
2011-07-14 18:52:21 +00:00
|
|
|
if ((conf_get_int(conf, CONF_sshprot) & ~1) != 2) /* is it 2 or 3? */
|
|
|
|
conf_set_int(conf, CONF_sshprot, 2);
|
2004-07-25 16:10:48 +00:00
|
|
|
|
2002-08-04 21:18:56 +00:00
|
|
|
/*
|
|
|
|
* Enact command-line overrides.
|
|
|
|
*/
|
Post-release destabilisation! Completely remove the struct type
'Config' in putty.h, which stores all PuTTY's settings and includes an
arbitrary length limit on every single one of those settings which is
stored in string form. In place of it is 'Conf', an opaque data type
everywhere outside the new file conf.c, which stores a list of (key,
value) pairs in which every key contains an integer identifying a
configuration setting, and for some of those integers the key also
contains extra parts (so that, for instance, CONF_environmt is a
string-to-string mapping). Everywhere that a Config was previously
used, a Conf is now; everywhere there was a Config structure copy,
conf_copy() is called; every lookup, adjustment, load and save
operation on a Config has been rewritten; and there's a mechanism for
serialising a Conf into a binary blob and back for use with Duplicate
Session.
User-visible effects of this change _should_ be minimal, though I
don't doubt I've introduced one or two bugs here and there which will
eventually be found. The _intended_ visible effects of this change are
that all arbitrary limits on configuration strings and lists (e.g.
limit on number of port forwardings) should now disappear; that list
boxes in the configuration will now be displayed in a sorted order
rather than the arbitrary order in which they were added to the list
(since the underlying data structure is now a sorted tree234 rather
than an ad-hoc comma-separated string); and one more specific change,
which is that local and dynamic port forwardings on the same port
number are now mutually exclusive in the configuration (putting 'D' in
the key rather than the value was a mistake in the first place).
One other reorganisation as a result of this is that I've moved all
the dialog.c standard handlers (dlg_stdeditbox_handler and friends)
out into config.c, because I can't really justify calling them generic
any more. When they took a pointer to an arbitrary structure type and
the offset of a field within that structure, they were independent of
whether that structure was a Config or something completely different,
but now they really do expect to talk to a Conf, which can _only_ be
used for PuTTY configuration, so I've renamed them all things like
conf_editbox_handler and moved them out of the nominally independent
dialog-box management module into the PuTTY-specific config.c.
[originally from svn r9214]
2011-07-14 18:52:21 +00:00
|
|
|
cmdline_run_saved(conf);
|
2002-08-04 21:18:56 +00:00
|
|
|
|
2001-10-30 21:45:27 +00:00
|
|
|
/*
|
Post-release destabilisation! Completely remove the struct type
'Config' in putty.h, which stores all PuTTY's settings and includes an
arbitrary length limit on every single one of those settings which is
stored in string form. In place of it is 'Conf', an opaque data type
everywhere outside the new file conf.c, which stores a list of (key,
value) pairs in which every key contains an integer identifying a
configuration setting, and for some of those integers the key also
contains extra parts (so that, for instance, CONF_environmt is a
string-to-string mapping). Everywhere that a Config was previously
used, a Conf is now; everywhere there was a Config structure copy,
conf_copy() is called; every lookup, adjustment, load and save
operation on a Config has been rewritten; and there's a mechanism for
serialising a Conf into a binary blob and back for use with Duplicate
Session.
User-visible effects of this change _should_ be minimal, though I
don't doubt I've introduced one or two bugs here and there which will
eventually be found. The _intended_ visible effects of this change are
that all arbitrary limits on configuration strings and lists (e.g.
limit on number of port forwardings) should now disappear; that list
boxes in the configuration will now be displayed in a sorted order
rather than the arbitrary order in which they were added to the list
(since the underlying data structure is now a sorted tree234 rather
than an ad-hoc comma-separated string); and one more specific change,
which is that local and dynamic port forwardings on the same port
number are now mutually exclusive in the configuration (putting 'D' in
the key rather than the value was a mistake in the first place).
One other reorganisation as a result of this is that I've moved all
the dialog.c standard handlers (dlg_stdeditbox_handler and friends)
out into config.c, because I can't really justify calling them generic
any more. When they took a pointer to an arbitrary structure type and
the offset of a field within that structure, they were independent of
whether that structure was a Config or something completely different,
but now they really do expect to talk to a Conf, which can _only_ be
used for PuTTY configuration, so I've renamed them all things like
conf_editbox_handler and moved them out of the nominally independent
dialog-box management module into the PuTTY-specific config.c.
[originally from svn r9214]
2011-07-14 18:52:21 +00:00
|
|
|
* Muck about with the hostname in various ways.
|
2001-10-30 21:45:27 +00:00
|
|
|
*/
|
|
|
|
{
|
Post-release destabilisation! Completely remove the struct type
'Config' in putty.h, which stores all PuTTY's settings and includes an
arbitrary length limit on every single one of those settings which is
stored in string form. In place of it is 'Conf', an opaque data type
everywhere outside the new file conf.c, which stores a list of (key,
value) pairs in which every key contains an integer identifying a
configuration setting, and for some of those integers the key also
contains extra parts (so that, for instance, CONF_environmt is a
string-to-string mapping). Everywhere that a Config was previously
used, a Conf is now; everywhere there was a Config structure copy,
conf_copy() is called; every lookup, adjustment, load and save
operation on a Config has been rewritten; and there's a mechanism for
serialising a Conf into a binary blob and back for use with Duplicate
Session.
User-visible effects of this change _should_ be minimal, though I
don't doubt I've introduced one or two bugs here and there which will
eventually be found. The _intended_ visible effects of this change are
that all arbitrary limits on configuration strings and lists (e.g.
limit on number of port forwardings) should now disappear; that list
boxes in the configuration will now be displayed in a sorted order
rather than the arbitrary order in which they were added to the list
(since the underlying data structure is now a sorted tree234 rather
than an ad-hoc comma-separated string); and one more specific change,
which is that local and dynamic port forwardings on the same port
number are now mutually exclusive in the configuration (putting 'D' in
the key rather than the value was a mistake in the first place).
One other reorganisation as a result of this is that I've moved all
the dialog.c standard handlers (dlg_stdeditbox_handler and friends)
out into config.c, because I can't really justify calling them generic
any more. When they took a pointer to an arbitrary structure type and
the offset of a field within that structure, they were independent of
whether that structure was a Config or something completely different,
but now they really do expect to talk to a Conf, which can _only_ be
used for PuTTY configuration, so I've renamed them all things like
conf_editbox_handler and moved them out of the nominally independent
dialog-box management module into the PuTTY-specific config.c.
[originally from svn r9214]
2011-07-14 18:52:21 +00:00
|
|
|
char *hostbuf = dupstr(conf_get_str(conf, CONF_host));
|
|
|
|
char *host = hostbuf;
|
|
|
|
char *p, *q;
|
2001-10-30 21:45:27 +00:00
|
|
|
|
Post-release destabilisation! Completely remove the struct type
'Config' in putty.h, which stores all PuTTY's settings and includes an
arbitrary length limit on every single one of those settings which is
stored in string form. In place of it is 'Conf', an opaque data type
everywhere outside the new file conf.c, which stores a list of (key,
value) pairs in which every key contains an integer identifying a
configuration setting, and for some of those integers the key also
contains extra parts (so that, for instance, CONF_environmt is a
string-to-string mapping). Everywhere that a Config was previously
used, a Conf is now; everywhere there was a Config structure copy,
conf_copy() is called; every lookup, adjustment, load and save
operation on a Config has been rewritten; and there's a mechanism for
serialising a Conf into a binary blob and back for use with Duplicate
Session.
User-visible effects of this change _should_ be minimal, though I
don't doubt I've introduced one or two bugs here and there which will
eventually be found. The _intended_ visible effects of this change are
that all arbitrary limits on configuration strings and lists (e.g.
limit on number of port forwardings) should now disappear; that list
boxes in the configuration will now be displayed in a sorted order
rather than the arbitrary order in which they were added to the list
(since the underlying data structure is now a sorted tree234 rather
than an ad-hoc comma-separated string); and one more specific change,
which is that local and dynamic port forwardings on the same port
number are now mutually exclusive in the configuration (putting 'D' in
the key rather than the value was a mistake in the first place).
One other reorganisation as a result of this is that I've moved all
the dialog.c standard handlers (dlg_stdeditbox_handler and friends)
out into config.c, because I can't really justify calling them generic
any more. When they took a pointer to an arbitrary structure type and
the offset of a field within that structure, they were independent of
whether that structure was a Config or something completely different,
but now they really do expect to talk to a Conf, which can _only_ be
used for PuTTY configuration, so I've renamed them all things like
conf_editbox_handler and moved them out of the nominally independent
dialog-box management module into the PuTTY-specific config.c.
[originally from svn r9214]
2011-07-14 18:52:21 +00:00
|
|
|
/*
|
|
|
|
* Trim leading whitespace.
|
|
|
|
*/
|
|
|
|
host += strspn(host, " \t");
|
2001-10-30 21:45:27 +00:00
|
|
|
|
Post-release destabilisation! Completely remove the struct type
'Config' in putty.h, which stores all PuTTY's settings and includes an
arbitrary length limit on every single one of those settings which is
stored in string form. In place of it is 'Conf', an opaque data type
everywhere outside the new file conf.c, which stores a list of (key,
value) pairs in which every key contains an integer identifying a
configuration setting, and for some of those integers the key also
contains extra parts (so that, for instance, CONF_environmt is a
string-to-string mapping). Everywhere that a Config was previously
used, a Conf is now; everywhere there was a Config structure copy,
conf_copy() is called; every lookup, adjustment, load and save
operation on a Config has been rewritten; and there's a mechanism for
serialising a Conf into a binary blob and back for use with Duplicate
Session.
User-visible effects of this change _should_ be minimal, though I
don't doubt I've introduced one or two bugs here and there which will
eventually be found. The _intended_ visible effects of this change are
that all arbitrary limits on configuration strings and lists (e.g.
limit on number of port forwardings) should now disappear; that list
boxes in the configuration will now be displayed in a sorted order
rather than the arbitrary order in which they were added to the list
(since the underlying data structure is now a sorted tree234 rather
than an ad-hoc comma-separated string); and one more specific change,
which is that local and dynamic port forwardings on the same port
number are now mutually exclusive in the configuration (putting 'D' in
the key rather than the value was a mistake in the first place).
One other reorganisation as a result of this is that I've moved all
the dialog.c standard handlers (dlg_stdeditbox_handler and friends)
out into config.c, because I can't really justify calling them generic
any more. When they took a pointer to an arbitrary structure type and
the offset of a field within that structure, they were independent of
whether that structure was a Config or something completely different,
but now they really do expect to talk to a Conf, which can _only_ be
used for PuTTY configuration, so I've renamed them all things like
conf_editbox_handler and moved them out of the nominally independent
dialog-box management module into the PuTTY-specific config.c.
[originally from svn r9214]
2011-07-14 18:52:21 +00:00
|
|
|
/*
|
|
|
|
* See if host is of the form user@host, and separate out
|
|
|
|
* the username if so.
|
|
|
|
*/
|
|
|
|
if (host[0] != '\0') {
|
|
|
|
char *atsign = strrchr(host, '@');
|
|
|
|
if (atsign) {
|
|
|
|
*atsign = '\0';
|
|
|
|
conf_set_str(conf, CONF_username, host);
|
|
|
|
host = atsign + 1;
|
2002-10-16 11:35:13 +00:00
|
|
|
}
|
|
|
|
}
|
Post-release destabilisation! Completely remove the struct type
'Config' in putty.h, which stores all PuTTY's settings and includes an
arbitrary length limit on every single one of those settings which is
stored in string form. In place of it is 'Conf', an opaque data type
everywhere outside the new file conf.c, which stores a list of (key,
value) pairs in which every key contains an integer identifying a
configuration setting, and for some of those integers the key also
contains extra parts (so that, for instance, CONF_environmt is a
string-to-string mapping). Everywhere that a Config was previously
used, a Conf is now; everywhere there was a Config structure copy,
conf_copy() is called; every lookup, adjustment, load and save
operation on a Config has been rewritten; and there's a mechanism for
serialising a Conf into a binary blob and back for use with Duplicate
Session.
User-visible effects of this change _should_ be minimal, though I
don't doubt I've introduced one or two bugs here and there which will
eventually be found. The _intended_ visible effects of this change are
that all arbitrary limits on configuration strings and lists (e.g.
limit on number of port forwardings) should now disappear; that list
boxes in the configuration will now be displayed in a sorted order
rather than the arbitrary order in which they were added to the list
(since the underlying data structure is now a sorted tree234 rather
than an ad-hoc comma-separated string); and one more specific change,
which is that local and dynamic port forwardings on the same port
number are now mutually exclusive in the configuration (putting 'D' in
the key rather than the value was a mistake in the first place).
One other reorganisation as a result of this is that I've moved all
the dialog.c standard handlers (dlg_stdeditbox_handler and friends)
out into config.c, because I can't really justify calling them generic
any more. When they took a pointer to an arbitrary structure type and
the offset of a field within that structure, they were independent of
whether that structure was a Config or something completely different,
but now they really do expect to talk to a Conf, which can _only_ be
used for PuTTY configuration, so I've renamed them all things like
conf_editbox_handler and moved them out of the nominally independent
dialog-box management module into the PuTTY-specific config.c.
[originally from svn r9214]
2011-07-14 18:52:21 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Remove any remaining whitespace.
|
|
|
|
*/
|
|
|
|
p = hostbuf;
|
|
|
|
q = host;
|
|
|
|
while (*q) {
|
|
|
|
if (*q != ' ' && *q != '\t')
|
|
|
|
*p++ = *q;
|
|
|
|
q++;
|
|
|
|
}
|
|
|
|
*p = '\0';
|
|
|
|
|
|
|
|
conf_set_str(conf, CONF_host, hostbuf);
|
|
|
|
sfree(hostbuf);
|
2002-10-16 11:35:13 +00:00
|
|
|
}
|
|
|
|
|
2001-02-24 16:08:56 +00:00
|
|
|
/* Set username */
|
|
|
|
if (user != NULL && user[0] != '\0') {
|
Post-release destabilisation! Completely remove the struct type
'Config' in putty.h, which stores all PuTTY's settings and includes an
arbitrary length limit on every single one of those settings which is
stored in string form. In place of it is 'Conf', an opaque data type
everywhere outside the new file conf.c, which stores a list of (key,
value) pairs in which every key contains an integer identifying a
configuration setting, and for some of those integers the key also
contains extra parts (so that, for instance, CONF_environmt is a
string-to-string mapping). Everywhere that a Config was previously
used, a Conf is now; everywhere there was a Config structure copy,
conf_copy() is called; every lookup, adjustment, load and save
operation on a Config has been rewritten; and there's a mechanism for
serialising a Conf into a binary blob and back for use with Duplicate
Session.
User-visible effects of this change _should_ be minimal, though I
don't doubt I've introduced one or two bugs here and there which will
eventually be found. The _intended_ visible effects of this change are
that all arbitrary limits on configuration strings and lists (e.g.
limit on number of port forwardings) should now disappear; that list
boxes in the configuration will now be displayed in a sorted order
rather than the arbitrary order in which they were added to the list
(since the underlying data structure is now a sorted tree234 rather
than an ad-hoc comma-separated string); and one more specific change,
which is that local and dynamic port forwardings on the same port
number are now mutually exclusive in the configuration (putting 'D' in
the key rather than the value was a mistake in the first place).
One other reorganisation as a result of this is that I've moved all
the dialog.c standard handlers (dlg_stdeditbox_handler and friends)
out into config.c, because I can't really justify calling them generic
any more. When they took a pointer to an arbitrary structure type and
the offset of a field within that structure, they were independent of
whether that structure was a Config or something completely different,
but now they really do expect to talk to a Conf, which can _only_ be
used for PuTTY configuration, so I've renamed them all things like
conf_editbox_handler and moved them out of the nominally independent
dialog-box management module into the PuTTY-specific config.c.
[originally from svn r9214]
2011-07-14 18:52:21 +00:00
|
|
|
conf_set_str(conf, CONF_username, user);
|
2001-02-24 16:08:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (portnumber)
|
Post-release destabilisation! Completely remove the struct type
'Config' in putty.h, which stores all PuTTY's settings and includes an
arbitrary length limit on every single one of those settings which is
stored in string form. In place of it is 'Conf', an opaque data type
everywhere outside the new file conf.c, which stores a list of (key,
value) pairs in which every key contains an integer identifying a
configuration setting, and for some of those integers the key also
contains extra parts (so that, for instance, CONF_environmt is a
string-to-string mapping). Everywhere that a Config was previously
used, a Conf is now; everywhere there was a Config structure copy,
conf_copy() is called; every lookup, adjustment, load and save
operation on a Config has been rewritten; and there's a mechanism for
serialising a Conf into a binary blob and back for use with Duplicate
Session.
User-visible effects of this change _should_ be minimal, though I
don't doubt I've introduced one or two bugs here and there which will
eventually be found. The _intended_ visible effects of this change are
that all arbitrary limits on configuration strings and lists (e.g.
limit on number of port forwardings) should now disappear; that list
boxes in the configuration will now be displayed in a sorted order
rather than the arbitrary order in which they were added to the list
(since the underlying data structure is now a sorted tree234 rather
than an ad-hoc comma-separated string); and one more specific change,
which is that local and dynamic port forwardings on the same port
number are now mutually exclusive in the configuration (putting 'D' in
the key rather than the value was a mistake in the first place).
One other reorganisation as a result of this is that I've moved all
the dialog.c standard handlers (dlg_stdeditbox_handler and friends)
out into config.c, because I can't really justify calling them generic
any more. When they took a pointer to an arbitrary structure type and
the offset of a field within that structure, they were independent of
whether that structure was a Config or something completely different,
but now they really do expect to talk to a Conf, which can _only_ be
used for PuTTY configuration, so I've renamed them all things like
conf_editbox_handler and moved them out of the nominally independent
dialog-box management module into the PuTTY-specific config.c.
[originally from svn r9214]
2011-07-14 18:52:21 +00:00
|
|
|
conf_set_int(conf, CONF_port, portnumber);
|
2001-02-24 16:08:56 +00:00
|
|
|
|
2001-09-12 20:11:48 +00:00
|
|
|
/*
|
|
|
|
* Disable scary things which shouldn't be enabled for simple
|
|
|
|
* things like SCP and SFTP: agent forwarding, port forwarding,
|
|
|
|
* X forwarding.
|
|
|
|
*/
|
Post-release destabilisation! Completely remove the struct type
'Config' in putty.h, which stores all PuTTY's settings and includes an
arbitrary length limit on every single one of those settings which is
stored in string form. In place of it is 'Conf', an opaque data type
everywhere outside the new file conf.c, which stores a list of (key,
value) pairs in which every key contains an integer identifying a
configuration setting, and for some of those integers the key also
contains extra parts (so that, for instance, CONF_environmt is a
string-to-string mapping). Everywhere that a Config was previously
used, a Conf is now; everywhere there was a Config structure copy,
conf_copy() is called; every lookup, adjustment, load and save
operation on a Config has been rewritten; and there's a mechanism for
serialising a Conf into a binary blob and back for use with Duplicate
Session.
User-visible effects of this change _should_ be minimal, though I
don't doubt I've introduced one or two bugs here and there which will
eventually be found. The _intended_ visible effects of this change are
that all arbitrary limits on configuration strings and lists (e.g.
limit on number of port forwardings) should now disappear; that list
boxes in the configuration will now be displayed in a sorted order
rather than the arbitrary order in which they were added to the list
(since the underlying data structure is now a sorted tree234 rather
than an ad-hoc comma-separated string); and one more specific change,
which is that local and dynamic port forwardings on the same port
number are now mutually exclusive in the configuration (putting 'D' in
the key rather than the value was a mistake in the first place).
One other reorganisation as a result of this is that I've moved all
the dialog.c standard handlers (dlg_stdeditbox_handler and friends)
out into config.c, because I can't really justify calling them generic
any more. When they took a pointer to an arbitrary structure type and
the offset of a field within that structure, they were independent of
whether that structure was a Config or something completely different,
but now they really do expect to talk to a Conf, which can _only_ be
used for PuTTY configuration, so I've renamed them all things like
conf_editbox_handler and moved them out of the nominally independent
dialog-box management module into the PuTTY-specific config.c.
[originally from svn r9214]
2011-07-14 18:52:21 +00:00
|
|
|
conf_set_int(conf, CONF_x11_forward, 0);
|
|
|
|
conf_set_int(conf, CONF_agentfwd, 0);
|
|
|
|
conf_set_int(conf, CONF_ssh_simple, TRUE);
|
|
|
|
{
|
|
|
|
char *key;
|
|
|
|
while ((key = conf_get_str_nthstrkey(conf, CONF_portfwd, 0)) != NULL)
|
|
|
|
conf_del_str_str(conf, CONF_portfwd, key);
|
|
|
|
}
|
2001-09-12 20:11:48 +00:00
|
|
|
|
2001-09-05 19:48:52 +00:00
|
|
|
/* Set up subsystem name. */
|
Post-release destabilisation! Completely remove the struct type
'Config' in putty.h, which stores all PuTTY's settings and includes an
arbitrary length limit on every single one of those settings which is
stored in string form. In place of it is 'Conf', an opaque data type
everywhere outside the new file conf.c, which stores a list of (key,
value) pairs in which every key contains an integer identifying a
configuration setting, and for some of those integers the key also
contains extra parts (so that, for instance, CONF_environmt is a
string-to-string mapping). Everywhere that a Config was previously
used, a Conf is now; everywhere there was a Config structure copy,
conf_copy() is called; every lookup, adjustment, load and save
operation on a Config has been rewritten; and there's a mechanism for
serialising a Conf into a binary blob and back for use with Duplicate
Session.
User-visible effects of this change _should_ be minimal, though I
don't doubt I've introduced one or two bugs here and there which will
eventually be found. The _intended_ visible effects of this change are
that all arbitrary limits on configuration strings and lists (e.g.
limit on number of port forwardings) should now disappear; that list
boxes in the configuration will now be displayed in a sorted order
rather than the arbitrary order in which they were added to the list
(since the underlying data structure is now a sorted tree234 rather
than an ad-hoc comma-separated string); and one more specific change,
which is that local and dynamic port forwardings on the same port
number are now mutually exclusive in the configuration (putting 'D' in
the key rather than the value was a mistake in the first place).
One other reorganisation as a result of this is that I've moved all
the dialog.c standard handlers (dlg_stdeditbox_handler and friends)
out into config.c, because I can't really justify calling them generic
any more. When they took a pointer to an arbitrary structure type and
the offset of a field within that structure, they were independent of
whether that structure was a Config or something completely different,
but now they really do expect to talk to a Conf, which can _only_ be
used for PuTTY configuration, so I've renamed them all things like
conf_editbox_handler and moved them out of the nominally independent
dialog-box management module into the PuTTY-specific config.c.
[originally from svn r9214]
2011-07-14 18:52:21 +00:00
|
|
|
conf_set_str(conf, CONF_remote_cmd, "sftp");
|
|
|
|
conf_set_int(conf, CONF_ssh_subsys, TRUE);
|
|
|
|
conf_set_int(conf, CONF_nopty, TRUE);
|
2001-02-24 16:08:56 +00:00
|
|
|
|
2001-09-05 19:48:52 +00:00
|
|
|
/*
|
2005-03-10 16:36:05 +00:00
|
|
|
* Set up fallback option, for SSH-1 servers or servers with the
|
2001-09-05 19:48:52 +00:00
|
|
|
* sftp subsystem not enabled but the server binary installed
|
|
|
|
* in the usual place. We only support fallback on Unix
|
2001-09-05 19:58:25 +00:00
|
|
|
* systems, and we use a kludgy piece of shellery which should
|
|
|
|
* try to find sftp-server in various places (the obvious
|
|
|
|
* systemwide spots /usr/lib and /usr/local/lib, and then the
|
|
|
|
* user's PATH) and finally give up.
|
2001-09-05 19:48:52 +00:00
|
|
|
*
|
2001-09-05 19:58:25 +00:00
|
|
|
* test -x /usr/lib/sftp-server && exec /usr/lib/sftp-server
|
|
|
|
* test -x /usr/local/lib/sftp-server && exec /usr/local/lib/sftp-server
|
|
|
|
* exec sftp-server
|
2001-09-05 19:48:52 +00:00
|
|
|
*
|
|
|
|
* the idea being that this will attempt to use either of the
|
|
|
|
* obvious pathnames and then give up, and when it does give up
|
|
|
|
* it will print the preferred pathname in the error messages.
|
|
|
|
*/
|
Post-release destabilisation! Completely remove the struct type
'Config' in putty.h, which stores all PuTTY's settings and includes an
arbitrary length limit on every single one of those settings which is
stored in string form. In place of it is 'Conf', an opaque data type
everywhere outside the new file conf.c, which stores a list of (key,
value) pairs in which every key contains an integer identifying a
configuration setting, and for some of those integers the key also
contains extra parts (so that, for instance, CONF_environmt is a
string-to-string mapping). Everywhere that a Config was previously
used, a Conf is now; everywhere there was a Config structure copy,
conf_copy() is called; every lookup, adjustment, load and save
operation on a Config has been rewritten; and there's a mechanism for
serialising a Conf into a binary blob and back for use with Duplicate
Session.
User-visible effects of this change _should_ be minimal, though I
don't doubt I've introduced one or two bugs here and there which will
eventually be found. The _intended_ visible effects of this change are
that all arbitrary limits on configuration strings and lists (e.g.
limit on number of port forwardings) should now disappear; that list
boxes in the configuration will now be displayed in a sorted order
rather than the arbitrary order in which they were added to the list
(since the underlying data structure is now a sorted tree234 rather
than an ad-hoc comma-separated string); and one more specific change,
which is that local and dynamic port forwardings on the same port
number are now mutually exclusive in the configuration (putting 'D' in
the key rather than the value was a mistake in the first place).
One other reorganisation as a result of this is that I've moved all
the dialog.c standard handlers (dlg_stdeditbox_handler and friends)
out into config.c, because I can't really justify calling them generic
any more. When they took a pointer to an arbitrary structure type and
the offset of a field within that structure, they were independent of
whether that structure was a Config or something completely different,
but now they really do expect to talk to a Conf, which can _only_ be
used for PuTTY configuration, so I've renamed them all things like
conf_editbox_handler and moved them out of the nominally independent
dialog-box management module into the PuTTY-specific config.c.
[originally from svn r9214]
2011-07-14 18:52:21 +00:00
|
|
|
conf_set_str(conf, CONF_remote_cmd2,
|
|
|
|
"test -x /usr/lib/sftp-server &&"
|
|
|
|
" exec /usr/lib/sftp-server\n"
|
|
|
|
"test -x /usr/local/lib/sftp-server &&"
|
|
|
|
" exec /usr/local/lib/sftp-server\n"
|
|
|
|
"exec sftp-server");
|
|
|
|
conf_set_int(conf, CONF_ssh_subsys2, FALSE);
|
2001-09-05 19:48:52 +00:00
|
|
|
|
Refactor the LogContext type.
LogContext is now the owner of the logevent() function that back ends
and so forth are constantly calling. Previously, logevent was owned by
the Frontend, which would store the message into its list for the GUI
Event Log dialog (or print it to standard error, or whatever) and then
pass it _back_ to LogContext to write to the currently open log file.
Now it's the other way round: LogContext gets the message from the
back end first, writes it to its log file if it feels so inclined, and
communicates it back to the front end.
This means that lots of parts of the back end system no longer need to
have a pointer to a full-on Frontend; the only thing they needed it
for was logging, so now they just have a LogContext (which many of
them had to have anyway, e.g. for logging SSH packets or session
traffic).
LogContext itself also doesn't get a full Frontend pointer any more:
it now talks back to the front end via a little vtable of its own
called LogPolicy, which contains the method that passes Event Log
entries through, the old askappend() function that decides whether to
truncate a pre-existing log file, and an emergency function for
printing an especially prominent message if the log file can't be
created. One minor nice effect of this is that console and GUI apps
can implement that last function subtly differently, so that Unix
console apps can write it with a plain \n instead of the \r\n
(harmless but inelegant) that the old centralised implementation
generated.
One other consequence of this is that the LogContext has to be
provided to backend_init() so that it's available to backends from the
instant of creation, rather than being provided via a separate API
call a couple of function calls later, because backends have typically
started doing things that need logging (like making network
connections) before the call to backend_provide_logctx. Fortunately,
there's no case in the whole code base where we don't already have
logctx by the time we make a backend (so I don't actually remember why
I ever delayed providing one). So that shortens the backend API by one
function, which is always nice.
While I'm tidying up, I've also moved the printf-style logeventf() and
the handy logevent_and_free() into logging.c, instead of having copies
of them scattered around other places. This has also let me remove
some stub functions from a couple of outlying applications like
Pageant. Finally, I've removed the pointless "_tag" at the end of
LogContext's official struct name.
2018-10-10 18:26:18 +00:00
|
|
|
logctx = log_init(default_logpolicy, conf);
|
2017-02-11 00:23:36 +00:00
|
|
|
|
2017-02-11 00:44:00 +00:00
|
|
|
platform_psftp_pre_conn_setup();
|
|
|
|
|
New abstraction 'Seat', to pass to backends.
This is a new vtable-based abstraction which is passed to a backend in
place of Frontend, and it implements only the subset of the Frontend
functions needed by a backend. (Many other Frontend functions still
exist, notably the wide range of things called by terminal.c providing
platform-independent operations on the GUI terminal window.)
The purpose of making it a vtable is that this opens up the
possibility of creating a backend as an internal implementation detail
of some other activity, by providing just that one backend with a
custom Seat that implements the methods differently.
For example, this refactoring should make it feasible to directly
implement an SSH proxy type, aka the 'jump host' feature supported by
OpenSSH, aka 'open a secondary SSH session in MAINCHAN_DIRECT_TCP
mode, and then expose the main channel of that as the Socket for the
primary connection'. (Which of course you can already do by spawning
'plink -nc' as a separate proxy process, but this would permit it in
the _same_ process without anything getting confused.)
I've centralised a full set of stub methods in misc.c for the new
abstraction, which allows me to get rid of several annoying stubs in
the previous code. Also, while I'm here, I've moved a lot of
duplicated modalfatalbox() type functions from application main
program files into wincons.c / uxcons.c, which I think saves
duplication overall. (A minor visible effect is that the prefixes on
those console-based fatal error messages will now be more consistent
between applications.)
2018-10-11 18:58:42 +00:00
|
|
|
err = backend_init(&ssh_backend, psftp_seat, &backend, logctx, conf,
|
2018-09-11 15:23:38 +00:00
|
|
|
conf_get_str(conf, CONF_host),
|
|
|
|
conf_get_int(conf, CONF_port),
|
|
|
|
&realhost, 0,
|
|
|
|
conf_get_int(conf, CONF_tcp_keepalives));
|
2001-02-24 16:08:56 +00:00
|
|
|
if (err != NULL) {
|
2001-12-13 18:42:34 +00:00
|
|
|
fprintf(stderr, "ssh_init: %s\n", err);
|
2001-02-24 16:08:56 +00:00
|
|
|
return 1;
|
|
|
|
}
|
2018-09-11 15:23:38 +00:00
|
|
|
while (!backend_sendok(backend)) {
|
|
|
|
if (backend_exitcode(backend) >= 0)
|
2008-07-06 12:24:56 +00:00
|
|
|
return 1;
|
2003-08-24 12:47:46 +00:00
|
|
|
if (ssh_sftp_loop_iteration() < 0) {
|
|
|
|
fprintf(stderr, "ssh_init: error during SSH connection setup\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
2001-02-24 16:08:56 +00:00
|
|
|
if (verbose && realhost != NULL)
|
|
|
|
printf("Connected to %s\n", realhost);
|
2003-12-19 12:44:46 +00:00
|
|
|
if (realhost != NULL)
|
|
|
|
sfree(realhost);
|
2001-12-13 18:42:34 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-05-15 10:15:42 +00:00
|
|
|
void cmdline_error(const char *p, ...)
|
2002-08-04 21:18:56 +00:00
|
|
|
{
|
|
|
|
va_list ap;
|
2002-11-20 20:09:02 +00:00
|
|
|
fprintf(stderr, "psftp: ");
|
2002-08-04 21:18:56 +00:00
|
|
|
va_start(ap, p);
|
|
|
|
vfprintf(stderr, p, ap);
|
|
|
|
va_end(ap);
|
2002-11-20 20:09:02 +00:00
|
|
|
fprintf(stderr, "\n try typing \"psftp -h\" for help\n");
|
2002-08-04 21:18:56 +00:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2013-11-17 14:05:41 +00:00
|
|
|
const int share_can_be_downstream = TRUE;
|
|
|
|
const int share_can_be_upstream = FALSE;
|
|
|
|
|
2001-12-13 18:42:34 +00:00
|
|
|
/*
|
|
|
|
* Main program. Parse arguments etc.
|
|
|
|
*/
|
2003-08-24 12:47:46 +00:00
|
|
|
int psftp_main(int argc, char *argv[])
|
2001-12-13 18:42:34 +00:00
|
|
|
{
|
2015-06-25 22:27:16 +00:00
|
|
|
int i, ret;
|
2001-12-13 18:42:34 +00:00
|
|
|
int portnumber = 0;
|
|
|
|
char *userhost, *user;
|
|
|
|
int mode = 0;
|
|
|
|
int modeflags = 0;
|
|
|
|
char *batchfile = NULL;
|
|
|
|
|
Remove FLAG_STDERR completely.
Originally, it controlled whether ssh.c should send terminal messages
(such as login and password prompts) to terminal.c or to stderr. But
we've had the from_backend() abstraction for ages now, which even has
an existing flag to indicate that the data is stderr rather than
stdout data; applications which set FLAG_STDERR are precisely those
that link against uxcons or wincons, so from_backend will do the
expected thing anyway with data sent to it with that flag set. So
there's no reason ssh.c can't just unconditionally pass everything
through that, and remove the special case.
FLAG_STDERR was also used by winproxy and uxproxy to decide whether to
capture standard error from a local proxy command, or whether to let
the proxy command send its diagnostics directly to the usual standard
error. On reflection, I think it's better to unconditionally capture
the proxy's stderr, for three reasons. Firstly, it means proxy
diagnostics are prefixed with 'proxy:' so that you can tell them apart
from any other stderr spew (which used to be particularly confusing if
both the main application and the proxy command were instances of
Plink); secondly, proxy diagnostics are now reliably copied to packet
log files along with all the other Event Log entries, even by
command-line tools; and thirdly, this means the option to suppress
proxy command diagnostics after the main session starts will actually
_work_ in the command-line tools, which it previously couldn't.
A more minor structure change is that copying of Event Log messages to
stderr in verbose mode is now done by wincons/uxcons, instead of
centrally in logging.c (since logging.c can now no longer check
FLAG_STDERR to decide whether to do it). The total amount of code to
do this is considerably smaller than the defensive-sounding comment in
logevent.c explaining why I did it the other way instead :-)
2018-09-21 15:15:49 +00:00
|
|
|
flags = FLAG_INTERACTIVE
|
2003-08-24 13:22:17 +00:00
|
|
|
#ifdef FLAG_SYNCAGENT
|
|
|
|
| FLAG_SYNCAGENT
|
|
|
|
#endif
|
|
|
|
;
|
2002-08-04 21:18:56 +00:00
|
|
|
cmdline_tooltype = TOOLTYPE_FILETRANSFER;
|
2001-12-13 18:42:34 +00:00
|
|
|
sk_init();
|
|
|
|
|
|
|
|
userhost = user = NULL;
|
|
|
|
|
2004-07-25 14:00:26 +00:00
|
|
|
/* Load Default Settings before doing anything else. */
|
Post-release destabilisation! Completely remove the struct type
'Config' in putty.h, which stores all PuTTY's settings and includes an
arbitrary length limit on every single one of those settings which is
stored in string form. In place of it is 'Conf', an opaque data type
everywhere outside the new file conf.c, which stores a list of (key,
value) pairs in which every key contains an integer identifying a
configuration setting, and for some of those integers the key also
contains extra parts (so that, for instance, CONF_environmt is a
string-to-string mapping). Everywhere that a Config was previously
used, a Conf is now; everywhere there was a Config structure copy,
conf_copy() is called; every lookup, adjustment, load and save
operation on a Config has been rewritten; and there's a mechanism for
serialising a Conf into a binary blob and back for use with Duplicate
Session.
User-visible effects of this change _should_ be minimal, though I
don't doubt I've introduced one or two bugs here and there which will
eventually be found. The _intended_ visible effects of this change are
that all arbitrary limits on configuration strings and lists (e.g.
limit on number of port forwardings) should now disappear; that list
boxes in the configuration will now be displayed in a sorted order
rather than the arbitrary order in which they were added to the list
(since the underlying data structure is now a sorted tree234 rather
than an ad-hoc comma-separated string); and one more specific change,
which is that local and dynamic port forwardings on the same port
number are now mutually exclusive in the configuration (putting 'D' in
the key rather than the value was a mistake in the first place).
One other reorganisation as a result of this is that I've moved all
the dialog.c standard handlers (dlg_stdeditbox_handler and friends)
out into config.c, because I can't really justify calling them generic
any more. When they took a pointer to an arbitrary structure type and
the offset of a field within that structure, they were independent of
whether that structure was a Config or something completely different,
but now they really do expect to talk to a Conf, which can _only_ be
used for PuTTY configuration, so I've renamed them all things like
conf_editbox_handler and moved them out of the nominally independent
dialog-box management module into the PuTTY-specific config.c.
[originally from svn r9214]
2011-07-14 18:52:21 +00:00
|
|
|
conf = conf_new();
|
|
|
|
do_defaults(NULL, conf);
|
2004-07-25 14:00:26 +00:00
|
|
|
loaded_session = FALSE;
|
|
|
|
|
2001-12-13 18:42:34 +00:00
|
|
|
for (i = 1; i < argc; i++) {
|
2002-08-04 21:18:56 +00:00
|
|
|
int ret;
|
2001-12-13 18:42:34 +00:00
|
|
|
if (argv[i][0] != '-') {
|
2002-08-04 21:18:56 +00:00
|
|
|
if (userhost)
|
|
|
|
usage();
|
|
|
|
else
|
|
|
|
userhost = dupstr(argv[i]);
|
|
|
|
continue;
|
|
|
|
}
|
Post-release destabilisation! Completely remove the struct type
'Config' in putty.h, which stores all PuTTY's settings and includes an
arbitrary length limit on every single one of those settings which is
stored in string form. In place of it is 'Conf', an opaque data type
everywhere outside the new file conf.c, which stores a list of (key,
value) pairs in which every key contains an integer identifying a
configuration setting, and for some of those integers the key also
contains extra parts (so that, for instance, CONF_environmt is a
string-to-string mapping). Everywhere that a Config was previously
used, a Conf is now; everywhere there was a Config structure copy,
conf_copy() is called; every lookup, adjustment, load and save
operation on a Config has been rewritten; and there's a mechanism for
serialising a Conf into a binary blob and back for use with Duplicate
Session.
User-visible effects of this change _should_ be minimal, though I
don't doubt I've introduced one or two bugs here and there which will
eventually be found. The _intended_ visible effects of this change are
that all arbitrary limits on configuration strings and lists (e.g.
limit on number of port forwardings) should now disappear; that list
boxes in the configuration will now be displayed in a sorted order
rather than the arbitrary order in which they were added to the list
(since the underlying data structure is now a sorted tree234 rather
than an ad-hoc comma-separated string); and one more specific change,
which is that local and dynamic port forwardings on the same port
number are now mutually exclusive in the configuration (putting 'D' in
the key rather than the value was a mistake in the first place).
One other reorganisation as a result of this is that I've moved all
the dialog.c standard handlers (dlg_stdeditbox_handler and friends)
out into config.c, because I can't really justify calling them generic
any more. When they took a pointer to an arbitrary structure type and
the offset of a field within that structure, they were independent of
whether that structure was a Config or something completely different,
but now they really do expect to talk to a Conf, which can _only_ be
used for PuTTY configuration, so I've renamed them all things like
conf_editbox_handler and moved them out of the nominally independent
dialog-box management module into the PuTTY-specific config.c.
[originally from svn r9214]
2011-07-14 18:52:21 +00:00
|
|
|
ret = cmdline_process_param(argv[i], i+1<argc?argv[i+1]:NULL, 1, conf);
|
2002-08-04 21:18:56 +00:00
|
|
|
if (ret == -2) {
|
|
|
|
cmdline_error("option \"%s\" requires an argument", argv[i]);
|
|
|
|
} else if (ret == 2) {
|
|
|
|
i++; /* skip next argument */
|
|
|
|
} else if (ret == 1) {
|
|
|
|
/* We have our own verbosity in addition to `flags'. */
|
|
|
|
if (flags & FLAG_VERBOSE)
|
|
|
|
verbose = 1;
|
2001-12-13 18:42:34 +00:00
|
|
|
} else if (strcmp(argv[i], "-h") == 0 ||
|
2012-09-19 17:08:15 +00:00
|
|
|
strcmp(argv[i], "-?") == 0 ||
|
|
|
|
strcmp(argv[i], "--help") == 0) {
|
2001-12-13 18:42:34 +00:00
|
|
|
usage();
|
2005-03-19 02:26:58 +00:00
|
|
|
} else if (strcmp(argv[i], "-pgpfp") == 0) {
|
|
|
|
pgp_fingerprints();
|
|
|
|
return 1;
|
2012-09-19 17:08:15 +00:00
|
|
|
} else if (strcmp(argv[i], "-V") == 0 ||
|
|
|
|
strcmp(argv[i], "--version") == 0) {
|
2004-04-17 20:25:09 +00:00
|
|
|
version();
|
2002-08-04 21:18:56 +00:00
|
|
|
} else if (strcmp(argv[i], "-batch") == 0) {
|
|
|
|
console_batch_mode = 1;
|
2001-12-13 18:42:34 +00:00
|
|
|
} else if (strcmp(argv[i], "-b") == 0 && i + 1 < argc) {
|
|
|
|
mode = 1;
|
|
|
|
batchfile = argv[++i];
|
2001-12-14 10:06:09 +00:00
|
|
|
} else if (strcmp(argv[i], "-bc") == 0) {
|
2001-12-13 18:42:34 +00:00
|
|
|
modeflags = modeflags | 1;
|
2001-12-14 10:06:09 +00:00
|
|
|
} else if (strcmp(argv[i], "-be") == 0) {
|
2001-12-13 18:42:34 +00:00
|
|
|
modeflags = modeflags | 2;
|
|
|
|
} else if (strcmp(argv[i], "--") == 0) {
|
|
|
|
i++;
|
|
|
|
break;
|
|
|
|
} else {
|
2002-11-20 20:09:02 +00:00
|
|
|
cmdline_error("unknown option \"%s\"", argv[i]);
|
2001-12-13 18:42:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
argc -= i;
|
|
|
|
argv += i;
|
2018-09-11 15:23:38 +00:00
|
|
|
backend = NULL;
|
2001-12-13 18:42:34 +00:00
|
|
|
|
2004-07-28 11:04:22 +00:00
|
|
|
/*
|
|
|
|
* If the loaded session provides a hostname, and a hostname has not
|
|
|
|
* otherwise been specified, pop it in `userhost' so that
|
|
|
|
* `psftp -load sessname' is sufficient to start a session.
|
|
|
|
*/
|
Post-release destabilisation! Completely remove the struct type
'Config' in putty.h, which stores all PuTTY's settings and includes an
arbitrary length limit on every single one of those settings which is
stored in string form. In place of it is 'Conf', an opaque data type
everywhere outside the new file conf.c, which stores a list of (key,
value) pairs in which every key contains an integer identifying a
configuration setting, and for some of those integers the key also
contains extra parts (so that, for instance, CONF_environmt is a
string-to-string mapping). Everywhere that a Config was previously
used, a Conf is now; everywhere there was a Config structure copy,
conf_copy() is called; every lookup, adjustment, load and save
operation on a Config has been rewritten; and there's a mechanism for
serialising a Conf into a binary blob and back for use with Duplicate
Session.
User-visible effects of this change _should_ be minimal, though I
don't doubt I've introduced one or two bugs here and there which will
eventually be found. The _intended_ visible effects of this change are
that all arbitrary limits on configuration strings and lists (e.g.
limit on number of port forwardings) should now disappear; that list
boxes in the configuration will now be displayed in a sorted order
rather than the arbitrary order in which they were added to the list
(since the underlying data structure is now a sorted tree234 rather
than an ad-hoc comma-separated string); and one more specific change,
which is that local and dynamic port forwardings on the same port
number are now mutually exclusive in the configuration (putting 'D' in
the key rather than the value was a mistake in the first place).
One other reorganisation as a result of this is that I've moved all
the dialog.c standard handlers (dlg_stdeditbox_handler and friends)
out into config.c, because I can't really justify calling them generic
any more. When they took a pointer to an arbitrary structure type and
the offset of a field within that structure, they were independent of
whether that structure was a Config or something completely different,
but now they really do expect to talk to a Conf, which can _only_ be
used for PuTTY configuration, so I've renamed them all things like
conf_editbox_handler and moved them out of the nominally independent
dialog-box management module into the PuTTY-specific config.c.
[originally from svn r9214]
2011-07-14 18:52:21 +00:00
|
|
|
if (!userhost && conf_get_str(conf, CONF_host)[0] != '\0') {
|
|
|
|
userhost = dupstr(conf_get_str(conf, CONF_host));
|
2004-07-28 11:04:22 +00:00
|
|
|
}
|
|
|
|
|
2001-12-13 18:42:34 +00:00
|
|
|
/*
|
|
|
|
* If a user@host string has already been provided, connect to
|
|
|
|
* it now.
|
|
|
|
*/
|
|
|
|
if (userhost) {
|
2003-12-19 12:44:46 +00:00
|
|
|
int ret;
|
|
|
|
ret = psftp_connect(userhost, user, portnumber);
|
|
|
|
sfree(userhost);
|
|
|
|
if (ret)
|
2001-12-13 18:42:34 +00:00
|
|
|
return 1;
|
2002-02-27 22:20:30 +00:00
|
|
|
if (do_sftp_init())
|
|
|
|
return 1;
|
2001-12-13 18:42:34 +00:00
|
|
|
} else {
|
|
|
|
printf("psftp: no hostname specified; use \"open host.name\""
|
2003-12-19 12:44:46 +00:00
|
|
|
" to connect\n");
|
2001-12-13 18:42:34 +00:00
|
|
|
}
|
2001-02-23 18:21:44 +00:00
|
|
|
|
2015-06-25 22:27:16 +00:00
|
|
|
ret = do_sftp(mode, modeflags, batchfile);
|
2001-02-24 16:08:56 +00:00
|
|
|
|
2018-09-11 15:23:38 +00:00
|
|
|
if (backend && backend_connected(backend)) {
|
2001-02-24 16:08:56 +00:00
|
|
|
char ch;
|
Rework special-commands system to add an integer argument.
In order to list cross-certifiable host keys in the GUI specials menu,
the SSH backend has been inventing new values on the end of the
Telnet_Special enumeration, starting from the value TS_LOCALSTART.
This is inelegant, and also makes it awkward to break up special
handlers (e.g. to dispatch different specials to different SSH
layers), since if all you know about a special is that it's somewhere
in the TS_LOCALSTART+n space, you can't tell what _general kind_ of
thing it is. Also, if I ever need another open-ended set of specials
in future, I'll have to remember which TS_LOCALSTART+n codes are in
which set.
So here's a revamp that causes every special to take an extra integer
argument. For all previously numbered specials, this argument is
passed as zero and ignored, but there's a new main special code for
SSH host key cross-certification, in which the integer argument is an
index into the backend's list of available keys. TS_LOCALSTART is now
a thing of the past: if I need any other open-ended sets of specials
in future, I can add a new top-level code with a nicely separated
space of arguments.
While I'm at it, I've removed the legacy misnomer 'Telnet_Special'
from the code completely; the enum is now SessionSpecialCode, the
struct containing full details of a menu entry is SessionSpecial, and
the enum values now start SS_ rather than TS_.
2018-09-24 08:35:52 +00:00
|
|
|
backend_special(backend, SS_EOF, 0);
|
2011-09-13 11:44:03 +00:00
|
|
|
sent_eof = TRUE;
|
2001-02-24 16:08:56 +00:00
|
|
|
sftp_recvdata(&ch, 1);
|
|
|
|
}
|
2004-12-16 19:19:59 +00:00
|
|
|
do_sftp_cleanup();
|
2001-02-24 16:08:56 +00:00
|
|
|
random_save_seed();
|
2003-12-19 12:44:46 +00:00
|
|
|
cmdline_cleanup();
|
|
|
|
sk_cleanup();
|
2001-02-24 16:08:56 +00:00
|
|
|
|
2015-06-25 22:27:16 +00:00
|
|
|
return ret;
|
2001-02-23 18:21:44 +00:00
|
|
|
}
|