diff --git a/src/sftp/objects.mk b/src/sftp/objects.mk index 27981a4603b36acaf411577bbbccc79ec4849f2f..2123ef195a44a1cc76058e8eb0a658c37fab4bad 100644 --- a/src/sftp/objects.mk +++ b/src/sftp/objects.mk @@ -2,4 +2,5 @@ MT_OBJS = \ $(MTOBJODIR)$(DIRSEP)sftp_pkt$(OFILE) \ $(MTOBJODIR)$(DIRSEP)sftp_str$(OFILE) \ $(MTOBJODIR)$(DIRSEP)sftp_client$(OFILE) \ + $(MTOBJODIR)$(DIRSEP)sftp_attr$(OFILE) \ diff --git a/src/sftp/sftp.h b/src/sftp/sftp.h index 64acc26251c7a7a16176602ed62ee808e281e916..2d12851cded3225da2b6c88443cc807c583582d1 100644 --- a/src/sftp/sftp.h +++ b/src/sftp/sftp.h @@ -8,34 +8,33 @@ // draft-ietf-secsh-filexfer-02 -#define SSH_FXP_INIT UINT8_C(1) -#define SSH_FXP_VERSION UINT8_C(2) -#define SSH_FXP_OPEN UINT8_C(3) -#define SSH_FXP_CLOSE UINT8_C(4) -#define SSH_FXP_READ UINT8_C(5) -#define SSH_FXP_WRITE UINT8_C(6) -#define SSH_FXP_LSTAT UINT8_C(7) -#define SSH_FXP_FSTAT UINT8_C(8) -#define SSH_FXP_SETSTAT UINT8_C(9) -#define SSH_FXP_FSETSTAT UINT8_C(10) -#define SSH_FXP_OPENDIR UINT8_C(11) -#define SSH_FXP_READDIR UINT8_C(12) -#define SSH_FXP_REMOVE UINT8_C(13) -#define SSH_FXP_MKDIR UINT8_C(14) -#define SSH_FXP_RMDIR UINT8_C(15) -#define SSH_FXP_REALPATH UINT8_C(16) -#define SSH_FXP_STAT UINT8_C(17) -#define SSH_FXP_RENAME UINT8_C(18) -#define SSH_FXP_READLINK UINT8_C(19) -#define SSH_FXP_SYMLINK UINT8_C(20) -#define SSH_FXP_STATUS UINT8_C(101) -#define SSH_FXP_HANDLE UINT8_C(102) -#define SSH_FXP_DATA UINT8_C(103) -#define SSH_FXP_NAME UINT8_C(104) -#define SSH_FXP_ATTRS UINT8_C(105) -#define SSH_FXP_EXTENDED UINT8_C(200) -#define SSH_FXP_EXTENDED_REPLY UINT8_C(201) - +#define SSH_FXP_INIT UINT8_C(1) +#define SSH_FXP_VERSION UINT8_C(2) +#define SSH_FXP_OPEN UINT8_C(3) +#define SSH_FXP_CLOSE UINT8_C(4) +#define SSH_FXP_READ UINT8_C(5) +#define SSH_FXP_WRITE UINT8_C(6) +#define SSH_FXP_LSTAT UINT8_C(7) +#define SSH_FXP_FSTAT UINT8_C(8) +#define SSH_FXP_SETSTAT UINT8_C(9) +#define SSH_FXP_FSETSTAT UINT8_C(10) +#define SSH_FXP_OPENDIR UINT8_C(11) +#define SSH_FXP_READDIR UINT8_C(12) +#define SSH_FXP_REMOVE UINT8_C(13) +#define SSH_FXP_MKDIR UINT8_C(14) +#define SSH_FXP_RMDIR UINT8_C(15) +#define SSH_FXP_REALPATH UINT8_C(16) +#define SSH_FXP_STAT UINT8_C(17) +#define SSH_FXP_RENAME UINT8_C(18) +#define SSH_FXP_READLINK UINT8_C(19) +#define SSH_FXP_SYMLINK UINT8_C(20) +#define SSH_FXP_STATUS UINT8_C(101) +#define SSH_FXP_HANDLE UINT8_C(102) +#define SSH_FXP_DATA UINT8_C(103) +#define SSH_FXP_NAME UINT8_C(104) +#define SSH_FXP_ATTRS UINT8_C(105) +#define SSH_FXP_EXTENDED UINT8_C(200) +#define SSH_FXP_EXTENDED_REPLY UINT8_C(201) #define SSH_FX_OK UINT32_C(0) #define SSH_FX_EOF UINT32_C(1) @@ -47,6 +46,19 @@ #define SSH_FX_CONNECTION_LOST UINT32_C(7) #define SSH_FX_OP_UNSUPPORTED UINT32_C(8) +#define SSH_FXF_READ UINT32_C(0x00000001) +#define SSH_FXF_WRITE UINT32_C(0x00000002) +#define SSH_FXF_APPEND UINT32_C(0x00000004) +#define SSH_FXF_CREAT UINT32_C(0x00000008) +#define SSH_FXF_TRUNC UINT32_C(0x00000010) +#define SSH_FXF_EXCL UINT32_C(0x00000020) + +#define SSH_FILEXFER_ATTR_SIZE UINT32_C(0x00000001) +#define SSH_FILEXFER_ATTR_UIDGID UINT32_C(0x00000002) +#define SSH_FILEXFER_ATTR_PERMISSIONS UINT32_C(0x00000004) +#define SSH_FILEXFER_ATTR_ACMODTIME UINT32_C(0x00000008) +#define SSH_FILEXFER_ATTR_EXTENDED UINT32_C(0x80000000) + #define SFTP_MIN_PACKET_ALLOC 4096 #define SFTP_VERSION 3 @@ -76,16 +88,8 @@ struct sftp_extended_file_attribute { struct sftp_string *data; }; -struct sftp_file_attributes { - uint32_t flags; - uint64_t size; - uint32_t uid; - uint32_t gid; - uint32_t perm; - uint32_t atime; - uint32_t mtime; - struct sftp_extended_file_attribute ext[]; -}; +struct sftp_file_attributes; +typedef struct sftp_file_attributes *sftp_file_attr_t; typedef struct sftp_client_state { bool (*send_cb)(uint8_t *buf, size_t len, void *cb_data); @@ -102,6 +106,14 @@ typedef struct sftp_client_state { uint32_t err_code; } *sftpc_state_t; +enum sftp_handle_type { + SFTP_HANDLE_TYPE_DIR, + SFTP_HANDLE_TYPE_FILE, +}; + +typedef sftp_str_t sftp_filehandle_t; +typedef sftp_str_t sftp_dirhandle_t; + /* sftp_pkt.c */ const char * const sftp_get_type_name(uint8_t type); bool sftp_have_pkt_sz(sftp_rx_pkt_t pkt); @@ -135,5 +147,28 @@ sftpc_state_t sftpc_begin(bool (*send_cb)(uint8_t *buf, size_t len, void *cb_dat bool sftpc_init(sftpc_state_t state); bool sftpc_recv(sftpc_state_t state, uint8_t *buf, uint32_t sz); bool sftpc_realpath(sftpc_state_t state, char *path, sftp_str_t *ret); +bool sftpc_open(sftpc_state_t state, char *path, uint32_t flags, sftp_file_attr_t attr, sftp_dirhandle_t *handle); +bool sftpc_close(sftpc_state_t state, sftp_filehandle_t *handle); +bool sftpc_read(sftpc_state_t state, sftp_filehandle_t handle, uint64_t offset, uint32_t len, sftp_str_t *ret); +bool sftpc_write(sftpc_state_t state, sftp_filehandle_t handle, uint64_t offset, sftp_str_t data); + +/* sftp_attr.c */ +sftp_file_attr_t sftp_fattr_alloc(void); +void sftp_fattr_free(sftp_file_attr_t fattr); +void sftp_fattr_set_size(sftp_file_attr_t fattr, uint64_t sz); +bool sftp_fattr_get_size(sftp_file_attr_t fattr, uint64_t *sz); +void sftp_fattr_set_uid_gid(sftp_file_attr_t fattr, uint32_t uid, uint32_t gid); +bool sftp_fattr_get_uid(sftp_file_attr_t fattr, uint32_t *uid); +bool sftp_fattr_get_gid(sftp_file_attr_t fattr, uint32_t *gid); +void sftp_fattr_set_permissions(sftp_file_attr_t fattr, uint64_t perm); +bool sftp_fattr_get_permissions(sftp_file_attr_t fattr, uint64_t *perm); +void sftp_fattr_set_times(sftp_file_attr_t fattr, uint32_t atime, uint32_t mtime); +bool sftp_fattr_get_atime(sftp_file_attr_t fattr, uint32_t *atime); +bool sftp_fattr_get_mtime(sftp_file_attr_t fattr, uint32_t *mtime); +bool sftp_fattr_add_ext(sftp_file_attr_t *fattr, sftp_str_t type, sftp_str_t data); +sftp_str_t sftp_fattr_get_ext_type(sftp_file_attr_t fattr, uint32_t index); +sftp_str_t sftp_fattr_get_ext_data(sftp_file_attr_t fattr, uint32_t index); +uint32_t sftp_fattr_get_ext_count(sftp_file_attr_t fattr); +bool sftp_appendfattr(sftp_tx_pkt_t *pktp, sftp_file_attr_t fattr); #endif diff --git a/src/sftp/sftp.vcxproj b/src/sftp/sftp.vcxproj index 432358d1fcfd255b7584e7b7d8862654e3a47fbb..52aad85399f967036611b9697ac940360c3f5fe1 100644 --- a/src/sftp/sftp.vcxproj +++ b/src/sftp/sftp.vcxproj @@ -112,10 +112,11 @@ </ItemDefinitionGroup> <ItemGroup> <ClCompile Include="sftp_client.c" /> + <ClCompile Include="sftp_attr.c" /> <ClCompile Include="sftp_pkt.c" /> <ClCompile Include="sftp_str.c" /> </ItemGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <ImportGroup Label="ExtensionTargets"> </ImportGroup> -</Project> \ No newline at end of file +</Project> diff --git a/src/sftp/sftp_client.c b/src/sftp/sftp_client.c index 965954778eba0d8eb12cbd6fb5367da006c7330a..012db6e674351231b77cff51b5dd836a0f195f28 100644 --- a/src/sftp/sftp_client.c +++ b/src/sftp/sftp_client.c @@ -42,7 +42,13 @@ append64(sftpc_state_t state, uint64_t u) } static bool -appendstring(sftpc_state_t state, sftp_str_t *s) +appendfattr(sftpc_state_t state, sftp_file_attr_t fattr) +{ + return sftp_appendfattr(&state->txp, fattr); +} + +static bool +appendandfreestring(sftpc_state_t state, sftp_str_t *s) { bool ret = sftp_appendstring(&state->txp, *s); free_sftp_str(*s); @@ -50,6 +56,13 @@ appendstring(sftpc_state_t state, sftp_str_t *s) return ret; } +static bool +appendstring(sftpc_state_t state, sftp_str_t s) +{ + bool ret = sftp_appendstring(&state->txp, s); + return ret; +} + void sftpc_finish(sftpc_state_t state) { @@ -134,12 +147,27 @@ appendheader(sftpc_state_t state, uint8_t type) return true; } +static bool +appendfhandle(sftpc_state_t state, sftp_filehandle_t handle) +{ + return appendstring(state, (sftp_str_t)handle); +} + +static bool +appenddhandle(sftpc_state_t state, sftp_dirhandle_t handle) +{ + return appendstring(state, (sftp_str_t)handle); +} + static bool get_result(sftpc_state_t state) { uint8_t *txbuf; size_t txsz; + assert(state->thread == pthread_self()); + if (state->thread != pthread_self()) + return false; if (!sftp_prep_tx_packet(state->txp, &txbuf, &txsz)) return false; if (!state->send_cb(txbuf, txsz, state->cb_data)) @@ -213,7 +241,7 @@ sftpc_realpath(sftpc_state_t state, char *path, sftp_str_t *ret) if (!appendheader(state, SSH_FXP_REALPATH)) return false; sftp_str_t pstr = sftp_strdup(path); - if (!appendstring(state, &pstr)) + if (!appendandfreestring(state, &pstr)) return false; if (!get_result(state)) return false; @@ -229,3 +257,129 @@ sftpc_realpath(sftpc_state_t state, char *path, sftp_str_t *ret) handle_error(state); return false; } + +static bool +parse_handle(sftpc_state_t state, sftp_str_t *handle) +{ + assert(state); + if (state == NULL) + return false; + assert(state->rxp); + if (state->rxp == NULL) + return false; + assert(state->rxp->type == SSH_FXP_HANDLE); + if (state->rxp->type != SSH_FXP_HANDLE) + return false; + assert(handle); + if (handle == NULL) + return false; + *handle = getstring(state); + if (*handle == NULL) + return false; + return true; +} + +bool +sftpc_open(sftpc_state_t state, char *path, uint32_t flags, sftp_file_attr_t attr, sftp_dirhandle_t *handle) +{ + assert(handle); + if (handle == NULL) + return false; + assert(!*handle); + if (*handle != NULL) + return false; + if (!appendheader(state, SSH_FXP_OPEN)) + return false; + sftp_str_t pstr = sftp_strdup(path); + if (!appendandfreestring(state, &pstr)) + return false; + if (!append32(state, flags)) + return false; + sftp_file_attr_t a = attr; + if (a == NULL) { + a = sftp_fattr_alloc(); + if (a == NULL) + return false; + } + if (!appendfattr(state, a)) { + if (a != attr) + sftp_fattr_free(a); + return false; + } + if (a != attr) + sftp_fattr_free(a); + if (!get_result(state)) + return false; + if (state->rxp->type == SSH_FXP_HANDLE) { + if (!parse_handle(state, (sftp_str_t *)handle)) { + response_handled(state); + return false; + } + response_handled(state); + return true; + } + handle_error(state); + return false; +} + +bool +sftpc_close(sftpc_state_t state, sftp_filehandle_t *handle) +{ + if (!appendheader(state, SSH_FXP_CLOSE)) + return false; + if (!appendfhandle(state, *handle)) + return false; + if (!get_result(state)) + return false; + handle_error(state); + free_sftp_str(*handle); + *handle = NULL; + return state->err_code == SSH_FX_OK; +} + +bool +sftpc_read(sftpc_state_t state, sftp_filehandle_t handle, uint64_t offset, uint32_t len, sftp_str_t *ret) +{ + assert(ret); + if (ret == NULL) + return false; + assert(*ret == NULL); + if (*ret != NULL) + return false; + if (!appendheader(state, SSH_FXP_READ)) + return false; + if (!appendfhandle(state, handle)) + return false; + if (!append64(state, offset)) + return false; + if (!append32(state, len)) + return false; + if (!get_result(state)) + return false; + if (state->rxp->type == SSH_FXP_DATA) { + *ret = getstring(state); + return *ret != NULL; + } + handle_error(state); + return false; +} + +bool +sftpc_write(sftpc_state_t state, sftp_filehandle_t handle, uint64_t offset, sftp_str_t data) +{ + assert(data); + if (data == NULL) + return false; + if (!appendheader(state, SSH_FXP_WRITE)) + return false; + if (!appendfhandle(state, handle)) + return false; + if (!append64(state, offset)) + return false; + if (!appendstring(state, data)) + return false; + if (!get_result(state)) + return false; + handle_error(state); + return state->err_code == SSH_FX_OK; +} diff --git a/src/syncterm/ssh.c b/src/syncterm/ssh.c index 5957bbcf074acb58b3d410bbe3846a99e6c6821f..f4065954639e29489747d2c0b569045a6b1dd4b9 100644 --- a/src/syncterm/ssh.c +++ b/src/syncterm/ssh.c @@ -250,7 +250,7 @@ error_popup(struct bbslist *bbs, const char *blurb, int status) char str[1024]; sprintf(str, "Error %d %s", status, blurb); if (!bbs->hidepopups) - uifcmsg("Error %s", str); + uifcmsg(str, str); conn_api.terminate = 1; if (!bbs->hidepopups) uifc.pop(NULL); @@ -301,8 +301,7 @@ ssh_connect(struct bbslist *bbs) if(cryptStatusError(status)) { error_popup(bbs, "creating context", status); } - status = cl.KeysetClose(ssh_keyset); - if (cryptStatusError(status)) { + if (cryptStatusError(cl.KeysetClose(ssh_keyset))) { error_popup(bbs, "closing keyset", status); } } @@ -314,7 +313,7 @@ ssh_connect(struct bbslist *bbs) error_popup(bbs, "creating context", status); break; } - status = cl.SetAttributeString(ssh_context, CRYPT_CTXINFO_LABEL, KEY_LABEL, 10); + status = cl.SetAttributeString(ssh_context, CRYPT_CTXINFO_LABEL, KEY_LABEL, strlen(KEY_LABEL)); if (cryptStatusError(status)) { error_popup(bbs, "setting label", status); break; @@ -417,12 +416,15 @@ ssh_connect(struct bbslist *bbs) return -1; } - if (!bbs->hidepopups) - uifc.pop("Setting Private Key"); - status = cl.SetAttribute(ssh_session, CRYPT_SESSINFO_PRIVATEKEY, ssh_context); - if (cryptStatusError(status)) { - error_popup(bbs, "setting private key", status); - return -1; + if (ssh_context != -1) { + if (!bbs->hidepopups) + uifc.pop("Setting Private Key"); + status = cl.SetAttribute(ssh_session, CRYPT_SESSINFO_PRIVATEKEY, ssh_context); + cl.DestroyContext(ssh_context); + if (cryptStatusError(status)) { + error_popup(bbs, "setting private key", status); + return -1; + } } } @@ -625,8 +627,14 @@ ssh_connect(struct bbslist *bbs) if (sftp_state != NULL) { if (sftpc_init(sftp_state)) { sftp_str_t ret = NULL; - if (sftpc_realpath(sftp_state, ".", &ret)) { - fprintf(stderr, "Home dir: %.*s\n", ret->len, ret->c_str); + sftp_filehandle_t f = NULL; + + if (sftpc_open(sftp_state, ".ssh/authorized_keys", SSH_FXF_READ, NULL, &f)) { + if (sftpc_read(sftp_state, f, 0, 1024, &ret)) { + fprintf(stderr, "First lines... %s\n", ret->c_str); + free_sftp_str(ret); + } + sftpc_close(sftp_state, &f); } } }