diff --git a/progressmeter.c b/progressmeter.c index bbbc7066b..319b7470a 100644 --- a/progressmeter.c +++ b/progressmeter.c @@ -1,4 +1,4 @@ -/* $OpenBSD: progressmeter.c,v 1.40 2013/09/19 00:24:52 djm Exp $ */ +/* $OpenBSD: progressmeter.c,v 1.41 2015/01/14 13:54:13 djm Exp $ */ /* * Copyright (c) 2003 Nils Nordman. All rights reserved. * @@ -65,7 +65,7 @@ static void update_progress_meter(int); static time_t start; /* start progress */ static time_t last_update; /* last progress update */ -static char *file; /* name of the file being transferred */ +static const char *file; /* name of the file being transferred */ static off_t start_pos; /* initial position of transfer */ static off_t end_pos; /* ending position of transfer */ static off_t cur_pos; /* transfer position as of last refresh */ @@ -248,7 +248,7 @@ update_progress_meter(int ignore) } void -start_progress_meter(char *f, off_t filesize, off_t *ctr) +start_progress_meter(const char *f, off_t filesize, off_t *ctr) { start = last_update = monotime(); file = f; diff --git a/progressmeter.h b/progressmeter.h index 10bab99ba..bf179dca6 100644 --- a/progressmeter.h +++ b/progressmeter.h @@ -1,4 +1,4 @@ -/* $OpenBSD: progressmeter.h,v 1.2 2006/03/25 22:22:43 djm Exp $ */ +/* $OpenBSD: progressmeter.h,v 1.3 2015/01/14 13:54:13 djm Exp $ */ /* * Copyright (c) 2002 Nils Nordman. All rights reserved. * @@ -23,5 +23,5 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -void start_progress_meter(char *, off_t, off_t *); +void start_progress_meter(const char *, off_t, off_t *); void stop_progress_meter(void); diff --git a/sftp-client.c b/sftp-client.c index 990b58d14..574da833a 100644 --- a/sftp-client.c +++ b/sftp-client.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sftp-client.c,v 1.115 2014/04/21 14:36:16 logan Exp $ */ +/* $OpenBSD: sftp-client.c,v 1.116 2015/01/14 13:54:13 djm Exp $ */ /* * Copyright (c) 2001-2004 Damien Miller * @@ -47,7 +47,8 @@ #include #include "xmalloc.h" -#include "buffer.h" +#include "ssherr.h" +#include "sshbuf.h" #include "log.h" #include "atomicio.h" #include "progressmeter.h" @@ -83,8 +84,8 @@ struct sftp_conn { struct bwlimit bwlimit_in, bwlimit_out; }; -static char * -get_handle(struct sftp_conn *conn, u_int expected_id, u_int *len, +static u_char * +get_handle(struct sftp_conn *conn, u_int expected_id, size_t *len, const char *errfmt, ...) __attribute__((format(printf, 4, 5))); /* ARGSUSED */ @@ -98,36 +99,39 @@ sftpio(void *_bwlimit, size_t amount) } static void -send_msg(struct sftp_conn *conn, Buffer *m) +send_msg(struct sftp_conn *conn, struct sshbuf *m) { u_char mlen[4]; struct iovec iov[2]; - if (buffer_len(m) > SFTP_MAX_MSG_LENGTH) - fatal("Outbound message too long %u", buffer_len(m)); + if (sshbuf_len(m) > SFTP_MAX_MSG_LENGTH) + fatal("Outbound message too long %zu", sshbuf_len(m)); /* Send length first */ - put_u32(mlen, buffer_len(m)); + put_u32(mlen, sshbuf_len(m)); iov[0].iov_base = mlen; iov[0].iov_len = sizeof(mlen); - iov[1].iov_base = buffer_ptr(m); - iov[1].iov_len = buffer_len(m); + iov[1].iov_base = (u_char *)sshbuf_ptr(m); + iov[1].iov_len = sshbuf_len(m); if (atomiciov6(writev, conn->fd_out, iov, 2, conn->limit_kbps > 0 ? sftpio : NULL, &conn->bwlimit_out) != - buffer_len(m) + sizeof(mlen)) + sshbuf_len(m) + sizeof(mlen)) fatal("Couldn't send packet: %s", strerror(errno)); - buffer_clear(m); + sshbuf_reset(m); } static void -get_msg(struct sftp_conn *conn, Buffer *m) +get_msg(struct sftp_conn *conn, struct sshbuf *m) { u_int msg_len; + u_char *p; + int r; - buffer_append_space(m, 4); - if (atomicio6(read, conn->fd_in, buffer_ptr(m), 4, + if ((r = sshbuf_reserve(m, 4, &p)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); + if (atomicio6(read, conn->fd_in, p, 4, conn->limit_kbps > 0 ? sftpio : NULL, &conn->bwlimit_in) != 4) { if (errno == EPIPE) fatal("Connection closed"); @@ -135,12 +139,14 @@ get_msg(struct sftp_conn *conn, Buffer *m) fatal("Couldn't read packet: %s", strerror(errno)); } - msg_len = buffer_get_int(m); + if ((r = sshbuf_get_u32(m, &msg_len)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); if (msg_len > SFTP_MAX_MSG_LENGTH) fatal("Received message too long %u", msg_len); - buffer_append_space(m, msg_len); - if (atomicio6(read, conn->fd_in, buffer_ptr(m), msg_len, + if ((r = sshbuf_reserve(m, msg_len, &p)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); + if (atomicio6(read, conn->fd_in, p, msg_len, conn->limit_kbps > 0 ? sftpio : NULL, &conn->bwlimit_in) != msg_len) { if (errno == EPIPE) @@ -151,46 +157,56 @@ get_msg(struct sftp_conn *conn, Buffer *m) } static void -send_string_request(struct sftp_conn *conn, u_int id, u_int code, char *s, +send_string_request(struct sftp_conn *conn, u_int id, u_int code, const char *s, u_int len) { - Buffer msg; + struct sshbuf *msg; + int r; - buffer_init(&msg); - buffer_put_char(&msg, code); - buffer_put_int(&msg, id); - buffer_put_string(&msg, s, len); - send_msg(conn, &msg); + if ((msg = sshbuf_new()) == NULL) + fatal("%s: sshbuf_new failed", __func__); + if ((r = sshbuf_put_u8(msg, code)) != 0 || + (r = sshbuf_put_u32(msg, id)) != 0 || + (r = sshbuf_put_string(msg, s, len)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); + send_msg(conn, msg); debug3("Sent message fd %d T:%u I:%u", conn->fd_out, code, id); - buffer_free(&msg); + sshbuf_free(msg); } static void send_string_attrs_request(struct sftp_conn *conn, u_int id, u_int code, - char *s, u_int len, Attrib *a) + const void *s, u_int len, Attrib *a) { - Buffer msg; + struct sshbuf *msg; + int r; - buffer_init(&msg); - buffer_put_char(&msg, code); - buffer_put_int(&msg, id); - buffer_put_string(&msg, s, len); - encode_attrib(&msg, a); - send_msg(conn, &msg); + if ((msg = sshbuf_new()) == NULL) + fatal("%s: sshbuf_new failed", __func__); + if ((r = sshbuf_put_u8(msg, code)) != 0 || + (r = sshbuf_put_u32(msg, id)) != 0 || + (r = sshbuf_put_string(msg, s, len)) != 0 || + (r = encode_attrib(msg, a)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); + send_msg(conn, msg); debug3("Sent message fd %d T:%u I:%u", conn->fd_out, code, id); - buffer_free(&msg); + sshbuf_free(msg); } static u_int get_status(struct sftp_conn *conn, u_int expected_id) { - Buffer msg; - u_int type, id, status; + struct sshbuf *msg; + u_char type; + u_int id, status; + int r; - buffer_init(&msg); - get_msg(conn, &msg); - type = buffer_get_char(&msg); - id = buffer_get_int(&msg); + if ((msg = sshbuf_new()) == NULL) + fatal("%s: sshbuf_new failed", __func__); + get_msg(conn, msg); + if ((r = sshbuf_get_u8(msg, &type)) != 0 || + (r = sshbuf_get_u32(msg, &id)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); if (id != expected_id) fatal("ID mismatch (%u != %u)", id, expected_id); @@ -198,112 +214,136 @@ get_status(struct sftp_conn *conn, u_int expected_id) fatal("Expected SSH2_FXP_STATUS(%u) packet, got %u", SSH2_FXP_STATUS, type); - status = buffer_get_int(&msg); - buffer_free(&msg); + if ((r = sshbuf_get_u32(msg, &status)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); + sshbuf_free(msg); debug3("SSH2_FXP_STATUS %u", status); return status; } -static char * -get_handle(struct sftp_conn *conn, u_int expected_id, u_int *len, +static u_char * +get_handle(struct sftp_conn *conn, u_int expected_id, size_t *len, const char *errfmt, ...) { - Buffer msg; - u_int type, id; - char *handle, errmsg[256]; + struct sshbuf *msg; + u_int id, status; + u_char type; + u_char *handle; + char errmsg[256]; va_list args; - int status; + int r; va_start(args, errfmt); if (errfmt != NULL) vsnprintf(errmsg, sizeof(errmsg), errfmt, args); va_end(args); - buffer_init(&msg); - get_msg(conn, &msg); - type = buffer_get_char(&msg); - id = buffer_get_int(&msg); + if ((msg = sshbuf_new()) == NULL) + fatal("%s: sshbuf_new failed", __func__); + get_msg(conn, msg); + if ((r = sshbuf_get_u8(msg, &type)) != 0 || + (r = sshbuf_get_u32(msg, &id)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); if (id != expected_id) fatal("%s: ID mismatch (%u != %u)", errfmt == NULL ? __func__ : errmsg, id, expected_id); if (type == SSH2_FXP_STATUS) { - status = buffer_get_int(&msg); + if ((r = sshbuf_get_u32(msg, &status)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); if (errfmt != NULL) error("%s: %s", errmsg, fx2txt(status)); - buffer_free(&msg); + sshbuf_free(msg); return(NULL); } else if (type != SSH2_FXP_HANDLE) fatal("%s: Expected SSH2_FXP_HANDLE(%u) packet, got %u", errfmt == NULL ? __func__ : errmsg, SSH2_FXP_HANDLE, type); - handle = buffer_get_string(&msg, len); - buffer_free(&msg); + if ((r = sshbuf_get_string(msg, &handle, len)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); + sshbuf_free(msg); - return(handle); + return handle; } static Attrib * get_decode_stat(struct sftp_conn *conn, u_int expected_id, int quiet) { - Buffer msg; - u_int type, id; - Attrib *a; + struct sshbuf *msg; + u_int id; + u_char type; + int r; + static Attrib a; - buffer_init(&msg); - get_msg(conn, &msg); + if ((msg = sshbuf_new()) == NULL) + fatal("%s: sshbuf_new failed", __func__); + get_msg(conn, msg); - type = buffer_get_char(&msg); - id = buffer_get_int(&msg); + if ((r = sshbuf_get_u8(msg, &type)) != 0 || + (r = sshbuf_get_u32(msg, &id)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); debug3("Received stat reply T:%u I:%u", type, id); if (id != expected_id) fatal("ID mismatch (%u != %u)", id, expected_id); if (type == SSH2_FXP_STATUS) { - int status = buffer_get_int(&msg); + u_int status; + if ((r = sshbuf_get_u32(msg, &status)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); if (quiet) debug("Couldn't stat remote file: %s", fx2txt(status)); else error("Couldn't stat remote file: %s", fx2txt(status)); - buffer_free(&msg); + sshbuf_free(msg); return(NULL); } else if (type != SSH2_FXP_ATTRS) { fatal("Expected SSH2_FXP_ATTRS(%u) packet, got %u", SSH2_FXP_ATTRS, type); } - a = decode_attrib(&msg); - buffer_free(&msg); + if ((r = decode_attrib(msg, &a)) != 0) { + error("%s: couldn't decode attrib: %s", __func__, ssh_err(r)); + sshbuf_free(msg); + return NULL; + } + sshbuf_free(msg); - return(a); + return &a; } static int get_decode_statvfs(struct sftp_conn *conn, struct sftp_statvfs *st, u_int expected_id, int quiet) { - Buffer msg; - u_int type, id, flag; + struct sshbuf *msg; + u_char type; + u_int id; + u_int64_t flag; + int r; - buffer_init(&msg); - get_msg(conn, &msg); + if ((msg = sshbuf_new()) == NULL) + fatal("%s: sshbuf_new failed", __func__); + get_msg(conn, msg); - type = buffer_get_char(&msg); - id = buffer_get_int(&msg); + if ((r = sshbuf_get_u8(msg, &type)) != 0 || + (r = sshbuf_get_u32(msg, &id)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); debug3("Received statvfs reply T:%u I:%u", type, id); if (id != expected_id) fatal("ID mismatch (%u != %u)", id, expected_id); if (type == SSH2_FXP_STATUS) { - int status = buffer_get_int(&msg); + u_int status; + if ((r = sshbuf_get_u32(msg, &status)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); if (quiet) debug("Couldn't statvfs: %s", fx2txt(status)); else error("Couldn't statvfs: %s", fx2txt(status)); - buffer_free(&msg); + sshbuf_free(msg); return -1; } else if (type != SSH2_FXP_EXTENDED_REPLY) { fatal("Expected SSH2_FXP_EXTENDED_REPLY(%u) packet, got %u", @@ -311,22 +351,23 @@ get_decode_statvfs(struct sftp_conn *conn, struct sftp_statvfs *st, } memset(st, 0, sizeof(*st)); - st->f_bsize = buffer_get_int64(&msg); - st->f_frsize = buffer_get_int64(&msg); - st->f_blocks = buffer_get_int64(&msg); - st->f_bfree = buffer_get_int64(&msg); - st->f_bavail = buffer_get_int64(&msg); - st->f_files = buffer_get_int64(&msg); - st->f_ffree = buffer_get_int64(&msg); - st->f_favail = buffer_get_int64(&msg); - st->f_fsid = buffer_get_int64(&msg); - flag = buffer_get_int64(&msg); - st->f_namemax = buffer_get_int64(&msg); + if ((r = sshbuf_get_u64(msg, &st->f_bsize)) != 0 || + (r = sshbuf_get_u64(msg, &st->f_frsize)) != 0 || + (r = sshbuf_get_u64(msg, &st->f_blocks)) != 0 || + (r = sshbuf_get_u64(msg, &st->f_bfree)) != 0 || + (r = sshbuf_get_u64(msg, &st->f_bavail)) != 0 || + (r = sshbuf_get_u64(msg, &st->f_files)) != 0 || + (r = sshbuf_get_u64(msg, &st->f_ffree)) != 0 || + (r = sshbuf_get_u64(msg, &st->f_favail)) != 0 || + (r = sshbuf_get_u64(msg, &st->f_fsid)) != 0 || + (r = sshbuf_get_u64(msg, &flag)) != 0 || + (r = sshbuf_get_u64(msg, &st->f_namemax)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); st->f_flag = (flag & SSH2_FXE_STATVFS_ST_RDONLY) ? ST_RDONLY : 0; st->f_flag |= (flag & SSH2_FXE_STATVFS_ST_NOSUID) ? ST_NOSUID : 0; - buffer_free(&msg); + sshbuf_free(msg); return 0; } @@ -335,9 +376,10 @@ struct sftp_conn * do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests, u_int64_t limit_kbps) { - u_int type; - Buffer msg; + u_char type; + struct sshbuf *msg; struct sftp_conn *ret; + int r; ret = xcalloc(1, sizeof(*ret)); ret->msg_id = 1; @@ -348,52 +390,61 @@ do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests, ret->exts = 0; ret->limit_kbps = 0; - buffer_init(&msg); - buffer_put_char(&msg, SSH2_FXP_INIT); - buffer_put_int(&msg, SSH2_FILEXFER_VERSION); - send_msg(ret, &msg); + if ((msg = sshbuf_new()) == NULL) + fatal("%s: sshbuf_new failed", __func__); + if ((r = sshbuf_put_u8(msg, SSH2_FXP_INIT)) != 0 || + (r = sshbuf_put_u32(msg, SSH2_FILEXFER_VERSION)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); + send_msg(ret, msg); - buffer_clear(&msg); + sshbuf_reset(msg); - get_msg(ret, &msg); + get_msg(ret, msg); /* Expecting a VERSION reply */ - if ((type = buffer_get_char(&msg)) != SSH2_FXP_VERSION) { + if ((r = sshbuf_get_u8(msg, &type)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); + if (type != SSH2_FXP_VERSION) { error("Invalid packet back from SSH2_FXP_INIT (type %u)", type); - buffer_free(&msg); + sshbuf_free(msg); return(NULL); } - ret->version = buffer_get_int(&msg); + if ((r = sshbuf_get_u32(msg, &ret->version)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); debug2("Remote version: %u", ret->version); /* Check for extensions */ - while (buffer_len(&msg) > 0) { - char *name = buffer_get_string(&msg, NULL); - char *value = buffer_get_string(&msg, NULL); + while (sshbuf_len(msg) > 0) { + char *name; + u_char *value; + size_t vlen; int known = 0; + if ((r = sshbuf_get_cstring(msg, &name, NULL)) != 0 || + (r = sshbuf_get_string(msg, &value, &vlen)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); if (strcmp(name, "posix-rename@openssh.com") == 0 && - strcmp(value, "1") == 0) { + strcmp((char *)value, "1") == 0) { ret->exts |= SFTP_EXT_POSIX_RENAME; known = 1; } else if (strcmp(name, "statvfs@openssh.com") == 0 && - strcmp(value, "2") == 0) { + strcmp((char *)value, "2") == 0) { ret->exts |= SFTP_EXT_STATVFS; known = 1; } else if (strcmp(name, "fstatvfs@openssh.com") == 0 && - strcmp(value, "2") == 0) { + strcmp((char *)value, "2") == 0) { ret->exts |= SFTP_EXT_FSTATVFS; known = 1; } else if (strcmp(name, "hardlink@openssh.com") == 0 && - strcmp(value, "1") == 0) { + strcmp((char *)value, "1") == 0) { ret->exts |= SFTP_EXT_HARDLINK; known = 1; - } else if (strcmp(name, "fsync@openssh.com") == 0 && - strcmp(value, "1") == 0) { - ret->exts |= SFTP_EXT_FSYNC; - known = 1; + } else if (strcmp(name, "fsync@openssh.com") == 0 && + strcmp((char *)value, "1") == 0) { + ret->exts |= SFTP_EXT_FSYNC; + known = 1; } if (known) { debug2("Server supports extension \"%s\" revision %s", @@ -405,7 +456,7 @@ do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests, free(value); } - buffer_free(&msg); + sshbuf_free(msg); /* Some filexfer v.0 servers don't support large packets */ if (ret->version == 0) @@ -429,54 +480,62 @@ sftp_proto_version(struct sftp_conn *conn) } int -do_close(struct sftp_conn *conn, char *handle, u_int handle_len) +do_close(struct sftp_conn *conn, const u_char *handle, u_int handle_len) { u_int id, status; - Buffer msg; + struct sshbuf *msg; + int r; - buffer_init(&msg); + if ((msg = sshbuf_new()) == NULL) + fatal("%s: sshbuf_new failed", __func__); id = conn->msg_id++; - buffer_put_char(&msg, SSH2_FXP_CLOSE); - buffer_put_int(&msg, id); - buffer_put_string(&msg, handle, handle_len); - send_msg(conn, &msg); + if ((r = sshbuf_put_u8(msg, SSH2_FXP_CLOSE)) != 0 || + (r = sshbuf_put_u32(msg, id)) != 0 || + (r = sshbuf_put_string(msg, handle, handle_len)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); + send_msg(conn, msg); debug3("Sent message SSH2_FXP_CLOSE I:%u", id); status = get_status(conn, id); if (status != SSH2_FX_OK) error("Couldn't close file: %s", fx2txt(status)); - buffer_free(&msg); + sshbuf_free(msg); - return status; + return status == SSH2_FX_OK ? 0 : -1; } static int -do_lsreaddir(struct sftp_conn *conn, char *path, int print_flag, +do_lsreaddir(struct sftp_conn *conn, const char *path, int print_flag, SFTP_DIRENT ***dir) { - Buffer msg; - u_int count, type, id, handle_len, i, expected_id, ents = 0; + struct sshbuf *msg; + u_int count, id, i, expected_id, ents = 0; + size_t handle_len; + u_char type; char *handle; int status = SSH2_FX_FAILURE; + int r; if (dir) *dir = NULL; id = conn->msg_id++; - buffer_init(&msg); - buffer_put_char(&msg, SSH2_FXP_OPENDIR); - buffer_put_int(&msg, id); - buffer_put_cstring(&msg, path); - send_msg(conn, &msg); + if ((msg = sshbuf_new()) == NULL) + fatal("%s: sshbuf_new failed", __func__); + if ((r = sshbuf_put_u8(msg, SSH2_FXP_OPENDIR)) != 0 || + (r = sshbuf_put_u32(msg, id)) != 0 || + (r = sshbuf_put_cstring(msg, path)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); + send_msg(conn, msg); handle = get_handle(conn, id, &handle_len, "remote readdir(\"%s\")", path); if (handle == NULL) { - buffer_free(&msg); + sshbuf_free(msg); return -1; } @@ -491,18 +550,20 @@ do_lsreaddir(struct sftp_conn *conn, char *path, int print_flag, debug3("Sending SSH2_FXP_READDIR I:%u", id); - buffer_clear(&msg); - buffer_put_char(&msg, SSH2_FXP_READDIR); - buffer_put_int(&msg, id); - buffer_put_string(&msg, handle, handle_len); - send_msg(conn, &msg); + sshbuf_reset(msg); + if ((r = sshbuf_put_u8(msg, SSH2_FXP_READDIR)) != 0 || + (r = sshbuf_put_u32(msg, id)) != 0 || + (r = sshbuf_put_string(msg, handle, handle_len)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); + send_msg(conn, msg); - buffer_clear(&msg); + sshbuf_reset(msg); - get_msg(conn, &msg); + get_msg(conn, msg); - type = buffer_get_char(&msg); - id = buffer_get_int(&msg); + if ((r = sshbuf_get_u8(msg, &type)) != 0 || + (r = sshbuf_get_u32(msg, &id)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); debug3("Received reply T:%u I:%u", type, id); @@ -510,27 +571,43 @@ do_lsreaddir(struct sftp_conn *conn, char *path, int print_flag, fatal("ID mismatch (%u != %u)", id, expected_id); if (type == SSH2_FXP_STATUS) { - status = buffer_get_int(&msg); - debug3("Received SSH2_FXP_STATUS %d", status); - if (status == SSH2_FX_EOF) + u_int rstatus; + + if ((r = sshbuf_get_u32(msg, &rstatus)) != 0) + fatal("%s: buffer error: %s", + __func__, ssh_err(r)); + debug3("Received SSH2_FXP_STATUS %d", rstatus); + if (rstatus == SSH2_FX_EOF) break; - error("Couldn't read directory: %s", fx2txt(status)); + error("Couldn't read directory: %s", fx2txt(rstatus)); goto out; } else if (type != SSH2_FXP_NAME) fatal("Expected SSH2_FXP_NAME(%u) packet, got %u", SSH2_FXP_NAME, type); - count = buffer_get_int(&msg); + if ((r = sshbuf_get_u32(msg, &count)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); if (count == 0) break; debug3("Received %d SSH2_FXP_NAME responses", count); for (i = 0; i < count; i++) { char *filename, *longname; - Attrib *a; + Attrib a; - filename = buffer_get_string(&msg, NULL); - longname = buffer_get_string(&msg, NULL); - a = decode_attrib(&msg); + if ((r = sshbuf_get_cstring(msg, &filename, + NULL)) != 0 || + (r = sshbuf_get_cstring(msg, &longname, + NULL)) != 0) + fatal("%s: buffer error: %s", + __func__, ssh_err(r)); + if ((r = decode_attrib(msg, &a)) != 0) { + error("%s: couldn't decode attrib: %s", + __func__, ssh_err(r)); + free(filename); + free(longname); + sshbuf_free(msg); + return -1; + } if (print_flag) printf("%s\n", longname); @@ -548,7 +625,7 @@ do_lsreaddir(struct sftp_conn *conn, char *path, int print_flag, (*dir)[ents] = xcalloc(1, sizeof(***dir)); (*dir)[ents]->filename = xstrdup(filename); (*dir)[ents]->longname = xstrdup(longname); - memcpy(&(*dir)[ents]->a, a, sizeof(*a)); + memcpy(&(*dir)[ents]->a, &a, sizeof(a)); (*dir)[++ents] = NULL; } free(filename); @@ -558,7 +635,7 @@ do_lsreaddir(struct sftp_conn *conn, char *path, int print_flag, status = 0; out: - buffer_free(&msg); + sshbuf_free(msg); do_close(conn, handle, handle_len); free(handle); @@ -577,7 +654,7 @@ do_lsreaddir(struct sftp_conn *conn, char *path, int print_flag, } int -do_readdir(struct sftp_conn *conn, char *path, SFTP_DIRENT ***dir) +do_readdir(struct sftp_conn *conn, const char *path, SFTP_DIRENT ***dir) { return(do_lsreaddir(conn, path, 0, dir)); } @@ -597,7 +674,7 @@ void free_sftp_dirents(SFTP_DIRENT **s) } int -do_rm(struct sftp_conn *conn, char *path) +do_rm(struct sftp_conn *conn, const char *path) { u_int status, id; @@ -608,11 +685,11 @@ do_rm(struct sftp_conn *conn, char *path) status = get_status(conn, id); if (status != SSH2_FX_OK) error("Couldn't delete file: %s", fx2txt(status)); - return(status); + return status == SSH2_FX_OK ? 0 : -1; } int -do_mkdir(struct sftp_conn *conn, char *path, Attrib *a, int print_flag) +do_mkdir(struct sftp_conn *conn, const char *path, Attrib *a, int print_flag) { u_int status, id; @@ -624,11 +701,11 @@ do_mkdir(struct sftp_conn *conn, char *path, Attrib *a, int print_flag) if (status != SSH2_FX_OK && print_flag) error("Couldn't create directory: %s", fx2txt(status)); - return(status); + return status == SSH2_FX_OK ? 0 : -1; } int -do_rmdir(struct sftp_conn *conn, char *path) +do_rmdir(struct sftp_conn *conn, const char *path) { u_int status, id; @@ -640,11 +717,11 @@ do_rmdir(struct sftp_conn *conn, char *path) if (status != SSH2_FX_OK) error("Couldn't remove directory: %s", fx2txt(status)); - return(status); + return status == SSH2_FX_OK ? 0 : -1; } Attrib * -do_stat(struct sftp_conn *conn, char *path, int quiet) +do_stat(struct sftp_conn *conn, const char *path, int quiet) { u_int id; @@ -658,7 +735,7 @@ do_stat(struct sftp_conn *conn, char *path, int quiet) } Attrib * -do_lstat(struct sftp_conn *conn, char *path, int quiet) +do_lstat(struct sftp_conn *conn, const char *path, int quiet) { u_int id; @@ -679,7 +756,8 @@ do_lstat(struct sftp_conn *conn, char *path, int quiet) #ifdef notyet Attrib * -do_fstat(struct sftp_conn *conn, char *handle, u_int handle_len, int quiet) +do_fstat(struct sftp_conn *conn, const u_char *handle, u_int handle_len, + int quiet) { u_int id; @@ -692,7 +770,7 @@ do_fstat(struct sftp_conn *conn, char *handle, u_int handle_len, int quiet) #endif int -do_setstat(struct sftp_conn *conn, char *path, Attrib *a) +do_setstat(struct sftp_conn *conn, const char *path, Attrib *a) { u_int status, id; @@ -705,11 +783,11 @@ do_setstat(struct sftp_conn *conn, char *path, Attrib *a) error("Couldn't setstat on \"%s\": %s", path, fx2txt(status)); - return(status); + return status == SSH2_FX_OK ? 0 : -1; } int -do_fsetstat(struct sftp_conn *conn, char *handle, u_int handle_len, +do_fsetstat(struct sftp_conn *conn, const u_char *handle, u_int handle_len, Attrib *a) { u_int status, id; @@ -722,181 +800,201 @@ do_fsetstat(struct sftp_conn *conn, char *handle, u_int handle_len, if (status != SSH2_FX_OK) error("Couldn't fsetstat: %s", fx2txt(status)); - return(status); + return status == SSH2_FX_OK ? 0 : -1; } char * -do_realpath(struct sftp_conn *conn, char *path) +do_realpath(struct sftp_conn *conn, const char *path) { - Buffer msg; - u_int type, expected_id, count, id; + struct sshbuf *msg; + u_int expected_id, count, id; char *filename, *longname; - Attrib *a; + Attrib a; + u_char type; + int r; expected_id = id = conn->msg_id++; send_string_request(conn, id, SSH2_FXP_REALPATH, path, strlen(path)); - buffer_init(&msg); + if ((msg = sshbuf_new()) == NULL) + fatal("%s: sshbuf_new failed", __func__); - get_msg(conn, &msg); - type = buffer_get_char(&msg); - id = buffer_get_int(&msg); + get_msg(conn, msg); + if ((r = sshbuf_get_u8(msg, &type)) != 0 || + (r = sshbuf_get_u32(msg, &id)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); if (id != expected_id) fatal("ID mismatch (%u != %u)", id, expected_id); if (type == SSH2_FXP_STATUS) { - u_int status = buffer_get_int(&msg); + u_int status; + if ((r = sshbuf_get_u32(msg, &status)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); error("Couldn't canonicalize: %s", fx2txt(status)); - buffer_free(&msg); + sshbuf_free(msg); return NULL; } else if (type != SSH2_FXP_NAME) fatal("Expected SSH2_FXP_NAME(%u) packet, got %u", SSH2_FXP_NAME, type); - count = buffer_get_int(&msg); + if ((r = sshbuf_get_u32(msg, &count)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); if (count != 1) fatal("Got multiple names (%d) from SSH_FXP_REALPATH", count); - filename = buffer_get_string(&msg, NULL); - longname = buffer_get_string(&msg, NULL); - a = decode_attrib(&msg); + if ((r = sshbuf_get_cstring(msg, &filename, NULL)) != 0 || + (r = sshbuf_get_cstring(msg, &longname, NULL)) != 0 || + (r = decode_attrib(msg, &a)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); debug3("SSH_FXP_REALPATH %s -> %s size %lu", path, filename, - (unsigned long)a->size); + (unsigned long)a.size); free(longname); - buffer_free(&msg); + sshbuf_free(msg); return(filename); } int -do_rename(struct sftp_conn *conn, char *oldpath, char *newpath, +do_rename(struct sftp_conn *conn, const char *oldpath, const char *newpath, int force_legacy) { - Buffer msg; + struct sshbuf *msg; u_int status, id; - int use_ext = (conn->exts & SFTP_EXT_POSIX_RENAME) && !force_legacy; + int r, use_ext = (conn->exts & SFTP_EXT_POSIX_RENAME) && !force_legacy; - buffer_init(&msg); + if ((msg = sshbuf_new()) == NULL) + fatal("%s: sshbuf_new failed", __func__); /* Send rename request */ id = conn->msg_id++; if (use_ext) { - buffer_put_char(&msg, SSH2_FXP_EXTENDED); - buffer_put_int(&msg, id); - buffer_put_cstring(&msg, "posix-rename@openssh.com"); + if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 || + (r = sshbuf_put_u32(msg, id)) != 0 || + (r = sshbuf_put_cstring(msg, + "posix-rename@openssh.com")) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); } else { - buffer_put_char(&msg, SSH2_FXP_RENAME); - buffer_put_int(&msg, id); + if ((r = sshbuf_put_u8(msg, SSH2_FXP_RENAME)) != 0 || + (r = sshbuf_put_u32(msg, id)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); } - buffer_put_cstring(&msg, oldpath); - buffer_put_cstring(&msg, newpath); - send_msg(conn, &msg); + if ((r = sshbuf_put_cstring(msg, oldpath)) != 0 || + (r = sshbuf_put_cstring(msg, newpath)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); + send_msg(conn, msg); debug3("Sent message %s \"%s\" -> \"%s\"", - use_ext ? "posix-rename@openssh.com" : "SSH2_FXP_RENAME", - oldpath, newpath); - buffer_free(&msg); + use_ext ? "posix-rename@openssh.com" : + "SSH2_FXP_RENAME", oldpath, newpath); + sshbuf_free(msg); status = get_status(conn, id); if (status != SSH2_FX_OK) error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath, newpath, fx2txt(status)); - return(status); + return status == SSH2_FX_OK ? 0 : -1; } int -do_hardlink(struct sftp_conn *conn, char *oldpath, char *newpath) +do_hardlink(struct sftp_conn *conn, const char *oldpath, const char *newpath) { - Buffer msg; + struct sshbuf *msg; u_int status, id; + int r; if ((conn->exts & SFTP_EXT_HARDLINK) == 0) { error("Server does not support hardlink@openssh.com extension"); return -1; } - buffer_init(&msg); + if ((msg = sshbuf_new()) == NULL) + fatal("%s: sshbuf_new failed", __func__); /* Send link request */ id = conn->msg_id++; - buffer_put_char(&msg, SSH2_FXP_EXTENDED); - buffer_put_int(&msg, id); - buffer_put_cstring(&msg, "hardlink@openssh.com"); - buffer_put_cstring(&msg, oldpath); - buffer_put_cstring(&msg, newpath); - send_msg(conn, &msg); + if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 || + (r = sshbuf_put_u32(msg, id)) != 0 || + (r = sshbuf_put_cstring(msg, "hardlink@openssh.com")) != 0 || + (r = sshbuf_put_cstring(msg, oldpath)) != 0 || + (r = sshbuf_put_cstring(msg, newpath)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); + send_msg(conn, msg); debug3("Sent message hardlink@openssh.com \"%s\" -> \"%s\"", oldpath, newpath); - buffer_free(&msg); + sshbuf_free(msg); status = get_status(conn, id); if (status != SSH2_FX_OK) error("Couldn't link file \"%s\" to \"%s\": %s", oldpath, newpath, fx2txt(status)); - return(status); + return status == SSH2_FX_OK ? 0 : -1; } int -do_symlink(struct sftp_conn *conn, char *oldpath, char *newpath) +do_symlink(struct sftp_conn *conn, const char *oldpath, const char *newpath) { - Buffer msg; + struct sshbuf *msg; u_int status, id; + int r; if (conn->version < 3) { error("This server does not support the symlink operation"); return(SSH2_FX_OP_UNSUPPORTED); } - buffer_init(&msg); + if ((msg = sshbuf_new()) == NULL) + fatal("%s: sshbuf_new failed", __func__); /* Send symlink request */ id = conn->msg_id++; - buffer_put_char(&msg, SSH2_FXP_SYMLINK); - buffer_put_int(&msg, id); - buffer_put_cstring(&msg, oldpath); - buffer_put_cstring(&msg, newpath); - send_msg(conn, &msg); + if ((r = sshbuf_put_u8(msg, SSH2_FXP_SYMLINK)) != 0 || + (r = sshbuf_put_u32(msg, id)) != 0 || + (r = sshbuf_put_cstring(msg, oldpath)) != 0 || + (r = sshbuf_put_cstring(msg, newpath)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); + send_msg(conn, msg); debug3("Sent message SSH2_FXP_SYMLINK \"%s\" -> \"%s\"", oldpath, newpath); - buffer_free(&msg); + sshbuf_free(msg); status = get_status(conn, id); if (status != SSH2_FX_OK) error("Couldn't symlink file \"%s\" to \"%s\": %s", oldpath, newpath, fx2txt(status)); - return(status); + return status == SSH2_FX_OK ? 0 : -1; } int -do_fsync(struct sftp_conn *conn, char *handle, u_int handle_len) +do_fsync(struct sftp_conn *conn, u_char *handle, u_int handle_len) { - Buffer msg; + struct sshbuf *msg; u_int status, id; + int r; /* Silently return if the extension is not supported */ if ((conn->exts & SFTP_EXT_FSYNC) == 0) return -1; - buffer_init(&msg); - /* Send fsync request */ + if ((msg = sshbuf_new()) == NULL) + fatal("%s: sshbuf_new failed", __func__); id = conn->msg_id++; - - buffer_put_char(&msg, SSH2_FXP_EXTENDED); - buffer_put_int(&msg, id); - buffer_put_cstring(&msg, "fsync@openssh.com"); - buffer_put_string(&msg, handle, handle_len); - send_msg(conn, &msg); + if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 || + (r = sshbuf_put_u32(msg, id)) != 0 || + (r = sshbuf_put_cstring(msg, "fsync@openssh.com")) != 0 || + (r = sshbuf_put_string(msg, handle, handle_len)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); + send_msg(conn, msg); debug3("Sent message fsync@openssh.com I:%u", id); - buffer_free(&msg); + sshbuf_free(msg); status = get_status(conn, id); if (status != SSH2_FX_OK) @@ -907,50 +1005,58 @@ do_fsync(struct sftp_conn *conn, char *handle, u_int handle_len) #ifdef notyet char * -do_readlink(struct sftp_conn *conn, char *path) +do_readlink(struct sftp_conn *conn, const char *path) { - Buffer msg; - u_int type, expected_id, count, id; + struct sshbuf *msg; + u_int expected_id, count, id; char *filename, *longname; - Attrib *a; + Attrib a; + u_char type; + int r; expected_id = id = conn->msg_id++; send_string_request(conn, id, SSH2_FXP_READLINK, path, strlen(path)); - buffer_init(&msg); + if ((msg = sshbuf_new()) == NULL) + fatal("%s: sshbuf_new failed", __func__); - get_msg(conn, &msg); - type = buffer_get_char(&msg); - id = buffer_get_int(&msg); + get_msg(conn, msg); + if ((r = sshbuf_get_u8(msg, &type)) != 0 || + (r = sshbuf_get_u32(msg, &id)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); if (id != expected_id) fatal("ID mismatch (%u != %u)", id, expected_id); if (type == SSH2_FXP_STATUS) { - u_int status = buffer_get_int(&msg); + u_int status; + if ((r = sshbuf_get_u32(msg, &status)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); error("Couldn't readlink: %s", fx2txt(status)); - buffer_free(&msg); + sshbuf_free(msg); return(NULL); } else if (type != SSH2_FXP_NAME) fatal("Expected SSH2_FXP_NAME(%u) packet, got %u", SSH2_FXP_NAME, type); - count = buffer_get_int(&msg); + if ((r = sshbuf_get_u32(msg, &count)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); if (count != 1) fatal("Got multiple names (%d) from SSH_FXP_READLINK", count); - filename = buffer_get_string(&msg, NULL); - longname = buffer_get_string(&msg, NULL); - a = decode_attrib(&msg); + if ((r = sshbuf_get_cstring(msg, &filename, NULL)) != 0 || + (r = sshbuf_get_cstring(msg, &longname, NULL)) != 0 || + (r = decode_attrib(msg, &a)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); debug3("SSH_FXP_READLINK %s -> %s", path, filename); free(longname); - buffer_free(&msg); + sshbuf_free(msg); - return(filename); + return filename; } #endif @@ -958,8 +1064,9 @@ int do_statvfs(struct sftp_conn *conn, const char *path, struct sftp_statvfs *st, int quiet) { - Buffer msg; + struct sshbuf *msg; u_int id; + int r; if ((conn->exts & SFTP_EXT_STATVFS) == 0) { error("Server does not support statvfs@openssh.com extension"); @@ -968,24 +1075,26 @@ do_statvfs(struct sftp_conn *conn, const char *path, struct sftp_statvfs *st, id = conn->msg_id++; - buffer_init(&msg); - buffer_clear(&msg); - buffer_put_char(&msg, SSH2_FXP_EXTENDED); - buffer_put_int(&msg, id); - buffer_put_cstring(&msg, "statvfs@openssh.com"); - buffer_put_cstring(&msg, path); - send_msg(conn, &msg); - buffer_free(&msg); + if ((msg = sshbuf_new()) == NULL) + fatal("%s: sshbuf_new failed", __func__); + sshbuf_reset(msg); + if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 || + (r = sshbuf_put_u32(msg, id)) != 0 || + (r = sshbuf_put_cstring(msg, "statvfs@openssh.com")) != 0 || + (r = sshbuf_put_cstring(msg, path)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); + send_msg(conn, msg); + sshbuf_free(msg); return get_decode_statvfs(conn, st, id, quiet); } #ifdef notyet int -do_fstatvfs(struct sftp_conn *conn, const char *handle, u_int handle_len, +do_fstatvfs(struct sftp_conn *conn, const u_char *handle, u_int handle_len, struct sftp_statvfs *st, int quiet) { - Buffer msg; + struct sshbuf *msg; u_int id; if ((conn->exts & SFTP_EXT_FSTATVFS) == 0) { @@ -995,14 +1104,16 @@ do_fstatvfs(struct sftp_conn *conn, const char *handle, u_int handle_len, id = conn->msg_id++; - buffer_init(&msg); - buffer_clear(&msg); - buffer_put_char(&msg, SSH2_FXP_EXTENDED); - buffer_put_int(&msg, id); - buffer_put_cstring(&msg, "fstatvfs@openssh.com"); - buffer_put_string(&msg, handle, handle_len); - send_msg(conn, &msg); - buffer_free(&msg); + if ((msg = sshbuf_new()) == NULL) + fatal("%s: sshbuf_new failed", __func__); + sshbuf_reset(msg); + if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 || + (r = sshbuf_put_u32(msg, id)) != 0 || + (r = sshbuf_put_cstring(msg, "fstatvfs@openssh.com")) != 0 || + (r = sshbuf_put_string(msg, handle, handle_len)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); + send_msg(conn, msg); + sshbuf_free(msg); return get_decode_statvfs(conn, st, id, quiet); } @@ -1010,42 +1121,48 @@ do_fstatvfs(struct sftp_conn *conn, const char *handle, u_int handle_len, static void send_read_request(struct sftp_conn *conn, u_int id, u_int64_t offset, - u_int len, char *handle, u_int handle_len) + u_int len, const u_char *handle, u_int handle_len) { - Buffer msg; + struct sshbuf *msg; + int r; - buffer_init(&msg); - buffer_clear(&msg); - buffer_put_char(&msg, SSH2_FXP_READ); - buffer_put_int(&msg, id); - buffer_put_string(&msg, handle, handle_len); - buffer_put_int64(&msg, offset); - buffer_put_int(&msg, len); - send_msg(conn, &msg); - buffer_free(&msg); + if ((msg = sshbuf_new()) == NULL) + fatal("%s: sshbuf_new failed", __func__); + sshbuf_reset(msg); + if ((r = sshbuf_put_u8(msg, SSH2_FXP_READ)) != 0 || + (r = sshbuf_put_u32(msg, id)) != 0 || + (r = sshbuf_put_string(msg, handle, handle_len)) != 0 || + (r = sshbuf_put_u64(msg, offset)) != 0 || + (r = sshbuf_put_u32(msg, len)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); + send_msg(conn, msg); + sshbuf_free(msg); } int -do_download(struct sftp_conn *conn, char *remote_path, char *local_path, - Attrib *a, int preserve_flag, int resume_flag, int fsync_flag) +do_download(struct sftp_conn *conn, const char *remote_path, + const char *local_path, Attrib *a, int preserve_flag, int resume_flag, + int fsync_flag) { Attrib junk; - Buffer msg; - char *handle; - int local_fd = -1, status = 0, write_error; - int read_error, write_errno, reordered = 0; + struct sshbuf *msg; + u_char *handle; + int local_fd = -1, write_error; + int read_error, write_errno, reordered = 0, r; u_int64_t offset = 0, size, highwater; - u_int handle_len, mode, type, id, buflen, num_req, max_req; + u_int mode, id, buflen, num_req, max_req, status = SSH2_FX_OK; off_t progress_counter; + size_t handle_len; struct stat st; struct request { u_int id; - u_int len; + size_t len; u_int64_t offset; TAILQ_ENTRY(request) tq; }; TAILQ_HEAD(reqhead, request) requests; struct request *req; + u_char type; TAILQ_INIT(&requests); @@ -1070,23 +1187,26 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path, size = 0; buflen = conn->transfer_buflen; - buffer_init(&msg); + if ((msg = sshbuf_new()) == NULL) + fatal("%s: sshbuf_new failed", __func__); + + attrib_clear(&junk); /* Send empty attributes */ /* Send open request */ id = conn->msg_id++; - buffer_put_char(&msg, SSH2_FXP_OPEN); - buffer_put_int(&msg, id); - buffer_put_cstring(&msg, remote_path); - buffer_put_int(&msg, SSH2_FXF_READ); - attrib_clear(&junk); /* Send empty attributes */ - encode_attrib(&msg, &junk); - send_msg(conn, &msg); + if ((r = sshbuf_put_u8(msg, SSH2_FXP_OPEN)) != 0 || + (r = sshbuf_put_u32(msg, id)) != 0 || + (r = sshbuf_put_cstring(msg, remote_path)) != 0 || + (r = sshbuf_put_u32(msg, SSH2_FXF_READ)) != 0 || + (r = encode_attrib(msg, &junk)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); + send_msg(conn, msg); debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path); handle = get_handle(conn, id, &handle_len, "remote open(\"%s\")", remote_path); if (handle == NULL) { - buffer_free(&msg); + sshbuf_free(msg); return(-1); } @@ -1113,7 +1233,7 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path, "local file is larger than remote", local_path); fail: do_close(conn, handle, handle_len); - buffer_free(&msg); + sshbuf_free(msg); free(handle); if (local_fd != -1) close(local_fd); @@ -1131,8 +1251,8 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path, start_progress_meter(remote_path, size, &progress_counter); while (num_req > 0 || max_req > 0) { - char *data; - u_int len; + u_char *data; + size_t len; /* * Simulate EOF on interrupt: stop sending new requests and @@ -1161,10 +1281,11 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path, req->len, handle, handle_len); } - buffer_clear(&msg); - get_msg(conn, &msg); - type = buffer_get_char(&msg); - id = buffer_get_int(&msg); + sshbuf_reset(msg); + get_msg(conn, msg); + if ((r = sshbuf_get_u8(msg, &type)) != 0 || + (r = sshbuf_get_u32(msg, &id)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); debug3("Received reply T:%u I:%u R:%d", type, id, max_req); /* Find the request in our queue */ @@ -1177,7 +1298,9 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path, switch (type) { case SSH2_FXP_STATUS: - status = buffer_get_int(&msg); + if ((r = sshbuf_get_u32(msg, &status)) != 0) + fatal("%s: buffer error: %s", + __func__, ssh_err(r)); if (status != SSH2_FX_EOF) read_error = 1; max_req = 0; @@ -1186,13 +1309,15 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path, num_req--; break; case SSH2_FXP_DATA: - data = buffer_get_string(&msg, &len); + if ((r = sshbuf_get_string(msg, &data, &len)) != 0) + fatal("%s: buffer error: %s", + __func__, ssh_err(r)); debug3("Received data %llu -> %llu", (unsigned long long)req->offset, (unsigned long long)req->offset + len - 1); if (len > req->len) fatal("Received more data than asked for " - "%u > %u", len, req->len); + "%zu > %zu", len, req->len); if ((lseek(local_fd, req->offset, SEEK_SET) == -1 || atomicio(vwrite, local_fd, data, len) != len) && !write_error) { @@ -1269,12 +1394,13 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path, } else if (write_error) { error("Couldn't write to \"%s\": %s", local_path, strerror(write_errno)); - status = -1; + status = SSH2_FX_FAILURE; do_close(conn, handle, handle_len); } else { - status = do_close(conn, handle, handle_len); - if (interrupted || status != SSH2_FX_OK) - status = -1; + if (do_close(conn, handle, handle_len) != 0 || interrupted) + status = SSH2_FX_FAILURE; + else + status = SSH2_FX_OK; /* Override umask and utimes if asked */ #ifdef HAVE_FCHMOD if (preserve_flag && fchmod(local_fd, mode) == -1) @@ -1301,16 +1427,16 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path, } } close(local_fd); - buffer_free(&msg); + sshbuf_free(msg); free(handle); return(status); } static int -download_dir_internal(struct sftp_conn *conn, char *src, char *dst, int depth, - Attrib *dirattrib, int preserve_flag, int print_flag, int resume_flag, - int fsync_flag) +download_dir_internal(struct sftp_conn *conn, const char *src, const char *dst, + int depth, Attrib *dirattrib, int preserve_flag, int print_flag, + int resume_flag, int fsync_flag) { int i, ret = 0; SFTP_DIRENT **dir_entries; @@ -1400,9 +1526,9 @@ download_dir_internal(struct sftp_conn *conn, char *src, char *dst, int depth, } int -download_dir(struct sftp_conn *conn, char *src, char *dst, - Attrib *dirattrib, int preserve_flag, int print_flag, - int resume_flag, int fsync_flag) +download_dir(struct sftp_conn *conn, const char *src, const char *dst, + Attrib *dirattrib, int preserve_flag, int print_flag, int resume_flag, + int fsync_flag) { char *src_canon; int ret; @@ -1419,15 +1545,16 @@ download_dir(struct sftp_conn *conn, char *src, char *dst, } int -do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, - int preserve_flag, int resume, int fsync_flag) +do_upload(struct sftp_conn *conn, const char *local_path, + const char *remote_path, int preserve_flag, int resume, int fsync_flag) { - int local_fd; - int status = SSH2_FX_OK; - u_int handle_len, id, type; + int r, local_fd; + u_int status = SSH2_FX_OK; + u_int id; + u_char type; off_t offset, progress_counter; - char *handle, *data; - Buffer msg; + u_char *handle, *data; + struct sshbuf *msg; struct stat sb; Attrib a, *c = NULL; u_int32_t startid; @@ -1440,6 +1567,7 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, }; TAILQ_HEAD(ackhead, outstanding_ack) acks; struct outstanding_ack *ack = NULL; + size_t handle_len; TAILQ_INIT(&acks); @@ -1487,26 +1615,28 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, } } - buffer_init(&msg); + if ((msg = sshbuf_new()) == NULL) + fatal("%s: sshbuf_new failed", __func__); /* Send open request */ id = conn->msg_id++; - buffer_put_char(&msg, SSH2_FXP_OPEN); - buffer_put_int(&msg, id); - buffer_put_cstring(&msg, remote_path); - buffer_put_int(&msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT| - (resume ? SSH2_FXF_APPEND : SSH2_FXF_TRUNC)); - encode_attrib(&msg, &a); - send_msg(conn, &msg); + if ((r = sshbuf_put_u8(msg, SSH2_FXP_OPEN)) != 0 || + (r = sshbuf_put_u32(msg, id)) != 0 || + (r = sshbuf_put_cstring(msg, remote_path)) != 0 || + (r = sshbuf_put_u32(msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT| + (resume ? SSH2_FXF_APPEND : SSH2_FXF_TRUNC))) != 0 || + (r = encode_attrib(msg, &a)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); + send_msg(conn, msg); debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path); - buffer_clear(&msg); + sshbuf_reset(msg); handle = get_handle(conn, id, &handle_len, "remote open(\"%s\")", remote_path); if (handle == NULL) { close(local_fd); - buffer_free(&msg); + sshbuf_free(msg); return -1; } @@ -1546,13 +1676,16 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, ack->len = len; TAILQ_INSERT_TAIL(&acks, ack, tq); - buffer_clear(&msg); - buffer_put_char(&msg, SSH2_FXP_WRITE); - buffer_put_int(&msg, ack->id); - buffer_put_string(&msg, handle, handle_len); - buffer_put_int64(&msg, offset); - buffer_put_string(&msg, data, len); - send_msg(conn, &msg); + sshbuf_reset(msg); + if ((r = sshbuf_put_u8(msg, SSH2_FXP_WRITE)) != 0 || + (r = sshbuf_put_u32(msg, ack->id)) != 0 || + (r = sshbuf_put_string(msg, handle, + handle_len)) != 0 || + (r = sshbuf_put_u64(msg, offset)) != 0 || + (r = sshbuf_put_string(msg, data, len)) != 0) + fatal("%s: buffer error: %s", + __func__, ssh_err(r)); + send_msg(conn, msg); debug3("Sent message SSH2_FXP_WRITE I:%u O:%llu S:%u", id, (unsigned long long)offset, len); } else if (TAILQ_FIRST(&acks) == NULL) @@ -1563,27 +1696,31 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, if (id == startid || len == 0 || id - ackid >= conn->num_requests) { - u_int r_id; + u_int rid; - buffer_clear(&msg); - get_msg(conn, &msg); - type = buffer_get_char(&msg); - r_id = buffer_get_int(&msg); + sshbuf_reset(msg); + get_msg(conn, msg); + if ((r = sshbuf_get_u8(msg, &type)) != 0 || + (r = sshbuf_get_u32(msg, &rid)) != 0) + fatal("%s: buffer error: %s", + __func__, ssh_err(r)); if (type != SSH2_FXP_STATUS) fatal("Expected SSH2_FXP_STATUS(%d) packet, " "got %d", SSH2_FXP_STATUS, type); - status = buffer_get_int(&msg); - debug3("SSH2_FXP_STATUS %d", status); + if ((r = sshbuf_get_u32(msg, &status)) != 0) + fatal("%s: buffer error: %s", + __func__, ssh_err(r)); + debug3("SSH2_FXP_STATUS %u", status); /* Find the request in our queue */ for (ack = TAILQ_FIRST(&acks); - ack != NULL && ack->id != r_id; + ack != NULL && ack->id != rid; ack = TAILQ_NEXT(ack, tq)) ; if (ack == NULL) - fatal("Can't find request for ID %u", r_id); + fatal("Can't find request for ID %u", rid); TAILQ_REMOVE(&acks, ack, tq); debug3("In write loop, ack for %u %u bytes at %lld", ack->id, ack->len, (long long)ack->offset); @@ -1595,7 +1732,7 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, if (offset < 0) fatal("%s: offset < 0", __func__); } - buffer_free(&msg); + sshbuf_free(msg); if (showprogress) stop_progress_meter(); @@ -1604,13 +1741,13 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, if (status != SSH2_FX_OK) { error("Couldn't write to remote file \"%s\": %s", remote_path, fx2txt(status)); - status = -1; + status = SSH2_FX_FAILURE; } if (close(local_fd) == -1) { error("Couldn't close local file \"%s\": %s", local_path, strerror(errno)); - status = -1; + status = SSH2_FX_FAILURE; } /* Override umask and utimes if asked */ @@ -1621,17 +1758,19 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, (void)do_fsync(conn, handle, handle_len); if (do_close(conn, handle, handle_len) != SSH2_FX_OK) - status = -1; + status = SSH2_FX_FAILURE; + free(handle); - return status; + return status == SSH2_FX_OK ? 0 : -1; } static int -upload_dir_internal(struct sftp_conn *conn, char *src, char *dst, int depth, - int preserve_flag, int print_flag, int resume, int fsync_flag) +upload_dir_internal(struct sftp_conn *conn, const char *src, const char *dst, + int depth, int preserve_flag, int print_flag, int resume, int fsync_flag) { - int ret = 0, status; + int ret = 0; + u_int status; DIR *dirp; struct dirent *dp; char *filename, *new_src, *new_dst; @@ -1721,8 +1860,8 @@ upload_dir_internal(struct sftp_conn *conn, char *src, char *dst, int depth, } int -upload_dir(struct sftp_conn *conn, char *src, char *dst, int preserve_flag, - int print_flag, int resume, int fsync_flag) +upload_dir(struct sftp_conn *conn, const char *src, const char *dst, + int preserve_flag, int print_flag, int resume, int fsync_flag) { char *dst_canon; int ret; @@ -1740,7 +1879,7 @@ upload_dir(struct sftp_conn *conn, char *src, char *dst, int preserve_flag, } char * -path_append(char *p1, char *p2) +path_append(const char *p1, const char *p2) { char *ret; size_t len = strlen(p1) + strlen(p2) + 2; diff --git a/sftp-client.h b/sftp-client.h index 967840b9c..507d763ea 100644 --- a/sftp-client.h +++ b/sftp-client.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sftp-client.h,v 1.25 2014/04/21 14:36:16 logan Exp $ */ +/* $OpenBSD: sftp-client.h,v 1.26 2015/01/14 13:54:13 djm Exp $ */ /* * Copyright (c) 2001-2004 Damien Miller @@ -56,79 +56,81 @@ struct sftp_conn *do_init(int, int, u_int, u_int, u_int64_t); u_int sftp_proto_version(struct sftp_conn *); /* Close file referred to by 'handle' */ -int do_close(struct sftp_conn *, char *, u_int); +int do_close(struct sftp_conn *, const u_char *, u_int); /* Read contents of 'path' to NULL-terminated array 'dir' */ -int do_readdir(struct sftp_conn *, char *, SFTP_DIRENT ***); +int do_readdir(struct sftp_conn *, const char *, SFTP_DIRENT ***); /* Frees a NULL-terminated array of SFTP_DIRENTs (eg. from do_readdir) */ void free_sftp_dirents(SFTP_DIRENT **); /* Delete file 'path' */ -int do_rm(struct sftp_conn *, char *); +int do_rm(struct sftp_conn *, const char *); /* Create directory 'path' */ -int do_mkdir(struct sftp_conn *, char *, Attrib *, int); +int do_mkdir(struct sftp_conn *, const char *, Attrib *, int); /* Remove directory 'path' */ -int do_rmdir(struct sftp_conn *, char *); +int do_rmdir(struct sftp_conn *, const char *); /* Get file attributes of 'path' (follows symlinks) */ -Attrib *do_stat(struct sftp_conn *, char *, int); +Attrib *do_stat(struct sftp_conn *, const char *, int); /* Get file attributes of 'path' (does not follow symlinks) */ -Attrib *do_lstat(struct sftp_conn *, char *, int); +Attrib *do_lstat(struct sftp_conn *, const char *, int); /* Set file attributes of 'path' */ -int do_setstat(struct sftp_conn *, char *, Attrib *); +int do_setstat(struct sftp_conn *, const char *, Attrib *); /* Set file attributes of open file 'handle' */ -int do_fsetstat(struct sftp_conn *, char *, u_int, Attrib *); +int do_fsetstat(struct sftp_conn *, const u_char *, u_int, Attrib *); /* Canonicalise 'path' - caller must free result */ -char *do_realpath(struct sftp_conn *, char *); +char *do_realpath(struct sftp_conn *, const char *); /* Get statistics for filesystem hosting file at "path" */ int do_statvfs(struct sftp_conn *, const char *, struct sftp_statvfs *, int); /* Rename 'oldpath' to 'newpath' */ -int do_rename(struct sftp_conn *, char *, char *m, int force_legacy); +int do_rename(struct sftp_conn *, const char *, const char *, int force_legacy); /* Link 'oldpath' to 'newpath' */ -int do_hardlink(struct sftp_conn *, char *, char *); +int do_hardlink(struct sftp_conn *, const char *, const char *); /* Rename 'oldpath' to 'newpath' */ -int do_symlink(struct sftp_conn *, char *, char *); +int do_symlink(struct sftp_conn *, const char *, const char *); /* Call fsync() on open file 'handle' */ -int do_fsync(struct sftp_conn *conn, char *, u_int); +int do_fsync(struct sftp_conn *conn, u_char *, u_int); /* * Download 'remote_path' to 'local_path'. Preserve permissions and times * if 'pflag' is set */ -int do_download(struct sftp_conn *, char *, char *, Attrib *, int, int, int); +int do_download(struct sftp_conn *, const char *, const char *, + Attrib *, int, int, int); /* * Recursively download 'remote_directory' to 'local_directory'. Preserve * times if 'pflag' is set */ -int download_dir(struct sftp_conn *, char *, char *, Attrib *, int, - int, int, int); +int download_dir(struct sftp_conn *, const char *, const char *, + Attrib *, int, int, int, int); /* * Upload 'local_path' to 'remote_path'. Preserve permissions and times * if 'pflag' is set */ -int do_upload(struct sftp_conn *, char *, char *, int, int, int); +int do_upload(struct sftp_conn *, const char *, const char *, int, int, int); /* * Recursively upload 'local_directory' to 'remote_directory'. Preserve * times if 'pflag' is set */ -int upload_dir(struct sftp_conn *, char *, char *, int, int, int, int); +int upload_dir(struct sftp_conn *, const char *, const char *, int, int, int, + int); /* Concatenate paths, taking care of slashes. Caller must free result. */ -char *path_append(char *, char *); +char *path_append(const char *, const char *); #endif diff --git a/sftp-common.c b/sftp-common.c index 70a929ccc..9c54d5c6b 100644 --- a/sftp-common.c +++ b/sftp-common.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sftp-common.c,v 1.26 2014/01/09 03:26:00 guenther Exp $ */ +/* $OpenBSD: sftp-common.c,v 1.27 2015/01/14 13:54:13 djm Exp $ */ /* * Copyright (c) 2001 Markus Friedl. All rights reserved. * Copyright (c) 2001 Damien Miller. All rights reserved. @@ -42,7 +42,8 @@ #endif #include "xmalloc.h" -#include "buffer.h" +#include "ssherr.h" +#include "sshbuf.h" #include "log.h" #include "sftp.h" @@ -100,59 +101,81 @@ attrib_to_stat(const Attrib *a, struct stat *st) } /* Decode attributes in buffer */ -Attrib * -decode_attrib(Buffer *b) +int +decode_attrib(struct sshbuf *b, Attrib *a) { - static Attrib a; + int r; - attrib_clear(&a); - a.flags = buffer_get_int(b); - if (a.flags & SSH2_FILEXFER_ATTR_SIZE) - a.size = buffer_get_int64(b); - if (a.flags & SSH2_FILEXFER_ATTR_UIDGID) { - a.uid = buffer_get_int(b); - a.gid = buffer_get_int(b); + attrib_clear(a); + if ((r = sshbuf_get_u32(b, &a->flags)) != 0) + return r; + if (a->flags & SSH2_FILEXFER_ATTR_SIZE) { + if ((r = sshbuf_get_u64(b, &a->size)) != 0) + return r; } - if (a.flags & SSH2_FILEXFER_ATTR_PERMISSIONS) - a.perm = buffer_get_int(b); - if (a.flags & SSH2_FILEXFER_ATTR_ACMODTIME) { - a.atime = buffer_get_int(b); - a.mtime = buffer_get_int(b); + if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) { + if ((r = sshbuf_get_u32(b, &a->uid)) != 0 || + (r = sshbuf_get_u32(b, &a->gid)) != 0) + return r; + } + if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) { + if ((r = sshbuf_get_u32(b, &a->perm)) != 0) + return r; + } + if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) { + if ((r = sshbuf_get_u32(b, &a->atime)) != 0 || + (r = sshbuf_get_u32(b, &a->mtime)) != 0) + return r; } /* vendor-specific extensions */ - if (a.flags & SSH2_FILEXFER_ATTR_EXTENDED) { - char *type, *data; - int i, count; + if (a->flags & SSH2_FILEXFER_ATTR_EXTENDED) { + char *type; + u_char *data; + size_t dlen; + u_int i, count; - count = buffer_get_int(b); + if ((r = sshbuf_get_u32(b, &count)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); for (i = 0; i < count; i++) { - type = buffer_get_string(b, NULL); - data = buffer_get_string(b, NULL); - debug3("Got file attribute \"%s\"", type); + if ((r = sshbuf_get_cstring(b, &type, NULL)) != 0 || + (r = sshbuf_get_string(b, &data, &dlen)) != 0) + return r; + debug3("Got file attribute \"%.100s\" len %zu", + type, dlen); free(type); free(data); } } - return &a; + return 0; } /* Encode attributes to buffer */ -void -encode_attrib(Buffer *b, const Attrib *a) +int +encode_attrib(struct sshbuf *b, const Attrib *a) { - buffer_put_int(b, a->flags); - if (a->flags & SSH2_FILEXFER_ATTR_SIZE) - buffer_put_int64(b, a->size); + int r; + + if ((r = sshbuf_put_u32(b, a->flags)) != 0) + return r; + if (a->flags & SSH2_FILEXFER_ATTR_SIZE) { + if ((r = sshbuf_put_u64(b, a->size)) != 0) + return r; + } if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) { - buffer_put_int(b, a->uid); - buffer_put_int(b, a->gid); + if ((r = sshbuf_put_u32(b, a->uid)) != 0 || + (r = sshbuf_put_u32(b, a->gid)) != 0) + return r; + } + if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) { + if ((r = sshbuf_put_u32(b, a->perm)) != 0) + return r; } - if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) - buffer_put_int(b, a->perm); if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) { - buffer_put_int(b, a->atime); - buffer_put_int(b, a->mtime); + if ((r = sshbuf_put_u32(b, a->atime)) != 0 || + (r = sshbuf_put_u32(b, a->mtime)) != 0) + return r; } + return 0; } /* Convert from SSH2_FX_ status to text error message */ diff --git a/sftp-common.h b/sftp-common.h index 9ed86c070..2e778a9ca 100644 --- a/sftp-common.h +++ b/sftp-common.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sftp-common.h,v 1.11 2010/01/13 01:40:16 djm Exp $ */ +/* $OpenBSD: sftp-common.h,v 1.12 2015/01/14 13:54:13 djm Exp $ */ /* * Copyright (c) 2001 Markus Friedl. All rights reserved. @@ -28,6 +28,7 @@ /* Maximum packet that we are willing to send/accept */ #define SFTP_MAX_MSG_LENGTH (256 * 1024) +struct sshbuf; typedef struct Attrib Attrib; /* File attributes */ @@ -44,8 +45,8 @@ struct Attrib { void attrib_clear(Attrib *); void stat_to_attrib(const struct stat *, Attrib *); void attrib_to_stat(const Attrib *, struct stat *); -Attrib *decode_attrib(Buffer *); -void encode_attrib(Buffer *, const Attrib *); +int decode_attrib(struct sshbuf *, Attrib *); +int encode_attrib(struct sshbuf *, const Attrib *); char *ls_file(const char *, const struct stat *, int, int); const char *fx2txt(int); diff --git a/sftp-glob.c b/sftp-glob.c index d85aecc9a..43a1bebad 100644 --- a/sftp-glob.c +++ b/sftp-glob.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sftp-glob.c,v 1.26 2013/11/08 11:15:19 dtucker Exp $ */ +/* $OpenBSD: sftp-glob.c,v 1.27 2015/01/14 13:54:13 djm Exp $ */ /* * Copyright (c) 2001-2004 Damien Miller * @@ -25,10 +25,10 @@ #include #include #include +#include #include "xmalloc.h" #include "sftp.h" -#include "buffer.h" #include "sftp-common.h" #include "sftp-client.h" diff --git a/sftp-server.c b/sftp-server.c index 0177130cf..aeff1aa17 100644 --- a/sftp-server.c +++ b/sftp-server.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sftp-server.c,v 1.103 2014/01/17 06:23:24 dtucker Exp $ */ +/* $OpenBSD: sftp-server.c,v 1.104 2015/01/14 13:54:13 djm Exp $ */ /* * Copyright (c) 2000-2004 Markus Friedl. All rights reserved. * @@ -46,7 +46,8 @@ #include #include "xmalloc.h" -#include "buffer.h" +#include "sshbuf.h" +#include "ssherr.h" #include "log.h" #include "misc.h" #include "match.h" @@ -55,11 +56,6 @@ #include "sftp.h" #include "sftp-common.h" -/* helper */ -#define get_int64() buffer_get_int64(&iqueue); -#define get_int() buffer_get_int(&iqueue); -#define get_string(lenp) buffer_get_string(&iqueue, lenp); - /* Our verbosity */ static LogLevel log_level = SYSLOG_LEVEL_ERROR; @@ -68,8 +64,8 @@ static struct passwd *pw = NULL; static char *client_addr = NULL; /* input and output queue */ -static Buffer iqueue; -static Buffer oqueue; +struct sshbuf *iqueue; +struct sshbuf *oqueue; /* Version of client */ static u_int version; @@ -275,12 +271,6 @@ string_from_portable(int pflags) return ret; } -static Attrib * -get_attrib(void) -{ - return decode_attrib(&iqueue); -} - /* handle handles */ typedef struct Handle Handle; @@ -344,7 +334,7 @@ handle_is_ok(int i, int type) } static int -handle_to_string(int handle, char **stringp, int *hlenp) +handle_to_string(int handle, u_char **stringp, int *hlenp) { if (stringp == NULL || hlenp == NULL) return -1; @@ -355,7 +345,7 @@ handle_to_string(int handle, char **stringp, int *hlenp) } static int -handle_from_string(const char *handle, u_int hlen) +handle_from_string(const u_char *handle, u_int hlen) { int val; @@ -477,29 +467,31 @@ handle_log_exit(void) } static int -get_handle(void) +get_handle(struct sshbuf *queue, int *hp) { - char *handle; - int val = -1; - u_int hlen; + u_char *handle; + int r; + size_t hlen; - handle = get_string(&hlen); + *hp = -1; + if ((r = sshbuf_get_string(queue, &handle, &hlen)) != 0) + return r; if (hlen < 256) - val = handle_from_string(handle, hlen); + *hp = handle_from_string(handle, hlen); free(handle); - return val; + return 0; } /* send replies */ static void -send_msg(Buffer *m) +send_msg(struct sshbuf *m) { - int mlen = buffer_len(m); + int r; - buffer_put_int(&oqueue, mlen); - buffer_append(&oqueue, buffer_ptr(m), mlen); - buffer_consume(m, mlen); + if ((r = sshbuf_put_stringb(oqueue, m)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); + sshbuf_reset(m); } static const char * @@ -523,38 +515,46 @@ status_to_message(u_int32_t status) static void send_status(u_int32_t id, u_int32_t status) { - Buffer msg; + struct sshbuf *msg; + int r; debug3("request %u: sent status %u", id, status); if (log_level > SYSLOG_LEVEL_VERBOSE || (status != SSH2_FX_OK && status != SSH2_FX_EOF)) logit("sent status %s", status_to_message(status)); - buffer_init(&msg); - buffer_put_char(&msg, SSH2_FXP_STATUS); - buffer_put_int(&msg, id); - buffer_put_int(&msg, status); + if ((msg = sshbuf_new()) == NULL) + fatal("%s: sshbuf_new failed", __func__); + if ((r = sshbuf_put_u8(msg, SSH2_FXP_STATUS)) != 0 || + (r = sshbuf_put_u32(msg, id)) != 0 || + (r = sshbuf_put_u32(msg, status)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); if (version >= 3) { - buffer_put_cstring(&msg, status_to_message(status)); - buffer_put_cstring(&msg, ""); + if ((r = sshbuf_put_cstring(msg, + status_to_message(status))) != 0 || + (r = sshbuf_put_cstring(msg, "")) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); } - send_msg(&msg); - buffer_free(&msg); + send_msg(msg); + sshbuf_free(msg); } static void -send_data_or_handle(char type, u_int32_t id, const char *data, int dlen) +send_data_or_handle(char type, u_int32_t id, const u_char *data, int dlen) { - Buffer msg; + struct sshbuf *msg; + int r; - buffer_init(&msg); - buffer_put_char(&msg, type); - buffer_put_int(&msg, id); - buffer_put_string(&msg, data, dlen); - send_msg(&msg); - buffer_free(&msg); + if ((msg = sshbuf_new()) == NULL) + fatal("%s: sshbuf_new failed", __func__); + if ((r = sshbuf_put_u8(msg, type)) != 0 || + (r = sshbuf_put_u32(msg, id)) != 0 || + (r = sshbuf_put_string(msg, data, dlen)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); + send_msg(msg); + sshbuf_free(msg); } static void -send_data(u_int32_t id, const char *data, int dlen) +send_data(u_int32_t id, const u_char *data, int dlen) { debug("request %u: sent data len %d", id, dlen); send_data_or_handle(SSH2_FXP_DATA, id, data, dlen); @@ -563,7 +563,7 @@ send_data(u_int32_t id, const char *data, int dlen) static void send_handle(u_int32_t id, int handle) { - char *string; + u_char *string; int hlen; handle_to_string(handle, &string, &hlen); @@ -575,62 +575,71 @@ send_handle(u_int32_t id, int handle) static void send_names(u_int32_t id, int count, const Stat *stats) { - Buffer msg; - int i; + struct sshbuf *msg; + int i, r; - buffer_init(&msg); - buffer_put_char(&msg, SSH2_FXP_NAME); - buffer_put_int(&msg, id); - buffer_put_int(&msg, count); + if ((msg = sshbuf_new()) == NULL) + fatal("%s: sshbuf_new failed", __func__); + if ((r = sshbuf_put_u8(msg, SSH2_FXP_NAME)) != 0 || + (r = sshbuf_put_u32(msg, id)) != 0 || + (r = sshbuf_put_u32(msg, count)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); debug("request %u: sent names count %d", id, count); for (i = 0; i < count; i++) { - buffer_put_cstring(&msg, stats[i].name); - buffer_put_cstring(&msg, stats[i].long_name); - encode_attrib(&msg, &stats[i].attrib); + if ((r = sshbuf_put_cstring(msg, stats[i].name)) != 0 || + (r = sshbuf_put_cstring(msg, stats[i].long_name)) != 0 || + (r = encode_attrib(msg, &stats[i].attrib)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); } - send_msg(&msg); - buffer_free(&msg); + send_msg(msg); + sshbuf_free(msg); } static void send_attrib(u_int32_t id, const Attrib *a) { - Buffer msg; + struct sshbuf *msg; + int r; debug("request %u: sent attrib have 0x%x", id, a->flags); - buffer_init(&msg); - buffer_put_char(&msg, SSH2_FXP_ATTRS); - buffer_put_int(&msg, id); - encode_attrib(&msg, a); - send_msg(&msg); - buffer_free(&msg); + if ((msg = sshbuf_new()) == NULL) + fatal("%s: sshbuf_new failed", __func__); + if ((r = sshbuf_put_u8(msg, SSH2_FXP_ATTRS)) != 0 || + (r = sshbuf_put_u32(msg, id)) != 0 || + (r = encode_attrib(msg, a)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); + send_msg(msg); + sshbuf_free(msg); } static void send_statvfs(u_int32_t id, struct statvfs *st) { - Buffer msg; + struct sshbuf *msg; u_int64_t flag; + int r; flag = (st->f_flag & ST_RDONLY) ? SSH2_FXE_STATVFS_ST_RDONLY : 0; flag |= (st->f_flag & ST_NOSUID) ? SSH2_FXE_STATVFS_ST_NOSUID : 0; - buffer_init(&msg); - buffer_put_char(&msg, SSH2_FXP_EXTENDED_REPLY); - buffer_put_int(&msg, id); - buffer_put_int64(&msg, st->f_bsize); - buffer_put_int64(&msg, st->f_frsize); - buffer_put_int64(&msg, st->f_blocks); - buffer_put_int64(&msg, st->f_bfree); - buffer_put_int64(&msg, st->f_bavail); - buffer_put_int64(&msg, st->f_files); - buffer_put_int64(&msg, st->f_ffree); - buffer_put_int64(&msg, st->f_favail); - buffer_put_int64(&msg, FSID_TO_ULONG(st->f_fsid)); - buffer_put_int64(&msg, flag); - buffer_put_int64(&msg, st->f_namemax); - send_msg(&msg); - buffer_free(&msg); + if ((msg = sshbuf_new()) == NULL) + fatal("%s: sshbuf_new failed", __func__); + if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED_REPLY)) != 0 || + (r = sshbuf_put_u32(msg, id)) != 0 || + (r = sshbuf_put_u64(msg, st->f_bsize)) != 0 || + (r = sshbuf_put_u64(msg, st->f_frsize)) != 0 || + (r = sshbuf_put_u64(msg, st->f_blocks)) != 0 || + (r = sshbuf_put_u64(msg, st->f_bfree)) != 0 || + (r = sshbuf_put_u64(msg, st->f_bavail)) != 0 || + (r = sshbuf_put_u64(msg, st->f_files)) != 0 || + (r = sshbuf_put_u64(msg, st->f_ffree)) != 0 || + (r = sshbuf_put_u64(msg, st->f_favail)) != 0 || + (r = sshbuf_put_u64(msg, FSID_TO_ULONG(st->f_fsid))) != 0 || + (r = sshbuf_put_u64(msg, flag)) != 0 || + (r = sshbuf_put_u64(msg, st->f_namemax)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); + send_msg(msg); + sshbuf_free(msg); } /* parse incoming */ @@ -638,53 +647,59 @@ send_statvfs(u_int32_t id, struct statvfs *st) static void process_init(void) { - Buffer msg; + struct sshbuf *msg; + int r; - version = get_int(); + if ((r = sshbuf_get_u32(iqueue, &version)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); verbose("received client version %u", version); - buffer_init(&msg); - buffer_put_char(&msg, SSH2_FXP_VERSION); - buffer_put_int(&msg, SSH2_FILEXFER_VERSION); - /* POSIX rename extension */ - buffer_put_cstring(&msg, "posix-rename@openssh.com"); - buffer_put_cstring(&msg, "1"); /* version */ - /* statvfs extension */ - buffer_put_cstring(&msg, "statvfs@openssh.com"); - buffer_put_cstring(&msg, "2"); /* version */ - /* fstatvfs extension */ - buffer_put_cstring(&msg, "fstatvfs@openssh.com"); - buffer_put_cstring(&msg, "2"); /* version */ - /* hardlink extension */ - buffer_put_cstring(&msg, "hardlink@openssh.com"); - buffer_put_cstring(&msg, "1"); /* version */ - /* fsync extension */ - buffer_put_cstring(&msg, "fsync@openssh.com"); - buffer_put_cstring(&msg, "1"); /* version */ - send_msg(&msg); - buffer_free(&msg); + if ((msg = sshbuf_new()) == NULL) + fatal("%s: sshbuf_new failed", __func__); + if ((r = sshbuf_put_u8(msg, SSH2_FXP_VERSION)) != 0 || + (r = sshbuf_put_u32(msg, SSH2_FILEXFER_VERSION)) != 0 || + /* POSIX rename extension */ + (r = sshbuf_put_cstring(msg, "posix-rename@openssh.com")) != 0 || + (r = sshbuf_put_cstring(msg, "1")) != 0 || /* version */ + /* statvfs extension */ + (r = sshbuf_put_cstring(msg, "statvfs@openssh.com")) != 0 || + (r = sshbuf_put_cstring(msg, "2")) != 0 || /* version */ + /* fstatvfs extension */ + (r = sshbuf_put_cstring(msg, "fstatvfs@openssh.com")) != 0 || + (r = sshbuf_put_cstring(msg, "2")) != 0 || /* version */ + /* hardlink extension */ + (r = sshbuf_put_cstring(msg, "hardlink@openssh.com")) != 0 || + (r = sshbuf_put_cstring(msg, "1")) != 0 || /* version */ + /* fsync extension */ + (r = sshbuf_put_cstring(msg, "fsync@openssh.com")) != 0 || + (r = sshbuf_put_cstring(msg, "1")) != 0) /* version */ + fatal("%s: buffer error: %s", __func__, ssh_err(r)); + send_msg(msg); + sshbuf_free(msg); } static void process_open(u_int32_t id) { u_int32_t pflags; - Attrib *a; + Attrib a; char *name; - int handle, fd, flags, mode, status = SSH2_FX_FAILURE; + int r, handle, fd, flags, mode, status = SSH2_FX_FAILURE; + + if ((r = sshbuf_get_cstring(iqueue, &name, NULL)) != 0 || + (r = sshbuf_get_u32(iqueue, &pflags)) != 0 || /* portable flags */ + (r = decode_attrib(iqueue, &a)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); - name = get_string(NULL); - pflags = get_int(); /* portable flags */ debug3("request %u: open flags %d", id, pflags); - a = get_attrib(); flags = flags_from_portable(pflags); - mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a->perm : 0666; + mode = (a.flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a.perm : 0666; logit("open \"%s\" flags %s mode 0%o", name, string_from_portable(pflags), mode); if (readonly && ((flags & O_ACCMODE) == O_WRONLY || (flags & O_ACCMODE) == O_RDWR)) { verbose("Refusing open request in read-only mode"); - status = SSH2_FX_PERMISSION_DENIED; + status = SSH2_FX_PERMISSION_DENIED; } else { fd = open(name, flags, mode); if (fd < 0) { @@ -707,9 +722,11 @@ process_open(u_int32_t id) static void process_close(u_int32_t id) { - int handle, ret, status = SSH2_FX_FAILURE; + int r, handle, ret, status = SSH2_FX_FAILURE; + + if ((r = get_handle(iqueue, &handle)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); - handle = get_handle(); debug3("request %u: close handle %u", id, handle); handle_log_close(handle, NULL); ret = handle_close(handle); @@ -720,14 +737,15 @@ process_close(u_int32_t id) static void process_read(u_int32_t id) { - char buf[64*1024]; + u_char buf[64*1024]; u_int32_t len; - int handle, fd, ret, status = SSH2_FX_FAILURE; + int r, handle, fd, ret, status = SSH2_FX_FAILURE; u_int64_t off; - handle = get_handle(); - off = get_int64(); - len = get_int(); + if ((r = get_handle(iqueue, &handle)) != 0 || + (r = sshbuf_get_u64(iqueue, &off)) != 0 || + (r = sshbuf_get_u32(iqueue, &len)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); debug("request %u: read \"%s\" (handle %d) off %llu len %d", id, handle_to_name(handle), handle, (unsigned long long)off, len); @@ -761,18 +779,19 @@ static void process_write(u_int32_t id) { u_int64_t off; - u_int len; - int handle, fd, ret, status; - char *data; + size_t len; + int r, handle, fd, ret, status; + u_char *data; - handle = get_handle(); - off = get_int64(); - data = get_string(&len); + if ((r = get_handle(iqueue, &handle)) != 0 || + (r = sshbuf_get_u64(iqueue, &off)) != 0 || + (r = sshbuf_get_string(iqueue, &data, &len)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); - debug("request %u: write \"%s\" (handle %d) off %llu len %d", + debug("request %u: write \"%s\" (handle %d) off %llu len %zu", id, handle_to_name(handle), handle, (unsigned long long)off, len); fd = handle_to_fd(handle); - + if (fd < 0) status = SSH2_FX_FAILURE; else { @@ -805,13 +824,15 @@ process_do_stat(u_int32_t id, int do_lstat) Attrib a; struct stat st; char *name; - int ret, status = SSH2_FX_FAILURE; + int r, status = SSH2_FX_FAILURE; + + if ((r = sshbuf_get_cstring(iqueue, &name, NULL)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); - name = get_string(NULL); debug3("request %u: %sstat", id, do_lstat ? "l" : ""); verbose("%sstat name \"%s\"", do_lstat ? "l" : "", name); - ret = do_lstat ? lstat(name, &st) : stat(name, &st); - if (ret < 0) { + r = do_lstat ? lstat(name, &st) : stat(name, &st); + if (r < 0) { status = errno_to_portable(errno); } else { stat_to_attrib(&st, &a); @@ -840,15 +861,16 @@ process_fstat(u_int32_t id) { Attrib a; struct stat st; - int fd, ret, handle, status = SSH2_FX_FAILURE; + int fd, r, handle, status = SSH2_FX_FAILURE; - handle = get_handle(); + if ((r = get_handle(iqueue, &handle)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); debug("request %u: fstat \"%s\" (handle %u)", id, handle_to_name(handle), handle); fd = handle_to_fd(handle); if (fd >= 0) { - ret = fstat(fd, &st); - if (ret < 0) { + r = fstat(fd, &st); + if (r < 0) { status = errno_to_portable(errno); } else { stat_to_attrib(&st, &a); @@ -875,42 +897,44 @@ attrib_to_tv(const Attrib *a) static void process_setstat(u_int32_t id) { - Attrib *a; + Attrib a; char *name; - int status = SSH2_FX_OK, ret; + int r, status = SSH2_FX_OK; + + if ((r = sshbuf_get_cstring(iqueue, &name, NULL)) != 0 || + (r = decode_attrib(iqueue, &a)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); - name = get_string(NULL); - a = get_attrib(); debug("request %u: setstat name \"%s\"", id, name); - if (a->flags & SSH2_FILEXFER_ATTR_SIZE) { + if (a.flags & SSH2_FILEXFER_ATTR_SIZE) { logit("set \"%s\" size %llu", - name, (unsigned long long)a->size); - ret = truncate(name, a->size); - if (ret == -1) + name, (unsigned long long)a.size); + r = truncate(name, a.size); + if (r == -1) status = errno_to_portable(errno); } - if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) { - logit("set \"%s\" mode %04o", name, a->perm); - ret = chmod(name, a->perm & 07777); - if (ret == -1) + if (a.flags & SSH2_FILEXFER_ATTR_PERMISSIONS) { + logit("set \"%s\" mode %04o", name, a.perm); + r = chmod(name, a.perm & 07777); + if (r == -1) status = errno_to_portable(errno); } - if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) { + if (a.flags & SSH2_FILEXFER_ATTR_ACMODTIME) { char buf[64]; - time_t t = a->mtime; + time_t t = a.mtime; strftime(buf, sizeof(buf), "%Y%m%d-%H:%M:%S", localtime(&t)); logit("set \"%s\" modtime %s", name, buf); - ret = utimes(name, attrib_to_tv(a)); - if (ret == -1) + r = utimes(name, attrib_to_tv(&a)); + if (r == -1) status = errno_to_portable(errno); } - if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) { + if (a.flags & SSH2_FILEXFER_ATTR_UIDGID) { logit("set \"%s\" owner %lu group %lu", name, - (u_long)a->uid, (u_long)a->gid); - ret = chown(name, a->uid, a->gid); - if (ret == -1) + (u_long)a.uid, (u_long)a.gid); + r = chown(name, a.uid, a.gid); + if (r == -1) status = errno_to_portable(errno); } send_status(id, status); @@ -920,12 +944,78 @@ process_setstat(u_int32_t id) static void process_fsetstat(u_int32_t id) { - Attrib *a; - int handle, fd, ret; + Attrib a; + int handle, fd, r; int status = SSH2_FX_OK; - handle = get_handle(); - a = get_attrib(); + if ((r = get_handle(iqueue, &handle)) != 0 || + (r = decode_attrib(iqueue, &a)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); + + debug("request %u: fsetstat handle %d", id, handle); + fd = handle_to_fd(handle); + if (fd < 0) + status = SSH2_FX_FAILURE; + else { + char *name = handle_to_name(handle); + + if (a.flags & SSH2_FILEXFER_ATTR_SIZE) { + logit("set \"%s\" size %llu", + name, (unsigned long long)a.size); + r = ftruncate(fd, a.size); + if (r == -1) + status = errno_to_portable(errno); + } + if (a.flags & SSH2_FILEXFER_ATTR_PERMISSIONS) { + logit("set \"%s\" mode %04o", name, a.perm); +#ifdef HAVE_FCHMOD + ret = fchmod(fd, a->perm & 07777); +#else + ret = chmod(name, a->perm & 07777); +#endif + if (r == -1) + status = errno_to_portable(errno); + } + if (a.flags & SSH2_FILEXFER_ATTR_ACMODTIME) { + char buf[64]; + time_t t = a.mtime; + + strftime(buf, sizeof(buf), "%Y%m%d-%H:%M:%S", + localtime(&t)); + logit("set \"%s\" modtime %s", name, buf); +#ifdef HAVE_FUTIMES + ret = futimes(fd, attrib_to_tv(a)); +#else + ret = utimes(name, attrib_to_tv(a)); +#endif + if (r == -1) + status = errno_to_portable(errno); + } + if (a.flags & SSH2_FILEXFER_ATTR_UIDGID) { + logit("set \"%s\" owner %lu group %lu", name, + (u_long)a.uid, (u_long)a.gid); +#ifdef HAVE_FCHOWN + ret = fchown(fd, a->uid, a->gid); +#else + ret = chown(name, a->uid, a->gid); +#endif + if (r == -1) + status = errno_to_portable(errno); + } + } + send_status(id, status); +} +static void +process_fsetstat(u_int32_t id) +{ + Attrib a; + int handle, fd, r; + int status = SSH2_FX_OK; + + if ((r = get_handle(iqueue, &handle)) != 0 || + (r = decode_attrib(iqueue, &a)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); + debug("request %u: fsetstat handle %d", id, handle); fd = handle_to_fd(handle); if (fd < 0) @@ -985,9 +1075,11 @@ process_opendir(u_int32_t id) { DIR *dirp = NULL; char *path; - int handle, status = SSH2_FX_FAILURE; + int r, handle, status = SSH2_FX_FAILURE; + + if ((r = sshbuf_get_cstring(iqueue, &path, NULL)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); - path = get_string(NULL); debug3("request %u: opendir", id); logit("opendir \"%s\"", path); dirp = opendir(path); @@ -1014,9 +1106,11 @@ process_readdir(u_int32_t id) DIR *dirp; struct dirent *dp; char *path; - int handle; + int r, handle; + + if ((r = get_handle(iqueue, &handle)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); - handle = get_handle(); debug("request %u: readdir \"%s\" (handle %d)", id, handle_to_name(handle), handle); dirp = handle_to_dir(handle); @@ -1066,14 +1160,15 @@ static void process_remove(u_int32_t id) { char *name; - int status = SSH2_FX_FAILURE; - int ret; + int r, status = SSH2_FX_FAILURE; + + if ((r = sshbuf_get_cstring(iqueue, &name, NULL)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); - name = get_string(NULL); debug3("request %u: remove", id); logit("remove name \"%s\"", name); - ret = unlink(name); - status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; + r = unlink(name); + status = (r == -1) ? errno_to_portable(errno) : SSH2_FX_OK; send_status(id, status); free(name); } @@ -1081,18 +1176,20 @@ process_remove(u_int32_t id) static void process_mkdir(u_int32_t id) { - Attrib *a; + Attrib a; char *name; - int ret, mode, status = SSH2_FX_FAILURE; + int r, mode, status = SSH2_FX_FAILURE; - name = get_string(NULL); - a = get_attrib(); - mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? - a->perm & 07777 : 0777; + if ((r = sshbuf_get_cstring(iqueue, &name, NULL)) != 0 || + (r = decode_attrib(iqueue, &a)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); + + mode = (a.flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? + a.perm & 07777 : 0777; debug3("request %u: mkdir", id); logit("mkdir name \"%s\" mode 0%o", name, mode); - ret = mkdir(name, mode); - status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; + r = mkdir(name, mode); + status = (r == -1) ? errno_to_portable(errno) : SSH2_FX_OK; send_status(id, status); free(name); } @@ -1101,13 +1198,15 @@ static void process_rmdir(u_int32_t id) { char *name; - int ret, status; + int r, status; + + if ((r = sshbuf_get_cstring(iqueue, &name, NULL)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); - name = get_string(NULL); debug3("request %u: rmdir", id); logit("rmdir name \"%s\"", name); - ret = rmdir(name); - status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; + r = rmdir(name); + status = (r == -1) ? errno_to_portable(errno) : SSH2_FX_OK; send_status(id, status); free(name); } @@ -1117,8 +1216,11 @@ process_realpath(u_int32_t id) { char resolvedname[MAXPATHLEN]; char *path; + int r; + + if ((r = sshbuf_get_cstring(iqueue, &path, NULL)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); - path = get_string(NULL); if (path[0] == '\0') { free(path); path = xstrdup("."); @@ -1140,11 +1242,13 @@ static void process_rename(u_int32_t id) { char *oldpath, *newpath; - int status; + int r, status; struct stat sb; - oldpath = get_string(NULL); - newpath = get_string(NULL); + if ((r = sshbuf_get_cstring(iqueue, &oldpath, NULL)) != 0 || + (r = sshbuf_get_cstring(iqueue, &newpath, NULL)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); + debug3("request %u: rename", id); logit("rename old \"%s\" new \"%s\"", oldpath, newpath); status = SSH2_FX_FAILURE; @@ -1197,11 +1301,13 @@ process_rename(u_int32_t id) static void process_readlink(u_int32_t id) { - int len; + int r, len; char buf[MAXPATHLEN]; char *path; - path = get_string(NULL); + if ((r = sshbuf_get_cstring(iqueue, &path, NULL)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); + debug3("request %u: readlink", id); verbose("readlink \"%s\"", path); if ((len = readlink(path, buf, sizeof(buf) - 1)) == -1) @@ -1221,15 +1327,17 @@ static void process_symlink(u_int32_t id) { char *oldpath, *newpath; - int ret, status; + int r, status; + + if ((r = sshbuf_get_cstring(iqueue, &oldpath, NULL)) != 0 || + (r = sshbuf_get_cstring(iqueue, &newpath, NULL)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); - oldpath = get_string(NULL); - newpath = get_string(NULL); debug3("request %u: symlink", id); logit("symlink old \"%s\" new \"%s\"", oldpath, newpath); /* this will fail if 'newpath' exists */ - ret = symlink(oldpath, newpath); - status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; + r = symlink(oldpath, newpath); + status = (r == -1) ? errno_to_portable(errno) : SSH2_FX_OK; send_status(id, status); free(oldpath); free(newpath); @@ -1239,14 +1347,16 @@ static void process_extended_posix_rename(u_int32_t id) { char *oldpath, *newpath; - int ret, status; + int r, status; + + if ((r = sshbuf_get_cstring(iqueue, &oldpath, NULL)) != 0 || + (r = sshbuf_get_cstring(iqueue, &newpath, NULL)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); - oldpath = get_string(NULL); - newpath = get_string(NULL); debug3("request %u: posix-rename", id); logit("posix-rename old \"%s\" new \"%s\"", oldpath, newpath); - ret = rename(oldpath, newpath); - status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; + r = rename(oldpath, newpath); + status = (r == -1) ? errno_to_portable(errno) : SSH2_FX_OK; send_status(id, status); free(oldpath); free(newpath); @@ -1257,8 +1367,10 @@ process_extended_statvfs(u_int32_t id) { char *path; struct statvfs st; + int r; - path = get_string(NULL); + if ((r = sshbuf_get_cstring(iqueue, &path, NULL)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); debug3("request %u: statvfs", id); logit("statvfs \"%s\"", path); @@ -1272,10 +1384,11 @@ process_extended_statvfs(u_int32_t id) static void process_extended_fstatvfs(u_int32_t id) { - int handle, fd; + int r, handle, fd; struct statvfs st; - handle = get_handle(); + if ((r = get_handle(iqueue, &handle)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); debug("request %u: fstatvfs \"%s\" (handle %u)", id, handle_to_name(handle), handle); if ((fd = handle_to_fd(handle)) < 0) { @@ -1292,14 +1405,16 @@ static void process_extended_hardlink(u_int32_t id) { char *oldpath, *newpath; - int ret, status; + int r, status; + + if ((r = sshbuf_get_cstring(iqueue, &oldpath, NULL)) != 0 || + (r = sshbuf_get_cstring(iqueue, &newpath, NULL)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); - oldpath = get_string(NULL); - newpath = get_string(NULL); debug3("request %u: hardlink", id); logit("hardlink old \"%s\" new \"%s\"", oldpath, newpath); - ret = link(oldpath, newpath); - status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; + r = link(oldpath, newpath); + status = (r == -1) ? errno_to_portable(errno) : SSH2_FX_OK; send_status(id, status); free(oldpath); free(newpath); @@ -1308,16 +1423,17 @@ process_extended_hardlink(u_int32_t id) static void process_extended_fsync(u_int32_t id) { - int handle, fd, ret, status = SSH2_FX_OP_UNSUPPORTED; + int handle, fd, r, status = SSH2_FX_OP_UNSUPPORTED; - handle = get_handle(); + if ((r = get_handle(iqueue, &handle)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); debug3("request %u: fsync (handle %u)", id, handle); verbose("fsync \"%s\"", handle_to_name(handle)); if ((fd = handle_to_fd(handle)) < 0) status = SSH2_FX_NO_SUCH_FILE; else if (handle_is_ok(handle, HANDLE_FILE)) { - ret = fsync(fd); - status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; + r = fsync(fd); + status = (r == -1) ? errno_to_portable(errno) : SSH2_FX_OK; } send_status(id, status); } @@ -1326,9 +1442,10 @@ static void process_extended(u_int32_t id) { char *request; - u_int i; + int i, r; - request = get_string(NULL); + if ((r = sshbuf_get_cstring(iqueue, &request, NULL)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); for (i = 0; extended_handlers[i].handler != NULL; i++) { if (strcmp(request, extended_handlers[i].ext_name) == 0) { if (!request_permitted(&extended_handlers[i])) @@ -1350,14 +1467,18 @@ process_extended(u_int32_t id) static void process(void) { - u_int msg_len, buf_len, consumed, type, i; - u_char *cp; + u_int msg_len; + u_int buf_len; + u_int consumed; + u_char type; + const u_char *cp; + int i, r; u_int32_t id; - buf_len = buffer_len(&iqueue); + buf_len = sshbuf_len(iqueue); if (buf_len < 5) return; /* Incomplete message. */ - cp = buffer_ptr(&iqueue); + cp = sshbuf_ptr(iqueue); msg_len = get_u32(cp); if (msg_len > SFTP_MAX_MSG_LENGTH) { error("bad message from %s local user %s", @@ -1366,9 +1487,11 @@ process(void) } if (buf_len < msg_len + 4) return; - buffer_consume(&iqueue, 4); + if ((r = sshbuf_consume(iqueue, 4)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); buf_len -= 4; - type = buffer_get_char(&iqueue); + if ((r = sshbuf_get_u8(iqueue, &type)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); switch (type) { case SSH2_FXP_INIT: @@ -1378,13 +1501,15 @@ process(void) case SSH2_FXP_EXTENDED: if (!init_done) fatal("Received extended request before init"); - id = get_int(); + if ((r = sshbuf_get_u32(iqueue, &id)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); process_extended(id); break; default: if (!init_done) fatal("Received %u request before init", type); - id = get_int(); + if ((r = sshbuf_get_u32(iqueue, &id)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); for (i = 0; handlers[i].handler != NULL; i++) { if (type == handlers[i].type) { if (!request_permitted(&handlers[i])) { @@ -1400,17 +1525,18 @@ process(void) error("Unknown message %u", type); } /* discard the remaining bytes from the current packet */ - if (buf_len < buffer_len(&iqueue)) { + if (buf_len < sshbuf_len(iqueue)) { error("iqueue grew unexpectedly"); sftp_server_cleanup_exit(255); } - consumed = buf_len - buffer_len(&iqueue); + consumed = buf_len - sshbuf_len(iqueue); if (msg_len < consumed) { error("msg_len %u < consumed %u", msg_len, consumed); sftp_server_cleanup_exit(255); } - if (msg_len > consumed) - buffer_consume(&iqueue, msg_len - consumed); + if (msg_len > consumed && + (r = sshbuf_consume(iqueue, msg_len - consumed)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); } /* Cleanup handler that logs active handles upon normal exit */ @@ -1443,7 +1569,7 @@ int sftp_server_main(int argc, char **argv, struct passwd *user_pw) { fd_set *rset, *wset; - int i, in, out, max, ch, skipargs = 0, log_stderr = 0; + int i, r, in, out, max, ch, skipargs = 0, log_stderr = 0; ssize_t len, olen, set_size; SyslogFacility log_facility = SYSLOG_FACILITY_AUTH; char *cp, *homedir = NULL, buf[4*4096]; @@ -1565,8 +1691,10 @@ sftp_server_main(int argc, char **argv, struct passwd *user_pw) if (out > max) max = out; - buffer_init(&iqueue); - buffer_init(&oqueue); + if ((iqueue = sshbuf_new()) == NULL) + fatal("%s: sshbuf_new failed", __func__); + if ((oqueue = sshbuf_new()) == NULL) + fatal("%s: sshbuf_new failed", __func__); set_size = howmany(max + 1, NFDBITS) * sizeof(fd_mask); rset = (fd_set *)xmalloc(set_size); @@ -1588,11 +1716,15 @@ sftp_server_main(int argc, char **argv, struct passwd *user_pw) * the worst-case length packet it can generate, * otherwise apply backpressure by stopping reads. */ - if (buffer_check_alloc(&iqueue, sizeof(buf)) && - buffer_check_alloc(&oqueue, SFTP_MAX_MSG_LENGTH)) + if ((r = sshbuf_check_reserve(iqueue, sizeof(buf))) == 0 && + (r = sshbuf_check_reserve(oqueue, + SFTP_MAX_MSG_LENGTH)) == 0) FD_SET(in, rset); + else if (r != SSH_ERR_NO_BUFFER_SPACE) + fatal("%s: sshbuf_check_reserve failed: %s", + __func__, ssh_err(r)); - olen = buffer_len(&oqueue); + olen = sshbuf_len(oqueue); if (olen > 0) FD_SET(out, wset); @@ -1612,18 +1744,20 @@ sftp_server_main(int argc, char **argv, struct passwd *user_pw) } else if (len < 0) { error("read: %s", strerror(errno)); sftp_server_cleanup_exit(1); - } else { - buffer_append(&iqueue, buf, len); + } else if ((r = sshbuf_put(iqueue, buf, len)) != 0) { + fatal("%s: buffer error: %s", + __func__, ssh_err(r)); } } /* send oqueue to stdout */ if (FD_ISSET(out, wset)) { - len = write(out, buffer_ptr(&oqueue), olen); + len = write(out, sshbuf_ptr(oqueue), olen); if (len < 0) { error("write: %s", strerror(errno)); sftp_server_cleanup_exit(1); - } else { - buffer_consume(&oqueue, len); + } else if ((r = sshbuf_consume(oqueue, len)) != 0) { + fatal("%s: buffer error: %s", + __func__, ssh_err(r)); } } @@ -1632,7 +1766,11 @@ sftp_server_main(int argc, char **argv, struct passwd *user_pw) * into the output buffer, otherwise stop processing input * and let the output queue drain. */ - if (buffer_check_alloc(&oqueue, SFTP_MAX_MSG_LENGTH)) + r = sshbuf_check_reserve(oqueue, SFTP_MAX_MSG_LENGTH); + if (r == 0) process(); + else if (r != SSH_ERR_NO_BUFFER_SPACE) + fatal("%s: sshbuf_check_reserve: %s", + __func__, ssh_err(r)); } } diff --git a/sftp.c b/sftp.c index 98a146ed4..eee472d08 100644 --- a/sftp.c +++ b/sftp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sftp.c,v 1.168 2014/11/26 18:34:51 millert Exp $ */ +/* $OpenBSD: sftp.c,v 1.169 2015/01/14 13:54:13 djm Exp $ */ /* * Copyright (c) 2001-2004 Damien Miller * @@ -63,7 +63,8 @@ typedef void EditLine; #include "misc.h" #include "sftp.h" -#include "buffer.h" +#include "ssherr.h" +#include "sshbuf.h" #include "sftp-common.h" #include "sftp-client.h"