mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-09 17:38:00 +00:00
3214563d8e
My normal habit these days, in new code, is to treat int and bool as _almost_ completely separate types. I'm still willing to use C's implicit test for zero on an integer (e.g. 'if (!blob.len)' is fine, no need to spell it out as blob.len != 0), but generally, if a variable is going to be conceptually a boolean, I like to declare it bool and assign to it using 'true' or 'false' rather than 0 or 1. PuTTY is an exception, because it predates the C99 bool, and I've stuck to its existing coding style even when adding new code to it. But it's been annoying me more and more, so now that I've decided C99 bool is an acceptable thing to require from our toolchain in the first place, here's a quite thorough trawl through the source doing 'boolification'. Many variables and function parameters are now typed as bool rather than int; many assignments of 0 or 1 to those variables are now spelled 'true' or 'false'. I managed this thorough conversion with the help of a custom clang plugin that I wrote to trawl the AST and apply heuristics to point out where things might want changing. So I've even managed to do a decent job on parts of the code I haven't looked at in years! To make the plugin's work easier, I pushed platform front ends generally in the direction of using standard 'bool' in preference to platform-specific boolean types like Windows BOOL or GTK's gboolean; I've left the platform booleans in places they _have_ to be for the platform APIs to work right, but variables only used by my own code have been converted wherever I found them. In a few places there are int values that look very like booleans in _most_ of the places they're used, but have a rarely-used third value, or a distinction between different nonzero values that most users don't care about. In these cases, I've _removed_ uses of 'true' and 'false' for the return values, to emphasise that there's something more subtle going on than a simple boolean answer: - the 'multisel' field in dialog.h's list box structure, for which the GTK front end in particular recognises a difference between 1 and 2 but nearly everything else treats as boolean - the 'urgent' parameter to plug_receive, where 1 vs 2 tells you something about the specific location of the urgent pointer, but most clients only care about 0 vs 'something nonzero' - the return value of wc_match, where -1 indicates a syntax error in the wildcard. - the return values from SSH-1 RSA-key loading functions, which use -1 for 'wrong passphrase' and 0 for all other failures (so any caller which already knows it's not loading an _encrypted private_ key can treat them as boolean) - term->esc_query, and the 'query' parameter in toggle_mode in terminal.c, which _usually_ hold 0 for ESC[123h or 1 for ESC[?123h, but can also hold -1 for some other intervening character that we don't support. In a few places there's an integer that I haven't turned into a bool even though it really _can_ only take values 0 or 1 (and, as above, tried to make the call sites consistent in not calling those values true and false), on the grounds that I thought it would make it more confusing to imply that the 0 value was in some sense 'negative' or bad and the 1 positive or good: - the return value of plug_accepting uses the POSIXish convention of 0=success and nonzero=error; I think if I made it bool then I'd also want to reverse its sense, and that's a job for a separate piece of work. - the 'screen' parameter to lineptr() in terminal.c, where 0 and 1 represent the default and alternate screens. There's no obvious reason why one of those should be considered 'true' or 'positive' or 'success' - they're just indices - so I've left it as int. ssh_scp_recv had particularly confusing semantics for its previous int return value: its call sites used '<= 0' to check for error, but it never actually returned a negative number, just 0 or 1. Now the function and its call sites agree that it's a bool. In a couple of places I've renamed variables called 'ret', because I don't like that name any more - it's unclear whether it means the return value (in preparation) for the _containing_ function or the return value received from a subroutine call, and occasionally I've accidentally used the same variable for both and introduced a bug. So where one of those got in my way, I've renamed it to 'toret' or 'retd' (the latter short for 'returned') in line with my usual modern practice, but I haven't done a thorough job of finding all of them. Finally, one amusing side effect of doing this is that I've had to separate quite a few chained assignments. It used to be perfectly fine to write 'a = b = c = TRUE' when a,b,c were int and TRUE was just a the 'true' defined by stdbool.h, that idiom provokes a warning from gcc: 'suggest parentheses around assignment used as truth value'!
520 lines
19 KiB
C
520 lines
19 KiB
C
/*
|
|
* sftp.h: definitions for SFTP and the sftp.c routines.
|
|
*/
|
|
|
|
#include "defs.h"
|
|
|
|
#define SSH_FXP_INIT 1 /* 0x1 */
|
|
#define SSH_FXP_VERSION 2 /* 0x2 */
|
|
#define SSH_FXP_OPEN 3 /* 0x3 */
|
|
#define SSH_FXP_CLOSE 4 /* 0x4 */
|
|
#define SSH_FXP_READ 5 /* 0x5 */
|
|
#define SSH_FXP_WRITE 6 /* 0x6 */
|
|
#define SSH_FXP_LSTAT 7 /* 0x7 */
|
|
#define SSH_FXP_FSTAT 8 /* 0x8 */
|
|
#define SSH_FXP_SETSTAT 9 /* 0x9 */
|
|
#define SSH_FXP_FSETSTAT 10 /* 0xa */
|
|
#define SSH_FXP_OPENDIR 11 /* 0xb */
|
|
#define SSH_FXP_READDIR 12 /* 0xc */
|
|
#define SSH_FXP_REMOVE 13 /* 0xd */
|
|
#define SSH_FXP_MKDIR 14 /* 0xe */
|
|
#define SSH_FXP_RMDIR 15 /* 0xf */
|
|
#define SSH_FXP_REALPATH 16 /* 0x10 */
|
|
#define SSH_FXP_STAT 17 /* 0x11 */
|
|
#define SSH_FXP_RENAME 18 /* 0x12 */
|
|
#define SSH_FXP_STATUS 101 /* 0x65 */
|
|
#define SSH_FXP_HANDLE 102 /* 0x66 */
|
|
#define SSH_FXP_DATA 103 /* 0x67 */
|
|
#define SSH_FXP_NAME 104 /* 0x68 */
|
|
#define SSH_FXP_ATTRS 105 /* 0x69 */
|
|
#define SSH_FXP_EXTENDED 200 /* 0xc8 */
|
|
#define SSH_FXP_EXTENDED_REPLY 201 /* 0xc9 */
|
|
|
|
#define SSH_FX_OK 0
|
|
#define SSH_FX_EOF 1
|
|
#define SSH_FX_NO_SUCH_FILE 2
|
|
#define SSH_FX_PERMISSION_DENIED 3
|
|
#define SSH_FX_FAILURE 4
|
|
#define SSH_FX_BAD_MESSAGE 5
|
|
#define SSH_FX_NO_CONNECTION 6
|
|
#define SSH_FX_CONNECTION_LOST 7
|
|
#define SSH_FX_OP_UNSUPPORTED 8
|
|
|
|
#define SSH_FILEXFER_ATTR_SIZE 0x00000001
|
|
#define SSH_FILEXFER_ATTR_UIDGID 0x00000002
|
|
#define SSH_FILEXFER_ATTR_PERMISSIONS 0x00000004
|
|
#define SSH_FILEXFER_ATTR_ACMODTIME 0x00000008
|
|
#define SSH_FILEXFER_ATTR_EXTENDED 0x80000000
|
|
|
|
#define SSH_FXF_READ 0x00000001
|
|
#define SSH_FXF_WRITE 0x00000002
|
|
#define SSH_FXF_APPEND 0x00000004
|
|
#define SSH_FXF_CREAT 0x00000008
|
|
#define SSH_FXF_TRUNC 0x00000010
|
|
#define SSH_FXF_EXCL 0x00000020
|
|
|
|
#define SFTP_PROTO_VERSION 3
|
|
|
|
#define PERMS_DIRECTORY 040000
|
|
|
|
/*
|
|
* External references. The sftp client module sftp.c expects to be
|
|
* able to get at these functions.
|
|
*
|
|
* sftp_recvdata must never return less than len. It either blocks
|
|
* until len is available and then returns true, or it returns false
|
|
* for failure.
|
|
*
|
|
* sftp_senddata returns true on success, false on failure.
|
|
*
|
|
* sftp_sendbuffer returns the size of the backlog of data in the
|
|
* transmit queue.
|
|
*/
|
|
bool sftp_senddata(char *data, int len);
|
|
int sftp_sendbuffer(void);
|
|
bool sftp_recvdata(char *data, int len);
|
|
|
|
/*
|
|
* Free sftp_requests
|
|
*/
|
|
void sftp_cleanup_request(void);
|
|
|
|
struct fxp_attrs {
|
|
unsigned long flags;
|
|
uint64_t size;
|
|
unsigned long uid;
|
|
unsigned long gid;
|
|
unsigned long permissions;
|
|
unsigned long atime;
|
|
unsigned long mtime;
|
|
};
|
|
extern const struct fxp_attrs no_attrs;
|
|
|
|
/*
|
|
* Copy between the possibly-unused permissions field in an fxp_attrs
|
|
* and a possibly-negative integer containing the same permissions.
|
|
*/
|
|
#define PUT_PERMISSIONS(attrs, perms) \
|
|
((perms) >= 0 ? \
|
|
((attrs).flags |= SSH_FILEXFER_ATTR_PERMISSIONS, \
|
|
(attrs).permissions = (perms)) : \
|
|
((attrs).flags &= ~SSH_FILEXFER_ATTR_PERMISSIONS))
|
|
#define GET_PERMISSIONS(attrs, defaultperms) \
|
|
((attrs).flags & SSH_FILEXFER_ATTR_PERMISSIONS ? \
|
|
(attrs).permissions : defaultperms)
|
|
|
|
struct fxp_handle {
|
|
char *hstring;
|
|
int hlen;
|
|
};
|
|
|
|
struct fxp_name {
|
|
char *filename, *longname;
|
|
struct fxp_attrs attrs;
|
|
};
|
|
|
|
struct fxp_names {
|
|
int nnames;
|
|
struct fxp_name *names;
|
|
};
|
|
|
|
struct sftp_request;
|
|
|
|
/*
|
|
* Packet-manipulation functions.
|
|
*/
|
|
|
|
struct sftp_packet {
|
|
char *data;
|
|
unsigned length, maxlen;
|
|
unsigned savedpos;
|
|
int type;
|
|
BinarySink_IMPLEMENTATION;
|
|
BinarySource_IMPLEMENTATION;
|
|
};
|
|
|
|
/* When sending a packet, create it with sftp_pkt_init, then add
|
|
* things to it by treating it as a BinarySink. When it's done, call
|
|
* sftp_send_prepare, and then pkt->data and pkt->length describe its
|
|
* wire format. */
|
|
struct sftp_packet *sftp_pkt_init(int pkt_type);
|
|
void sftp_send_prepare(struct sftp_packet *pkt);
|
|
|
|
/* When receiving a packet, create it with sftp_recv_prepare once you
|
|
* decode its length from the first 4 bytes of wire data. Then write
|
|
* that many bytes into pkt->data, and call sftp_recv_finish to set up
|
|
* the type code and BinarySource. */
|
|
struct sftp_packet *sftp_recv_prepare(unsigned length);
|
|
bool sftp_recv_finish(struct sftp_packet *pkt);
|
|
|
|
/* Either kind of packet can be freed afterwards with sftp_pkt_free. */
|
|
void sftp_pkt_free(struct sftp_packet *pkt);
|
|
|
|
void BinarySink_put_fxp_attrs(BinarySink *bs, struct fxp_attrs attrs);
|
|
bool BinarySource_get_fxp_attrs(BinarySource *src, struct fxp_attrs *attrs);
|
|
#define put_fxp_attrs(bs, attrs) \
|
|
BinarySink_put_fxp_attrs(BinarySink_UPCAST(bs), attrs)
|
|
#define get_fxp_attrs(bs, attrs) \
|
|
BinarySource_get_fxp_attrs(BinarySource_UPCAST(bs), attrs)
|
|
|
|
/*
|
|
* Error handling.
|
|
*/
|
|
|
|
const char *fxp_error(void);
|
|
int fxp_error_type(void);
|
|
|
|
/*
|
|
* Perform exchange of init/version packets. Return false on failure.
|
|
*/
|
|
bool fxp_init(void);
|
|
|
|
/*
|
|
* Canonify a pathname. Concatenate the two given path elements
|
|
* with a separating slash, unless the second is NULL.
|
|
*/
|
|
struct sftp_request *fxp_realpath_send(const char *path);
|
|
char *fxp_realpath_recv(struct sftp_packet *pktin, struct sftp_request *req);
|
|
|
|
/*
|
|
* Open a file. 'attrs' contains attributes to be applied to the file
|
|
* if it's being created.
|
|
*/
|
|
struct sftp_request *fxp_open_send(const char *path, int type,
|
|
const struct fxp_attrs *attrs);
|
|
struct fxp_handle *fxp_open_recv(struct sftp_packet *pktin,
|
|
struct sftp_request *req);
|
|
|
|
/*
|
|
* Open a directory.
|
|
*/
|
|
struct sftp_request *fxp_opendir_send(const char *path);
|
|
struct fxp_handle *fxp_opendir_recv(struct sftp_packet *pktin,
|
|
struct sftp_request *req);
|
|
|
|
/*
|
|
* Close a file/dir. Returns true on success, false on error.
|
|
*/
|
|
struct sftp_request *fxp_close_send(struct fxp_handle *handle);
|
|
bool fxp_close_recv(struct sftp_packet *pktin, struct sftp_request *req);
|
|
|
|
/*
|
|
* Make a directory.
|
|
*/
|
|
struct sftp_request *fxp_mkdir_send(const char *path,
|
|
const struct fxp_attrs *attrs);
|
|
bool fxp_mkdir_recv(struct sftp_packet *pktin, struct sftp_request *req);
|
|
|
|
/*
|
|
* Remove a directory.
|
|
*/
|
|
struct sftp_request *fxp_rmdir_send(const char *path);
|
|
bool fxp_rmdir_recv(struct sftp_packet *pktin, struct sftp_request *req);
|
|
|
|
/*
|
|
* Remove a file.
|
|
*/
|
|
struct sftp_request *fxp_remove_send(const char *fname);
|
|
bool fxp_remove_recv(struct sftp_packet *pktin, struct sftp_request *req);
|
|
|
|
/*
|
|
* Rename a file.
|
|
*/
|
|
struct sftp_request *fxp_rename_send(const char *srcfname,
|
|
const char *dstfname);
|
|
bool fxp_rename_recv(struct sftp_packet *pktin, struct sftp_request *req);
|
|
|
|
/*
|
|
* Return file attributes.
|
|
*/
|
|
struct sftp_request *fxp_stat_send(const char *fname);
|
|
bool fxp_stat_recv(struct sftp_packet *pktin, struct sftp_request *req,
|
|
struct fxp_attrs *attrs);
|
|
struct sftp_request *fxp_fstat_send(struct fxp_handle *handle);
|
|
bool fxp_fstat_recv(struct sftp_packet *pktin, struct sftp_request *req,
|
|
struct fxp_attrs *attrs);
|
|
|
|
/*
|
|
* Set file attributes.
|
|
*/
|
|
struct sftp_request *fxp_setstat_send(const char *fname,
|
|
struct fxp_attrs attrs);
|
|
bool fxp_setstat_recv(struct sftp_packet *pktin, struct sftp_request *req);
|
|
struct sftp_request *fxp_fsetstat_send(struct fxp_handle *handle,
|
|
struct fxp_attrs attrs);
|
|
bool fxp_fsetstat_recv(struct sftp_packet *pktin, struct sftp_request *req);
|
|
|
|
/*
|
|
* Read from a file.
|
|
*/
|
|
struct sftp_request *fxp_read_send(struct fxp_handle *handle,
|
|
uint64_t offset, int len);
|
|
int fxp_read_recv(struct sftp_packet *pktin, struct sftp_request *req,
|
|
char *buffer, int len);
|
|
|
|
/*
|
|
* Write to a file.
|
|
*/
|
|
struct sftp_request *fxp_write_send(struct fxp_handle *handle,
|
|
void *buffer, uint64_t offset, int len);
|
|
bool fxp_write_recv(struct sftp_packet *pktin, struct sftp_request *req);
|
|
|
|
/*
|
|
* Read from a directory.
|
|
*/
|
|
struct sftp_request *fxp_readdir_send(struct fxp_handle *handle);
|
|
struct fxp_names *fxp_readdir_recv(struct sftp_packet *pktin,
|
|
struct sftp_request *req);
|
|
|
|
/*
|
|
* Free up an fxp_names structure.
|
|
*/
|
|
void fxp_free_names(struct fxp_names *names);
|
|
|
|
/*
|
|
* Duplicate and free fxp_name structures.
|
|
*/
|
|
struct fxp_name *fxp_dup_name(struct fxp_name *name);
|
|
void fxp_free_name(struct fxp_name *name);
|
|
|
|
/*
|
|
* Store user data in an sftp_request structure.
|
|
*/
|
|
void *fxp_get_userdata(struct sftp_request *req);
|
|
void fxp_set_userdata(struct sftp_request *req, void *data);
|
|
|
|
/*
|
|
* These functions might well be temporary placeholders to be
|
|
* replaced with more useful similar functions later. They form the
|
|
* main dispatch loop for processing incoming SFTP responses.
|
|
*/
|
|
void sftp_register(struct sftp_request *req);
|
|
struct sftp_request *sftp_find_request(struct sftp_packet *pktin);
|
|
struct sftp_packet *sftp_recv(void);
|
|
|
|
/*
|
|
* A wrapper to go round fxp_read_* and fxp_write_*, which manages
|
|
* the queueing of multiple read/write requests.
|
|
*/
|
|
|
|
struct fxp_xfer;
|
|
|
|
struct fxp_xfer *xfer_download_init(struct fxp_handle *fh, uint64_t offset);
|
|
void xfer_download_queue(struct fxp_xfer *xfer);
|
|
int xfer_download_gotpkt(struct fxp_xfer *xfer, struct sftp_packet *pktin);
|
|
bool xfer_download_data(struct fxp_xfer *xfer, void **buf, int *len);
|
|
|
|
struct fxp_xfer *xfer_upload_init(struct fxp_handle *fh, uint64_t offset);
|
|
bool xfer_upload_ready(struct fxp_xfer *xfer);
|
|
void xfer_upload_data(struct fxp_xfer *xfer, char *buffer, int len);
|
|
int xfer_upload_gotpkt(struct fxp_xfer *xfer, struct sftp_packet *pktin);
|
|
|
|
bool xfer_done(struct fxp_xfer *xfer);
|
|
void xfer_set_error(struct fxp_xfer *xfer);
|
|
void xfer_cleanup(struct fxp_xfer *xfer);
|
|
|
|
/*
|
|
* Vtable for the platform-specific filesystem implementation that
|
|
* answers requests in an SFTP server.
|
|
*/
|
|
typedef struct SftpReplyBuilder SftpReplyBuilder;
|
|
struct SftpServer {
|
|
const SftpServerVtable *vt;
|
|
};
|
|
struct SftpServerVtable {
|
|
SftpServer *(*new)(const SftpServerVtable *vt);
|
|
void (*free)(SftpServer *srv);
|
|
|
|
/*
|
|
* Handle actual filesystem requests.
|
|
*
|
|
* Each of these functions replies by calling an appropiate
|
|
* sftp_reply_foo() function on the given reply packet.
|
|
*/
|
|
|
|
/* Should call fxp_reply_error or fxp_reply_simple_name */
|
|
void (*realpath)(SftpServer *srv, SftpReplyBuilder *reply,
|
|
ptrlen path);
|
|
|
|
/* Should call fxp_reply_error or fxp_reply_handle */
|
|
void (*open)(SftpServer *srv, SftpReplyBuilder *reply,
|
|
ptrlen path, unsigned flags, struct fxp_attrs attrs);
|
|
|
|
/* Should call fxp_reply_error or fxp_reply_handle */
|
|
void (*opendir)(SftpServer *srv, SftpReplyBuilder *reply,
|
|
ptrlen path);
|
|
|
|
/* Should call fxp_reply_error or fxp_reply_ok */
|
|
void (*close)(SftpServer *srv, SftpReplyBuilder *reply, ptrlen handle);
|
|
|
|
/* Should call fxp_reply_error or fxp_reply_ok */
|
|
void (*mkdir)(SftpServer *srv, SftpReplyBuilder *reply,
|
|
ptrlen path, struct fxp_attrs attrs);
|
|
|
|
/* Should call fxp_reply_error or fxp_reply_ok */
|
|
void (*rmdir)(SftpServer *srv, SftpReplyBuilder *reply, ptrlen path);
|
|
|
|
/* Should call fxp_reply_error or fxp_reply_ok */
|
|
void (*remove)(SftpServer *srv, SftpReplyBuilder *reply, ptrlen path);
|
|
|
|
/* Should call fxp_reply_error or fxp_reply_ok */
|
|
void (*rename)(SftpServer *srv, SftpReplyBuilder *reply,
|
|
ptrlen srcpath, ptrlen dstpath);
|
|
|
|
/* Should call fxp_reply_error or fxp_reply_attrs */
|
|
void (*stat)(SftpServer *srv, SftpReplyBuilder *reply, ptrlen path,
|
|
bool follow_symlinks);
|
|
|
|
/* Should call fxp_reply_error or fxp_reply_attrs */
|
|
void (*fstat)(SftpServer *srv, SftpReplyBuilder *reply, ptrlen handle);
|
|
|
|
/* Should call fxp_reply_error or fxp_reply_ok */
|
|
void (*setstat)(SftpServer *srv, SftpReplyBuilder *reply,
|
|
ptrlen path, struct fxp_attrs attrs);
|
|
|
|
/* Should call fxp_reply_error or fxp_reply_ok */
|
|
void (*fsetstat)(SftpServer *srv, SftpReplyBuilder *reply,
|
|
ptrlen handle, struct fxp_attrs attrs);
|
|
|
|
/* Should call fxp_reply_error or fxp_reply_data */
|
|
void (*read)(SftpServer *srv, SftpReplyBuilder *reply,
|
|
ptrlen handle, uint64_t offset, unsigned length);
|
|
|
|
/* Should call fxp_reply_error or fxp_reply_ok */
|
|
void (*write)(SftpServer *srv, SftpReplyBuilder *reply,
|
|
ptrlen handle, uint64_t offset, ptrlen data);
|
|
|
|
/* Should call fxp_reply_error, or fxp_reply_name_count once and
|
|
* then fxp_reply_full_name that many times */
|
|
void (*readdir)(SftpServer *srv, SftpReplyBuilder *reply, ptrlen handle,
|
|
int max_entries, bool omit_longname);
|
|
};
|
|
|
|
#define sftpsrv_new(vt) \
|
|
((vt)->new(vt))
|
|
#define sftpsrv_free(srv) \
|
|
((srv)->vt->free(srv))
|
|
#define sftpsrv_realpath(srv, reply, path) \
|
|
((srv)->vt->realpath(srv, reply, path))
|
|
#define sftpsrv_open(srv, reply, path, flags, attrs) \
|
|
((srv)->vt->open(srv, reply, path, flags, attrs))
|
|
#define sftpsrv_opendir(srv, reply, path) \
|
|
((srv)->vt->opendir(srv, reply, path))
|
|
#define sftpsrv_close(srv, reply, handle) \
|
|
((srv)->vt->close(srv, reply, handle))
|
|
#define sftpsrv_mkdir(srv, reply, path, attrs) \
|
|
((srv)->vt->mkdir(srv, reply, path, attrs))
|
|
#define sftpsrv_rmdir(srv, reply, path) \
|
|
((srv)->vt->rmdir(srv, reply, path))
|
|
#define sftpsrv_remove(srv, reply, path) \
|
|
((srv)->vt->remove(srv, reply, path))
|
|
#define sftpsrv_rename(srv, reply, srcpath, dstpath) \
|
|
((srv)->vt->rename(srv, reply, srcpath, dstpath))
|
|
#define sftpsrv_stat(srv, reply, path, follow) \
|
|
((srv)->vt->stat(srv, reply, path, follow))
|
|
#define sftpsrv_fstat(srv, reply, handle) \
|
|
((srv)->vt->fstat(srv, reply, handle))
|
|
#define sftpsrv_setstat(srv, reply, path, attrs) \
|
|
((srv)->vt->setstat(srv, reply, path, attrs))
|
|
#define sftpsrv_fsetstat(srv, reply, handle, attrs) \
|
|
((srv)->vt->fsetstat(srv, reply, handle, attrs))
|
|
#define sftpsrv_read(srv, reply, handle, offset, length) \
|
|
((srv)->vt->read(srv, reply, handle, offset, length))
|
|
#define sftpsrv_write(srv, reply, handle, offset, data) \
|
|
((srv)->vt->write(srv, reply, handle, offset, data))
|
|
#define sftpsrv_readdir(srv, reply, handle, max, nolongname) \
|
|
((srv)->vt->readdir(srv, reply, handle, max, nolongname))
|
|
|
|
typedef struct SftpReplyBuilderVtable SftpReplyBuilderVtable;
|
|
struct SftpReplyBuilder {
|
|
const SftpReplyBuilderVtable *vt;
|
|
};
|
|
struct SftpReplyBuilderVtable {
|
|
void (*reply_ok)(SftpReplyBuilder *reply);
|
|
void (*reply_error)(SftpReplyBuilder *reply, unsigned code,
|
|
const char *msg);
|
|
void (*reply_simple_name)(SftpReplyBuilder *reply, ptrlen name);
|
|
void (*reply_name_count)(SftpReplyBuilder *reply, unsigned count);
|
|
void (*reply_full_name)(SftpReplyBuilder *reply, ptrlen name,
|
|
ptrlen longname, struct fxp_attrs attrs);
|
|
void (*reply_handle)(SftpReplyBuilder *reply, ptrlen handle);
|
|
void (*reply_data)(SftpReplyBuilder *reply, ptrlen data);
|
|
void (*reply_attrs)(SftpReplyBuilder *reply, struct fxp_attrs attrs);
|
|
};
|
|
|
|
#define fxp_reply_ok(reply) \
|
|
((reply)->vt->reply_ok(reply))
|
|
#define fxp_reply_error(reply, code, msg) \
|
|
((reply)->vt->reply_error(reply, code, msg))
|
|
#define fxp_reply_simple_name(reply, name) \
|
|
((reply)->vt->reply_simple_name(reply, name))
|
|
#define fxp_reply_name_count(reply, count) \
|
|
((reply)->vt->reply_name_count(reply, count))
|
|
#define fxp_reply_full_name(reply, name, longname, attrs) \
|
|
((reply)->vt->reply_full_name(reply, name, longname, attrs))
|
|
#define fxp_reply_handle(reply, handle) \
|
|
((reply)->vt->reply_handle(reply, handle))
|
|
#define fxp_reply_data(reply, data) \
|
|
((reply)->vt->reply_data(reply, data))
|
|
#define fxp_reply_attrs(reply, attrs) \
|
|
((reply)->vt->reply_attrs(reply, attrs))
|
|
|
|
/*
|
|
* The usual implementation of an SftpReplyBuilder, containing a
|
|
* 'struct sftp_packet' which is assumed to be already initialised
|
|
* before one of the above request methods is called.
|
|
*/
|
|
extern const struct SftpReplyBuilderVtable DefaultSftpReplyBuilder_vt;
|
|
typedef struct DefaultSftpReplyBuilder DefaultSftpReplyBuilder;
|
|
struct DefaultSftpReplyBuilder {
|
|
SftpReplyBuilder rb;
|
|
struct sftp_packet *pkt;
|
|
};
|
|
|
|
/*
|
|
* The top-level function that handles an SFTP request, given an
|
|
* implementation of the above SftpServer abstraction to do the actual
|
|
* filesystem work. It handles all the marshalling and unmarshalling
|
|
* of packets, and the copying of request ids into the responses.
|
|
*/
|
|
struct sftp_packet *sftp_handle_request(
|
|
SftpServer *srv, struct sftp_packet *request);
|
|
|
|
/* ----------------------------------------------------------------------
|
|
* Not exactly SFTP-related, but here's a system that implements an
|
|
* old-fashioned SCP server module, given an SftpServer vtable to use
|
|
* as its underlying filesystem access.
|
|
*/
|
|
|
|
typedef struct ScpServer ScpServer;
|
|
typedef struct ScpServerVtable ScpServerVtable;
|
|
struct ScpServer {
|
|
const struct ScpServerVtable *vt;
|
|
};
|
|
struct ScpServerVtable {
|
|
void (*free)(ScpServer *s);
|
|
|
|
int (*send)(ScpServer *s, const void *data, size_t length);
|
|
void (*throttle)(ScpServer *s, bool throttled);
|
|
void (*eof)(ScpServer *s);
|
|
};
|
|
|
|
#define scp_free(s) ((s)->vt->free(s))
|
|
#define scp_send(s, data, len) ((s)->vt->send(s, data, len))
|
|
#define scp_throttle(s, th) ((s)->vt->throttle(s, th))
|
|
#define scp_eof(s) ((s)->vt->eof(s))
|
|
|
|
/*
|
|
* Create an ScpServer by calling this function, giving it the command
|
|
* you received from the SSH client to execute. If that command is
|
|
* recognised as an scp command, it will construct an ScpServer object
|
|
* and return it; otherwise, it will return NULL, and you should
|
|
* execute the command in whatever way you normally would.
|
|
*
|
|
* The ScpServer will generate output for the client by writing it to
|
|
* the provided SshChannel using sshfwd_write; you pass it input using
|
|
* the send method in its own vtable.
|
|
*/
|
|
ScpServer *scp_recognise_exec(
|
|
SshChannel *sc, const SftpServerVtable *sftpserver_vt, ptrlen command);
|