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(),
 
  207        nRet = OnOpen(m_Session);
 
  215    ssh_disconnect(m_Session);
 
 
  221void CChannelSSH::close()
 
  223    qDebug(log) << Q_FUNC_INFO;
 
  225    if(!isOpen()) 
return;
 
  230        if(ssh_is_connected(m_Session))
 
  231            ssh_disconnect(m_Session);
 
  238        ssh_pcap_file_close(m_pcapFile);
 
  239        ssh_pcap_file_free(m_pcapFile);
 
  240        m_pcapFile = 
nullptr;
 
  246int CChannelSSH::verifyKnownhost(ssh_session session)
 
  250    ssh_key srv_pubkey = NULL;
 
  252    auto &net = m_pParameter->m_Net;
 
  254    nRet = ssh_get_server_publickey(session, &srv_pubkey);
 
  256        szErr = tr(
"SSH failed: Get server public key.") + 
" " + net.GetHost() + 
"; [";
 
  257        szErr += ssh_get_error(session);
 
  259        qCritical(log) << szErr;
 
  260        setErrorString(szErr);
 
  263    unsigned char *hash = NULL;
 
  265    nRet  = ssh_get_publickey_hash(srv_pubkey,
 
  266                                  SSH_PUBLICKEY_HASH_SHA1,
 
  269    ssh_key_free(srv_pubkey);
 
  271        szErr = tr(
"SSH failed: Get public key hash value fail.");
 
  272        qCritical(log) << szErr;
 
  273        setErrorString(szErr);
 
  276    QByteArray baHash((
const char*)hash, nLen);
 
  277    QString szHash = baHash.toHex(
':').toStdString().c_str();
 
  278    ssh_clean_pubkey_hash(&hash);
 
  280    QMessageBox::StandardButton btRet = QMessageBox::Yes;
 
  281    bool checkBox = 
false;
 
  282    enum ssh_known_hosts_e state = ssh_session_is_known_server(session);
 
  284    case SSH_KNOWN_HOSTS_OK:
 
  287    case SSH_KNOWN_HOSTS_CHANGED:
 
  289        szErr = net.GetHost() + 
" " + tr(
"the host key for server changed. it is now:") + 
"\n";
 
  290        szErr += szHash + 
"\n";
 
  291        szErr += tr(
"For security reasons, connection will be stopped.") + 
"\n";
 
  292        szErr += tr(
"Please look at the OpenSSL documentation on " 
  293                    "how to add a private CA to the store.");
 
  294        qCritical(log) << szErr;
 
  295        setErrorString(szErr);
 
  297    case SSH_KNOWN_HOSTS_OTHER:
 
  299        szErr = net.GetHost() + 
" " + tr(
"the host key for this server was not found but an other type of key exists.") + 
"\n";
 
  300        szErr += tr(
"An attacker might change the default server key to " 
  301                    "confuse your client into thinking the key does not exist") + 
"\n";
 
  302        szErr += tr(
"For security reasons, connection will be stopped.") + 
"\n";
 
  303        szErr += tr(
"Please look at the OpenSSL documentation on " 
  304                    "how to add a private CA to the store.");
 
  305        qCritical(log) << szErr;
 
  306        setErrorString(szErr);
 
  308    case SSH_KNOWN_HOSTS_NOT_FOUND:
 
  310        szErr = net.GetHost() + 
" " + tr(
"is not find in known host file.") + 
"\n";
 
  311        szErr += tr(
"If you accept the host key here, the file will be " 
  312                    "automatically created.") + 
"\n";
 
  313        szErr += tr(
"Host key hash:") + 
"\n" + szHash;
 
  314        qDebug(log) << szErr;
 
  315        if(!m_pBackend) 
break;
 
  320                                                    QMessageBox::No | QMessageBox::Ignore,
 
  322        if(QMessageBox::Yes == btRet) {
 
  323            nRet = ssh_session_update_known_hosts(session);
 
  326                qCritical(log) << 
"ssh_session_update_known_hosts fail." 
  327                               << ssh_get_error(session);
 
  329        } 
if(QMessageBox::Ignore == btRet)
 
  332            setErrorString(tr(
"Reject the host key"));
 
  334    case SSH_KNOWN_HOSTS_UNKNOWN:
 
  336        szErr = net.GetHost() + 
" " + tr(
"is unknown. Do you trust the host key?") + 
"\n";
 
  337        szErr += tr(
"Host key hash:") + 
"\n" + szHash;
 
  338        qDebug(log) << szErr;
 
  339        if(!m_pBackend) 
break;
 
  344                                                    QMessageBox::No | QMessageBox::Ignore,
 
  346        if(QMessageBox::Yes == btRet) {
 
  347            nRet = ssh_session_update_known_hosts(session);
 
  348            if (SSH_OK != nRet) {
 
  349                qCritical(log) << 
"ssh_session_update_known_hosts fail." 
  350                               << ssh_get_error(session);
 
  352        } 
if(QMessageBox::Ignore == btRet)
 
  355            setErrorString(tr(
"Reject the host key"));
 
  357    case SSH_KNOWN_HOSTS_ERROR:
 
  359        szErr = tr(
"Error:") + ssh_get_error(session) + 
"\n";
 
  360        szErr += net.GetHost() + 
" " + tr(
"the host key hash:") + 
"\n" + szHash + 
"\n";
 
  361        szErr += tr(
"Will be stopped.");
 
  362        qCritical(log) << szErr;
 
  363        setErrorString(szErr);
 
  374    const QString szUser,
 
  375    const QString szPassword,
 
  376    const QString szPassphrase,
 
  380    int nServerMethod = nMethod;
 
  382    qDebug(log) << 
"Authentication method:" << nMethod;
 
  384    nRet = ssh_userauth_none(session,
 
  385                             szUser.toStdString().c_str());
 
  386    qDebug(log) << 
"ssh_userauth_none:" << nRet;
 
  387    if(SSH_AUTH_SUCCESS == nRet)
 
  390    char *banner = 
nullptr;
 
  391    banner = ssh_get_issue_banner(session);
 
  394        qInfo(log) << 
"banner:" << banner;
 
  398    nServerMethod = ssh_userauth_list(session,
 
  399                                      szUser.toStdString().c_str());
 
  400    qDebug(log) << 
"ssh_userauth_list:" << nServerMethod;
 
  403    if(nServerMethod & nMethod & SSH_AUTH_METHOD_PUBLICKEY) {
 
  404        auto &user = m_pParameter->m_Net.
m_User;
 
  405        if(user.GetUseSystemFile()) {
 
  406            qDebug(log) << 
"User authentication with ssh_userauth_publickey_auto";
 
  407            nRet = ssh_userauth_publickey_auto(session,
 
  408                                               szUser.toStdString().c_str(),
 
  409                                               szPassphrase.toStdString().c_str());
 
  410            if(SSH_AUTH_SUCCESS == nRet)
 
  412            QString szErr = tr(
"SSH failed: Failed authenticating with publickey:")
 
  413                            + ssh_get_error(m_Session);
 
  414            qCritical(log) << szErr;
 
  415            setErrorString(szErr);
 
  417            qDebug(log) << 
"User authentication with publickey";
 
  418            nRet = authenticationPublicKey(
 
  421                user.GetPublicKeyFile(),
 
  422                user.GetPrivateKeyFile(),
 
  423                user.GetPassphrase());
 
  424            if(SSH_AUTH_SUCCESS == nRet)
 
  429    if(nServerMethod & nMethod & SSH_AUTH_METHOD_PASSWORD) {
 
  430        qDebug(log) << 
"User authentication with password";
 
  432        nRet = ssh_userauth_password(session,
 
  433                                     szUser.toStdString().c_str(),
 
  434                                     szPassword.toStdString().c_str());
 
  436            QString szErr = tr(
"Failed authenticating with password. User: ")
 
  438                + ssh_get_error(session);
 
  439            qCritical(log) << szErr;
 
  440            setErrorString(szErr);
 
 
  448int CChannelSSH::authenticationPublicKey(
 
  450    const QString szUser,
 
  451    const QString szPublicKeyFile,
 
  452    const QString szPrivateKeyFile,
 
  453    const QString szPassphrase)
 
  457    ssh_key publicKey = NULL;
 
  458    ssh_key privateKey = NULL;
 
  461        if(szPublicKeyFile.isEmpty())
 
  463            szErr = tr(
"SSH failed: There is not set public key file.");
 
  464            qCritical(log) << szErr;
 
  465            setErrorString(szErr);
 
  468        nRet = ssh_pki_import_pubkey_file(
 
  469            szPublicKeyFile.toStdString().c_str(),
 
  472            szErr = tr(
"SSH failed: Import public key fail.") + szPublicKeyFile;
 
  474                szErr += 
"\n" + tr(
"The file doesn't exist or permission denied:");
 
  475            qCritical(log) << szErr;
 
  476            setErrorString(szErr);
 
  480        nRet = ssh_userauth_try_publickey(
 
  482            szUser.toStdString().c_str(),
 
  484        if(SSH_AUTH_SUCCESS != nRet)
 
  486            szErr = tr(
"SSH failed: Authentication failed. User:") + szUser + 
"\n";
 
  487            szErr += ssh_get_error(session);
 
  488            qCritical(log) << szErr;
 
  489            setErrorString(szErr);
 
  493        if(szPrivateKeyFile.isEmpty())
 
  495            szErr = tr(
"SSH failed: There is not set private key file.");
 
  496            qCritical(log) << szErr;
 
  497            setErrorString(szErr);
 
  500        nRet = ssh_pki_import_privkey_file(
 
  501            szPrivateKeyFile.toStdString().c_str(),
 
  502            szPassphrase.toStdString().c_str(),
 
  503            NULL, NULL, &privateKey);
 
  506            szErr = tr(
"SSH failed: Import private key fail.") + szPrivateKeyFile;
 
  508                szErr += 
"\n" + tr(
"The file doesn't exist or permission denied:");
 
  509            qCritical(log) << szErr;
 
  510            setErrorString(szErr);
 
  514        nRet = ssh_userauth_publickey(
 
  516            szUser.toStdString().c_str(),
 
  518        if(SSH_AUTH_SUCCESS != nRet) {
 
  519            szErr = tr(
"SSH failed: Authentication failed. User:") + szUser + 
"\n";
 
  520            szErr += ssh_get_error(session);            
 
  521            qCritical(log) << szErr;
 
  522            setErrorString(szErr);
 
  528        ssh_key_free(publicKey);
 
  530        ssh_key_free(privateKey);
 
  535int CChannelSSH::OnOpen(ssh_session session)
 
  542void CChannelSSH::OnClose()
 
void sigBlockShowMessageBox(const QString &szTitle, const QString &szMessage, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton &nRet, bool &checkBox, QString checkBoxContext=QString())
Block background threads and display message dialogs in foreground threads (QMessageBox)
 
void sigBlockShowWidget(const QString &className, int &nRet, void *pContext)
Blocks the background thread and displays the window in the foreground thread.
 
virtual QString GetDetails() override
Depend on information.
 
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
 
The channel interface class.
 
void sigConnected()
emit when the channel is connected.
 
void sigError(int nErr, const QString &szErr)
emit when the channel is error
 
CParameterUser m_User
[Instance user]