SSHSession.cc 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. /* <!-- copyright */
  2. /*
  3. * aria2 - The high speed download utility
  4. *
  5. * Copyright (C) 2015 Tatsuhiro Tsujikawa
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20. *
  21. * In addition, as a special exception, the copyright holders give
  22. * permission to link the code of portions of this program with the
  23. * OpenSSL library under certain conditions as described in each
  24. * individual source file, and distribute linked combinations
  25. * including the two.
  26. * You must obey the GNU General Public License in all respects
  27. * for all of the code used other than OpenSSL. If you modify
  28. * file(s) with this exception, you may extend this exception to your
  29. * version of the file(s), but you are not obligated to do so. If you
  30. * do not wish to do so, delete this exception statement from your
  31. * version. If you delete this exception statement from all source
  32. * files in the program, then also delete it here.
  33. */
  34. /* copyright --> */
  35. #include "SSHSession.h"
  36. #include <cassert>
  37. #include "MessageDigest.h"
  38. namespace aria2 {
  39. SSHSession::SSHSession()
  40. : ssh2_(nullptr), sftp_(nullptr), sftph_(nullptr), fd_(-1)
  41. {
  42. }
  43. SSHSession::~SSHSession() { closeConnection(); }
  44. int SSHSession::closeConnection()
  45. {
  46. if (sftph_) {
  47. // TODO this could return LIBSSH2_ERROR_EAGAIN
  48. libssh2_sftp_close(sftph_);
  49. sftph_ = nullptr;
  50. }
  51. if (sftp_) {
  52. // TODO this could return LIBSSH2_ERROR_EAGAIN
  53. libssh2_sftp_shutdown(sftp_);
  54. sftp_ = nullptr;
  55. }
  56. if (ssh2_) {
  57. // TODO this could return LIBSSH2_ERROR_EAGAIN
  58. libssh2_session_disconnect(ssh2_, "bye");
  59. libssh2_session_free(ssh2_);
  60. ssh2_ = nullptr;
  61. }
  62. return SSH_ERR_OK;
  63. }
  64. int SSHSession::gracefulShutdown()
  65. {
  66. if (sftph_) {
  67. auto rv = libssh2_sftp_close(sftph_);
  68. if (rv == LIBSSH2_ERROR_EAGAIN) {
  69. return SSH_ERR_WOULDBLOCK;
  70. }
  71. if (rv != 0) {
  72. return SSH_ERR_ERROR;
  73. }
  74. sftph_ = nullptr;
  75. }
  76. if (sftp_) {
  77. auto rv = libssh2_sftp_shutdown(sftp_);
  78. if (rv == LIBSSH2_ERROR_EAGAIN) {
  79. return SSH_ERR_WOULDBLOCK;
  80. }
  81. if (rv != 0) {
  82. return SSH_ERR_ERROR;
  83. }
  84. sftp_ = nullptr;
  85. }
  86. if (ssh2_) {
  87. auto rv = libssh2_session_disconnect(ssh2_, "bye");
  88. if (rv == LIBSSH2_ERROR_EAGAIN) {
  89. return SSH_ERR_WOULDBLOCK;
  90. }
  91. if (rv != 0) {
  92. return SSH_ERR_ERROR;
  93. }
  94. libssh2_session_free(ssh2_);
  95. ssh2_ = nullptr;
  96. }
  97. return SSH_ERR_OK;
  98. }
  99. int SSHSession::sftpClose()
  100. {
  101. if (!sftph_) {
  102. return SSH_ERR_OK;
  103. }
  104. auto rv = libssh2_sftp_close(sftph_);
  105. if (rv == LIBSSH2_ERROR_EAGAIN) {
  106. return SSH_ERR_WOULDBLOCK;
  107. }
  108. if (rv != 0) {
  109. return SSH_ERR_ERROR;
  110. }
  111. sftph_ = nullptr;
  112. return SSH_ERR_OK;
  113. }
  114. int SSHSession::init(sock_t sockfd)
  115. {
  116. ssh2_ = libssh2_session_init();
  117. if (!ssh2_) {
  118. return SSH_ERR_ERROR;
  119. }
  120. libssh2_session_set_blocking(ssh2_, 0);
  121. fd_ = sockfd;
  122. return SSH_ERR_OK;
  123. }
  124. int SSHSession::checkDirection()
  125. {
  126. auto dir = libssh2_session_block_directions(ssh2_);
  127. if (dir & LIBSSH2_SESSION_BLOCK_OUTBOUND) {
  128. return SSH_WANT_WRITE;
  129. }
  130. return SSH_WANT_READ;
  131. }
  132. ssize_t SSHSession::writeData(const void* data, size_t len)
  133. {
  134. // net implemented yet
  135. assert(0);
  136. }
  137. ssize_t SSHSession::readData(void* data, size_t len)
  138. {
  139. auto nread = libssh2_sftp_read(sftph_, static_cast<char*>(data), len);
  140. if (nread == LIBSSH2_ERROR_EAGAIN) {
  141. return SSH_ERR_WOULDBLOCK;
  142. }
  143. if (nread < 0) {
  144. return SSH_ERR_ERROR;
  145. }
  146. return nread;
  147. }
  148. int SSHSession::handshake()
  149. {
  150. auto rv = libssh2_session_handshake(ssh2_, fd_);
  151. if (rv == LIBSSH2_ERROR_EAGAIN) {
  152. return SSH_ERR_WOULDBLOCK;
  153. }
  154. if (rv != 0) {
  155. return SSH_ERR_ERROR;
  156. }
  157. return SSH_ERR_OK;
  158. }
  159. std::string SSHSession::hostkeyMessageDigest(const std::string& hashType)
  160. {
  161. int h;
  162. if (hashType == "sha-1") {
  163. h = LIBSSH2_HOSTKEY_HASH_SHA1;
  164. }
  165. else if (hashType == "md5") {
  166. h = LIBSSH2_HOSTKEY_HASH_MD5;
  167. }
  168. else {
  169. return "";
  170. }
  171. auto fingerprint = libssh2_hostkey_hash(ssh2_, h);
  172. if (!fingerprint) {
  173. return "";
  174. }
  175. return std::string(fingerprint, MessageDigest::getDigestLength(hashType));
  176. }
  177. int SSHSession::authPassword(const std::string& user,
  178. const std::string& password)
  179. {
  180. auto rv = libssh2_userauth_password(ssh2_, user.c_str(), password.c_str());
  181. if (rv == LIBSSH2_ERROR_EAGAIN) {
  182. return SSH_ERR_WOULDBLOCK;
  183. }
  184. if (rv != 0) {
  185. return SSH_ERR_ERROR;
  186. }
  187. return SSH_ERR_OK;
  188. }
  189. int SSHSession::sftpOpen(const std::string& path)
  190. {
  191. if (!sftp_) {
  192. sftp_ = libssh2_sftp_init(ssh2_);
  193. if (!sftp_) {
  194. if (libssh2_session_last_errno(ssh2_) == LIBSSH2_ERROR_EAGAIN) {
  195. return SSH_ERR_WOULDBLOCK;
  196. }
  197. return SSH_ERR_ERROR;
  198. }
  199. }
  200. if (!sftph_) {
  201. sftph_ = libssh2_sftp_open(sftp_, path.c_str(), LIBSSH2_FXF_READ, 0);
  202. if (!sftph_) {
  203. if (libssh2_session_last_errno(ssh2_) == LIBSSH2_ERROR_EAGAIN) {
  204. return SSH_ERR_WOULDBLOCK;
  205. }
  206. return SSH_ERR_ERROR;
  207. }
  208. }
  209. return SSH_ERR_OK;
  210. }
  211. int SSHSession::sftpStat(int64_t& totalLength, time_t& mtime)
  212. {
  213. LIBSSH2_SFTP_ATTRIBUTES attrs;
  214. auto rv = libssh2_sftp_fstat_ex(sftph_, &attrs, 0);
  215. if (rv == LIBSSH2_ERROR_EAGAIN) {
  216. return SSH_ERR_WOULDBLOCK;
  217. }
  218. if (rv != 0) {
  219. return SSH_ERR_ERROR;
  220. }
  221. totalLength = attrs.filesize;
  222. mtime = attrs.mtime;
  223. return SSH_ERR_OK;
  224. }
  225. void SSHSession::sftpSeek(int64_t pos) { libssh2_sftp_seek64(sftph_, pos); }
  226. std::string SSHSession::getLastErrorString()
  227. {
  228. if (!ssh2_) {
  229. return "SSH session has not been initialized yet";
  230. }
  231. char* errmsg;
  232. libssh2_session_last_error(ssh2_, &errmsg, nullptr, 0);
  233. return errmsg;
  234. }
  235. } // namespace aria2