MochiuWiki : SUSE, EC, PCB
案内
メインページ
最近の更新
おまかせ表示
MediaWiki についてのヘルプ
ツール
リンク元
関連ページの更新状況
特別ページ
ページ情報
We ask for
Donations
検索
個人用ツール
ログイン
Toggle dark mode
名前空間
ページ
議論
表示
閲覧
ソースを閲覧
履歴を表示
Qtの基礎 - SSHのソースを表示
提供: MochiuWiki : SUSE, EC, PCB
←
Qtの基礎 - SSH
あなたには「このページの編集」を行う権限がありません。理由は以下の通りです:
この操作は、次のグループのいずれかに属する利用者のみが実行できます:
管理者
、new-group。
このページのソースの閲覧やコピーができます。
== 概要 == Qtにおいて、簡潔にSSH接続を確立する手順を記載する。<br> <br> * libsshまたはlibssh2を使用する。 * QProcessクラスを使用して、外部のSSHプロセスを呼び出して接続を確立する。 * 他のSSHライブラリを購入する。<br>http://netsieben.com/products/ssh <br><br> == libSSHとlibSSH2の比較 == libSSHとlibSSH2は、どちらもSSHプロトコルを実装したライブラリである。<br> libSSHはC言語、libSSH2はC++言語で記述されている。<br> <br> また、libSSHは単独のライブラリとして提供されているのに対して、libSSH2はlibSSL等の他のライブラリと組み合わせて使用することが多い。<br> <br> プロジェクトの起源と開発者<br> * libSSH *: libSSHは、フランスのBenjamin GilbertとArel Corderoによって開発された。 *: libSSHは、SSHプロトコルの実装を提供しており、クライアントおよびサーバの機能をサポートしている。 *: <br> * libSSH2 *: libSSH2は、curlライブラリの主要な開発者でもあるスウェーデンのDaniel Stenbergによって開発された。 *: libSSH2は、SSHのクライアントおよびサーバ機能を提供することを目的としている。 *: ただし、libSSH2はサーバサイドのサポートは行っていない。 <br> 使用されるコードベース<br> * libSSH *: libSSHは、元々PuTTYの一部として開発され、その後独立したプロジェクトになった。 *: PuTTYは、Windows環境でのSSHクライアントとして広く知られている。 *: <br> * libSSH2 *: libSSH2は、curlライブラリとは独立したプロジェクトとして開発されている。 <br> <center> {| class="wikitable" | style="background-color:#fefefe;" |- ! style="background-color:#66CCFF; width: 50%;" | 項目 ! style="background-color:#66CCFF; width: 25%;" | libSSH2 ! style="background-color:#66CCFF; width: 25%;" | libSSH |- | ライブラリ名 || libssh2.so || libssh.so |- | ライセンス || 3条項BSD || LGPL 2.1 |- | サーバサイドのサポート || No || Yes |- | GSSAPI認証 || No || Yes |- | 楕円曲線鍵の交換 || No || Yes |- | 楕円曲線鍵のホスト鍵 || No || Yes |- | ナイトリーテストによるテストケースの自動化 || No || Yes |- | Stable API || Yes || ほとんどの部分 |- | C言語との互換 || C89 || C99 |- | 厳格な名前空間 || Yes || Yes |- | 全ての関数のマニュアル || Yes || No |- | 全ての関数のDoxygenドキュメント || No || Yes |- | Tutorial || Yes || Yes |- | SSH v1のサポート || No || Yes |} </center> <br><br> == libSSHライブラリのインストール == ==== libSSHとは ==== libSSHの多くは、LGPL 2.1ライセンスである。<br> 一部の機能には、2条項BSDライセンスのものがある。<br> <br> ==== パッケージ管理システムからインストール ==== sudo zypper install libssh-devel <br> ==== ソースコードからインストール ==== libSSHのビルドに必要なライブラリをインストールする。<br> sudo zypper install zlib-devel readline-devel libpcap-devel libopenssl-devel libopenssl-1_1-devel libgcrypt-devel p11-kit-devel libsodium-devel libcmocka-devel doxygen \ # 以下に示すライブラリは不要の可能性あり openpgm-devel ldns-devel zeromq-devel unbound-devel libunwind-devel \ libheimdal-devel libgssglue-devel gssntlmssp-devel <br> [https://www.libssh.org/ libSSHの公式Webサイト]または[https://git.libssh.org/projects/libssh.git libSSH向けのGit]にアクセスして、libSSHのソースコードをダウンロードする。<br> ダウンロードしたファイルを解凍する。<br> tar xf libssh-<バージョン>.tar.xz cd libssh-<バージョン> <br> libSSHをビルドおよびインストールする。<br> mkdir build && cd build cmake .. \ -DCMAKE_INSTALL_PREFIX=/<libSSHのインストールディレクトリ> -DCMAKE_BUILD_TYPE=Release \ -DWITH_GSSAPI=ON -DWITH_DSA=ON -DWITH_GCRYPT=ON \ # オプション -DWITH_PKCS11_URI=ON -DWITH_BLOWFISH_CIPHER=ON \ # オプション -DCMAKE_C_COMPILER=/<GCCのインストールディレクトリ>/bin/gcc \ # オプション -DCMAKE_CXX_COMPILER=/<GCCのインストールディレクトリ>/bin/g++ # オプション make -j $(nproc) make install <br> libSSHの使用例は、以下に示すURLを参考にすること。<br> https://api.libssh.org/stable/libssh_tutorial.html <br><br> == libSSH2ライブラリのインストール == ==== libSSH2とは ==== libSSH2は、3条項BSDライセンスである。(4条項BSDライセンスから、3番目にあった「宣伝条項」を削除したもの)<br> これにより、GPLと互換性が生まれたため、BSDライセンスのソフトウェアをGPLで配布することができる。(その逆は不可)<br> <br> ==== パッケージ管理システムからインストール ==== sudo zypper install libssh2-devel <br> ==== ソースコードからインストール ==== libSSH2のビルドに必要なライブラリをインストールする。<br> sudo zypper install zlib-devel libopenssl-devel libopenssl-1_1-devel <br> [https://www.libssh2.org/ libSSH2の公式Webサイト]または[https://github.com/libssh2/libssh2 Github]にアクセスして、libSSH2のソースコードをダウンロードする。<br> ダウンロードしたソースコードを解凍する。<br> tar xf libssh2.tar.xz cd libssh2 <br> libSSH2をビルドおよびインストールする。<br> mkdir build && cd build # configureスクリプトを使用する場合 ../cofigur --prefix=<libSSH2のインストールディレクトリ> \ --enable-examples-build --disable-debug --with-libz make -j $(nproc) make install # CMakeを使用する場合 cmake .. \ -DCMAKE_INSTALL_PREFIX=/<libssh2のインストールディレクトリ> \ -DLINT=ON -DBUILD_SHARED_LIBS=ON -DCLEAR_MEMORY=ON -DCMAKE_BUILD_TYPE=Release -DENABLE_DEBUG_LOGGING=OFF \ -DCMAKE_C_COMPILER=/<GCCのインストールディレクトリ>/bin/gcc \ # オプション -DCMAKE_CXX_COMPILER=/<GCCのインストールディレクトリ>/bin/g++ # オプション make -j $(nproc) make install <br> libSSH2の使用例は、以下に示すURLを参考にすること。<br> http://www.chaosstuff.com/2013/09/gnome-mplayer-remote-with-qt-and-libssh2.html<br> https://bitbucket.org/nchokoev/qtsshremote<br> <br> Windowsの場合、CMakeおよびVisual Studioを使用してlibSSH2をビルドおよびインストールすることができる。<br> * CMakeを使用する場合 ** 32ビット Windows **: <code>cmake -DBUILD_SHARED_LIBS=ON -DBUILD_EXAMPLES=OFF -DBUILD_TESTING=OFF -A Win32 .. -B "x86"</code> **: <code>cmake --build x86 --config Release</code> **: <br> ** 64ビット Windows **: <code>cmake -DBUILD_SHARED_LIBS=ON -DBUILD_EXAMPLES=OFF -DBUILD_TESTING=OFF -A x64 .. -B "x64"</code> **: <code>cmake --build x64 --config Release</code> **: <br> *: コンパイルされたDLLファイルとlibファイルは、x86とx64のディレクトリのsrc/Releaseディレクトリに配置される。 *: <br> * Visual Studioを使用する場合 *: libSSH2ディレクトリと同階層にプロジェクトを作成する。 *: プロジェクトのプロパティを選択して、プロパティ画面左ペインにある[General] - プロパティ画面右ペインにある[ターゲット名]を"libSSH2_x64"等と入力する。 *: プロパティ画面左ペインにある[リンカ] - [Advanced] - プロパティ画面右ペインにある[インポートライブラリ]プルダウンから[<Inherit from parent or project defaults>]を選択する。 <br> また、ビルドされたDLLファイルは、以下に示すWebサイトからダウンロードできる。<br> https://download.csdn.net/download/sdhongjun/15682389<br> <br><br> == libSSHの使用例 == 以下の例では、公開鍵認証を使用してリモートPCへSSH接続している。<br> <br> <syntaxhighlight lang="make"> # .pro プロジェクトファイル # pkg-configを使用する場合 CONFIG += link_pkgconfig LIBS += \ -L/<libSSHのインストールディレクトリ>/lib64 -lssh # pkg-configを使用しない場合 LIBS += \ -L/<libSSHのインストールディレクトリ>/lib64 -lssh INCLUDEPATH += \ /<libSSHのインストールディレクトリ>/include </syntaxhighlight> <br> <syntaxhighlight lang="c++"> #include <QCoreApplication> #include <QMessageBox> #include <libssh/libssh.h> int VerifyKnownsHost(ssh_session session, QString &strErrMsg); int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); // SSHセッションの作成 ssh_session ssh_session = ssh_new(); if (my_ssh_session == NULL) { // 作成に失敗した場合 return -1; } // SSHセッションの設定 QString host = "<リモートPCのIPアドレス または ホスト名>"; QString user = "<リモートPCのユーザ名>"; QString port = "<SSHポート番号 例: 22>"; ssh_options_set(ssh_session, SSH_OPTIONS_HOST, host.toUtf8().data()); ssh_options_set(ssh_session, SSH_OPTIONS_USER, user.toUtf8().data()); ssh_options_set(ssh_session, SSH_OPTIONS_PORT_STR, port.toUtf8().data()); // SSH接続 int rc = ssh_connect(ssh_session); if (rc != SSH_OK) { // 接続に失敗した場合 fprintf(stderr, "Error connecting to host: %s\n", ssh_get_error(ssh_session)); ssh_free(ssh_session); return -1; } // ~/.sshディレクトリ等にあるファイルに記述されているサーバのIDを検証 QString strErrMsg = ""; if(VerifyKnownsHost(ssh_session, strErrMsg) < 0) { if(ssh_session != nullptr) { ssh_disconnect(ssh_session); ssh_free(ssh_session); } return -1; } // 公開鍵認証 // 秘密鍵の設定 const char *private_key_path = "<秘密鍵のパス 例: /home/user/sshkey/id_rsa"; // 秘密鍵のパスフレーズを設定していない場合 rc = ssh_userauth_privatekey_file(ssh_session, nullptr, private_key_path, nullptr); // 秘密鍵のパスフレーズを設定している場合 rc = ssh_userauth_privatekey_file(ssh_session, nullptr, private_key_path, "<秘密鍵のパスフレーズ>"); if (rc != SSH_AUTH_SUCCESS) { // 認証に失敗した場合 fprintf(stderr, "Error authenticating with private key: %s\n", ssh_get_error(my_ssh_session)); ssh_disconnect(my_ssh_session); ssh_free(my_ssh_session); return -1; } // SSHセッションを使用して任意の処理を実行 // scpコマンドの実行、または、リモート先で任意のコマンドの実行等 // ...略 // SSH接続の切断 ssh_disconnect(ssh_session); // SSHセッションの解放 ssh_free(ssh_session); return 0; } int VerifyKnownsHost(ssh_session ssh_session, QString &strErrMsg) { // Authenticating the server. ssh_key srv_pubkey = {}; if(ssh_get_server_publickey(ssh_session, &srv_pubkey) < 0) { strErrMsg = tr("Failed to get public key."); return -1; } unsigned char *hash = nullptr; size_t hlen = 0L; auto iRet = ssh_get_publickey_hash(srv_pubkey, SSH_PUBLICKEY_HASH_SHA256, &hash, &hlen); ssh_key_free(srv_pubkey); if(iRet < 0) { strErrMsg = tr("Failed to get public key hash."); return -1; } auto state = ssh_session_is_known_server(ssh_session); if(state == ssh_known_hosts_e::SSH_KNOWN_HOSTS_OK) { // Authentication Successful } else if(state == ssh_known_hosts_e::SSH_KNOWN_HOSTS_CHANGED) { QString strHexa = ssh_get_hexa(hash, hlen); // print string in reverse order strErrMsg = tr("Host key for server changed:") + "<br>" + tr("For security reasons, connection will be stopped.") + "<br><br>" + tr("Public key hash:") + "<br>" + strHexa + "<br>" + hlen; ssh_clean_pubkey_hash(&hash); return -1; } else if(state == ssh_known_hosts_e::SSH_KNOWN_HOSTS_OTHER) { strErrMsg = tr("The host key for this server was not found but an other type of key exists.") + "<br>" + tr("An attacker might change the default server key to confuse your client into") + "<br>" + tr("thinking the key does not exist"); ssh_clean_pubkey_hash(&hash); return -1; } else if(state == ssh_known_hosts_e::SSH_KNOWN_HOSTS_NOT_FOUND) { /* FALL THROUGH to SSH_KNOWN_HOSTS_UNKNOWN behavior */ QString strHexa = ssh_get_hexa(hash, hlen); QString strAddHostMessage = tr("Could not find known host file.") + "\n" + tr("If you accept the host key here, the file will be automatically created.") + "\n\n" + tr("The server is unknown. Do you trust the host key?") + "\n" + tr("Public key hash: ") + "\n" + strHexa; auto ret = QMessageBox(QMessageBox::Warning, QMessageBox::tr("Add Host"), strAddHostMessage, QMessageBox::Yes | QMessageBox::No, nullptr).exec(); ssh_clean_pubkey_hash(&hash); if(ret == QMessageBox::No) { strErrMsg = tr("To connect, please add host key."); return -1; } else { iRet = ssh_session_update_known_hosts(ssh_session); if(iRet < 0) { strErrMsg = tr("Failed to update host key."); return -1; } } } else if(state == ssh_known_hosts_e::SSH_KNOWN_HOSTS_UNKNOWN) { QString strHexa = ssh_get_hexa(hash, hlen); QString strAddHostMessage = tr("The server is unknown. Do you trust the host key?") + "\n" + tr("Public key hash: ") + "\n" + strHexa; auto msgRet = QMessageBox(QMessageBox::Warning, QMessageBox::tr("Add Host"), strAddHostMessage, QMessageBox::Yes | QMessageBox::No, nullptr).exec(); ssh_clean_pubkey_hash(&hash); if(msgRet == QMessageBox::No) { strErrMsg = tr("To connect, please add host key."); return -1; } else { iRet = ssh_session_update_known_hosts(ssh_session); if(iRet < 0) { strErrMsg = tr("Failed to update host key."); return -1; } } } else if(state == ssh_known_hosts_e::SSH_KNOWN_HOSTS_ERROR) { strErrMsg = tr("There was an error in checking the host."); ssh_clean_pubkey_hash(&hash); return -1; } ssh_clean_pubkey_hash(&hash); return 0; } </syntaxhighlight> <br><br> == 独自クラスの使用 == 以下に示すクラスは、クロスプラットフォームの非同期SSHおよびSCPソケットである。<br> このクラスは、libSSHを必要とする。(RSA鍵の受け渡しを隠したり、コマンドの応答をreadyReadシグナル経由ではなく、シングルショットで送信している)<br> <br> Windowsで動作させるには、このクラスを使用するファイルの最上部にインクルードする必要がある。<br> これにより、QtがWindowsソケットをインクルードする前にWindows.hファイルをインクルードさせないようにする。<br> <br> <center><code><u>[[ファイル:CSSH.zip|フレームなし|中央]]</u></code></center> <br><br> __FORCETOC__ [[カテゴリ:Qt]]
Qtの基礎 - SSH
に戻る。
案内
メインページ
最近の更新
おまかせ表示
MediaWiki についてのヘルプ
ツール
リンク元
関連ページの更新状況
特別ページ
ページ情報
We ask for
Donations
Collapse