3#include <QLoggingCategory>
5static Q_LOGGING_CATEGORY(log,
"SSH")
6static Q_LOGGING_CATEGORY(logSSH, "SSH.log")
9 bool bWakeUp, QObject *parent)
13 , m_pBackend(pBackend)
22CChannelSSH::~CChannelSSH()
24 qDebug(log) << Q_FUNC_INFO;
29 QString szDetail =
" - " + tr(
"libssh version:") +
" " + ssh_version(0) +
"\n";
30 szDetail +=
" - " + tr(
"libssh protocol version:") +
" " + QString::number(ssh_get_version(m_Session)) +
"\n";
31 szDetail +=
" - " + tr(
"OpenSSH server:") +
" " + QString::number(ssh_get_openssh_version(m_Session)) +
"\n";
35void CChannelSSH::cb_log(ssh_session session,
42 qWarning(logSSH) << message;
45 qInfo(logSSH) << message;
48 qDebug(logSSH) << message;
54int CChannelSSH::WakeUp()
56 if(!m_pEvent)
return 0;
57 return m_pEvent->WakeUp();
66 qCritical(log) <<
"The parameter is null";
68 Q_ASSERT(m_pParameter);
70 bool bRet = QIODevice::open(mode);
74 m_Session = ssh_new();
77 szErr = tr(
"SSH failed: ssh_new.");
78 qCritical(log) << szErr;
79 setErrorString(szErr);
84 struct ssh_callbacks_struct cb;
85 memset(&cb, 0,
sizeof(
struct ssh_callbacks_struct));
87 cb.log_function = cb_log;
88 ssh_callbacks_init(&cb);
89 ssh_set_callbacks(m_Session, &cb);
90 ssh_set_log_level(SSH_LOG_TRACE);
104 int verbosity = SSH_LOG_NOLOG;
105 ssh_options_set(m_Session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
107 auto &net = m_pParameter->m_Net;
108 if(net.GetHost().isEmpty()) {
109 szErr = tr(
"SSH failed: the server is empty");
110 qCritical(log) << szErr;
111 setErrorString(szErr);
114 nRet = ssh_options_set(m_Session, SSH_OPTIONS_HOST,
115 net.GetHost().toStdString().c_str());
117 szErr = tr(
"SSH failed: Set host fail. host:")
118 + net.GetHost() +
";"
119 + ssh_get_error(m_Session);
120 qCritical(log) << szErr;
121 setErrorString(szErr);
126 uint nPort = net.GetPort();
127 nRet = ssh_options_set(m_Session, SSH_OPTIONS_PORT, &nPort);
129 szErr = tr(
"SSH failed: Set port fail. port:")
130 + QString::number(net.GetPort()) +
";"
131 + ssh_get_error(m_Session);
132 qCritical(log) << szErr;
133 setErrorString(szErr);
137 if(!m_pParameter->GetPcapFile().isEmpty())
139 m_pcapFile = ssh_pcap_file_new();
141 if (ssh_pcap_file_open(
142 m_pcapFile, m_pParameter->GetPcapFile().toStdString().c_str())
144 qCritical(log) <<
"SSH failed: Error opening pcap file: "
145 << m_pParameter->GetPcapFile();
146 ssh_pcap_file_free(m_pcapFile);
147 m_pcapFile =
nullptr;
150 ssh_set_pcap_file(m_Session, m_pcapFile);
152 szErr = tr(
"SSH failed: ssh_pcap_file_new: ")
153 + ssh_get_error(m_Session);
154 qCritical(log) << szErr;
158 nRet = ssh_connect(m_Session);
160 szErr = tr(
"SSH failed: ssh connect ")
162 +
":" + QString::number(net.GetPort())
164 + ssh_get_error(m_Session);
166 qCritical(log) << szErr;
167 setErrorString(szErr);
171 nRet = verifyKnownhost(m_Session);
176 auto &user = m_pParameter->m_Net.
m_User;
177 if(((user.GetUsedType() == CParameterUser::TYPE::UserPassword)
178 && (user.GetPassword().isEmpty() || user.GetUser().isEmpty()))
179 || ((user.GetUsedType() == CParameterUser::TYPE::PublicKey)
180 && user.GetPassphrase().isEmpty())
183 if(QDialog::Accepted != nRet)
185 setErrorString(tr(
"User cancel"));
190 int nMeth = SSH_AUTH_METHOD_PUBLICKEY;
191 switch(user.GetUsedType()) {
192 case CParameterUser::TYPE::UserPassword:
193 nMeth = SSH_AUTH_METHOD_PASSWORD;
195 case CParameterUser::TYPE::PublicKey:
196 nMeth = SSH_AUTH_METHOD_PUBLICKEY;
203 user.GetPassphrase(),
209 nRet = OnOpen(m_Session);
217 ssh_disconnect(m_Session);
223void CChannelSSH::close()
225 qDebug(log) << Q_FUNC_INFO;
227 if(!isOpen())
return;
232 if(ssh_is_connected(m_Session))
233 ssh_disconnect(m_Session);
240 ssh_pcap_file_close(m_pcapFile);
241 ssh_pcap_file_free(m_pcapFile);
242 m_pcapFile =
nullptr;
248int CChannelSSH::verifyKnownhost(ssh_session session)
252 ssh_key srv_pubkey = NULL;
254 auto &net = m_pParameter->m_Net;
256 nRet = ssh_get_server_publickey(session, &srv_pubkey);
258 szErr = tr(
"SSH failed: Get server public key.") +
" " + net.GetHost() +
"; [";
259 szErr += ssh_get_error(session);
261 qCritical(log) << szErr;
262 setErrorString(szErr);
265 unsigned char *hash = NULL;
267 nRet = ssh_get_publickey_hash(srv_pubkey,
268 SSH_PUBLICKEY_HASH_SHA1,
271 ssh_key_free(srv_pubkey);
273 szErr = tr(
"SSH failed: Get public key hash value fail.");
274 qCritical(log) << szErr;
275 setErrorString(szErr);
278 QByteArray baHash((
const char*)hash, nLen);
279 QString szHash = baHash.toHex(
':').toStdString().c_str();
280 ssh_clean_pubkey_hash(&hash);
282 QMessageBox::StandardButton btRet = QMessageBox::Yes;
283 bool checkBox =
false;
284 enum ssh_known_hosts_e state = ssh_session_is_known_server(session);
286 case SSH_KNOWN_HOSTS_OK:
289 case SSH_KNOWN_HOSTS_CHANGED:
291 szErr = net.GetHost() +
" " + tr(
"the host key for server changed. it is now:") +
"\n";
292 szErr += szHash +
"\n";
293 szErr += tr(
"For security reasons, connection will be stopped.") +
"\n";
294 szErr += tr(
"Please look at the OpenSSL documentation on "
295 "how to add a private CA to the store.");
296 qCritical(log) << szErr;
297 setErrorString(szErr);
299 case SSH_KNOWN_HOSTS_OTHER:
301 szErr = net.GetHost() +
" " + tr(
"the host key for this server was not found but an other type of key exists.") +
"\n";
302 szErr += tr(
"An attacker might change the default server key to "
303 "confuse your client into thinking the key does not exist") +
"\n";
304 szErr += tr(
"For security reasons, connection will be stopped.") +
"\n";
305 szErr += tr(
"Please look at the OpenSSL documentation on "
306 "how to add a private CA to the store.");
307 qCritical(log) << szErr;
308 setErrorString(szErr);
310 case SSH_KNOWN_HOSTS_NOT_FOUND:
312 szErr = net.GetHost() +
" " + tr(
"is not find in known host file.") +
"\n";
313 szErr += tr(
"If you accept the host key here, the file will be "
314 "automatically created.") +
"\n";
315 szErr += tr(
"Host key hash:") +
"\n" + szHash;
316 qDebug(log) << szErr;
317 if(!m_pBackend)
break;
322 QMessageBox::No | QMessageBox::Ignore,
324 if(QMessageBox::Yes == btRet) {
325 nRet = ssh_session_update_known_hosts(session);
328 qCritical(log) <<
"ssh_session_update_known_hosts fail."
329 << ssh_get_error(session);
331 }
if(QMessageBox::Ignore == btRet)
334 setErrorString(tr(
"Reject the host key"));
336 case SSH_KNOWN_HOSTS_UNKNOWN:
338 szErr = net.GetHost() +
" " + tr(
"is unknown. Do you trust the host key?") +
"\n";
339 szErr += tr(
"Host key hash:") +
"\n" + szHash;
340 qDebug(log) << szErr;
341 if(!m_pBackend)
break;
346 QMessageBox::No | QMessageBox::Ignore,
348 if(QMessageBox::Yes == btRet) {
349 nRet = ssh_session_update_known_hosts(session);
350 if (SSH_OK != nRet) {
351 qCritical(log) <<
"ssh_session_update_known_hosts fail."
352 << ssh_get_error(session);
354 }
if(QMessageBox::Ignore == btRet)
357 setErrorString(tr(
"Reject the host key"));
359 case SSH_KNOWN_HOSTS_ERROR:
361 szErr = tr(
"Error:") + ssh_get_error(session) +
"\n";
362 szErr += net.GetHost() +
" " + tr(
"the host key hash:") +
"\n" + szHash +
"\n";
363 szErr += tr(
"Will be stopped.");
364 qCritical(log) << szErr;
365 setErrorString(szErr);
376 const QString szUser,
377 const QString szPassword,
378 const QString szPassphrase,
382 int nServerMethod = nMethod;
384 qDebug(log) <<
"Authentication method:" << nMethod;
386 nRet = ssh_userauth_none(session,
387 szUser.toStdString().c_str());
388 qDebug(log) <<
"ssh_userauth_none:" << nRet;
389 if(SSH_AUTH_SUCCESS == nRet)
392 char *banner =
nullptr;
393 banner = ssh_get_issue_banner(session);
396 qInfo(log) <<
"banner:" << banner;
400 nServerMethod = ssh_userauth_list(session,
401 szUser.toStdString().c_str());
402 qDebug(log) <<
"ssh_userauth_list:" << nServerMethod;
405 if(nServerMethod & nMethod & SSH_AUTH_METHOD_PUBLICKEY) {
406 auto &user = m_pParameter->m_Net.
m_User;
407 if(user.GetUseSystemFile()) {
408 qDebug(log) <<
"User authentication with ssh_userauth_publickey_auto";
409 nRet = ssh_userauth_publickey_auto(session,
410 szUser.toStdString().c_str(),
411 szPassphrase.toStdString().c_str());
412 if(SSH_AUTH_SUCCESS == nRet)
414 QString szErr = tr(
"SSH failed: Failed authenticating with publickey:")
415 + ssh_get_error(m_Session);
416 qCritical(log) << szErr;
417 setErrorString(szErr);
419 qDebug(log) <<
"User authentication with publickey";
420 nRet = authenticationPublicKey(
423 user.GetPublicKeyFile(),
424 user.GetPrivateKeyFile(),
425 user.GetPassphrase());
426 if(SSH_AUTH_SUCCESS == nRet)
431 if(nServerMethod & nMethod & SSH_AUTH_METHOD_PASSWORD) {
432 qDebug(log) <<
"User authentication with password";
434 nRet = ssh_userauth_password(session,
435 szUser.toStdString().c_str(),
436 szPassword.toStdString().c_str());
438 QString szErr = tr(
"Failed authenticating with password. User: ")
440 + ssh_get_error(session);
441 qCritical(log) << szErr;
442 setErrorString(szErr);
450int CChannelSSH::authenticationPublicKey(
452 const QString szUser,
453 const QString szPublicKeyFile,
454 const QString szPrivateKeyFile,
455 const QString szPassphrase)
459 ssh_key publicKey = NULL;
460 ssh_key privateKey = NULL;
463 if(szPublicKeyFile.isEmpty())
465 szErr = tr(
"SSH failed: There is not set public key file.");
466 qCritical(log) << szErr;
467 setErrorString(szErr);
470 nRet = ssh_pki_import_pubkey_file(
471 szPublicKeyFile.toStdString().c_str(),
474 szErr = tr(
"SSH failed: Import public key fail.") + szPublicKeyFile;
476 szErr +=
"\n" + tr(
"The file doesn't exist or permission denied:");
477 qCritical(log) << szErr;
478 setErrorString(szErr);
482 nRet = ssh_userauth_try_publickey(
484 szUser.toStdString().c_str(),
486 if(SSH_AUTH_SUCCESS != nRet)
488 szErr = tr(
"SSH failed: Authentication failed. User:") + szUser +
"\n";
489 szErr += ssh_get_error(session);
490 qCritical(log) << szErr;
491 setErrorString(szErr);
495 if(szPrivateKeyFile.isEmpty())
497 szErr = tr(
"SSH failed: There is not set private key file.");
498 qCritical(log) << szErr;
499 setErrorString(szErr);
502 nRet = ssh_pki_import_privkey_file(
503 szPrivateKeyFile.toStdString().c_str(),
504 szPassphrase.toStdString().c_str(),
505 NULL, NULL, &privateKey);
508 szErr = tr(
"SSH failed: Import private key fail.") + szPrivateKeyFile;
510 szErr +=
"\n" + tr(
"The file doesn't exist or permission denied:");
511 qCritical(log) << szErr;
512 setErrorString(szErr);
516 nRet = ssh_userauth_publickey(
518 szUser.toStdString().c_str(),
520 if(SSH_AUTH_SUCCESS != nRet) {
521 szErr = tr(
"SSH failed: Authentication failed. User:") + szUser +
"\n";
522 szErr += ssh_get_error(session);
523 qCritical(log) << szErr;
524 setErrorString(szErr);
530 ssh_key_free(publicKey);
532 ssh_key_free(privateKey);
537int CChannelSSH::OnOpen(ssh_session session)
544void CChannelSSH::OnClose()
后端接口。它由协议插件实现。 它默认启动一个定时器来开启一个非 Qt 事件循环(就是普通的循环处理)。 详见: Start()、 slotTimeOut()、 OnProcess() 。 当然,它仍然支...
void sigBlockShowMessageBox(const QString &szTitle, const QString &szMessage, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton &nRet, bool &checkBox, QString checkBoxContext=QString())
阻塞后台线程,并在前台线程中显示消息对话框(QMessageBox)
void sigBlockShowWidget(const QString &className, int &nRet, void *pContext)
阻塞后台线程,并在前台线程中显示窗口。
virtual QString GetDetails() override
依赖信息
int authentication(ssh_session session, const QString szUser, const QString szPassword, const QString szPassphrase, const int nMethod=SSH_AUTH_METHOD_PASSWORD)
virtual bool open(OpenMode mode) override
void sigConnected()
emit when the channel is connected.
void sigError(int nErr, const QString &szErr)
emit when the channel is error
void sigSecurityLevel(CSecurityLevel::Levels level)
当安全级别改变时触发
CParameterUser m_User
[Instance user]