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
37 #include <cassert>
38
39 #include "MessageDigest.h"
40
41 namespace aria2 {
42
SSHSession()43 SSHSession::SSHSession()
44 : ssh2_(nullptr), sftp_(nullptr), sftph_(nullptr), fd_(-1)
45 {
46 }
47
~SSHSession()48 SSHSession::~SSHSession() { closeConnection(); }
49
closeConnection()50 int SSHSession::closeConnection()
51 {
52 if (sftph_) {
53 // TODO this could return LIBSSH2_ERROR_EAGAIN
54 libssh2_sftp_close(sftph_);
55 sftph_ = nullptr;
56 }
57 if (sftp_) {
58 // TODO this could return LIBSSH2_ERROR_EAGAIN
59 libssh2_sftp_shutdown(sftp_);
60 sftp_ = nullptr;
61 }
62 if (ssh2_) {
63 // TODO this could return LIBSSH2_ERROR_EAGAIN
64 libssh2_session_disconnect(ssh2_, "bye");
65 libssh2_session_free(ssh2_);
66 ssh2_ = nullptr;
67 }
68 return SSH_ERR_OK;
69 }
70
gracefulShutdown()71 int SSHSession::gracefulShutdown()
72 {
73 if (sftph_) {
74 auto rv = libssh2_sftp_close(sftph_);
75 if (rv == LIBSSH2_ERROR_EAGAIN) {
76 return SSH_ERR_WOULDBLOCK;
77 }
78 if (rv != 0) {
79 return SSH_ERR_ERROR;
80 }
81 sftph_ = nullptr;
82 }
83 if (sftp_) {
84 auto rv = libssh2_sftp_shutdown(sftp_);
85 if (rv == LIBSSH2_ERROR_EAGAIN) {
86 return SSH_ERR_WOULDBLOCK;
87 }
88 if (rv != 0) {
89 return SSH_ERR_ERROR;
90 }
91 sftp_ = nullptr;
92 }
93 if (ssh2_) {
94 auto rv = libssh2_session_disconnect(ssh2_, "bye");
95 if (rv == LIBSSH2_ERROR_EAGAIN) {
96 return SSH_ERR_WOULDBLOCK;
97 }
98 if (rv != 0) {
99 return SSH_ERR_ERROR;
100 }
101 libssh2_session_free(ssh2_);
102 ssh2_ = nullptr;
103 }
104 return SSH_ERR_OK;
105 }
106
sftpClose()107 int SSHSession::sftpClose()
108 {
109 if (!sftph_) {
110 return SSH_ERR_OK;
111 }
112
113 auto rv = libssh2_sftp_close(sftph_);
114 if (rv == LIBSSH2_ERROR_EAGAIN) {
115 return SSH_ERR_WOULDBLOCK;
116 }
117 if (rv != 0) {
118 return SSH_ERR_ERROR;
119 }
120 sftph_ = nullptr;
121 return SSH_ERR_OK;
122 }
123
init(sock_t sockfd)124 int SSHSession::init(sock_t sockfd)
125 {
126 ssh2_ = libssh2_session_init();
127 if (!ssh2_) {
128 return SSH_ERR_ERROR;
129 }
130 libssh2_session_set_blocking(ssh2_, 0);
131 fd_ = sockfd;
132 return SSH_ERR_OK;
133 }
134
checkDirection()135 int SSHSession::checkDirection()
136 {
137 auto dir = libssh2_session_block_directions(ssh2_);
138 if (dir & LIBSSH2_SESSION_BLOCK_OUTBOUND) {
139 return SSH_WANT_WRITE;
140 }
141 return SSH_WANT_READ;
142 }
143
writeData(const void * data,size_t len)144 ssize_t SSHSession::writeData(const void* data, size_t len)
145 {
146 // net implemented yet
147 assert(0);
148 }
149
readData(void * data,size_t len)150 ssize_t SSHSession::readData(void* data, size_t len)
151 {
152 auto nread = libssh2_sftp_read(sftph_, static_cast<char*>(data), len);
153 if (nread == LIBSSH2_ERROR_EAGAIN) {
154 return SSH_ERR_WOULDBLOCK;
155 }
156 if (nread < 0) {
157 return SSH_ERR_ERROR;
158 }
159 return nread;
160 }
161
handshake()162 int SSHSession::handshake()
163 {
164 auto rv = libssh2_session_handshake(ssh2_, fd_);
165 if (rv == LIBSSH2_ERROR_EAGAIN) {
166 return SSH_ERR_WOULDBLOCK;
167 }
168 if (rv != 0) {
169 return SSH_ERR_ERROR;
170 }
171 return SSH_ERR_OK;
172 }
173
hostkeyMessageDigest(const std::string & hashType)174 std::string SSHSession::hostkeyMessageDigest(const std::string& hashType)
175 {
176 int h;
177 if (hashType == "sha-1") {
178 h = LIBSSH2_HOSTKEY_HASH_SHA1;
179 }
180 else if (hashType == "md5") {
181 h = LIBSSH2_HOSTKEY_HASH_MD5;
182 }
183 else {
184 return "";
185 }
186 auto fingerprint = libssh2_hostkey_hash(ssh2_, h);
187 if (!fingerprint) {
188 return "";
189 }
190 return std::string(fingerprint, MessageDigest::getDigestLength(hashType));
191 }
192
authPassword(const std::string & user,const std::string & password)193 int SSHSession::authPassword(const std::string& user,
194 const std::string& password)
195 {
196 auto rv = libssh2_userauth_password(ssh2_, user.c_str(), password.c_str());
197 if (rv == LIBSSH2_ERROR_EAGAIN) {
198 return SSH_ERR_WOULDBLOCK;
199 }
200 if (rv != 0) {
201 return SSH_ERR_ERROR;
202 }
203 return SSH_ERR_OK;
204 }
205
sftpOpen(const std::string & path)206 int SSHSession::sftpOpen(const std::string& path)
207 {
208 if (!sftp_) {
209 sftp_ = libssh2_sftp_init(ssh2_);
210 if (!sftp_) {
211 if (libssh2_session_last_errno(ssh2_) == LIBSSH2_ERROR_EAGAIN) {
212 return SSH_ERR_WOULDBLOCK;
213 }
214 return SSH_ERR_ERROR;
215 }
216 }
217 if (!sftph_) {
218 sftph_ = libssh2_sftp_open(sftp_, path.c_str(), LIBSSH2_FXF_READ, 0);
219 if (!sftph_) {
220 if (libssh2_session_last_errno(ssh2_) == LIBSSH2_ERROR_EAGAIN) {
221 return SSH_ERR_WOULDBLOCK;
222 }
223 return SSH_ERR_ERROR;
224 }
225 }
226 return SSH_ERR_OK;
227 }
228
sftpStat(int64_t & totalLength,time_t & mtime)229 int SSHSession::sftpStat(int64_t& totalLength, time_t& mtime)
230 {
231 LIBSSH2_SFTP_ATTRIBUTES attrs;
232 auto rv = libssh2_sftp_fstat_ex(sftph_, &attrs, 0);
233 if (rv == LIBSSH2_ERROR_EAGAIN) {
234 return SSH_ERR_WOULDBLOCK;
235 }
236 if (rv != 0) {
237 return SSH_ERR_ERROR;
238 }
239 totalLength = attrs.filesize;
240 mtime = attrs.mtime;
241 return SSH_ERR_OK;
242 }
243
sftpSeek(int64_t pos)244 void SSHSession::sftpSeek(int64_t pos) { libssh2_sftp_seek64(sftph_, pos); }
245
getLastErrorString()246 std::string SSHSession::getLastErrorString()
247 {
248 if (!ssh2_) {
249 return "SSH session has not been initialized yet";
250 }
251 char* errmsg;
252 libssh2_session_last_error(ssh2_, &errmsg, nullptr, 0);
253 return errmsg;
254 }
255
256 } // namespace aria2
257