static int main_cmd_is_sftp = 0;
static int fallback_cmd_is_sftp = 0;
static int using_sftp = 0;
+static int uploading = 0;
static Backend *back;
static void *backhandle;
cleanup_exit(1);
}
+void nonfatal(char *fmt, ...)
+{
+ char *str, *str2;
+ va_list ap;
+ va_start(ap, fmt);
+ str = dupvprintf(fmt, ap);
+ str2 = dupcat("Error: ", str, "\n", NULL);
+ sfree(str);
+ va_end(ap);
+ tell_str(stderr, str2);
+ sfree(str2);
+ errs++;
+}
void connection_fatal(void *frontend, char *fmt, ...)
{
char *str, *str2;
int from_backend_eof(void *frontend)
{
/*
- * We expect to be the party deciding when to close the
+ * We usually expect to be the party deciding when to close the
* connection, so if we see EOF before we sent it ourselves, we
- * should panic.
+ * should panic. The exception is if we're using old-style scp and
+ * downloading rather than uploading.
*/
- if (!sent_eof) {
+ if ((using_sftp || uploading) && !sent_eof) {
connection_fatal(frontend,
"Received unexpected end-of-file from server");
}
cleanup_exit(1);
}
+/*
+ * Wait for the reply to a single SFTP request. Parallels the same
+ * function in psftp.c (but isn't centralised into sftp.c because the
+ * latter module handles SFTP only and shouldn't assume that SFTP is
+ * the only thing going on by calling connection_fatal).
+ */
+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();
+ if (pktin == NULL)
+ connection_fatal(NULL, "did not receive SFTP response packet "
+ "from server");
+ rreq = sftp_find_request(pktin);
+ if (rreq != req)
+ connection_fatal(NULL, "unable to understand SFTP response packet "
+ "from server: %s", fxp_error());
+ return pktin;
+}
+
/*
* Open an SSH connection to user@host and execute cmd.
*/
bump("Empty host name");
/*
- * Remove fiddly bits of address: remove a colon suffix, and
- * the square brackets around an IPv6 literal address.
+ * Remove a colon suffix.
*/
- if (host[0] == '[') {
- host++;
- host[strcspn(host, "]")] = '\0';
- } else {
- host[strcspn(host, ":")] = '\0';
- }
+ host[host_strcspn(host, ":")] = '\0';
/*
* If we haven't loaded session details already (e.g., from -load),
console_provide_logctx(logctx);
ssh_scp_init();
if (verbose && realhost != NULL && errs == 0)
- tell_user(stderr, "Connected to %s\n", realhost);
+ tell_user(stderr, "Connected to %s", realhost);
sfree(realhost);
}
if (str[0] == '\0' || str[0] == ':' ||
(str[0] != '[' && str[1] == ':'))
return (NULL);
- while (*str != '\0' && *str != ':' && *str != '/' && *str != '\\') {
- if (*str == '[') {
- /* Skip over IPv6 literal addresses
- * (eg: 'jeroen@[2001:db8::1]:myfile.txt') */
- char *ipv6_end = strchr(str, ']');
- if (ipv6_end) {
- str = ipv6_end;
- }
- }
- str++;
- }
+ str += host_strcspn(str, ":/\\");
if (*str == ':')
return (str);
else
} while (p < sizeof(rbuf) && ch != '\n');
rbuf[p - 1] = '\0';
if (resp == 1)
- tell_user(stderr, "%s\n", rbuf);
+ tell_user(stderr, "%s", rbuf);
else
bump("%s", rbuf);
errs++;
struct fxp_names *names;
struct fxp_name *ournames;
struct sftp_packet *pktin;
- struct sftp_request *req, *rreq;
+ struct sftp_request *req;
int nnames, namesize;
int i;
printf("Listing directory %s\n", dirname);
- sftp_register(req = fxp_opendir_send(dirname));
- rreq = sftp_find_request(pktin = sftp_recv());
- assert(rreq == req);
- dirh = fxp_opendir_recv(pktin, rreq);
+ req = fxp_opendir_send(dirname);
+ pktin = sftp_wait_for_reply(req);
+ dirh = fxp_opendir_recv(pktin, req);
if (dirh == NULL) {
printf("Unable to open %s: %s\n", dirname, fxp_error());
while (1) {
- sftp_register(req = fxp_readdir_send(dirh));
- rreq = sftp_find_request(pktin = sftp_recv());
- assert(rreq == req);
- names = fxp_readdir_recv(pktin, rreq);
+ req = fxp_readdir_send(dirh);
+ pktin = sftp_wait_for_reply(req);
+ names = fxp_readdir_recv(pktin, req);
if (names == NULL) {
if (fxp_error_type() == SSH_FX_EOF)
names->nnames = 0; /* prevent free_names */
fxp_free_names(names);
}
- sftp_register(req = fxp_close_send(dirh));
- rreq = sftp_find_request(pktin = sftp_recv());
- assert(rreq == req);
- fxp_close_recv(pktin, rreq);
+ req = fxp_close_send(dirh);
+ pktin = sftp_wait_for_reply(req);
+ fxp_close_recv(pktin, req);
/*
* Now we have our filenames. Sort them by actual file
* name, and then output the longname parts.
*/
- qsort(ournames, nnames, sizeof(*ournames), sftp_ls_compare);
+ if (nnames > 0)
+ qsort(ournames, nnames, sizeof(*ournames), sftp_ls_compare);
/*
* And print them.
*/
for (i = 0; i < nnames; i++)
printf("%s\n", ournames[i].longname);
+
+ sfree(ournames);
}
}
* directory.
*/
struct sftp_packet *pktin;
- struct sftp_request *req, *rreq;
+ struct sftp_request *req;
struct fxp_attrs attrs;
int ret;
return 1;
}
- sftp_register(req = fxp_stat_send(target));
- rreq = sftp_find_request(pktin = sftp_recv());
- assert(rreq == req);
- ret = fxp_stat_recv(pktin, rreq, &attrs);
+ req = fxp_stat_send(target);
+ pktin = sftp_wait_for_reply(req);
+ ret = fxp_stat_recv(pktin, req, &attrs);
if (!ret || !(attrs.flags & SSH_FILEXFER_ATTR_PERMISSIONS))
scp_sftp_targetisdir = 0;
if (using_sftp) {
char *fullname;
struct sftp_packet *pktin;
- struct sftp_request *req, *rreq;
+ struct sftp_request *req;
struct fxp_attrs attrs;
if (scp_sftp_targetisdir) {
attrs.flags = 0;
PUT_PERMISSIONS(attrs, permissions);
- sftp_register(req = fxp_open_send(fullname, SSH_FXF_WRITE |
- SSH_FXF_CREAT | SSH_FXF_TRUNC,
- &attrs));
- rreq = sftp_find_request(pktin = sftp_recv());
- assert(rreq == req);
- scp_sftp_filehandle = fxp_open_recv(pktin, rreq);
+ req = fxp_open_send(fullname,
+ SSH_FXF_WRITE | SSH_FXF_CREAT | SSH_FXF_TRUNC,
+ &attrs);
+ pktin = sftp_wait_for_reply(req);
+ scp_sftp_filehandle = fxp_open_recv(pktin, req);
if (!scp_sftp_filehandle) {
tell_user(stderr, "pscp: unable to open %s: %s",
fullname, fxp_error());
+ sfree(fullname);
errs++;
return 1;
}
while (!xfer_upload_ready(scp_sftp_xfer)) {
pktin = sftp_recv();
ret = xfer_upload_gotpkt(scp_sftp_xfer, pktin);
- if (!ret) {
- tell_user(stderr, "error while writing: %s\n", fxp_error());
+ if (ret <= 0) {
+ tell_user(stderr, "error while writing: %s", fxp_error());
+ if (ret == INT_MIN) /* pktin not even freed */
+ sfree(pktin);
errs++;
return 1;
}
if (using_sftp) {
struct fxp_attrs attrs;
struct sftp_packet *pktin;
- struct sftp_request *req, *rreq;
+ struct sftp_request *req;
int ret;
while (!xfer_done(scp_sftp_xfer)) {
pktin = sftp_recv();
- xfer_upload_gotpkt(scp_sftp_xfer, pktin);
+ ret = xfer_upload_gotpkt(scp_sftp_xfer, pktin);
+ if (ret <= 0) {
+ tell_user(stderr, "error while writing: %s", fxp_error());
+ if (ret == INT_MIN) /* pktin not even freed */
+ sfree(pktin);
+ errs++;
+ return 1;
+ }
}
xfer_cleanup(scp_sftp_xfer);
attrs.flags = SSH_FILEXFER_ATTR_ACMODTIME;
attrs.atime = scp_sftp_atime;
attrs.mtime = scp_sftp_mtime;
- sftp_register(req = fxp_fsetstat_send(scp_sftp_filehandle, attrs));
- rreq = sftp_find_request(pktin = sftp_recv());
- assert(rreq == req);
- ret = fxp_fsetstat_recv(pktin, rreq);
+ req = fxp_fsetstat_send(scp_sftp_filehandle, attrs);
+ pktin = sftp_wait_for_reply(req);
+ ret = fxp_fsetstat_recv(pktin, req);
if (!ret) {
- tell_user(stderr, "unable to set file times: %s\n", fxp_error());
+ tell_user(stderr, "unable to set file times: %s", fxp_error());
errs++;
}
}
- sftp_register(req = fxp_close_send(scp_sftp_filehandle));
- rreq = sftp_find_request(pktin = sftp_recv());
- assert(rreq == req);
- fxp_close_recv(pktin, rreq);
+ req = fxp_close_send(scp_sftp_filehandle);
+ pktin = sftp_wait_for_reply(req);
+ fxp_close_recv(pktin, req);
scp_has_times = 0;
return 0;
} else {
char const *err;
struct fxp_attrs attrs;
struct sftp_packet *pktin;
- struct sftp_request *req, *rreq;
+ struct sftp_request *req;
int ret;
if (scp_sftp_targetisdir) {
* exists and is a directory we will assume we were either
* successful or it didn't matter.
*/
- sftp_register(req = fxp_mkdir_send(fullname));
- rreq = sftp_find_request(pktin = sftp_recv());
- assert(rreq == req);
- ret = fxp_mkdir_recv(pktin, rreq);
+ req = fxp_mkdir_send(fullname);
+ pktin = sftp_wait_for_reply(req);
+ ret = fxp_mkdir_recv(pktin, req);
if (!ret)
err = fxp_error();
else
err = "server reported no error";
- sftp_register(req = fxp_stat_send(fullname));
- rreq = sftp_find_request(pktin = sftp_recv());
- assert(rreq == req);
- ret = fxp_stat_recv(pktin, rreq, &attrs);
+ req = fxp_stat_send(fullname);
+ pktin = sftp_wait_for_reply(req);
+ ret = fxp_stat_recv(pktin, req, &attrs);
if (!ret || !(attrs.flags & SSH_FILEXFER_ATTR_PERMISSIONS) ||
!(attrs.permissions & 0040000)) {
tell_user(stderr, "unable to create directory %s: %s",
fullname, err);
+ sfree(fullname);
errs++;
return 1;
}
if (!wc_unescape(newsource, source)) {
/* Yes, here we go; it's a wildcard. Bah. */
char *dupsource, *lastpart, *dirpart, *wildcard;
+
+ sfree(newsource);
+
dupsource = dupstr(source);
lastpart = stripslashes(dupsource, 0);
wildcard = dupstr(lastpart);
int must_free_fname;
struct fxp_attrs attrs;
struct sftp_packet *pktin;
- struct sftp_request *req, *rreq;
+ struct sftp_request *req;
int ret;
if (!scp_sftp_dirstack_head) {
* Now we have a filename. Stat it, and see if it's a file
* or a directory.
*/
- sftp_register(req = fxp_stat_send(fname));
- rreq = sftp_find_request(pktin = sftp_recv());
- assert(rreq == req);
- ret = fxp_stat_recv(pktin, rreq, &attrs);
+ req = fxp_stat_send(fname);
+ pktin = sftp_wait_for_reply(req);
+ ret = fxp_stat_recv(pktin, req, &attrs);
if (!ret || !(attrs.flags & SSH_FILEXFER_ATTR_PERMISSIONS)) {
tell_user(stderr, "unable to identify %s: %s", fname,
ret ? "file type not supplied" : fxp_error());
+ if (must_free_fname) sfree(fname);
errs++;
return 1;
}
* list), we must push the other (target,namelist) pair
* on a stack.
*/
- sftp_register(req = fxp_opendir_send(fname));
- rreq = sftp_find_request(pktin = sftp_recv());
- assert(rreq == req);
- dirhandle = fxp_opendir_recv(pktin, rreq);
+ req = fxp_opendir_send(fname);
+ pktin = sftp_wait_for_reply(req);
+ dirhandle = fxp_opendir_recv(pktin, req);
if (!dirhandle) {
- tell_user(stderr, "scp: unable to open directory %s: %s",
+ tell_user(stderr, "pscp: unable to open directory %s: %s",
fname, fxp_error());
if (must_free_fname) sfree(fname);
errs++;
while (1) {
int i;
- sftp_register(req = fxp_readdir_send(dirhandle));
- rreq = sftp_find_request(pktin = sftp_recv());
- assert(rreq == req);
- names = fxp_readdir_recv(pktin, rreq);
+ req = fxp_readdir_send(dirhandle);
+ pktin = sftp_wait_for_reply(req);
+ names = fxp_readdir_recv(pktin, req);
if (names == NULL) {
if (fxp_error_type() == SSH_FX_EOF)
break;
- tell_user(stderr, "scp: reading directory %s: %s\n",
+ tell_user(stderr, "pscp: reading directory %s: %s",
fname, fxp_error());
+
+ req = fxp_close_send(dirhandle);
+ pktin = sftp_wait_for_reply(req);
+ fxp_close_recv(pktin, req);
+
if (must_free_fname) sfree(fname);
sfree(ournames);
errs++;
*/
} else if (!vet_filename(names->names[i].filename)) {
tell_user(stderr, "ignoring potentially dangerous server-"
- "supplied filename '%s'\n",
+ "supplied filename '%s'",
names->names[i].filename);
} else
ournames[nnames++] = names->names[i];
names->nnames = 0; /* prevent free_names */
fxp_free_names(names);
}
- sftp_register(req = fxp_close_send(dirhandle));
- rreq = sftp_find_request(pktin = sftp_recv());
- assert(rreq == req);
- fxp_close_recv(pktin, rreq);
+ req = fxp_close_send(dirhandle);
+ pktin = sftp_wait_for_reply(req);
+ fxp_close_recv(pktin, req);
newitem = snew(struct scp_sftp_dirstack);
newitem->next = scp_sftp_dirstack_head;
act->buf[i - 1] = '\0';
switch (action) {
case '\01': /* error */
- tell_user(stderr, "%s\n", act->buf);
+ tell_user(stderr, "%s", act->buf);
errs++;
continue; /* go round again */
case '\02': /* fatal error */
{
if (using_sftp) {
struct sftp_packet *pktin;
- struct sftp_request *req, *rreq;
+ struct sftp_request *req;
- sftp_register(req = fxp_open_send(scp_sftp_currentname, SSH_FXF_READ,
- NULL));
- rreq = sftp_find_request(pktin = sftp_recv());
- assert(rreq == req);
- scp_sftp_filehandle = fxp_open_recv(pktin, rreq);
+ req = fxp_open_send(scp_sftp_currentname, SSH_FXF_READ, NULL);
+ pktin = sftp_wait_for_reply(req);
+ scp_sftp_filehandle = fxp_open_recv(pktin, req);
if (!scp_sftp_filehandle) {
tell_user(stderr, "pscp: unable to open %s: %s",
xfer_download_queue(scp_sftp_xfer);
pktin = sftp_recv();
ret = xfer_download_gotpkt(scp_sftp_xfer, pktin);
-
- if (ret < 0) {
+ if (ret <= 0) {
tell_user(stderr, "pscp: error while reading: %s", fxp_error());
+ if (ret == INT_MIN) /* pktin not even freed */
+ sfree(pktin);
errs++;
return -1;
}
{
if (using_sftp) {
struct sftp_packet *pktin;
- struct sftp_request *req, *rreq;
+ struct sftp_request *req;
/*
* Ensure that xfer_done() will work correctly, so we can
xfer_set_error(scp_sftp_xfer);
while (!xfer_done(scp_sftp_xfer)) {
void *vbuf;
- int len;
+ int ret, len;
pktin = sftp_recv();
- xfer_download_gotpkt(scp_sftp_xfer, pktin);
+ ret = xfer_download_gotpkt(scp_sftp_xfer, pktin);
+ if (ret <= 0) {
+ tell_user(stderr, "pscp: error while reading: %s", fxp_error());
+ if (ret == INT_MIN) /* pktin not even freed */
+ sfree(pktin);
+ errs++;
+ return -1;
+ }
if (xfer_download_data(scp_sftp_xfer, &vbuf, &len))
sfree(vbuf);
}
xfer_cleanup(scp_sftp_xfer);
- sftp_register(req = fxp_close_send(scp_sftp_filehandle));
- rreq = sftp_find_request(pktin = sftp_recv());
- assert(rreq == req);
- fxp_close_recv(pktin, rreq);
+ req = fxp_close_send(scp_sftp_filehandle);
+ pktin = sftp_wait_for_reply(req);
+ fxp_close_recv(pktin, req);
return 0;
} else {
back->send(backhandle, "", 1);
va_start(ap, fmt);
errs++;
str = dupvprintf(fmt, ap);
- str2 = dupcat("scp: ", str, "\n", NULL);
+ str2 = dupcat("pscp: ", str, "\n", NULL);
sfree(str);
scp_send_errmsg(str2);
tell_user(stderr, "%s", str2);
return;
}
if (preserve) {
- if (scp_send_filetimes(mtime, atime))
+ if (scp_send_filetimes(mtime, atime)) {
+ close_rfile(f);
return;
+ }
}
if (verbose) {
uint64_decimal(size, sizestr);
tell_user(stderr, "Sending file %s, size=%s", last, sizestr);
}
- if (scp_send_filename(last, size, permissions))
+ if (scp_send_filename(last, size, permissions)) {
+ close_rfile(f);
return;
+ }
stat_bytes = uint64_make(0,0);
stat_starttime = time(NULL);
if (act.action == SCP_SINK_DIR) {
if (exists && attr != FILE_TYPE_DIRECTORY) {
run_err("%s: Not a directory", destfname);
+ sfree(destfname);
continue;
}
if (!exists) {
if (!create_directory(destfname)) {
run_err("%s: Cannot create directory", destfname);
+ sfree(destfname);
continue;
}
}
sink(destfname, NULL);
/* can we set the timestamp for directories ? */
+ sfree(destfname);
continue;
}
f = open_new_file(destfname, act.permissions);
if (f == NULL) {
run_err("%s: Cannot create file", destfname);
+ sfree(destfname);
continue;
}
- if (scp_accept_filexfer())
+ if (scp_accept_filexfer()) {
+ sfree(destfname);
+ close_wfile(f);
return;
+ }
stat_bytes = uint64_make(0, 0);
stat_starttime = time(NULL);
close_wfile(f);
if (wrerror) {
run_err("%s: Write error", destfname);
+ sfree(destfname);
continue;
}
(void) scp_finish_filerecv();
char *cmd;
int i, wc_type;
+ uploading = 1;
+
targ = argv[argc - 1];
/* Separate host from filename */
char *src, *targ, *host, *user;
char *cmd;
+ uploading = 0;
+
if (argc != 2)
bump("More than one remote source not supported");
printf(" -1 -2 force use of particular SSH protocol version\n");
printf(" -4 -6 force use of IPv4 or IPv6\n");
printf(" -C enable compression\n");
- printf(" -i key private key file for authentication\n");
+ printf(" -i key private key file for user authentication\n");
printf(" -noagent disable use of Pageant\n");
printf(" -agent enable use of Pageant\n");
+ printf(" -hostkey aa:bb:cc:...\n");
+ printf(" manually specify a host key (may be repeated)\n");
printf(" -batch disable all interactive prompts\n");
printf(" -unsafe allow server-side wildcards (DANGEROUS)\n");
printf(" -sftp force use of SFTP protocol\n");
exit(1);
}
+const int share_can_be_downstream = TRUE;
+const int share_can_be_upstream = FALSE;
+
/*
* Main program. (Called `psftp_main' because it gets called from
* *sftp.c; bit silly, I know, but it had to be called _something_.)