123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280 |
- /*
- * Implement the centralised parts of the server side of SFTP.
- */
- #include <assert.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include "putty.h"
- #include "ssh.h"
- #include "sftp.h"
- struct sftp_packet *sftp_handle_request(
- SftpServer *srv, struct sftp_packet *req)
- {
- struct sftp_packet *reply;
- unsigned id;
- uint32_t flags;
- ptrlen path, dstpath, handle, data;
- uint64_t offset;
- unsigned length;
- struct fxp_attrs attrs;
- DefaultSftpReplyBuilder dsrb;
- SftpReplyBuilder *rb;
- if (req->type == SSH_FXP_INIT) {
- /*
- * Special case which doesn't have a request id at the start.
- */
- reply = sftp_pkt_init(SSH_FXP_VERSION);
- /*
- * Since we support only the lowest protocol version, we don't
- * need to take the min of this and the client's version, or
- * even to bother reading the client version number out of the
- * input packet.
- */
- put_uint32(reply, SFTP_PROTO_VERSION);
- return reply;
- }
- /*
- * Centralise the request id handling. We'll overwrite the type
- * code of the output packet later.
- */
- id = get_uint32(req);
- reply = sftp_pkt_init(0);
- put_uint32(reply, id);
- dsrb.rb.vt = &DefaultSftpReplyBuilder_vt;
- dsrb.pkt = reply;
- rb = &dsrb.rb;
- switch (req->type) {
- case SSH_FXP_REALPATH:
- path = get_string(req);
- if (get_err(req))
- goto decode_error;
- sftpsrv_realpath(srv, rb, path);
- break;
- case SSH_FXP_OPEN:
- path = get_string(req);
- flags = get_uint32(req);
- get_fxp_attrs(req, &attrs);
- if (get_err(req))
- goto decode_error;
- if ((flags & (SSH_FXF_READ|SSH_FXF_WRITE)) == 0) {
- fxp_reply_error(rb, SSH_FX_BAD_MESSAGE,
- "open without READ or WRITE flag");
- } else if ((flags & (SSH_FXF_CREAT|SSH_FXF_TRUNC)) == SSH_FXF_TRUNC) {
- fxp_reply_error(rb, SSH_FX_BAD_MESSAGE,
- "open with TRUNC but not CREAT");
- } else if ((flags & (SSH_FXF_CREAT|SSH_FXF_EXCL)) == SSH_FXF_EXCL) {
- fxp_reply_error(rb, SSH_FX_BAD_MESSAGE,
- "open with EXCL but not CREAT");
- } else {
- sftpsrv_open(srv, rb, path, flags, attrs);
- }
- break;
- case SSH_FXP_OPENDIR:
- path = get_string(req);
- if (get_err(req))
- goto decode_error;
- sftpsrv_opendir(srv, rb, path);
- break;
- case SSH_FXP_CLOSE:
- handle = get_string(req);
- if (get_err(req))
- goto decode_error;
- sftpsrv_close(srv, rb, handle);
- break;
- case SSH_FXP_MKDIR:
- path = get_string(req);
- get_fxp_attrs(req, &attrs);
- if (get_err(req))
- goto decode_error;
- sftpsrv_mkdir(srv, rb, path, attrs);
- break;
- case SSH_FXP_RMDIR:
- path = get_string(req);
- if (get_err(req))
- goto decode_error;
- sftpsrv_rmdir(srv, rb, path);
- break;
- case SSH_FXP_REMOVE:
- path = get_string(req);
- if (get_err(req))
- goto decode_error;
- sftpsrv_remove(srv, rb, path);
- break;
- case SSH_FXP_RENAME:
- path = get_string(req);
- dstpath = get_string(req);
- if (get_err(req))
- goto decode_error;
- sftpsrv_rename(srv, rb, path, dstpath);
- break;
- case SSH_FXP_STAT:
- path = get_string(req);
- if (get_err(req))
- goto decode_error;
- sftpsrv_stat(srv, rb, path, true);
- break;
- case SSH_FXP_LSTAT:
- path = get_string(req);
- if (get_err(req))
- goto decode_error;
- sftpsrv_stat(srv, rb, path, false);
- break;
- case SSH_FXP_FSTAT:
- handle = get_string(req);
- if (get_err(req))
- goto decode_error;
- sftpsrv_fstat(srv, rb, handle);
- break;
- case SSH_FXP_SETSTAT:
- path = get_string(req);
- get_fxp_attrs(req, &attrs);
- if (get_err(req))
- goto decode_error;
- sftpsrv_setstat(srv, rb, path, attrs);
- break;
- case SSH_FXP_FSETSTAT:
- handle = get_string(req);
- get_fxp_attrs(req, &attrs);
- if (get_err(req))
- goto decode_error;
- sftpsrv_fsetstat(srv, rb, handle, attrs);
- break;
- case SSH_FXP_READ:
- handle = get_string(req);
- offset = get_uint64(req);
- length = get_uint32(req);
- if (get_err(req))
- goto decode_error;
- sftpsrv_read(srv, rb, handle, offset, length);
- break;
- case SSH_FXP_READDIR:
- handle = get_string(req);
- if (get_err(req))
- goto decode_error;
- sftpsrv_readdir(srv, rb, handle, INT_MAX, false);
- break;
- case SSH_FXP_WRITE:
- handle = get_string(req);
- offset = get_uint64(req);
- data = get_string(req);
- if (get_err(req))
- goto decode_error;
- sftpsrv_write(srv, rb, handle, offset, data);
- break;
- default:
- if (get_err(req))
- goto decode_error;
- fxp_reply_error(rb, SSH_FX_OP_UNSUPPORTED,
- "Unrecognised request type");
- break;
- decode_error:
- fxp_reply_error(rb, SSH_FX_BAD_MESSAGE, "Unable to decode request");
- }
- return reply;
- }
- static void default_reply_ok(SftpReplyBuilder *reply)
- {
- DefaultSftpReplyBuilder *d =
- container_of(reply, DefaultSftpReplyBuilder, rb);
- d->pkt->type = SSH_FXP_STATUS;
- put_uint32(d->pkt, SSH_FX_OK);
- put_stringz(d->pkt, "");
- }
- static void default_reply_error(
- SftpReplyBuilder *reply, unsigned code, const char *msg)
- {
- DefaultSftpReplyBuilder *d =
- container_of(reply, DefaultSftpReplyBuilder, rb);
- d->pkt->type = SSH_FXP_STATUS;
- put_uint32(d->pkt, code);
- put_stringz(d->pkt, msg);
- }
- static void default_reply_name_count(SftpReplyBuilder *reply, unsigned count)
- {
- DefaultSftpReplyBuilder *d =
- container_of(reply, DefaultSftpReplyBuilder, rb);
- d->pkt->type = SSH_FXP_NAME;
- put_uint32(d->pkt, count);
- }
- static void default_reply_full_name(SftpReplyBuilder *reply, ptrlen name,
- ptrlen longname, struct fxp_attrs attrs)
- {
- DefaultSftpReplyBuilder *d =
- container_of(reply, DefaultSftpReplyBuilder, rb);
- d->pkt->type = SSH_FXP_NAME;
- put_stringpl(d->pkt, name);
- put_stringpl(d->pkt, longname);
- put_fxp_attrs(d->pkt, attrs);
- }
- static void default_reply_simple_name(SftpReplyBuilder *reply, ptrlen name)
- {
- fxp_reply_name_count(reply, 1);
- fxp_reply_full_name(reply, name, PTRLEN_LITERAL(""), no_attrs);
- }
- static void default_reply_handle(SftpReplyBuilder *reply, ptrlen handle)
- {
- DefaultSftpReplyBuilder *d =
- container_of(reply, DefaultSftpReplyBuilder, rb);
- d->pkt->type = SSH_FXP_HANDLE;
- put_stringpl(d->pkt, handle);
- }
- static void default_reply_data(SftpReplyBuilder *reply, ptrlen data)
- {
- DefaultSftpReplyBuilder *d =
- container_of(reply, DefaultSftpReplyBuilder, rb);
- d->pkt->type = SSH_FXP_DATA;
- put_stringpl(d->pkt, data);
- }
- static void default_reply_attrs(
- SftpReplyBuilder *reply, struct fxp_attrs attrs)
- {
- DefaultSftpReplyBuilder *d =
- container_of(reply, DefaultSftpReplyBuilder, rb);
- d->pkt->type = SSH_FXP_ATTRS;
- put_fxp_attrs(d->pkt, attrs);
- }
- const SftpReplyBuilderVtable DefaultSftpReplyBuilder_vt = {
- .reply_ok = default_reply_ok,
- .reply_error = default_reply_error,
- .reply_simple_name = default_reply_simple_name,
- .reply_name_count = default_reply_name_count,
- .reply_full_name = default_reply_full_name,
- .reply_handle = default_reply_handle,
- .reply_data = default_reply_data,
- .reply_attrs = default_reply_attrs,
- };
|