Merge branch 'dev'

This commit is contained in:
pokamest 2023-04-11 18:00:54 +01:00
commit af29637163
201 changed files with 2229 additions and 1503287 deletions

12
.gitmodules vendored
View file

@ -1,6 +1,3 @@
[submodule "3rd/QtSsh"]
path = 3rd/QtSsh
url = https://github.com/amnezia-vpn/QtSsh.git
[submodule "client/3rd/wireguard-tools"]
path = client/3rd/wireguard-tools
url = https://github.com/WireGuard/wireguard-tools/
@ -25,9 +22,18 @@
[submodule "client/3rd/qtkeychain"]
path = client/3rd/qtkeychain
url = https://github.com/frankosterfeld/qtkeychain.git
[submodule "client/3rd/libssh"]
path = client/3rd/libssh
url = https://git.libssh.org/projects/libssh.git/
[submodule "client/3rd/zlib"]
path = client/3rd/zlib
url = https://github.com/madler/zlib.git
[submodule "deploy/amnezia-ios-certificates"]
path = deploy/amnezia-ios-certificates
url = https://github.com/amnezia-vpn/amnezia-ios-certificates.git
[submodule "client/3rd/SortFilterProxyModel"]
path = client/3rd/SortFilterProxyModel
url = https://github.com/mitchcurtis/SortFilterProxyModel.git
[submodule "client/3rd/mbedtls"]
path = client/3rd/mbedtls
url = https://github.com/Mbed-TLS/mbedtls.git

View file

@ -1,50 +0,0 @@
# User settings
*.user
macOSPackage/
# C++ objects and libs
*.slo
*.lo
*.o
*.a
*.la
*.lai
*.so
*.dll
*.dylib
# Qt-es
/.qmake.cache
/.qmake.stash
*.pro.user
*.pro.user.*
*.qbs.user
*.qbs.user.*
*.moc
moc_*.cpp
qrc_*.cpp
ui_*.h
Makefile*
*build-*
# QtCreator
*.autosave
# QtCtreator Qml
*.qmlproject.user
*.qmlproject.user.*
# QtCtreator CMake
CMakeLists.txt.user*
# MACOS files
.DS_Store
._.DS_Store
._*
# tmp files
*.*~
# Certificates
*.p12

View file

@ -1,3 +0,0 @@
load(qt_build_config)
MODULE_VERSION = 4.3.1

View file

@ -1 +0,0 @@
load(qt_parts)

View file

@ -1,46 +0,0 @@
# QSsh
this project is base on Qt-creator-open-source-4.3.1
project is at
`http://code.qt.io/cgit/qt-creator/qt-creator.git/`
you can download code zip at
`http://download.qt.io/official_releases/qtcreator/4.3/4.3.1/`
## Getting Started
> * For linux user, if your Qt is installed through package manager tools such "apt-get", make sure that you have installed the Qt5 develop package *qtbase5-private-dev*
### Usage(1): Use QtSsh as Qt5's addon module
#### Building the module
> **Note**: Perl is needed in this step.
* Download the source code.
* Put the source code in any directory you like
* Go to top directory of the project in a terminal and run
```
qmake
make
make install
```
The library, the header files, and others will be installed to your system.
#### Import the module
` QT += ssh`
#### Include Headerfile
` #include<QtSsh/sshconnection.h>`
#### Close qtc.ssh log
` QLoggingCategory::setFilterRules(QStringLiteral("qtc.ssh=false")`

View file

@ -1,2 +0,0 @@
TEMPLATE = subdirs
SUBDIRS = gitlab

View file

@ -1,5 +0,0 @@
<RCC>
<qresource prefix="/">
<file>Qml/Main.qml</file>
</qresource>
</RCC>

View file

@ -1,51 +0,0 @@
import QtQuick 2.0
import QtQuick.Controls 2.0
import Ssh 1.0
Item {
width: 1024
height: 768
TextField {
id: input
x: 104
y: 44
width: 482
height: 40
implicitWidth: 200
selectByMouse: true
text: "https://www.zhihu.com"
}
function get(url) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState === XMLHttpRequest.DONE) {
console.log(xhr.responseXML, xhr.responseText.toString())
} else if (xhr.readyState === XMLHttpRequest) {
}
}
xhr.open('GET', url)
xhr.send()
}
Button {
x: 627
y: 44
text: "get"
onClicked: {
get(input.text)
}
}
Button {
id: button
x: 104
y: 170
text: qsTr("Ssh")
onClicked: ssh.connectToHost()
}
Ssh {
id: ssh
}
}

View file

@ -1,17 +0,0 @@
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQuickView>
#include "Ssh.hpp"
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
qmlRegisterType<Ssh> ("Ssh", 1, 0, "Ssh");
QQuickView view;
view.setSource(QUrl("qrc:/Qml/Main.qml"));
view.show();
return app.exec();
}

View file

@ -1,61 +0,0 @@
#include "Ssh.hpp"
#include <QDir>
#include <QDebug>
#include <QLoggingCategory>
Ssh::Ssh(QObject *parent) : QObject(parent) {
//关掉qtc.ssh中的各种打印信息
QLoggingCategory::setFilterRules(QStringLiteral("qtc.ssh=false"));
mParams.host="ftb.autoio.org";
mParams.userName = "ftb";
mParams.port = 11122;
mParams.privateKeyFile = QDir::homePath() + QStringLiteral("/.ssh/id_rsa");
mParams.timeout = 5;
mParams.authenticationType = SshConnectionParameters::AuthenticationTypePublicKey;
mParams.options = SshIgnoreDefaultProxy;
mParams.hostKeyCheckingMode = SshHostKeyCheckingNone;
mConnections = std::make_shared<SshConnection>(mParams);
connect(mConnections.get(), &SshConnection::error, [&](QSsh::SshError){
qWarning() << "Error: " << mConnections->errorString();
});
connect(mConnections.get(), &SshConnection::connected, [&](){
qWarning() << "Connected";
create();
});
connect(mConnections.get(), &SshConnection::disconnected, [](){
qWarning() << "Disconnected";
});
connect(mConnections.get(), &SshConnection::dataAvailable, [](const QString &message){
qWarning() << "Message: " << message;
});
}
void Ssh::connectToHost() {
mConnections->connectToHost();
}
void Ssh::create() {
mRemoteProcess = mConnections->createRemoteProcess(QString::fromLatin1("/bin/ls -a").toUtf8());
if (!mRemoteProcess) {
qWarning() << QLatin1String("Error: UnmRemoteProcess SSH connection creates remote process.");
return;
}
connect(mRemoteProcess.data(), &SshRemoteProcess::started, [&](){
qWarning() << "started";
});
connect(mRemoteProcess.data(), &SshRemoteProcess::readyReadStandardOutput, [&](){
qWarning() << "StandardOutput";
qWarning() << QString::fromLatin1(mRemoteProcess->readAllStandardOutput()).split('\n');
});
connect(mRemoteProcess.data(), &SshRemoteProcess::readyReadStandardError, [&](){
qWarning() << "StandardError" << mRemoteProcess->readAllStandardError();
});
connect(mRemoteProcess.data(), &SshRemoteProcess::closed, [&](int exitStatus){
qWarning() << "Exit" << exitStatus;
});
mRemoteProcess->start();
}

View file

@ -1,26 +0,0 @@
#pragma once
#include <memory>
#include <cstdlib>
#include <functional>
#include <QObject>
#include <QtSsh/sshconnection.h>
#include <QtSsh/sshremoteprocess.h>
using namespace QSsh;
class Ssh : public QObject {
Q_OBJECT
public:
explicit Ssh(QObject *parent = nullptr);
Q_INVOKABLE void connectToHost();
void create();
private:
SshConnectionParameters mParams;
std::shared_ptr<SshConnection> mConnections;
QSharedPointer<SshRemoteProcess> mRemoteProcess;
};

View file

@ -1,29 +0,0 @@
QT += quick network ssh
CONFIG += c++11
TEMPLATE = app
# The following define makes your compiler emit warnings if you use
# any feature of Qt which as been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
#DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += Src/Main.cpp \
Src/Ssh.cpp
RESOURCES += Qml.qrc
# Additional import path used to resolve QML modules in Qt Creator's code model
QML_IMPORT_PATH =
# Additional import path used to resolve QML modules just for Qt Quick Designer
QML_DESIGNER_IMPORT_PATH =
HEADERS += \
Src/Ssh.hpp

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,71 +0,0 @@
include_directories(
${CMAKE_CURRENT_LIST_DIR}/include
${CMAKE_CURRENT_LIST_DIR}/include/external
)
if(WIN32)
add_compile_definitions(MVPN_WINDOWS)
add_compile_options(/bigobj)
set(LIBS ${LIBS}
crypt32
)
if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8")
include_directories(${CMAKE_CURRENT_LIST_DIR}/windows/x86_64)
set(HEADERS ${HEADERS} ${CMAKE_CURRENT_LIST_DIR}/windows/x86_64/botan_all.h)
set(SOURCES ${SOURCES} ${CMAKE_CURRENT_LIST_DIR}/windows/x86_64/botan_all.cpp)
else()
include_directories(${CMAKE_CURRENT_LIST_DIR}/windows/x86)
set(HEADERS ${HEADERS} ${CMAKE_CURRENT_LIST_DIR}/windows/x86/botan_all.h)
set(SOURCES ${SOURCES} ${CMAKE_CURRENT_LIST_DIR}/windows/x86/botan_all.cpp)
endif()
endif()
if(APPLE AND NOT IOS)
include_directories(${CMAKE_CURRENT_LIST_DIR}/macos)
set(HEADERS ${HEADERS} ${CMAKE_CURRENT_LIST_DIR}/macos/botan_all.h)
set(SOURCES ${SOURCES} ${CMAKE_CURRENT_LIST_DIR}/macos/botan_all.cpp)
endif()
if(LINUX AND NOT ANDROID)
include_directories(${CMAKE_CURRENT_LIST_DIR}/linux)
set(HEADERS ${HEADERS} ${CMAKE_CURRENT_LIST_DIR}/linux/botan_all.h)
set(SOURCES ${SOURCES} ${CMAKE_CURRENT_LIST_DIR}/linux/botan_all.cpp)
set(LIBS ${LIBS} dl)
endif()
if(ANDROID)
# We need to include qtprivate api's
# As QAndroidBinder is not yet implemented with a public api
set(LIBS ${LIBS} Qt6::CorePrivate)
set(abi ${CMAKE_ANDROID_ARCH_ABI})
include_directories(${CMAKE_CURRENT_LIST_DIR}/android/${abi})
link_directories(${CMAKE_CURRENT_LIST_DIR}/android/${abi})
set(HEADERS ${HEADERS} ${CMAKE_CURRENT_LIST_DIR}/android/${abi}/botan_all.h)
set(SOURCES ${SOURCES} ${CMAKE_CURRENT_LIST_DIR}/android/${abi}/botan_all.cpp)
endif()
if(IOS)
# CONFIG(iphoneos, iphoneos|iphonesimulator) {
# contains(QT_ARCH, arm64) {
# INCLUDEPATH += $$PWD/ios/iphone
# HEADERS += $$PWD/ios/iphone/botan_all.h
# SOURCES += $$PWD/ios/iphone/botan_all.cpp
# } else {
# message("Building for iOS/ARM v7 (32-bit) architecture")
# ARCH_TAG = "ios_armv7"
# }
# }
# CONFIG(iphonesimulator, iphoneos|iphonesimulator) {
# INCLUDEPATH += $$PWD/ios/iphone
# HEADERS += $$PWD/ios/iphone/botan_all.h
# SOURCES += $$PWD/ios/iphone/botan_all.cpp
# }
include_directories(${CMAKE_CURRENT_LIST_DIR}/ios/iphone)
set(HEADERS ${HEADERS} ${CMAKE_CURRENT_LIST_DIR}/ios/iphone/botan_all.h)
set(SOURCES ${SOURCES} ${CMAKE_CURRENT_LIST_DIR}/ios/iphone/botan_all.cpp)
endif()

View file

@ -1,86 +0,0 @@
INCLUDEPATH += $$PWD/include
DEPENDPATH += $$PWD
CONFIG += c++17
INCLUDEPATH += $$PWD/include/external
win32 {
QMAKE_CXXFLAGS += -bigobj
LIBS += \
-lcrypt32 \
!contains(QMAKE_TARGET.arch, x86_64) {
INCLUDEPATH += $$PWD/windows/x86
HEADERS += $$PWD/windows/x86/botan_all.h
SOURCES += $$PWD/windows/x86/botan_all.cpp
}
else {
INCLUDEPATH += $$PWD/windows/x86_64
HEADERS += $$PWD/windows/x86_64/botan_all.h
SOURCES += $$PWD/windows/x86_64/botan_all.cpp
}
}
macx:!ios {
INCLUDEPATH += $$PWD/macos
HEADERS += $$PWD/macos/botan_all.h
SOURCES += $$PWD/macos/botan_all.cpp
}
linux-g++ {
INCLUDEPATH += $$PWD/linux
HEADERS += $$PWD/linux/botan_all.h
SOURCES += $$PWD/linux/botan_all.cpp
LIBS += -ldl
}
android {
versionAtLeast(QT_VERSION, 6.0.0) {
# We need to include qtprivate api's
# As QAndroidBinder is not yet implemented with a public api
QT+=core-private
ANDROID_ABIS=ANDROID_TARGET_ARCH
INCLUDEPATH += $$PWD/android/$${ANDROID_TARGET_ARCH}
HEADERS += $$PWD/android/$${ANDROID_TARGET_ARCH}/botan_all.h
SOURCES += $$PWD/android/$${ANDROID_TARGET_ARCH}/botan_all.cpp
}
else {
QT += androidextras
for (abi, ANDROID_ABIS): {
equals(ANDROID_TARGET_ARCH,$$abi) {
INCLUDEPATH += $$PWD/android/$${abi}
HEADERS += $$PWD/android/$${abi}/botan_all.h
SOURCES += $$PWD/android/$${abi}/botan_all.cpp
}
}
}
}
ios: {
CONFIG(iphoneos, iphoneos|iphonesimulator) {
contains(QT_ARCH, arm64) {
INCLUDEPATH += $$PWD/ios/iphone
HEADERS += $$PWD/ios/iphone/botan_all.h
SOURCES += $$PWD/ios/iphone/botan_all.cpp
} else {
message("Building for iOS/ARM v7 (32-bit) architecture")
ARCH_TAG = "ios_armv7"
}
}
CONFIG(iphonesimulator, iphoneos|iphonesimulator) {
INCLUDEPATH += $$PWD/ios/iphone
HEADERS += $$PWD/ios/iphone/botan_all.h
SOURCES += $$PWD/ios/iphone/botan_all.cpp
}
# CONFIG(iphonesimulator, iphoneos|iphonesimulator) {
# INCLUDEPATH += $$PWD/ios/simulator
# HEADERS += $$PWD/ios/simulator/botan_all.h
# SOURCES += $$PWD/ios/simulator/botan_all.cpp
# }
}

View file

@ -1,264 +0,0 @@
/*
* PKCS #11 Cryptographic Token Interface Base Specification Version 2.40 Errata 01
* Committee Specification Draft 01 / Public Review Draft 01
* 09 December 2015
* Copyright (c) OASIS Open 2015. All Rights Reserved.
* Source: http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/errata01/csprd01/include/pkcs11-v2.40/
* Latest version of the specification: http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html
* https://www.oasis-open.org/policies-guidelines/ipr
*/
#ifndef _PKCS11_H_
#define _PKCS11_H_ 1
#ifdef __cplusplus
extern "C" {
#endif
/* Before including this file (pkcs11.h) (or pkcs11t.h by
* itself), 5 platform-specific macros must be defined. These
* macros are described below, and typical definitions for them
* are also given. Be advised that these definitions can depend
* on both the platform and the compiler used (and possibly also
* on whether a Cryptoki library is linked statically or
* dynamically).
*
* In addition to defining these 5 macros, the packing convention
* for Cryptoki structures should be set. The Cryptoki
* convention on packing is that structures should be 1-byte
* aligned.
*
* If you're using Microsoft Developer Studio 5.0 to produce
* Win32 stuff, this might be done by using the following
* preprocessor directive before including pkcs11.h or pkcs11t.h:
*
* #pragma pack(push, cryptoki, 1)
*
* and using the following preprocessor directive after including
* pkcs11.h or pkcs11t.h:
*
* #pragma pack(pop, cryptoki)
*
* If you're using an earlier version of Microsoft Developer
* Studio to produce Win16 stuff, this might be done by using
* the following preprocessor directive before including
* pkcs11.h or pkcs11t.h:
*
* #pragma pack(1)
*
* In a UNIX environment, you're on your own for this. You might
* not need to do (or be able to do!) anything.
*
*
* Now for the macros:
*
*
* 1. CK_PTR: The indirection string for making a pointer to an
* object. It can be used like this:
*
* typedef CK_BYTE CK_PTR CK_BYTE_PTR;
*
* If you're using Microsoft Developer Studio 5.0 to produce
* Win32 stuff, it might be defined by:
*
* #define CK_PTR *
*
* If you're using an earlier version of Microsoft Developer
* Studio to produce Win16 stuff, it might be defined by:
*
* #define CK_PTR far *
*
* In a typical UNIX environment, it might be defined by:
*
* #define CK_PTR *
*
*
* 2. CK_DECLARE_FUNCTION(returnType, name): A macro which makes
* an importable Cryptoki library function declaration out of a
* return type and a function name. It should be used in the
* following fashion:
*
* extern CK_DECLARE_FUNCTION(CK_RV, C_Initialize)(
* CK_VOID_PTR pReserved
* );
*
* If you're using Microsoft Developer Studio 5.0 to declare a
* function in a Win32 Cryptoki .dll, it might be defined by:
*
* #define CK_DECLARE_FUNCTION(returnType, name) \
* returnType __declspec(dllimport) name
*
* If you're using an earlier version of Microsoft Developer
* Studio to declare a function in a Win16 Cryptoki .dll, it
* might be defined by:
*
* #define CK_DECLARE_FUNCTION(returnType, name) \
* returnType __export _far _pascal name
*
* In a UNIX environment, it might be defined by:
*
* #define CK_DECLARE_FUNCTION(returnType, name) \
* returnType name
*
*
* 3. CK_DECLARE_FUNCTION_POINTER(returnType, name): A macro
* which makes a Cryptoki API function pointer declaration or
* function pointer type declaration out of a return type and a
* function name. It should be used in the following fashion:
*
* // Define funcPtr to be a pointer to a Cryptoki API function
* // taking arguments args and returning CK_RV.
* CK_DECLARE_FUNCTION_POINTER(CK_RV, funcPtr)(args);
*
* or
*
* // Define funcPtrType to be the type of a pointer to a
* // Cryptoki API function taking arguments args and returning
* // CK_RV, and then define funcPtr to be a variable of type
* // funcPtrType.
* typedef CK_DECLARE_FUNCTION_POINTER(CK_RV, funcPtrType)(args);
* funcPtrType funcPtr;
*
* If you're using Microsoft Developer Studio 5.0 to access
* functions in a Win32 Cryptoki .dll, in might be defined by:
*
* #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
* returnType __declspec(dllimport) (* name)
*
* If you're using an earlier version of Microsoft Developer
* Studio to access functions in a Win16 Cryptoki .dll, it might
* be defined by:
*
* #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
* returnType __export _far _pascal (* name)
*
* In a UNIX environment, it might be defined by:
*
* #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
* returnType (* name)
*
*
* 4. CK_CALLBACK_FUNCTION(returnType, name): A macro which makes
* a function pointer type for an application callback out of
* a return type for the callback and a name for the callback.
* It should be used in the following fashion:
*
* CK_CALLBACK_FUNCTION(CK_RV, myCallback)(args);
*
* to declare a function pointer, myCallback, to a callback
* which takes arguments args and returns a CK_RV. It can also
* be used like this:
*
* typedef CK_CALLBACK_FUNCTION(CK_RV, myCallbackType)(args);
* myCallbackType myCallback;
*
* If you're using Microsoft Developer Studio 5.0 to do Win32
* Cryptoki development, it might be defined by:
*
* #define CK_CALLBACK_FUNCTION(returnType, name) \
* returnType (* name)
*
* If you're using an earlier version of Microsoft Developer
* Studio to do Win16 development, it might be defined by:
*
* #define CK_CALLBACK_FUNCTION(returnType, name) \
* returnType _far _pascal (* name)
*
* In a UNIX environment, it might be defined by:
*
* #define CK_CALLBACK_FUNCTION(returnType, name) \
* returnType (* name)
*
*
* 5. NULL_PTR: This macro is the value of a NULL pointer.
*
* In any ANSI/ISO C environment (and in many others as well),
* this should best be defined by
*
* #ifndef NULL_PTR
* #define NULL_PTR 0
* #endif
*/
/* All the various Cryptoki types and #define'd values are in the
* file pkcs11t.h.
*/
#include "pkcs11t.h"
#define __PASTE(x,y) x##y
/* ==============================================================
* Define the "extern" form of all the entry points.
* ==============================================================
*/
#define CK_NEED_ARG_LIST 1
#define CK_PKCS11_FUNCTION_INFO(name) \
extern CK_DECLARE_FUNCTION(CK_RV, name)
/* pkcs11f.h has all the information about the Cryptoki
* function prototypes.
*/
#include "pkcs11f.h"
#undef CK_NEED_ARG_LIST
#undef CK_PKCS11_FUNCTION_INFO
/* ==============================================================
* Define the typedef form of all the entry points. That is, for
* each Cryptoki function C_XXX, define a type CK_C_XXX which is
* a pointer to that kind of function.
* ==============================================================
*/
#define CK_NEED_ARG_LIST 1
#define CK_PKCS11_FUNCTION_INFO(name) \
typedef CK_DECLARE_FUNCTION_POINTER(CK_RV, __PASTE(CK_,name))
/* pkcs11f.h has all the information about the Cryptoki
* function prototypes.
*/
#include "pkcs11f.h"
#undef CK_NEED_ARG_LIST
#undef CK_PKCS11_FUNCTION_INFO
/* ==============================================================
* Define structed vector of entry points. A CK_FUNCTION_LIST
* contains a CK_VERSION indicating a library's Cryptoki version
* and then a whole slew of function pointers to the routines in
* the library. This type was declared, but not defined, in
* pkcs11t.h.
* ==============================================================
*/
#define CK_PKCS11_FUNCTION_INFO(name) \
__PASTE(CK_,name) name;
struct CK_FUNCTION_LIST {
CK_VERSION version; /* Cryptoki version */
/* Pile all the function pointers into the CK_FUNCTION_LIST. */
/* pkcs11f.h has all the information about the Cryptoki
* function prototypes.
*/
#include "pkcs11f.h"
};
#undef CK_PKCS11_FUNCTION_INFO
#undef __PASTE
#ifdef __cplusplus
}
#endif
#endif /* _PKCS11_H_ */

View file

@ -1,938 +0,0 @@
/*
* PKCS #11 Cryptographic Token Interface Base Specification Version 2.40 Errata 01
* Committee Specification Draft 01 / Public Review Draft 01
* 09 December 2015
* Copyright (c) OASIS Open 2015. All Rights Reserved.
* Source: http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/errata01/csprd01/include/pkcs11-v2.40/
* Latest version of the specification: http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html
* https://www.oasis-open.org/policies-guidelines/ipr
*/
/* This header file contains pretty much everything about all the
* Cryptoki function prototypes. Because this information is
* used for more than just declaring function prototypes, the
* order of the functions appearing herein is important, and
* should not be altered.
*/
/* General-purpose */
/* C_Initialize initializes the Cryptoki library. */
CK_PKCS11_FUNCTION_INFO(C_Initialize)
#ifdef CK_NEED_ARG_LIST
(
CK_VOID_PTR pInitArgs /* if this is not NULL_PTR, it gets
* cast to CK_C_INITIALIZE_ARGS_PTR
* and dereferenced
*/
);
#endif
/* C_Finalize indicates that an application is done with the
* Cryptoki library.
*/
CK_PKCS11_FUNCTION_INFO(C_Finalize)
#ifdef CK_NEED_ARG_LIST
(
CK_VOID_PTR pReserved /* reserved. Should be NULL_PTR */
);
#endif
/* C_GetInfo returns general information about Cryptoki. */
CK_PKCS11_FUNCTION_INFO(C_GetInfo)
#ifdef CK_NEED_ARG_LIST
(
CK_INFO_PTR pInfo /* location that receives information */
);
#endif
/* C_GetFunctionList returns the function list. */
CK_PKCS11_FUNCTION_INFO(C_GetFunctionList)
#ifdef CK_NEED_ARG_LIST
(
CK_FUNCTION_LIST_PTR_PTR ppFunctionList /* receives pointer to
* function list
*/
);
#endif
/* Slot and token management */
/* C_GetSlotList obtains a list of slots in the system. */
CK_PKCS11_FUNCTION_INFO(C_GetSlotList)
#ifdef CK_NEED_ARG_LIST
(
CK_BBOOL tokenPresent, /* only slots with tokens */
CK_SLOT_ID_PTR pSlotList, /* receives array of slot IDs */
CK_ULONG_PTR pulCount /* receives number of slots */
);
#endif
/* C_GetSlotInfo obtains information about a particular slot in
* the system.
*/
CK_PKCS11_FUNCTION_INFO(C_GetSlotInfo)
#ifdef CK_NEED_ARG_LIST
(
CK_SLOT_ID slotID, /* the ID of the slot */
CK_SLOT_INFO_PTR pInfo /* receives the slot information */
);
#endif
/* C_GetTokenInfo obtains information about a particular token
* in the system.
*/
CK_PKCS11_FUNCTION_INFO(C_GetTokenInfo)
#ifdef CK_NEED_ARG_LIST
(
CK_SLOT_ID slotID, /* ID of the token's slot */
CK_TOKEN_INFO_PTR pInfo /* receives the token information */
);
#endif
/* C_GetMechanismList obtains a list of mechanism types
* supported by a token.
*/
CK_PKCS11_FUNCTION_INFO(C_GetMechanismList)
#ifdef CK_NEED_ARG_LIST
(
CK_SLOT_ID slotID, /* ID of token's slot */
CK_MECHANISM_TYPE_PTR pMechanismList, /* gets mech. array */
CK_ULONG_PTR pulCount /* gets # of mechs. */
);
#endif
/* C_GetMechanismInfo obtains information about a particular
* mechanism possibly supported by a token.
*/
CK_PKCS11_FUNCTION_INFO(C_GetMechanismInfo)
#ifdef CK_NEED_ARG_LIST
(
CK_SLOT_ID slotID, /* ID of the token's slot */
CK_MECHANISM_TYPE type, /* type of mechanism */
CK_MECHANISM_INFO_PTR pInfo /* receives mechanism info */
);
#endif
/* C_InitToken initializes a token. */
CK_PKCS11_FUNCTION_INFO(C_InitToken)
#ifdef CK_NEED_ARG_LIST
(
CK_SLOT_ID slotID, /* ID of the token's slot */
CK_UTF8CHAR_PTR pPin, /* the SO's initial PIN */
CK_ULONG ulPinLen, /* length in bytes of the PIN */
CK_UTF8CHAR_PTR pLabel /* 32-byte token label (blank padded) */
);
#endif
/* C_InitPIN initializes the normal user's PIN. */
CK_PKCS11_FUNCTION_INFO(C_InitPIN)
#ifdef CK_NEED_ARG_LIST
(
CK_SESSION_HANDLE hSession, /* the session's handle */
CK_UTF8CHAR_PTR pPin, /* the normal user's PIN */
CK_ULONG ulPinLen /* length in bytes of the PIN */
);
#endif
/* C_SetPIN modifies the PIN of the user who is logged in. */
CK_PKCS11_FUNCTION_INFO(C_SetPIN)
#ifdef CK_NEED_ARG_LIST
(
CK_SESSION_HANDLE hSession, /* the session's handle */
CK_UTF8CHAR_PTR pOldPin, /* the old PIN */
CK_ULONG ulOldLen, /* length of the old PIN */
CK_UTF8CHAR_PTR pNewPin, /* the new PIN */
CK_ULONG ulNewLen /* length of the new PIN */
);
#endif
/* Session management */
/* C_OpenSession opens a session between an application and a
* token.
*/
CK_PKCS11_FUNCTION_INFO(C_OpenSession)
#ifdef CK_NEED_ARG_LIST
(
CK_SLOT_ID slotID, /* the slot's ID */
CK_FLAGS flags, /* from CK_SESSION_INFO */
CK_VOID_PTR pApplication, /* passed to callback */
CK_NOTIFY Notify, /* callback function */
CK_SESSION_HANDLE_PTR phSession /* gets session handle */
);
#endif
/* C_CloseSession closes a session between an application and a
* token.
*/
CK_PKCS11_FUNCTION_INFO(C_CloseSession)
#ifdef CK_NEED_ARG_LIST
(
CK_SESSION_HANDLE hSession /* the session's handle */
);
#endif
/* C_CloseAllSessions closes all sessions with a token. */
CK_PKCS11_FUNCTION_INFO(C_CloseAllSessions)
#ifdef CK_NEED_ARG_LIST
(
CK_SLOT_ID slotID /* the token's slot */
);
#endif
/* C_GetSessionInfo obtains information about the session. */
CK_PKCS11_FUNCTION_INFO(C_GetSessionInfo)
#ifdef CK_NEED_ARG_LIST
(
CK_SESSION_HANDLE hSession, /* the session's handle */
CK_SESSION_INFO_PTR pInfo /* receives session info */
);
#endif
/* C_GetOperationState obtains the state of the cryptographic operation
* in a session.
*/
CK_PKCS11_FUNCTION_INFO(C_GetOperationState)
#ifdef CK_NEED_ARG_LIST
(
CK_SESSION_HANDLE hSession, /* session's handle */
CK_BYTE_PTR pOperationState, /* gets state */
CK_ULONG_PTR pulOperationStateLen /* gets state length */
);
#endif
/* C_SetOperationState restores the state of the cryptographic
* operation in a session.
*/
CK_PKCS11_FUNCTION_INFO(C_SetOperationState)
#ifdef CK_NEED_ARG_LIST
(
CK_SESSION_HANDLE hSession, /* session's handle */
CK_BYTE_PTR pOperationState, /* holds state */
CK_ULONG ulOperationStateLen, /* holds state length */
CK_OBJECT_HANDLE hEncryptionKey, /* en/decryption key */
CK_OBJECT_HANDLE hAuthenticationKey /* sign/verify key */
);
#endif
/* C_Login logs a user into a token. */
CK_PKCS11_FUNCTION_INFO(C_Login)
#ifdef CK_NEED_ARG_LIST
(
CK_SESSION_HANDLE hSession, /* the session's handle */
CK_USER_TYPE userType, /* the user type */
CK_UTF8CHAR_PTR pPin, /* the user's PIN */
CK_ULONG ulPinLen /* the length of the PIN */
);
#endif
/* C_Logout logs a user out from a token. */
CK_PKCS11_FUNCTION_INFO(C_Logout)
#ifdef CK_NEED_ARG_LIST
(
CK_SESSION_HANDLE hSession /* the session's handle */
);
#endif
/* Object management */
/* C_CreateObject creates a new object. */
CK_PKCS11_FUNCTION_INFO(C_CreateObject)
#ifdef CK_NEED_ARG_LIST
(
CK_SESSION_HANDLE hSession, /* the session's handle */
CK_ATTRIBUTE_PTR pTemplate, /* the object's template */
CK_ULONG ulCount, /* attributes in template */
CK_OBJECT_HANDLE_PTR phObject /* gets new object's handle. */
);
#endif
/* C_CopyObject copies an object, creating a new object for the
* copy.
*/
CK_PKCS11_FUNCTION_INFO(C_CopyObject)
#ifdef CK_NEED_ARG_LIST
(
CK_SESSION_HANDLE hSession, /* the session's handle */
CK_OBJECT_HANDLE hObject, /* the object's handle */
CK_ATTRIBUTE_PTR pTemplate, /* template for new object */
CK_ULONG ulCount, /* attributes in template */
CK_OBJECT_HANDLE_PTR phNewObject /* receives handle of copy */
);
#endif
/* C_DestroyObject destroys an object. */
CK_PKCS11_FUNCTION_INFO(C_DestroyObject)
#ifdef CK_NEED_ARG_LIST
(
CK_SESSION_HANDLE hSession, /* the session's handle */
CK_OBJECT_HANDLE hObject /* the object's handle */
);
#endif
/* C_GetObjectSize gets the size of an object in bytes. */
CK_PKCS11_FUNCTION_INFO(C_GetObjectSize)
#ifdef CK_NEED_ARG_LIST
(
CK_SESSION_HANDLE hSession, /* the session's handle */
CK_OBJECT_HANDLE hObject, /* the object's handle */
CK_ULONG_PTR pulSize /* receives size of object */
);
#endif
/* C_GetAttributeValue obtains the value of one or more object
* attributes.
*/
CK_PKCS11_FUNCTION_INFO(C_GetAttributeValue)
#ifdef CK_NEED_ARG_LIST
(
CK_SESSION_HANDLE hSession, /* the session's handle */
CK_OBJECT_HANDLE hObject, /* the object's handle */
CK_ATTRIBUTE_PTR pTemplate, /* specifies attrs; gets vals */
CK_ULONG ulCount /* attributes in template */
);
#endif
/* C_SetAttributeValue modifies the value of one or more object
* attributes.
*/
CK_PKCS11_FUNCTION_INFO(C_SetAttributeValue)
#ifdef CK_NEED_ARG_LIST
(
CK_SESSION_HANDLE hSession, /* the session's handle */
CK_OBJECT_HANDLE hObject, /* the object's handle */
CK_ATTRIBUTE_PTR pTemplate, /* specifies attrs and values */
CK_ULONG ulCount /* attributes in template */
);
#endif
/* C_FindObjectsInit initializes a search for token and session
* objects that match a template.
*/
CK_PKCS11_FUNCTION_INFO(C_FindObjectsInit)
#ifdef CK_NEED_ARG_LIST
(
CK_SESSION_HANDLE hSession, /* the session's handle */
CK_ATTRIBUTE_PTR pTemplate, /* attribute values to match */
CK_ULONG ulCount /* attrs in search template */
);
#endif
/* C_FindObjects continues a search for token and session
* objects that match a template, obtaining additional object
* handles.
*/
CK_PKCS11_FUNCTION_INFO(C_FindObjects)
#ifdef CK_NEED_ARG_LIST
(
CK_SESSION_HANDLE hSession, /* session's handle */
CK_OBJECT_HANDLE_PTR phObject, /* gets obj. handles */
CK_ULONG ulMaxObjectCount, /* max handles to get */
CK_ULONG_PTR pulObjectCount /* actual # returned */
);
#endif
/* C_FindObjectsFinal finishes a search for token and session
* objects.
*/
CK_PKCS11_FUNCTION_INFO(C_FindObjectsFinal)
#ifdef CK_NEED_ARG_LIST
(
CK_SESSION_HANDLE hSession /* the session's handle */
);
#endif
/* Encryption and decryption */
/* C_EncryptInit initializes an encryption operation. */
CK_PKCS11_FUNCTION_INFO(C_EncryptInit)
#ifdef CK_NEED_ARG_LIST
(
CK_SESSION_HANDLE hSession, /* the session's handle */
CK_MECHANISM_PTR pMechanism, /* the encryption mechanism */
CK_OBJECT_HANDLE hKey /* handle of encryption key */
);
#endif
/* C_Encrypt encrypts single-part data. */
CK_PKCS11_FUNCTION_INFO(C_Encrypt)
#ifdef CK_NEED_ARG_LIST
(
CK_SESSION_HANDLE hSession, /* session's handle */
CK_BYTE_PTR pData, /* the plaintext data */
CK_ULONG ulDataLen, /* bytes of plaintext */
CK_BYTE_PTR pEncryptedData, /* gets ciphertext */
CK_ULONG_PTR pulEncryptedDataLen /* gets c-text size */
);
#endif
/* C_EncryptUpdate continues a multiple-part encryption
* operation.
*/
CK_PKCS11_FUNCTION_INFO(C_EncryptUpdate)
#ifdef CK_NEED_ARG_LIST
(
CK_SESSION_HANDLE hSession, /* session's handle */
CK_BYTE_PTR pPart, /* the plaintext data */
CK_ULONG ulPartLen, /* plaintext data len */
CK_BYTE_PTR pEncryptedPart, /* gets ciphertext */
CK_ULONG_PTR pulEncryptedPartLen /* gets c-text size */
);
#endif
/* C_EncryptFinal finishes a multiple-part encryption
* operation.
*/
CK_PKCS11_FUNCTION_INFO(C_EncryptFinal)
#ifdef CK_NEED_ARG_LIST
(
CK_SESSION_HANDLE hSession, /* session handle */
CK_BYTE_PTR pLastEncryptedPart, /* last c-text */
CK_ULONG_PTR pulLastEncryptedPartLen /* gets last size */
);
#endif
/* C_DecryptInit initializes a decryption operation. */
CK_PKCS11_FUNCTION_INFO(C_DecryptInit)
#ifdef CK_NEED_ARG_LIST
(
CK_SESSION_HANDLE hSession, /* the session's handle */
CK_MECHANISM_PTR pMechanism, /* the decryption mechanism */
CK_OBJECT_HANDLE hKey /* handle of decryption key */
);
#endif
/* C_Decrypt decrypts encrypted data in a single part. */
CK_PKCS11_FUNCTION_INFO(C_Decrypt)
#ifdef CK_NEED_ARG_LIST
(
CK_SESSION_HANDLE hSession, /* session's handle */
CK_BYTE_PTR pEncryptedData, /* ciphertext */
CK_ULONG ulEncryptedDataLen, /* ciphertext length */
CK_BYTE_PTR pData, /* gets plaintext */
CK_ULONG_PTR pulDataLen /* gets p-text size */
);
#endif
/* C_DecryptUpdate continues a multiple-part decryption
* operation.
*/
CK_PKCS11_FUNCTION_INFO(C_DecryptUpdate)
#ifdef CK_NEED_ARG_LIST
(
CK_SESSION_HANDLE hSession, /* session's handle */
CK_BYTE_PTR pEncryptedPart, /* encrypted data */
CK_ULONG ulEncryptedPartLen, /* input length */
CK_BYTE_PTR pPart, /* gets plaintext */
CK_ULONG_PTR pulPartLen /* p-text size */
);
#endif
/* C_DecryptFinal finishes a multiple-part decryption
* operation.
*/
CK_PKCS11_FUNCTION_INFO(C_DecryptFinal)
#ifdef CK_NEED_ARG_LIST
(
CK_SESSION_HANDLE hSession, /* the session's handle */
CK_BYTE_PTR pLastPart, /* gets plaintext */
CK_ULONG_PTR pulLastPartLen /* p-text size */
);
#endif
/* Message digesting */
/* C_DigestInit initializes a message-digesting operation. */
CK_PKCS11_FUNCTION_INFO(C_DigestInit)
#ifdef CK_NEED_ARG_LIST
(
CK_SESSION_HANDLE hSession, /* the session's handle */
CK_MECHANISM_PTR pMechanism /* the digesting mechanism */
);
#endif
/* C_Digest digests data in a single part. */
CK_PKCS11_FUNCTION_INFO(C_Digest)
#ifdef CK_NEED_ARG_LIST
(
CK_SESSION_HANDLE hSession, /* the session's handle */
CK_BYTE_PTR pData, /* data to be digested */
CK_ULONG ulDataLen, /* bytes of data to digest */
CK_BYTE_PTR pDigest, /* gets the message digest */
CK_ULONG_PTR pulDigestLen /* gets digest length */
);
#endif
/* C_DigestUpdate continues a multiple-part message-digesting
* operation.
*/
CK_PKCS11_FUNCTION_INFO(C_DigestUpdate)
#ifdef CK_NEED_ARG_LIST
(
CK_SESSION_HANDLE hSession, /* the session's handle */
CK_BYTE_PTR pPart, /* data to be digested */
CK_ULONG ulPartLen /* bytes of data to be digested */
);
#endif
/* C_DigestKey continues a multi-part message-digesting
* operation, by digesting the value of a secret key as part of
* the data already digested.
*/
CK_PKCS11_FUNCTION_INFO(C_DigestKey)
#ifdef CK_NEED_ARG_LIST
(
CK_SESSION_HANDLE hSession, /* the session's handle */
CK_OBJECT_HANDLE hKey /* secret key to digest */
);
#endif
/* C_DigestFinal finishes a multiple-part message-digesting
* operation.
*/
CK_PKCS11_FUNCTION_INFO(C_DigestFinal)
#ifdef CK_NEED_ARG_LIST
(
CK_SESSION_HANDLE hSession, /* the session's handle */
CK_BYTE_PTR pDigest, /* gets the message digest */
CK_ULONG_PTR pulDigestLen /* gets byte count of digest */
);
#endif
/* Signing and MACing */
/* C_SignInit initializes a signature (private key encryption)
* operation, where the signature is (will be) an appendix to
* the data, and plaintext cannot be recovered from the
* signature.
*/
CK_PKCS11_FUNCTION_INFO(C_SignInit)
#ifdef CK_NEED_ARG_LIST
(
CK_SESSION_HANDLE hSession, /* the session's handle */
CK_MECHANISM_PTR pMechanism, /* the signature mechanism */
CK_OBJECT_HANDLE hKey /* handle of signature key */
);
#endif
/* C_Sign signs (encrypts with private key) data in a single
* part, where the signature is (will be) an appendix to the
* data, and plaintext cannot be recovered from the signature.
*/
CK_PKCS11_FUNCTION_INFO(C_Sign)
#ifdef CK_NEED_ARG_LIST
(
CK_SESSION_HANDLE hSession, /* the session's handle */
CK_BYTE_PTR pData, /* the data to sign */
CK_ULONG ulDataLen, /* count of bytes to sign */
CK_BYTE_PTR pSignature, /* gets the signature */
CK_ULONG_PTR pulSignatureLen /* gets signature length */
);
#endif
/* C_SignUpdate continues a multiple-part signature operation,
* where the signature is (will be) an appendix to the data,
* and plaintext cannot be recovered from the signature.
*/
CK_PKCS11_FUNCTION_INFO(C_SignUpdate)
#ifdef CK_NEED_ARG_LIST
(
CK_SESSION_HANDLE hSession, /* the session's handle */
CK_BYTE_PTR pPart, /* the data to sign */
CK_ULONG ulPartLen /* count of bytes to sign */
);
#endif
/* C_SignFinal finishes a multiple-part signature operation,
* returning the signature.
*/
CK_PKCS11_FUNCTION_INFO(C_SignFinal)
#ifdef CK_NEED_ARG_LIST
(
CK_SESSION_HANDLE hSession, /* the session's handle */
CK_BYTE_PTR pSignature, /* gets the signature */
CK_ULONG_PTR pulSignatureLen /* gets signature length */
);
#endif
/* C_SignRecoverInit initializes a signature operation, where
* the data can be recovered from the signature.
*/
CK_PKCS11_FUNCTION_INFO(C_SignRecoverInit)
#ifdef CK_NEED_ARG_LIST
(
CK_SESSION_HANDLE hSession, /* the session's handle */
CK_MECHANISM_PTR pMechanism, /* the signature mechanism */
CK_OBJECT_HANDLE hKey /* handle of the signature key */
);
#endif
/* C_SignRecover signs data in a single operation, where the
* data can be recovered from the signature.
*/
CK_PKCS11_FUNCTION_INFO(C_SignRecover)
#ifdef CK_NEED_ARG_LIST
(
CK_SESSION_HANDLE hSession, /* the session's handle */
CK_BYTE_PTR pData, /* the data to sign */
CK_ULONG ulDataLen, /* count of bytes to sign */
CK_BYTE_PTR pSignature, /* gets the signature */
CK_ULONG_PTR pulSignatureLen /* gets signature length */
);
#endif
/* Verifying signatures and MACs */
/* C_VerifyInit initializes a verification operation, where the
* signature is an appendix to the data, and plaintext cannot
* cannot be recovered from the signature (e.g. DSA).
*/
CK_PKCS11_FUNCTION_INFO(C_VerifyInit)
#ifdef CK_NEED_ARG_LIST
(
CK_SESSION_HANDLE hSession, /* the session's handle */
CK_MECHANISM_PTR pMechanism, /* the verification mechanism */
CK_OBJECT_HANDLE hKey /* verification key */
);
#endif
/* C_Verify verifies a signature in a single-part operation,
* where the signature is an appendix to the data, and plaintext
* cannot be recovered from the signature.
*/
CK_PKCS11_FUNCTION_INFO(C_Verify)
#ifdef CK_NEED_ARG_LIST
(
CK_SESSION_HANDLE hSession, /* the session's handle */
CK_BYTE_PTR pData, /* signed data */
CK_ULONG ulDataLen, /* length of signed data */
CK_BYTE_PTR pSignature, /* signature */
CK_ULONG ulSignatureLen /* signature length*/
);
#endif
/* C_VerifyUpdate continues a multiple-part verification
* operation, where the signature is an appendix to the data,
* and plaintext cannot be recovered from the signature.
*/
CK_PKCS11_FUNCTION_INFO(C_VerifyUpdate)
#ifdef CK_NEED_ARG_LIST
(
CK_SESSION_HANDLE hSession, /* the session's handle */
CK_BYTE_PTR pPart, /* signed data */
CK_ULONG ulPartLen /* length of signed data */
);
#endif
/* C_VerifyFinal finishes a multiple-part verification
* operation, checking the signature.
*/
CK_PKCS11_FUNCTION_INFO(C_VerifyFinal)
#ifdef CK_NEED_ARG_LIST
(
CK_SESSION_HANDLE hSession, /* the session's handle */
CK_BYTE_PTR pSignature, /* signature to verify */
CK_ULONG ulSignatureLen /* signature length */
);
#endif
/* C_VerifyRecoverInit initializes a signature verification
* operation, where the data is recovered from the signature.
*/
CK_PKCS11_FUNCTION_INFO(C_VerifyRecoverInit)
#ifdef CK_NEED_ARG_LIST
(
CK_SESSION_HANDLE hSession, /* the session's handle */
CK_MECHANISM_PTR pMechanism, /* the verification mechanism */
CK_OBJECT_HANDLE hKey /* verification key */
);
#endif
/* C_VerifyRecover verifies a signature in a single-part
* operation, where the data is recovered from the signature.
*/
CK_PKCS11_FUNCTION_INFO(C_VerifyRecover)
#ifdef CK_NEED_ARG_LIST
(
CK_SESSION_HANDLE hSession, /* the session's handle */
CK_BYTE_PTR pSignature, /* signature to verify */
CK_ULONG ulSignatureLen, /* signature length */
CK_BYTE_PTR pData, /* gets signed data */
CK_ULONG_PTR pulDataLen /* gets signed data len */
);
#endif
/* Dual-function cryptographic operations */
/* C_DigestEncryptUpdate continues a multiple-part digesting
* and encryption operation.
*/
CK_PKCS11_FUNCTION_INFO(C_DigestEncryptUpdate)
#ifdef CK_NEED_ARG_LIST
(
CK_SESSION_HANDLE hSession, /* session's handle */
CK_BYTE_PTR pPart, /* the plaintext data */
CK_ULONG ulPartLen, /* plaintext length */
CK_BYTE_PTR pEncryptedPart, /* gets ciphertext */
CK_ULONG_PTR pulEncryptedPartLen /* gets c-text length */
);
#endif
/* C_DecryptDigestUpdate continues a multiple-part decryption and
* digesting operation.
*/
CK_PKCS11_FUNCTION_INFO(C_DecryptDigestUpdate)
#ifdef CK_NEED_ARG_LIST
(
CK_SESSION_HANDLE hSession, /* session's handle */
CK_BYTE_PTR pEncryptedPart, /* ciphertext */
CK_ULONG ulEncryptedPartLen, /* ciphertext length */
CK_BYTE_PTR pPart, /* gets plaintext */
CK_ULONG_PTR pulPartLen /* gets plaintext len */
);
#endif
/* C_SignEncryptUpdate continues a multiple-part signing and
* encryption operation.
*/
CK_PKCS11_FUNCTION_INFO(C_SignEncryptUpdate)
#ifdef CK_NEED_ARG_LIST
(
CK_SESSION_HANDLE hSession, /* session's handle */
CK_BYTE_PTR pPart, /* the plaintext data */
CK_ULONG ulPartLen, /* plaintext length */
CK_BYTE_PTR pEncryptedPart, /* gets ciphertext */
CK_ULONG_PTR pulEncryptedPartLen /* gets c-text length */
);
#endif
/* C_DecryptVerifyUpdate continues a multiple-part decryption and
* verify operation.
*/
CK_PKCS11_FUNCTION_INFO(C_DecryptVerifyUpdate)
#ifdef CK_NEED_ARG_LIST
(
CK_SESSION_HANDLE hSession, /* session's handle */
CK_BYTE_PTR pEncryptedPart, /* ciphertext */
CK_ULONG ulEncryptedPartLen, /* ciphertext length */
CK_BYTE_PTR pPart, /* gets plaintext */
CK_ULONG_PTR pulPartLen /* gets p-text length */
);
#endif
/* Key management */
/* C_GenerateKey generates a secret key, creating a new key
* object.
*/
CK_PKCS11_FUNCTION_INFO(C_GenerateKey)
#ifdef CK_NEED_ARG_LIST
(
CK_SESSION_HANDLE hSession, /* the session's handle */
CK_MECHANISM_PTR pMechanism, /* key generation mech. */
CK_ATTRIBUTE_PTR pTemplate, /* template for new key */
CK_ULONG ulCount, /* # of attrs in template */
CK_OBJECT_HANDLE_PTR phKey /* gets handle of new key */
);
#endif
/* C_GenerateKeyPair generates a public-key/private-key pair,
* creating new key objects.
*/
CK_PKCS11_FUNCTION_INFO(C_GenerateKeyPair)
#ifdef CK_NEED_ARG_LIST
(
CK_SESSION_HANDLE hSession, /* session handle */
CK_MECHANISM_PTR pMechanism, /* key-gen mech. */
CK_ATTRIBUTE_PTR pPublicKeyTemplate, /* template for pub. key */
CK_ULONG ulPublicKeyAttributeCount, /* # pub. attrs. */
CK_ATTRIBUTE_PTR pPrivateKeyTemplate, /* template for priv. key */
CK_ULONG ulPrivateKeyAttributeCount, /* # priv. attrs. */
CK_OBJECT_HANDLE_PTR phPublicKey, /* gets pub. key handle */
CK_OBJECT_HANDLE_PTR phPrivateKey /* gets priv. key handle */
);
#endif
/* C_WrapKey wraps (i.e., encrypts) a key. */
CK_PKCS11_FUNCTION_INFO(C_WrapKey)
#ifdef CK_NEED_ARG_LIST
(
CK_SESSION_HANDLE hSession, /* the session's handle */
CK_MECHANISM_PTR pMechanism, /* the wrapping mechanism */
CK_OBJECT_HANDLE hWrappingKey, /* wrapping key */
CK_OBJECT_HANDLE hKey, /* key to be wrapped */
CK_BYTE_PTR pWrappedKey, /* gets wrapped key */
CK_ULONG_PTR pulWrappedKeyLen /* gets wrapped key size */
);
#endif
/* C_UnwrapKey unwraps (decrypts) a wrapped key, creating a new
* key object.
*/
CK_PKCS11_FUNCTION_INFO(C_UnwrapKey)
#ifdef CK_NEED_ARG_LIST
(
CK_SESSION_HANDLE hSession, /* session's handle */
CK_MECHANISM_PTR pMechanism, /* unwrapping mech. */
CK_OBJECT_HANDLE hUnwrappingKey, /* unwrapping key */
CK_BYTE_PTR pWrappedKey, /* the wrapped key */
CK_ULONG ulWrappedKeyLen, /* wrapped key len */
CK_ATTRIBUTE_PTR pTemplate, /* new key template */
CK_ULONG ulAttributeCount, /* template length */
CK_OBJECT_HANDLE_PTR phKey /* gets new handle */
);
#endif
/* C_DeriveKey derives a key from a base key, creating a new key
* object.
*/
CK_PKCS11_FUNCTION_INFO(C_DeriveKey)
#ifdef CK_NEED_ARG_LIST
(
CK_SESSION_HANDLE hSession, /* session's handle */
CK_MECHANISM_PTR pMechanism, /* key deriv. mech. */
CK_OBJECT_HANDLE hBaseKey, /* base key */
CK_ATTRIBUTE_PTR pTemplate, /* new key template */
CK_ULONG ulAttributeCount, /* template length */
CK_OBJECT_HANDLE_PTR phKey /* gets new handle */
);
#endif
/* Random number generation */
/* C_SeedRandom mixes additional seed material into the token's
* random number generator.
*/
CK_PKCS11_FUNCTION_INFO(C_SeedRandom)
#ifdef CK_NEED_ARG_LIST
(
CK_SESSION_HANDLE hSession, /* the session's handle */
CK_BYTE_PTR pSeed, /* the seed material */
CK_ULONG ulSeedLen /* length of seed material */
);
#endif
/* C_GenerateRandom generates random data. */
CK_PKCS11_FUNCTION_INFO(C_GenerateRandom)
#ifdef CK_NEED_ARG_LIST
(
CK_SESSION_HANDLE hSession, /* the session's handle */
CK_BYTE_PTR RandomData, /* receives the random data */
CK_ULONG ulRandomLen /* # of bytes to generate */
);
#endif
/* Parallel function management */
/* C_GetFunctionStatus is a legacy function; it obtains an
* updated status of a function running in parallel with an
* application.
*/
CK_PKCS11_FUNCTION_INFO(C_GetFunctionStatus)
#ifdef CK_NEED_ARG_LIST
(
CK_SESSION_HANDLE hSession /* the session's handle */
);
#endif
/* C_CancelFunction is a legacy function; it cancels a function
* running in parallel.
*/
CK_PKCS11_FUNCTION_INFO(C_CancelFunction)
#ifdef CK_NEED_ARG_LIST
(
CK_SESSION_HANDLE hSession /* the session's handle */
);
#endif
/* C_WaitForSlotEvent waits for a slot event (token insertion,
* removal, etc.) to occur.
*/
CK_PKCS11_FUNCTION_INFO(C_WaitForSlotEvent)
#ifdef CK_NEED_ARG_LIST
(
CK_FLAGS flags, /* blocking/nonblocking flag */
CK_SLOT_ID_PTR pSlot, /* location that receives the slot ID */
CK_VOID_PTR pRserved /* reserved. Should be NULL_PTR */
);
#endif

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 862 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 430 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 345 B

View file

@ -1,200 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "opensshkeyfilereader_p.h"
#include "sshcapabilities_p.h"
#include "ssherrors.h"
#include "sshexception_p.h"
#include "sshlogging_p.h"
#include "sshpacketparser_p.h"
#include "ssh_global.h"
#include <botan_all.h>
#include <memory>
namespace QSsh {
namespace Internal {
using namespace Botan;
bool OpenSshKeyFileReader::parseKey(const QByteArray &privKeyFileContents)
{
static const QByteArray magicPrefix = "-----BEGIN OPENSSH PRIVATE KEY-----\n";
static const QByteArray magicSuffix = "-----END OPENSSH PRIVATE KEY-----\n";
if (!privKeyFileContents.startsWith(magicPrefix)) {
qCDebug(sshLog) << "not an OpenSSH key file: prefix does not match";
return false;
}
if (!privKeyFileContents.endsWith(magicSuffix))
throwException(SSH_TR("Unexpected end-of-file marker."));
const QByteArray payload = QByteArray::fromBase64
(privKeyFileContents.mid(magicPrefix.size(), privKeyFileContents.size()
- magicPrefix.size() - magicSuffix.size()));
doParse(payload);
return true;
}
std::unique_ptr<Private_Key> OpenSshKeyFileReader::privateKey() const
{
if (m_keyType == SshCapabilities::PubKeyRsa) {
QSSH_ASSERT_AND_RETURN_VALUE(m_parameters.size() == 5, nullptr);
const BigInt &e = m_parameters.at(0);
const BigInt &n = m_parameters.at(1);
const BigInt &p = m_parameters.at(2);
const BigInt &q = m_parameters.at(3);
const BigInt &d = m_parameters.at(4);
return std::make_unique<RSA_PrivateKey>(p, q, e, d, n);
} else if (m_keyType == SshCapabilities::PubKeyDss) {
QSSH_ASSERT_AND_RETURN_VALUE(m_parameters.size() == 5, nullptr);
const BigInt &p = m_parameters.at(0);
const BigInt &q = m_parameters.at(1);
const BigInt &g = m_parameters.at(2);
const BigInt &x = m_parameters.at(4);
return std::make_unique<DSA_PrivateKey>(m_rng, DL_Group(p, q, g), x);
} else if (m_keyType.startsWith(SshCapabilities::PubKeyEcdsaPrefix)) {
QSSH_ASSERT_AND_RETURN_VALUE(m_parameters.size() == 1, nullptr);
const BigInt &value = m_parameters.first();
const EC_Group group(SshCapabilities::oid(m_keyType));
return std::make_unique<ECDSA_PrivateKey>(m_rng, group, value);
}
QSSH_ASSERT_AND_RETURN_VALUE(false, nullptr);
}
QList<BigInt> OpenSshKeyFileReader::publicParameters() const
{
if (m_keyType == SshCapabilities::PubKeyRsa)
return m_parameters.mid(0, 2);
if (m_keyType == SshCapabilities::PubKeyDss)
return m_parameters.mid(0, 4);
if (m_keyType.startsWith(SshCapabilities::PubKeyEcdsaPrefix))
return QList<BigInt>();
QSSH_ASSERT_AND_RETURN_VALUE(false, QList<BigInt>());
}
void OpenSshKeyFileReader::doParse(const QByteArray &payload)
{
// See PROTOCOL.key in OpenSSH sources.
static const QByteArray magicString = "openssh-key-v1";
if (!payload.startsWith(magicString))
throwException(SSH_TR("Unexpected magic string."));
try {
quint32 offset = magicString.size() + 1; // null byte
m_cipherName = SshPacketParser::asString(payload, &offset);
qCDebug(sshLog) << "cipher:" << m_cipherName;
m_kdf = SshPacketParser::asString(payload, &offset);
qCDebug(sshLog) << "kdf:" << m_kdf;
parseKdfOptions(SshPacketParser::asString(payload, &offset));
const quint32 keyCount = SshPacketParser::asUint32(payload, &offset);
if (keyCount != 1) {
qCWarning(sshLog) << "more than one key found in OpenSSH private key file, ignoring "
"all but the first one";
}
for (quint32 i = 0; i < keyCount; ++i) // Skip the public key blob(s).
SshPacketParser::asString(payload, &offset);
m_privateKeyList = SshPacketParser::asString(payload, &offset);
decryptPrivateKeyList();
parsePrivateKeyList();
} catch (const SshPacketParseException &) {
throwException(SSH_TR("Parse error."));
} catch (const Exception &e) {
throwException(QLatin1String(e.what()));
}
}
void OpenSshKeyFileReader::parseKdfOptions(const QByteArray &kdfOptions)
{
if (m_cipherName == "none")
return;
quint32 offset = 0;
m_salt = SshPacketParser::asString(kdfOptions, &offset);
if (m_salt.size() != 16)
throwException(SSH_TR("Invalid salt size %1.").arg(m_salt.size()));
m_rounds = SshPacketParser::asUint32(kdfOptions, &offset);
qCDebug(sshLog) << "salt:" << m_salt.toHex();
qCDebug(sshLog) << "rounds:" << m_rounds;
}
void OpenSshKeyFileReader::decryptPrivateKeyList()
{
if (m_cipherName == "none")
return;
if (m_kdf != "bcrypt") {
throwException(SSH_TR("Unexpected key derivation function '%1'.")
.arg(QLatin1String(m_kdf)));
}
// OpenSSH uses a proprietary algorithm for the key derivation. We'd basically have to
// copy the code.
// TODO: If the lower-level operations (hashing primitives, blowfish stuff) can be taken
// over by Botan, that might be feasible. Investigate.
throwException(SSH_TR("Encrypted keys are currently not supported in this format."));
}
void OpenSshKeyFileReader::parsePrivateKeyList()
{
quint32 offset = 0;
const quint32 checkInt1 = SshPacketParser::asUint32(m_privateKeyList, &offset);
const quint32 checkInt2 = SshPacketParser::asUint32(m_privateKeyList, &offset);
if (checkInt1 != checkInt2)
throwException(SSH_TR("Verification failed."));
m_keyType = SshPacketParser::asString(m_privateKeyList, &offset);
qCDebug(sshLog) << "key type:" << m_keyType;
if (m_keyType == SshCapabilities::PubKeyRsa) {
const BigInt n = SshPacketParser::asBigInt(m_privateKeyList, &offset);
const BigInt e = SshPacketParser::asBigInt(m_privateKeyList, &offset);
const BigInt d = SshPacketParser::asBigInt(m_privateKeyList, &offset);
SshPacketParser::asBigInt(m_privateKeyList, &offset); // iqmp
const BigInt p = SshPacketParser::asBigInt(m_privateKeyList, &offset);
const BigInt q = SshPacketParser::asBigInt(m_privateKeyList, &offset);
m_parameters = QList<BigInt>{e, n, p, q, d};
} else if (m_keyType == SshCapabilities::PubKeyDss) {
const BigInt p = SshPacketParser::asBigInt(m_privateKeyList, &offset);
const BigInt q = SshPacketParser::asBigInt(m_privateKeyList, &offset);
const BigInt g = SshPacketParser::asBigInt(m_privateKeyList, &offset);
const BigInt y = SshPacketParser::asBigInt(m_privateKeyList, &offset);
const BigInt x = SshPacketParser::asBigInt(m_privateKeyList, &offset);
m_parameters = QList<BigInt>{p, q, g, y, x};
} else if (m_keyType.startsWith(SshCapabilities::PubKeyEcdsaPrefix)) {
SshPacketParser::asString(m_privateKeyList, &offset); // name
SshPacketParser::asString(m_privateKeyList, &offset); // pubkey representation
m_parameters = {SshPacketParser::asBigInt(m_privateKeyList, &offset)};
} else {
throwException(SSH_TR("Private key type '%1' is not supported.")
.arg(QString::fromLatin1(m_keyType)));
}
const QByteArray comment = SshPacketParser::asString(m_privateKeyList, &offset);
qCDebug(sshLog) << "comment:" << comment;
}
void OpenSshKeyFileReader::throwException(const QString &reason)
{
throw SshClientException(SshKeyFileError,
SSH_TR("Processing OpenSSH private key file failed: %1").arg(reason));
}
} // namespace Internal
} // namespace QSsh

View file

@ -1,73 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <QByteArray>
#include <QList>
#include <botan_all.h>
#include <memory>
namespace Botan {
class Private_Key;
class RandomNumberGenerator;
}
namespace QSsh {
namespace Internal {
class OpenSshKeyFileReader
{
public:
OpenSshKeyFileReader(Botan::RandomNumberGenerator &rng) : m_rng(rng) {}
bool parseKey(const QByteArray &privKeyFileContents);
QByteArray keyType() const { return m_keyType; }
std::unique_ptr<Botan::Private_Key> privateKey() const;
QList<Botan::BigInt> allParameters() const { return m_parameters; }
QList<Botan::BigInt> publicParameters() const;
private:
void doParse(const QByteArray &payload);
void parseKdfOptions(const QByteArray &kdfOptions);
void decryptPrivateKeyList();
void parsePrivateKeyList();
[[noreturn]] void throwException(const QString &reason);
Botan::RandomNumberGenerator &m_rng;
QByteArray m_keyType;
QList<Botan::BigInt> m_parameters;
QByteArray m_cipherName;
QByteArray m_kdf;
QByteArray m_salt;
quint32 m_rounds;
QByteArray m_privateKeyList;
};
} // namespace Internal
} // namespace QSsh

View file

@ -1,96 +0,0 @@
include_directories(${CMAKE_CURRENT_LIST_DIR})
find_package(Qt6 REQUIRED COMPONENTS
Widgets Gui Network Core5Compat
)
set(LIBS ${LIBS} Qt6::Widgets Qt6::Gui Qt6::Network Qt6::Core5Compat)
set(SOURCES ${SOURCES}
${CMAKE_CURRENT_LIST_DIR}/sshsendfacility.cpp
${CMAKE_CURRENT_LIST_DIR}/sshremoteprocess.cpp
${CMAKE_CURRENT_LIST_DIR}/sshpacketparser.cpp
${CMAKE_CURRENT_LIST_DIR}/sshpacket.cpp
${CMAKE_CURRENT_LIST_DIR}/sshoutgoingpacket.cpp
${CMAKE_CURRENT_LIST_DIR}/sshkeygenerator.cpp
${CMAKE_CURRENT_LIST_DIR}/sshkeyexchange.cpp
${CMAKE_CURRENT_LIST_DIR}/sshincomingpacket.cpp
${CMAKE_CURRENT_LIST_DIR}/sshcryptofacility.cpp
${CMAKE_CURRENT_LIST_DIR}/sshconnection.cpp
${CMAKE_CURRENT_LIST_DIR}/sshchannelmanager.cpp
${CMAKE_CURRENT_LIST_DIR}/sshchannel.cpp
${CMAKE_CURRENT_LIST_DIR}/sshcapabilities.cpp
${CMAKE_CURRENT_LIST_DIR}/sftppacket.cpp
${CMAKE_CURRENT_LIST_DIR}/sftpoutgoingpacket.cpp
${CMAKE_CURRENT_LIST_DIR}/sftpoperation.cpp
${CMAKE_CURRENT_LIST_DIR}/sftpincomingpacket.cpp
${CMAKE_CURRENT_LIST_DIR}/sftpdefs.cpp
${CMAKE_CURRENT_LIST_DIR}/sftpchannel.cpp
${CMAKE_CURRENT_LIST_DIR}/sshremoteprocessrunner.cpp
${CMAKE_CURRENT_LIST_DIR}/sshconnectionmanager.cpp
${CMAKE_CURRENT_LIST_DIR}/sshkeypasswordretriever.cpp
${CMAKE_CURRENT_LIST_DIR}/sftpfilesystemmodel.cpp
${CMAKE_CURRENT_LIST_DIR}/sshdirecttcpiptunnel.cpp
${CMAKE_CURRENT_LIST_DIR}/sshhostkeydatabase.cpp
${CMAKE_CURRENT_LIST_DIR}/sshlogging.cpp
${CMAKE_CURRENT_LIST_DIR}/sshtcpipforwardserver.cpp
${CMAKE_CURRENT_LIST_DIR}/sshtcpiptunnel.cpp
${CMAKE_CURRENT_LIST_DIR}/sshforwardedtcpiptunnel.cpp
${CMAKE_CURRENT_LIST_DIR}/sshagent.cpp
${CMAKE_CURRENT_LIST_DIR}/sshx11channel.cpp
${CMAKE_CURRENT_LIST_DIR}/sshx11inforetriever.cpp
${CMAKE_CURRENT_LIST_DIR}/opensshkeyfilereader.cpp
)
set(PUBLIC_HEADERS ${PUBLIC_HEADERS}
${CMAKE_CURRENT_LIST_DIR}/sftpdefs.h
${CMAKE_CURRENT_LIST_DIR}/ssherrors.h
${CMAKE_CURRENT_LIST_DIR}/sshremoteprocess.h
${CMAKE_CURRENT_LIST_DIR}/sftpchannel.h
${CMAKE_CURRENT_LIST_DIR}/sshkeygenerator.h
${CMAKE_CURRENT_LIST_DIR}/sshremoteprocessrunner.h
${CMAKE_CURRENT_LIST_DIR}/sshconnectionmanager.h
${CMAKE_CURRENT_LIST_DIR}/sshpseudoterminal.h
${CMAKE_CURRENT_LIST_DIR}/sftpfilesystemmodel.h
${CMAKE_CURRENT_LIST_DIR}/sshdirecttcpiptunnel.h
${CMAKE_CURRENT_LIST_DIR}/sshtcpipforwardserver.h
${CMAKE_CURRENT_LIST_DIR}/sshhostkeydatabase.h
${CMAKE_CURRENT_LIST_DIR}/sshforwardedtcpiptunnel.h
${CMAKE_CURRENT_LIST_DIR}/ssh_global.h
${CMAKE_CURRENT_LIST_DIR}/sshconnection.h
)
set(HEADERS ${HEADERS}
${PUBLIC_HEADERS}
${CMAKE_CURRENT_LIST_DIR}/sshsendfacility_p.h
${CMAKE_CURRENT_LIST_DIR}/sshremoteprocess_p.h
${CMAKE_CURRENT_LIST_DIR}/sshpacketparser_p.h
${CMAKE_CURRENT_LIST_DIR}/sshpacket_p.h
${CMAKE_CURRENT_LIST_DIR}/sshoutgoingpacket_p.h
${CMAKE_CURRENT_LIST_DIR}/sshkeyexchange_p.h
${CMAKE_CURRENT_LIST_DIR}/sshincomingpacket_p.h
${CMAKE_CURRENT_LIST_DIR}/sshexception_p.h
${CMAKE_CURRENT_LIST_DIR}/sshcryptofacility_p.h
${CMAKE_CURRENT_LIST_DIR}/sshconnection_p.h
${CMAKE_CURRENT_LIST_DIR}/sshchannelmanager_p.h
${CMAKE_CURRENT_LIST_DIR}/sshchannel_p.h
${CMAKE_CURRENT_LIST_DIR}/sshcapabilities_p.h
${CMAKE_CURRENT_LIST_DIR}/sshbotanconversions_p.h
${CMAKE_CURRENT_LIST_DIR}/sftppacket_p.h
${CMAKE_CURRENT_LIST_DIR}/sftpoutgoingpacket_p.h
${CMAKE_CURRENT_LIST_DIR}/sftpoperation_p.h
${CMAKE_CURRENT_LIST_DIR}/sftpincomingpacket_p.h
${CMAKE_CURRENT_LIST_DIR}/sftpchannel_p.h
${CMAKE_CURRENT_LIST_DIR}/sshkeypasswordretriever_p.h
${CMAKE_CURRENT_LIST_DIR}/sshdirecttcpiptunnel_p.h
${CMAKE_CURRENT_LIST_DIR}/sshlogging_p.h
${CMAKE_CURRENT_LIST_DIR}/sshtcpipforwardserver_p.h
${CMAKE_CURRENT_LIST_DIR}/sshtcpiptunnel_p.h
${CMAKE_CURRENT_LIST_DIR}/sshforwardedtcpiptunnel_p.h
${CMAKE_CURRENT_LIST_DIR}/sshagent_p.h
${CMAKE_CURRENT_LIST_DIR}/sshx11channel_p.h
${CMAKE_CURRENT_LIST_DIR}/sshx11displayinfo_p.h
${CMAKE_CURRENT_LIST_DIR}/sshx11inforetriever_p.h
${CMAKE_CURRENT_LIST_DIR}/opensshkeyfilereader_p.h
)
# qt6_add_resources(QRC ${QRC} ${CMAKE_CURRENT_LIST_DIR}/qssh.qrc)

View file

@ -1,98 +0,0 @@
QT += gui network widgets
equals(QT_MAJOR_VERSION, 6): QT += core5compat
INCLUDEPATH += $$PWD
DEPENDPATH += $$PWD
#!win32-msvc* {
# QMAKE_CXXFLAGS += -Wextra -pedantic
#}
#contains(QT_CONFIG, reduce_exports):CONFIG += hide_symbols
SOURCES = $$PWD/sshsendfacility.cpp \
$$PWD/sshremoteprocess.cpp \
$$PWD/sshpacketparser.cpp \
$$PWD/sshpacket.cpp \
$$PWD/sshoutgoingpacket.cpp \
$$PWD/sshkeygenerator.cpp \
$$PWD/sshkeyexchange.cpp \
$$PWD/sshincomingpacket.cpp \
$$PWD/sshcryptofacility.cpp \
$$PWD/sshconnection.cpp \
$$PWD/sshchannelmanager.cpp \
$$PWD/sshchannel.cpp \
$$PWD/sshcapabilities.cpp \
$$PWD/sftppacket.cpp \
$$PWD/sftpoutgoingpacket.cpp \
$$PWD/sftpoperation.cpp \
$$PWD/sftpincomingpacket.cpp \
$$PWD/sftpdefs.cpp \
$$PWD/sftpchannel.cpp \
$$PWD/sshremoteprocessrunner.cpp \
$$PWD/sshconnectionmanager.cpp \
$$PWD/sshkeypasswordretriever.cpp \
$$PWD/sftpfilesystemmodel.cpp \
$$PWD/sshdirecttcpiptunnel.cpp \
$$PWD/sshhostkeydatabase.cpp \
$$PWD/sshlogging.cpp \
$$PWD/sshtcpipforwardserver.cpp \
$$PWD/sshtcpiptunnel.cpp \
$$PWD/sshforwardedtcpiptunnel.cpp \
$$PWD/sshagent.cpp \
$$PWD/sshx11channel.cpp \
$$PWD/sshx11inforetriever.cpp \
$$PWD/opensshkeyfilereader.cpp \
PUBLIC_HEADERS = \
$$PWD/sftpdefs.h \
$$PWD/ssherrors.h \
$$PWD/sshremoteprocess.h \
$$PWD/sftpchannel.h \
$$PWD/sshkeygenerator.h \
$$PWD/sshremoteprocessrunner.h \
$$PWD/sshconnectionmanager.h \
$$PWD/sshpseudoterminal.h \
$$PWD/sftpfilesystemmodel.h \
$$PWD/sshdirecttcpiptunnel.h \
$$PWD/sshtcpipforwardserver.h \
$$PWD/sshhostkeydatabase.h \
$$PWD/sshforwardedtcpiptunnel.h \
$$PWD/ssh_global.h \
$$PWD/sshconnection.h \
HEADERS = $$PUBLIC_HEADERS \
$$PWD/sshsendfacility_p.h \
$$PWD/sshremoteprocess_p.h \
$$PWD/sshpacketparser_p.h \
$$PWD/sshpacket_p.h \
$$PWD/sshoutgoingpacket_p.h \
$$PWD/sshkeyexchange_p.h \
$$PWD/sshincomingpacket_p.h \
$$PWD/sshexception_p.h \
$$PWD/sshcryptofacility_p.h \
$$PWD/sshconnection_p.h \
$$PWD/sshchannelmanager_p.h \
$$PWD/sshchannel_p.h \
$$PWD/sshcapabilities_p.h \
$$PWD/sshbotanconversions_p.h \
$$PWD/sftppacket_p.h \
$$PWD/sftpoutgoingpacket_p.h \
$$PWD/sftpoperation_p.h \
$$PWD/sftpincomingpacket_p.h \
$$PWD/sftpchannel_p.h \
$$PWD/sshkeypasswordretriever_p.h \
$$PWD/sshdirecttcpiptunnel_p.h \
$$PWD/sshlogging_p.h \
$$PWD/sshtcpipforwardserver_p.h \
$$PWD/sshtcpiptunnel_p.h \
$$PWD/sshforwardedtcpiptunnel_p.h \
$$PWD/sshagent_p.h \
$$PWD/sshx11channel_p.h \
$$PWD/sshx11displayinfo_p.h \
$$PWD/sshx11inforetriever_p.h \
$$PWD/opensshkeyfilereader_p.h \
RESOURCES += $$PWD/qssh.qrc

View file

@ -1,7 +0,0 @@
<RCC>
<qresource prefix="/ssh">
<file>images/dir.png</file>
<file>images/help.png</file>
<file>images/unknownfile.png</file>
</qresource>
</RCC>

File diff suppressed because it is too large Load diff

View file

@ -1,263 +0,0 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: http://www.qt-project.org/
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**************************************************************************/
#ifndef SFTCHANNEL_H
#define SFTCHANNEL_H
#include "sftpdefs.h"
#include "ssh_global.h"
#include <QByteArray>
#include <QObject>
#include <QSharedPointer>
#include <QString>
namespace QSsh {
namespace Internal {
class SftpChannelPrivate;
class SshChannelManager;
class SshSendFacility;
} // namespace Internal
/*!
\class QSsh::SftpChannel
\brief This class provides SFTP operations.
Objects are created via SshConnection::createSftpChannel().
The channel needs to be initialized with
a call to initialize() and is closed via closeChannel(). After closing
a channel, no more operations are possible. It cannot be re-opened
using initialize(); use SshConnection::createSftpChannel() if you need
a new one.
After the initialized() signal has been emitted, operations can be started.
All SFTP operations are asynchronous (non-blocking) and can be in-flight
simultaneously (though callers must ensure that concurrently running jobs
are independent of each other, e.g. they must not write to the same file).
Operations are identified by their job id, which is returned by
the respective member function. If the function can right away detect that
the operation cannot succeed, it returns SftpInvalidJob. If an error occurs
later, the finished() signal is emitted for the respective job with a
non-empty error string.
Note that directory names must not have a trailing slash.
*/
class QSSH_EXPORT SftpChannel : public QObject
{
Q_OBJECT
friend class Internal::SftpChannelPrivate;
friend class Internal::SshChannelManager;
public:
/// Convenience typedef
typedef QSharedPointer<SftpChannel> Ptr;
/// \see state
enum State { Uninitialized, Initializing, Initialized, Closing, Closed };
/// Current state of this channel
State state() const;
/*!
* @brief Makes this channel ready to use.
*/
void initialize();
/*!
* @brief Call this when you are done with the channel.
*/
void closeChannel();
/*!
* \brief Get information about a remote path, file or directory
* \param path Remote path to state
* \return A unique ID identifying this job
*/
SftpJobId statFile(const QString &path);
/*!
* \brief Get list of contents of a directory
* \param dirPath Remote path of directory
* \return A unique ID identifying this job
*/
SftpJobId listDirectory(const QString &dirPath);
/*!
* \brief Create remote directory
* \param dirPath Remote path of directory
* \return A unique ID identifying this job
*/
SftpJobId createDirectory(const QString &dirPath);
/*!
* \brief Remove remote directory
* \param dirPath Remote path of directory
* \return A unique ID identifying this job
*/
SftpJobId removeDirectory(const QString &dirPath);
/*!
* \brief Remove remote file
* \param filePath Remote path of file
* \return A unique ID identifying this job
*/
SftpJobId removeFile(const QString &filePath);
/*!
* \brief Rename or move a remote file or directory
* \param oldPath Path of existing file or directory
* \param newPath New path the file or directory should be available as
* \return A unique ID identifying this job
*/
SftpJobId renameFileOrDirectory(const QString &oldPath,
const QString &newPath);
/*!
* \brief Create a new empty file.
* \param filePath Remote path of the file.
* \param mode The behavior if the file already exists.
* \return A unique ID identifying this job
*/
SftpJobId createFile(const QString &filePath, SftpOverwriteMode mode);
/*!
* \brief Creates a symbolic link pointing to another file.
* \param filePath The path of the symbolic
* \param target The path the symbolic link should point to
* \return A unique ID identifying this job
*/
SftpJobId createLink(const QString &filePath, const QString &target);
/*!
* \brief Creates a remote file and fills it with data from \a device
* \param device If this is not open already it will be opened in \a QIODevice::ReadOnly mode
* \param remoteFilePath The path on the server to upload the file to
* \param mode #QSsh::SftpOverwriteMode defines the behavior if the file already exists
* \return A unique ID identifying this job
*/
SftpJobId uploadFile(QSharedPointer<QIODevice> device,
const QString &remoteFilePath, SftpOverwriteMode mode);
/*!
* \brief Uploads a local file to the remote host.
* \param localFilePath The local path to an existing file
* \param remoteFilePath The remote path the file should be uploaded to
* \param mode What it will do if the file already exists
* \return A unique ID identifying this job
*/
SftpJobId uploadFile(const QString &localFilePath,
const QString &remoteFilePath, SftpOverwriteMode mode);
/*!
* \brief Downloads a remote file to a local path
* \param remoteFilePath The remote path to the file to be downloaded
* \param localFilePath The local path for where to download the file
* \param mode Controls what happens if the local file already exists
* \return A unique ID identifying this job
*/
SftpJobId downloadFile(const QString &remoteFilePath,
const QString &localFilePath, SftpOverwriteMode mode);
/*!
* \brief Retrieves the contents of a remote file and writes it to \a device
* \param remoteFilePath The remote path of the file to retrieve the contents of
* \param device The QIODevice to write the data to, this needs to be open in a writable mode
* \return A unique ID identifying this job
*/
SftpJobId downloadFile(const QString &remoteFilePath,
QSharedPointer<QIODevice> device);
/*!
* \brief Uploads a local directory (recursively) with files to the remote host
* \param localDirPath The path to an existing local directory
* \param remoteParentDirPath The remote path to upload it to, the name of the local directory will be appended to this
* \return A unique ID identifying this job
*/
SftpJobId uploadDir(const QString &localDirPath,
const QString &remoteParentDirPath);
/*!
* \brief Downloads a remote directory (recursively) to a local path
* \param remoteDirPath The remote path of an existing directory to download
* \param localDirPath The local path to download the directory to
* \param mode
* \return
*/
SftpJobId downloadDir(const QString &remoteDirPath,
const QString &localDirPath, SftpOverwriteMode mode);
~SftpChannel();
signals:
/// Emitted when you can start using the channel
void initialized();
/// Emitted when an error happened
void channelError(const QString &reason);
/// Emitted when the channel has closed for some reason, either an error occured or it was asked for.
void closed();
/// error.isEmpty means it finished successfully
void finished(QSsh::SftpJobId job, const SftpError errorType = SftpError::NoError, const QString &error = QString());
/*!
* Continously emitted during data transfer.
* Does not emit for each file copied by uploadDir().
*/
void dataAvailable(QSsh::SftpJobId job, const QString &data);
/*!
* This signal is emitted as a result of:
* - statFile() (with the list having exactly one element)
* - listDirectory() (potentially more than once)
* It will continously be emitted as data is discovered, not only when the job is done.
*/
void fileInfoAvailable(QSsh::SftpJobId job, const QList<QSsh::SftpFileInfo> &fileInfoList);
/*!
* Emitted during upload or download
*/
void transferProgress(QSsh::SftpJobId job, quint64 progress, quint64 total);
private:
SftpChannel(quint32 channelId, Internal::SshSendFacility &sendFacility);
Internal::SftpChannelPrivate *d;
};
} // namespace QSsh
#endif // SFTPCHANNEL_H

View file

@ -1,135 +0,0 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: http://www.qt-project.org/
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**************************************************************************/
#ifndef SFTCHANNEL_P_H
#define SFTCHANNEL_P_H
#include "sftpdefs.h"
#include "sftpincomingpacket_p.h"
#include "sftpoperation_p.h"
#include "sftpoutgoingpacket_p.h"
#include "sshchannel_p.h"
#include <QByteArray>
#include <QMap>
namespace QSsh {
class SftpChannel;
namespace Internal {
class SftpChannelPrivate : public AbstractSshChannel
{
Q_OBJECT
friend class QSsh::SftpChannel;
public:
enum SftpState { Inactive, SubsystemRequested, InitSent, Initialized };
signals:
void initialized();
void channelError(const QString &reason);
void closed();
void finished(QSsh::SftpJobId job, const SftpError errorType = SftpError::NoError, const QString &error = QString());
void dataAvailable(QSsh::SftpJobId job, const QString &data);
void fileInfoAvailable(QSsh::SftpJobId job, const QList<QSsh::SftpFileInfo> &fileInfoList);
void transferProgress(QSsh::SftpJobId job, quint64 progress, quint64 total);
private:
typedef QMap<SftpJobId, AbstractSftpOperation::Ptr> JobMap;
SftpChannelPrivate(quint32 channelId, SshSendFacility &sendFacility,
SftpChannel *sftp);
SftpJobId createJob(const AbstractSftpOperation::Ptr &job);
virtual void handleChannelSuccess();
virtual void handleChannelFailure();
virtual void handleOpenSuccessInternal();
virtual void handleOpenFailureInternal(const QString &reason);
virtual void handleChannelDataInternal(const QByteArray &data);
virtual void handleChannelExtendedDataInternal(quint32 type,
const QByteArray &data);
virtual void handleExitStatus(const SshChannelExitStatus &exitStatus);
virtual void handleExitSignal(const SshChannelExitSignal &signal);
virtual void closeHook();
void handleCurrentPacket();
void handleServerVersion();
void handleHandle();
void handleStatus();
void handleName();
void handleReadData();
void handleAttrs();
void handleDownloadDir(SftpListDir::Ptr op, const QList<SftpFileInfo> & fileInfoList);
void handleStatusGeneric(JobMap::Iterator it,
const SftpStatusResponse &response);
void handleMkdirStatus(JobMap::Iterator it,
const SftpStatusResponse &response);
void handleLsStatus(JobMap::Iterator it,
const SftpStatusResponse &response);
void handleGetStatus(JobMap::Iterator it,
const SftpStatusResponse &response);
void handlePutStatus(JobMap::Iterator it,
const SftpStatusResponse &response);
void handleLsHandle(JobMap::Iterator it);
void handleCreateFileHandle(JobMap::Iterator it);
void handleGetHandle(JobMap::Iterator it);
void handlePutHandle(JobMap::Iterator it);
void spawnReadRequests(const SftpDownload::Ptr &job);
void spawnWriteRequests(JobMap::Iterator it);
void sendReadRequest(const SftpDownload::Ptr &job, quint32 requestId);
void sendWriteRequest(JobMap::Iterator it);
void finishTransferRequest(JobMap::Iterator it);
void removeTransferRequest(JobMap::Iterator it);
void reportRequestError(const AbstractSftpOperationWithHandle::Ptr &job, const SftpError errorType,
const QString &error);
void sendTransferCloseHandle(const AbstractSftpTransfer::Ptr &job,
quint32 requestId);
void attributesToFileInfo(const SftpFileAttributes &attributes, SftpFileInfo &fileInfo) const;
JobMap::Iterator lookupJob(SftpJobId id);
JobMap m_jobs;
SftpOutgoingPacket m_outgoingPacket;
SftpIncomingPacket m_incomingPacket;
QByteArray m_incomingData;
SftpJobId m_nextJobId;
SftpState m_sftpState;
SftpChannel *m_sftp;
};
} // namespace Internal
} // namespace QSsh
#endif // SFTPCHANNEL_P_H

View file

@ -1,33 +0,0 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: http://www.qt-project.org/
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**************************************************************************/
#include "sftpdefs.h"
namespace QSsh { const SftpJobId SftpInvalidJob = 0; }

View file

@ -1,119 +0,0 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: http://www.qt-project.org/
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**************************************************************************/
#ifndef SFTPDEFS_H
#define SFTPDEFS_H
#include "ssh_global.h"
#include <QFile>
#include <QString>
/*!
* \namespace QSsh
* \brief The namespace used for the entire library
*/
namespace QSsh {
/*!
*\brief Unique ID used for tracking individual jobs.
*/
typedef quint32 SftpJobId;
/*!
Special ID representing an invalid job, e. g. if a requested job could not be started.
*/
QSSH_EXPORT extern const SftpJobId SftpInvalidJob;
/*!
* \brief The behavior when uploading a file and the remote path already exists
*/
enum SftpOverwriteMode {
/*! Overwrite any existing files */
SftpOverwriteExisting,
/*! Append new content if the file already exists */
SftpAppendToExisting,
/*! If the file or directory already exists skip it */
SftpSkipExisting
};
/*!
* \brief The type of a remote file.
*/
enum SftpFileType { FileTypeRegular, FileTypeDirectory, FileTypeOther, FileTypeUnknown };
/*!
* \brief Possible errors.
*/
enum SftpError { NoError, EndOfFile, FileNotFound, PermissionDenied, GenericFailure, BadMessage, NoConnection, ConnectionLost, UnsupportedOperation };
/*!
\brief Contains information about a remote file.
*/
class QSSH_EXPORT SftpFileInfo
{
public:
SftpFileInfo() : type(FileTypeUnknown), sizeValid(false), permissionsValid(false) { }
/// The remote file name, only file attribute required by the RFC to be present so this is always set
QString name;
/// The type of file
SftpFileType type = FileTypeUnknown;
/// The remote file size in bytes.
quint64 size = 0;
/// The permissions set on the file, might be empty as the RFC allows an SFTP server not to support any file attributes beyond the name.
QFileDevice::Permissions permissions{};
/// Last time file was accessed.
quint32 atime = 0;
/// Last time file was modified.
quint32 mtime = 0;
/// If the timestamps (\ref atime and \ref mtime) are valid, the RFC allows an SFTP server not to support any file attributes beyond the name.
bool timestampsValid = false;
/// The RFC allows an SFTP server not to support any file attributes beyond the name.
bool sizeValid = false;
/// The RFC allows an SFTP server not to support any file attributes beyond the name.
bool permissionsValid = false;
};
} // namespace QSsh
#endif // SFTPDEFS_H

View file

@ -1,401 +0,0 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: http://www.qt-project.org/
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**************************************************************************/
#include "sftpfilesystemmodel.h"
#include "sftpchannel.h"
#include "sshconnection.h"
#include "sshconnectionmanager.h"
#include <QFileInfo>
#include <QHash>
#include <QIcon>
#include <QList>
#include <QString>
namespace QSsh {
namespace Internal {
namespace {
class SftpDirNode;
class SftpFileNode
{
public:
SftpFileNode() : parent(nullptr) { }
virtual ~SftpFileNode() { }
QString path;
SftpFileInfo fileInfo;
SftpDirNode *parent;
};
class SftpDirNode : public SftpFileNode
{
public:
SftpDirNode() : lsState(LsNotYetCalled) { }
~SftpDirNode() { qDeleteAll(children); }
enum { LsNotYetCalled, LsRunning, LsFinished } lsState;
QList<SftpFileNode *> children;
};
typedef QHash<SftpJobId, SftpDirNode *> DirNodeHash;
SftpFileNode *indexToFileNode(const QModelIndex &index)
{
return static_cast<SftpFileNode *>(index.internalPointer());
}
SftpDirNode *indexToDirNode(const QModelIndex &index)
{
SftpFileNode * const fileNode = indexToFileNode(index);
QSSH_ASSERT(fileNode);
return dynamic_cast<SftpDirNode *>(fileNode);
}
} // anonymous namespace
class SftpFileSystemModelPrivate
{
public:
SshConnection *sshConnection;
SftpChannel::Ptr sftpChannel;
QString rootDirectory;
SftpFileNode *rootNode;
SftpJobId statJobId;
DirNodeHash lsOps;
QList<SftpJobId> externalJobs;
};
} // namespace Internal
using namespace Internal;
SftpFileSystemModel::SftpFileSystemModel(QObject *parent)
: QAbstractItemModel(parent), d(new SftpFileSystemModelPrivate)
{
d->sshConnection = nullptr;
d->rootDirectory = QLatin1Char('/');
d->rootNode = nullptr;
d->statJobId = SftpInvalidJob;
}
SftpFileSystemModel::~SftpFileSystemModel()
{
shutDown();
delete d;
}
void SftpFileSystemModel::setSshConnection(const SshConnectionParameters &sshParams)
{
QSSH_ASSERT_AND_RETURN(!d->sshConnection);
d->sshConnection = QSsh::acquireConnection(sshParams);
connect(d->sshConnection, &SshConnection::error,
this, &SftpFileSystemModel::handleSshConnectionFailure);
if (d->sshConnection->state() == SshConnection::Connected) {
handleSshConnectionEstablished();
return;
}
connect(d->sshConnection, &SshConnection::connected,
this, &SftpFileSystemModel::handleSshConnectionEstablished);
if (d->sshConnection->state() == SshConnection::Unconnected)
d->sshConnection->connectToHost();
}
void SftpFileSystemModel::setRootDirectory(const QString &path)
{
beginResetModel();
d->rootDirectory = path;
delete d->rootNode;
d->rootNode = nullptr;
d->lsOps.clear();
d->statJobId = SftpInvalidJob;
endResetModel();
statRootDirectory();
}
QString SftpFileSystemModel::rootDirectory() const
{
return d->rootDirectory;
}
SftpJobId SftpFileSystemModel::downloadFile(const QModelIndex &index, const QString &targetFilePath)
{
QSSH_ASSERT_AND_RETURN_VALUE(d->rootNode, SftpInvalidJob);
const SftpFileNode * const fileNode = indexToFileNode(index);
QSSH_ASSERT_AND_RETURN_VALUE(fileNode, SftpInvalidJob);
QSSH_ASSERT_AND_RETURN_VALUE(fileNode->fileInfo.type == FileTypeRegular, SftpInvalidJob);
const SftpJobId jobId = d->sftpChannel->downloadFile(fileNode->path, targetFilePath,
SftpOverwriteExisting);
if (jobId != SftpInvalidJob)
d->externalJobs << jobId;
return jobId;
}
int SftpFileSystemModel::columnCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return 2; // type + name
}
QVariant SftpFileSystemModel::data(const QModelIndex &index, int role) const
{
if (!index.internalPointer()) {
return QVariant();
}
const SftpFileNode * const node = indexToFileNode(index);
if (index.column() == 0 && role == Qt::DecorationRole) {
switch (node->fileInfo.type) {
case FileTypeRegular:
case FileTypeOther:
return QIcon(QStringLiteral(":/ssh/images/unknownfile.png"));
case FileTypeDirectory:
return QIcon(QStringLiteral(":/ssh/images/dir.png"));
case FileTypeUnknown:
return QIcon(QStringLiteral(":/ssh/images/help.png")); // Shows a question mark.
}
}
if (index.column() == 1) {
if (role == Qt::DisplayRole)
return node->fileInfo.name;
if (role == PathRole)
return node->path;
}
return QVariant();
}
Qt::ItemFlags SftpFileSystemModel::flags(const QModelIndex &index) const
{
if (!index.isValid())
return Qt::NoItemFlags;
return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
}
QVariant SftpFileSystemModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation != Qt::Horizontal)
return QVariant();
if (role != Qt::DisplayRole)
return QVariant();
if (section == 0)
return tr("File Type");
if (section == 1)
return tr("File Name");
return QVariant();
}
QModelIndex SftpFileSystemModel::index(int row, int column, const QModelIndex &parent) const
{
if (row < 0 || row >= rowCount(parent) || column < 0 || column >= columnCount(parent))
return QModelIndex();
if (!d->rootNode)
return QModelIndex();
if (!parent.isValid())
return createIndex(row, column, d->rootNode);
const SftpDirNode * const parentNode = indexToDirNode(parent);
QSSH_ASSERT_AND_RETURN_VALUE(parentNode, QModelIndex());
QSSH_ASSERT_AND_RETURN_VALUE(row < parentNode->children.count(), QModelIndex());
SftpFileNode * const childNode = parentNode->children.at(row);
return createIndex(row, column, childNode);
}
QModelIndex SftpFileSystemModel::parent(const QModelIndex &child) const
{
if (!child.isValid()) // Don't assert on this, since the model tester tries it.
return QModelIndex();
const SftpFileNode * const childNode = indexToFileNode(child);
QSSH_ASSERT_AND_RETURN_VALUE(childNode, QModelIndex());
if (childNode == d->rootNode)
return QModelIndex();
SftpDirNode * const parentNode = childNode->parent;
if (parentNode == d->rootNode)
return createIndex(0, 0, d->rootNode);
const SftpDirNode * const grandParentNode = parentNode->parent;
QSSH_ASSERT_AND_RETURN_VALUE(grandParentNode, QModelIndex());
return createIndex(grandParentNode->children.indexOf(parentNode), 0, parentNode);
}
int SftpFileSystemModel::rowCount(const QModelIndex &parent) const
{
if (!d->rootNode)
return 1; // fake it until we make it, otherwise QTreeView isn't happy
if (!parent.isValid())
return 1;
if (parent.column() != 0)
return 0;
SftpDirNode * const dirNode = indexToDirNode(parent);
if (!dirNode)
return 0;
if (dirNode->lsState != SftpDirNode::LsNotYetCalled)
return dirNode->children.count();
d->lsOps.insert(d->sftpChannel->listDirectory(dirNode->path), dirNode);
dirNode->lsState = SftpDirNode::LsRunning;
return 0;
}
void SftpFileSystemModel::statRootDirectory()
{
if (!d->sftpChannel) {
return;
}
d->statJobId = d->sftpChannel->statFile(d->rootDirectory);
}
void SftpFileSystemModel::shutDown()
{
if (d->sftpChannel) {
disconnect(d->sftpChannel.data(), nullptr, this, nullptr);
d->sftpChannel->closeChannel();
d->sftpChannel.clear();
}
if (d->sshConnection) {
disconnect(d->sshConnection, nullptr, this, nullptr);
QSsh::releaseConnection(d->sshConnection);
d->sshConnection = nullptr;
}
delete d->rootNode;
d->rootNode = nullptr;
}
void SftpFileSystemModel::handleSshConnectionFailure()
{
emit connectionError(d->sshConnection->errorString());
beginResetModel();
shutDown();
endResetModel();
}
void SftpFileSystemModel::handleSftpChannelInitialized()
{
connect(d->sftpChannel.data(),
&SftpChannel::fileInfoAvailable,
this, &SftpFileSystemModel::handleFileInfo);
connect(d->sftpChannel.data(), &SftpChannel::finished,
this, &SftpFileSystemModel::handleSftpJobFinished);
statRootDirectory();
}
void SftpFileSystemModel::handleSshConnectionEstablished()
{
d->sftpChannel = d->sshConnection->createSftpChannel();
connect(d->sftpChannel.data(), &SftpChannel::initialized,
this, &SftpFileSystemModel::handleSftpChannelInitialized);
connect(d->sftpChannel.data(), &SftpChannel::channelError,
this, &SftpFileSystemModel::handleSftpChannelError);
d->sftpChannel->initialize();
}
void SftpFileSystemModel::handleSftpChannelError(const QString &reason)
{
emit connectionError(reason);
beginResetModel();
shutDown();
endResetModel();
}
void SftpFileSystemModel::handleFileInfo(SftpJobId jobId, const QList<SftpFileInfo> &fileInfoList)
{
if (jobId == d->statJobId) {
QSSH_ASSERT_AND_RETURN(!d->rootNode);
beginInsertRows(QModelIndex(), 0, 0);
d->rootNode = new SftpDirNode;
d->rootNode->path = d->rootDirectory;
d->rootNode->fileInfo = fileInfoList.first();
d->rootNode->fileInfo.name = d->rootDirectory == QLatin1String("/")
? d->rootDirectory : QFileInfo(d->rootDirectory).fileName();
endInsertRows();
return;
}
SftpDirNode * const parentNode = d->lsOps.value(jobId);
QSSH_ASSERT_AND_RETURN(parentNode);
QList<SftpFileInfo> filteredList;
foreach (const SftpFileInfo &fi, fileInfoList) {
if (fi.name != QLatin1String(".") && fi.name != QLatin1String(".."))
filteredList << fi;
}
if (filteredList.isEmpty())
return;
if (parentNode->parent) {
QModelIndex parentIndex = createIndex(parentNode->parent->children.indexOf(parentNode), 0, parentNode);
beginInsertRows(parentIndex, rowCount(parentIndex), rowCount(parentIndex) + filteredList.count());
} else {
// root node
beginInsertRows(QModelIndex(), 0, 1);
}
foreach (const SftpFileInfo &fileInfo, filteredList) {
SftpFileNode *childNode;
if (fileInfo.type == FileTypeDirectory)
childNode = new SftpDirNode;
else
childNode = new SftpFileNode;
childNode->path = parentNode->path;
if (!childNode->path.endsWith(QLatin1Char('/')))
childNode->path += QLatin1Char('/');
childNode->path += fileInfo.name;
childNode->fileInfo = fileInfo;
childNode->parent = parentNode;
parentNode->children << childNode;
}
endInsertRows();
}
void SftpFileSystemModel::handleSftpJobFinished(SftpJobId jobId, const SftpError error, const QString &errorMessage)
{
Q_UNUSED(error);
if (jobId == d->statJobId) {
d->statJobId = SftpInvalidJob;
if (!errorMessage.isEmpty())
emit sftpOperationFailed(tr("Error getting \"stat\" info about \"%1\": %2")
.arg(rootDirectory(), errorMessage));
return;
}
DirNodeHash::Iterator it = d->lsOps.find(jobId);
if (it != d->lsOps.end()) {
QSSH_ASSERT(it.value()->lsState == SftpDirNode::LsRunning);
it.value()->lsState = SftpDirNode::LsFinished;
if (!errorMessage.isEmpty())
emit sftpOperationFailed(tr("Error listing contents of directory \"%1\": %2")
.arg(it.value()->path, errorMessage));
d->lsOps.erase(it);
return;
}
const int jobIndex = d->externalJobs.indexOf(jobId);
QSSH_ASSERT_AND_RETURN(jobIndex != -1);
d->externalJobs.removeAt(jobIndex);
emit sftpOperationFinished(jobId, errorMessage);
}
} // namespace QSsh

View file

@ -1,107 +0,0 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: http://www.qt-project.org/
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**************************************************************************/
#ifndef SFTPFILESYSTEMMODEL_H
#define SFTPFILESYSTEMMODEL_H
#include "sftpdefs.h"
#include "ssh_global.h"
#include <QAbstractItemModel>
namespace QSsh {
class SshConnectionParameters;
namespace Internal { class SftpFileSystemModelPrivate; }
// Very simple read-only model. Symbolic links are not followed.
class QSSH_EXPORT SftpFileSystemModel : public QAbstractItemModel
{
Q_OBJECT
public:
explicit SftpFileSystemModel(QObject *parent = nullptr);
~SftpFileSystemModel();
/*
* Once this is called, an SFTP connection is established and the model is populated.
* The effect of additional calls is undefined.
*/
void setSshConnection(const SshConnectionParameters &sshParams);
void setRootDirectory(const QString &path); // Default is "/".
QString rootDirectory() const;
SftpJobId downloadFile(const QModelIndex &index, const QString &targetFilePath);
// Use this to get the full path of a file or directory.
static const int PathRole = Qt::UserRole;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
signals:
/*
* E.g. "Permission denied". Note that this can happen without direct user intervention,
* due to e.g. the view calling rowCount() on a non-readable directory. This signal should
* therefore not result in a message box or similar, since it might occur very often.
*/
void sftpOperationFailed(const QString &errorMessage);
/*
* This error is not recoverable. The model will not have any content after
* the signal has been emitted.
*/
void connectionError(const QString &errorMessage);
// Success <=> error.isEmpty().
void sftpOperationFinished(QSsh::SftpJobId, const QString &error);
private:
void handleSshConnectionEstablished();
void handleSshConnectionFailure();
void handleSftpChannelInitialized();
void handleSftpChannelError(const QString &reason);
void handleFileInfo(QSsh::SftpJobId jobId, const QList<QSsh::SftpFileInfo> &fileInfoList);
void handleSftpJobFinished(QSsh::SftpJobId jobId, const SftpError error, const QString &errorMessage);
int columnCount(const QModelIndex &parent = QModelIndex()) const;
Qt::ItemFlags flags(const QModelIndex &index) const;
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
QModelIndex parent(const QModelIndex &child) const;
int rowCount(const QModelIndex &parent = QModelIndex()) const;
void statRootDirectory();
void shutDown();
Internal::SftpFileSystemModelPrivate * const d;
};
} // namespace QSsh;
#endif // SFTPFILESYSTEMMODEL_H

View file

@ -1,223 +0,0 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: http://www.qt-project.org/
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**************************************************************************/
#include "sftpincomingpacket_p.h"
#include "sshexception_p.h"
#include "sshlogging_p.h"
#include "sshpacketparser_p.h"
namespace QSsh {
namespace Internal {
SftpIncomingPacket::SftpIncomingPacket() : m_length(0)
{
}
void SftpIncomingPacket::consumeData(QByteArray &newData)
{
qCDebug(sshLog, "%s: current data size = %d, new data size = %d", Q_FUNC_INFO,
m_data.size(), newData.size());
if (isComplete() || dataSize() + newData.size() < sizeof m_length)
return;
if (dataSize() < sizeof m_length) {
moveFirstBytes(m_data, newData, sizeof m_length - m_data.size());
m_length = SshPacketParser::asUint32(m_data, static_cast<quint32>(0));
if (m_length < static_cast<quint32>(TypeOffset + 1)
|| m_length > MaxPacketSize) {
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
"Invalid length field in SFTP packet.");
}
}
moveFirstBytes(m_data, newData,
qMin<quint32>(m_length - dataSize() + 4, newData.size()));
}
void SftpIncomingPacket::moveFirstBytes(QByteArray &target, QByteArray &source,
int n)
{
target.append(source.left(n));
source.remove(0, n);
}
bool SftpIncomingPacket::isComplete() const
{
return m_length == dataSize() - 4;
}
void SftpIncomingPacket::clear()
{
m_data.clear();
m_length = 0;
}
quint32 SftpIncomingPacket::extractServerVersion() const
{
Q_ASSERT(isComplete());
Q_ASSERT(type() == SSH_FXP_VERSION);
try {
return SshPacketParser::asUint32(m_data, TypeOffset + 1);
} catch (const SshPacketParseException &) {
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
"Invalid SSH_FXP_VERSION packet.");
}
}
SftpHandleResponse SftpIncomingPacket::asHandleResponse() const
{
Q_ASSERT(isComplete());
Q_ASSERT(type() == SSH_FXP_HANDLE);
try {
SftpHandleResponse response;
quint32 offset = RequestIdOffset;
response.requestId = SshPacketParser::asUint32(m_data, &offset);
response.handle = SshPacketParser::asString(m_data, &offset);
return response;
} catch (const SshPacketParseException &) {
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
"Invalid SSH_FXP_HANDLE packet");
}
}
SftpStatusResponse SftpIncomingPacket::asStatusResponse() const
{
Q_ASSERT(isComplete());
Q_ASSERT(type() == SSH_FXP_STATUS);
try {
SftpStatusResponse response;
quint32 offset = RequestIdOffset;
response.requestId = SshPacketParser::asUint32(m_data, &offset);
response.status = static_cast<SftpStatusCode>(SshPacketParser::asUint32(m_data, &offset));
response.errorString = SshPacketParser::asUserString(m_data, &offset);
response.language = SshPacketParser::asString(m_data, &offset);
return response;
} catch (const SshPacketParseException &) {
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
"Invalid SSH_FXP_STATUS packet.");
}
}
SftpNameResponse SftpIncomingPacket::asNameResponse() const
{
Q_ASSERT(isComplete());
Q_ASSERT(type() == SSH_FXP_NAME);
try {
SftpNameResponse response;
quint32 offset = RequestIdOffset;
response.requestId = SshPacketParser::asUint32(m_data, &offset);
const quint32 count = SshPacketParser::asUint32(m_data, &offset);
for (quint32 i = 0; i < count; ++i)
response.files << asFile(offset);
return response;
} catch (const SshPacketParseException &) {
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
"Invalid SSH_FXP_NAME packet.");
}
}
SftpDataResponse SftpIncomingPacket::asDataResponse() const
{
Q_ASSERT(isComplete());
Q_ASSERT(type() == SSH_FXP_DATA);
try {
SftpDataResponse response;
quint32 offset = RequestIdOffset;
response.requestId = SshPacketParser::asUint32(m_data, &offset);
response.data = SshPacketParser::asString(m_data, &offset);
return response;
} catch (const SshPacketParseException &) {
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
"Invalid SSH_FXP_DATA packet.");
}
}
SftpAttrsResponse SftpIncomingPacket::asAttrsResponse() const
{
Q_ASSERT(isComplete());
Q_ASSERT(type() == SSH_FXP_ATTRS);
try {
SftpAttrsResponse response;
quint32 offset = RequestIdOffset;
response.requestId = SshPacketParser::asUint32(m_data, &offset);
response.attrs = asFileAttributes(offset);
return response;
} catch (const SshPacketParseException &) {
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
"Invalid SSH_FXP_ATTRS packet.");
}
}
SftpFile SftpIncomingPacket::asFile(quint32 &offset) const
{
SftpFile file;
file.fileName
= QString::fromUtf8(SshPacketParser::asString(m_data, &offset));
file.longName
= QString::fromUtf8(SshPacketParser::asString(m_data, &offset));
file.attributes = asFileAttributes(offset);
return file;
}
SftpFileAttributes SftpIncomingPacket::asFileAttributes(quint32 &offset) const
{
SftpFileAttributes attributes;
const quint32 flags = SshPacketParser::asUint32(m_data, &offset);
attributes.sizePresent = flags & SSH_FILEXFER_ATTR_SIZE;
attributes.timesPresent = flags & SSH_FILEXFER_ATTR_ACMODTIME;
attributes.uidAndGidPresent = flags & SSH_FILEXFER_ATTR_UIDGID;
attributes.permissionsPresent = flags & SSH_FILEXFER_ATTR_PERMISSIONS;
if (attributes.sizePresent) {
attributes.size = SshPacketParser::asUint64(m_data, &offset);
}
if (attributes.uidAndGidPresent) {
attributes.uid = SshPacketParser::asUint32(m_data, &offset);
attributes.gid = SshPacketParser::asUint32(m_data, &offset);
}
if (attributes.permissionsPresent)
attributes.permissions = SshPacketParser::asUint32(m_data, &offset);
if (attributes.timesPresent) {
attributes.atime = SshPacketParser::asUint32(m_data, &offset);
attributes.mtime = SshPacketParser::asUint32(m_data, &offset);
}
if (flags & SSH_FILEXFER_ATTR_EXTENDED) {
const quint32 count = SshPacketParser::asUint32(m_data, &offset);
for (quint32 i = 0; i < count; ++i) {
SshPacketParser::asString(m_data, &offset);
SshPacketParser::asString(m_data, &offset);
}
}
return attributes;
}
} // namespace Internal
} // namespace QSsh

View file

@ -1,112 +0,0 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: http://www.qt-project.org/
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**************************************************************************/
#ifndef SFTPINCOMINGPACKET_P_H
#define SFTPINCOMINGPACKET_P_H
#include "sftppacket_p.h"
namespace QSsh {
namespace Internal {
struct SftpHandleResponse {
quint32 requestId;
QByteArray handle;
};
struct SftpStatusResponse {
quint32 requestId;
SftpStatusCode status;
QString errorString;
QByteArray language;
};
struct SftpFileAttributes {
bool sizePresent;
bool timesPresent;
bool uidAndGidPresent;
bool permissionsPresent;
quint64 size;
quint32 uid;
quint32 gid;
quint32 permissions;
quint32 atime;
quint32 mtime;
};
struct SftpFile {
QString fileName;
QString longName; // Not present in later RFCs, so we don't expose this to the user.
SftpFileAttributes attributes;
};
struct SftpNameResponse {
quint32 requestId;
QList<SftpFile> files;
};
struct SftpDataResponse {
quint32 requestId;
QByteArray data;
};
struct SftpAttrsResponse {
quint32 requestId;
SftpFileAttributes attrs;
};
class SftpIncomingPacket : public AbstractSftpPacket
{
public:
SftpIncomingPacket();
void consumeData(QByteArray &data);
void clear();
bool isComplete() const;
quint32 extractServerVersion() const;
SftpHandleResponse asHandleResponse() const;
SftpStatusResponse asStatusResponse() const;
SftpNameResponse asNameResponse() const;
SftpDataResponse asDataResponse() const;
SftpAttrsResponse asAttrsResponse() const;
private:
void moveFirstBytes(QByteArray &target, QByteArray &source, int n);
SftpFileAttributes asFileAttributes(quint32 &offset) const;
SftpFile asFile(quint32 &offset) const;
quint32 m_length;
};
} // namespace Internal
} // namespace QSsh
#endif // SFTPINCOMINGPACKET_P_H

View file

@ -1,236 +0,0 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: http://www.qt-project.org/
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**************************************************************************/
#include "sftpoperation_p.h"
#include "sftpoutgoingpacket_p.h"
#include <QFile>
namespace QSsh {
namespace Internal {
AbstractSftpOperation::AbstractSftpOperation(SftpJobId jobId) : jobId(jobId)
{
}
AbstractSftpOperation::~AbstractSftpOperation() { }
SftpStatFile::SftpStatFile(SftpJobId jobId, const QString &path)
: AbstractSftpOperation(jobId), path(path)
{
}
SftpOutgoingPacket &SftpStatFile::initialPacket(SftpOutgoingPacket &packet)
{
return packet.generateStat(path, jobId);
}
SftpMakeDir::SftpMakeDir(SftpJobId jobId, const QString &path,
const SftpUploadDir::Ptr &parentJob)
: AbstractSftpOperation(jobId), parentJob(parentJob), remoteDir(path)
{
}
SftpOutgoingPacket &SftpMakeDir::initialPacket(SftpOutgoingPacket &packet)
{
return packet.generateMkDir(remoteDir, jobId);
}
SftpRmDir::SftpRmDir(SftpJobId id, const QString &path)
: AbstractSftpOperation(id), remoteDir(path)
{
}
SftpOutgoingPacket &SftpRmDir::initialPacket(SftpOutgoingPacket &packet)
{
return packet.generateRmDir(remoteDir, jobId);
}
SftpRm::SftpRm(SftpJobId jobId, const QString &path)
: AbstractSftpOperation(jobId), remoteFile(path) {}
SftpOutgoingPacket &SftpRm::initialPacket(SftpOutgoingPacket &packet)
{
return packet.generateRm(remoteFile, jobId);
}
SftpRename::SftpRename(SftpJobId jobId, const QString &oldPath,
const QString &newPath)
: AbstractSftpOperation(jobId), oldPath(oldPath), newPath(newPath)
{
}
SftpOutgoingPacket &SftpRename::initialPacket(SftpOutgoingPacket &packet)
{
return packet.generateRename(oldPath, newPath, jobId);
}
SftpCreateLink::SftpCreateLink(SftpJobId jobId, const QString &filePath, const QString &target)
: AbstractSftpOperation(jobId), filePath(filePath), target(target)
{
}
SftpOutgoingPacket &SftpCreateLink::initialPacket(SftpOutgoingPacket &packet)
{
return packet.generateCreateLink(filePath, target, jobId);
}
AbstractSftpOperationWithHandle::AbstractSftpOperationWithHandle(SftpJobId jobId,
const QString &remotePath)
: AbstractSftpOperation(jobId),
remotePath(remotePath), state(Inactive), hasError(false)
{
}
AbstractSftpOperationWithHandle::~AbstractSftpOperationWithHandle() { }
SftpListDir::SftpListDir(SftpJobId jobId, const QString &path,
const QSharedPointer<SftpDownloadDir> &parentJob)
: AbstractSftpOperationWithHandle(jobId, path), parentJob(parentJob)
{
}
SftpOutgoingPacket &SftpListDir::initialPacket(SftpOutgoingPacket &packet)
{
state = OpenRequested;
return packet.generateOpenDir(remotePath, jobId);
}
SftpCreateFile::SftpCreateFile(SftpJobId jobId, const QString &path,
SftpOverwriteMode mode)
: AbstractSftpOperationWithHandle(jobId, path), mode(mode)
{
}
SftpOutgoingPacket & SftpCreateFile::initialPacket(SftpOutgoingPacket &packet)
{
state = OpenRequested;
return packet.generateOpenFileForWriting(remotePath, mode,
SftpOutgoingPacket::DefaultPermissions, jobId);
}
const int AbstractSftpTransfer::MaxInFlightCount = 10; // Experimentally found to be enough.
AbstractSftpTransfer::AbstractSftpTransfer(SftpJobId jobId, const QString &remotePath,
const QSharedPointer<QIODevice> &localFile)
: AbstractSftpOperationWithHandle(jobId, remotePath),
localFile(localFile), fileSize(0), offset(0), inFlightCount(0),
statRequested(false)
{
}
AbstractSftpTransfer::~AbstractSftpTransfer() {}
void AbstractSftpTransfer::calculateInFlightCount(quint32 chunkSize)
{
if (fileSize == 0) {
inFlightCount = 1;
} else {
inFlightCount = fileSize / chunkSize;
if (fileSize % chunkSize)
++inFlightCount;
if (inFlightCount > MaxInFlightCount)
inFlightCount = MaxInFlightCount;
}
}
SftpDownload::SftpDownload(SftpJobId jobId, const QString &remotePath,
const QSharedPointer<QIODevice> &localFile, SftpOverwriteMode mode,
const QSharedPointer<QSsh::Internal::SftpDownloadDir> &parentJob)
: AbstractSftpTransfer(jobId, remotePath, localFile), eofId(SftpInvalidJob), mode(mode),
parentJob(parentJob)
{
}
SftpOutgoingPacket &SftpDownload::initialPacket(SftpOutgoingPacket &packet)
{
state = OpenRequested;
return packet.generateOpenFileForReading(remotePath, jobId);
}
SftpUploadFile::SftpUploadFile(SftpJobId jobId, const QString &remotePath,
const QSharedPointer<QIODevice> &localFile, SftpOverwriteMode mode,
const SftpUploadDir::Ptr &parentJob)
: AbstractSftpTransfer(jobId, remotePath, localFile),
parentJob(parentJob), mode(mode)
{
fileSize = localFile->size();
}
SftpOutgoingPacket &SftpUploadFile::initialPacket(SftpOutgoingPacket &packet)
{
state = OpenRequested;
quint32 permissions = 0;
QFileDevice *fileDevice = qobject_cast<QFileDevice*>(localFile.data());
if (fileDevice) {
const QFile::Permissions &qtPermissions = fileDevice->permissions();
if (qtPermissions & QFile::ExeOther)
permissions |= 1 << 0;
if (qtPermissions & QFile::WriteOther)
permissions |= 1 << 1;
if (qtPermissions & QFile::ReadOther)
permissions |= 1 << 2;
if (qtPermissions & QFile::ExeGroup)
permissions |= 1<< 3;
if (qtPermissions & QFile::WriteGroup)
permissions |= 1<< 4;
if (qtPermissions & QFile::ReadGroup)
permissions |= 1<< 5;
if (qtPermissions & QFile::ExeOwner)
permissions |= 1<< 6;
if (qtPermissions & QFile::WriteOwner)
permissions |= 1<< 7;
if (qtPermissions & QFile::ReadOwner)
permissions |= 1<< 8;
} else {
// write owner
permissions |= 1<< 7;
// read owner
permissions |= 1<< 8;
}
return packet.generateOpenFileForWriting(remotePath, mode, permissions, jobId);
}
SftpUploadDir::~SftpUploadDir() {}
} // namespace Internal
} // namespace QSsh

View file

@ -1,290 +0,0 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: http://www.qt-project.org/
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**************************************************************************/
#ifndef SFTPOPERATION_P_H
#define SFTPOPERATION_P_H
#include "sftpdefs.h"
#include <QByteArray>
#include <QList>
#include <QMap>
#include <QSharedPointer>
QT_BEGIN_NAMESPACE
class QIODevice;
QT_END_NAMESPACE
namespace QSsh {
namespace Internal {
class SftpOutgoingPacket;
struct AbstractSftpOperation
{
typedef QSharedPointer<AbstractSftpOperation> Ptr;
enum Type {
StatFile, ListDir, MakeDir, RmDir, Rm, Rename, CreateLink, CreateFile, Download, UploadFile
};
AbstractSftpOperation(SftpJobId jobId);
virtual ~AbstractSftpOperation();
virtual Type type() const = 0;
virtual SftpOutgoingPacket &initialPacket(SftpOutgoingPacket &packet) = 0;
const SftpJobId jobId;
private:
AbstractSftpOperation(const AbstractSftpOperation &);
AbstractSftpOperation &operator=(const AbstractSftpOperation &);
};
struct SftpUploadDir;
struct SftpDownloadDir;
struct SftpStatFile : public AbstractSftpOperation
{
typedef QSharedPointer<SftpStatFile> Ptr;
SftpStatFile(SftpJobId jobId, const QString &path);
virtual Type type() const { return StatFile; }
virtual SftpOutgoingPacket &initialPacket(SftpOutgoingPacket &packet);
const QString path;
};
struct SftpMakeDir : public AbstractSftpOperation
{
typedef QSharedPointer<SftpMakeDir> Ptr;
SftpMakeDir(SftpJobId jobId, const QString &path,
const QSharedPointer<SftpUploadDir> &parentJob = QSharedPointer<SftpUploadDir>());
virtual Type type() const { return MakeDir; }
virtual SftpOutgoingPacket &initialPacket(SftpOutgoingPacket &packet);
const QSharedPointer<SftpUploadDir> parentJob;
const QString remoteDir;
};
struct SftpRmDir : public AbstractSftpOperation
{
typedef QSharedPointer<SftpRmDir> Ptr;
SftpRmDir(SftpJobId id, const QString &path);
virtual Type type() const { return RmDir; }
virtual SftpOutgoingPacket &initialPacket(SftpOutgoingPacket &packet);
const QString remoteDir;
};
struct SftpRm : public AbstractSftpOperation
{
typedef QSharedPointer<SftpRm> Ptr;
SftpRm(SftpJobId jobId, const QString &path);
virtual Type type() const { return Rm; }
virtual SftpOutgoingPacket &initialPacket(SftpOutgoingPacket &packet);
const QString remoteFile;
};
struct SftpRename : public AbstractSftpOperation
{
typedef QSharedPointer<SftpRename> Ptr;
SftpRename(SftpJobId jobId, const QString &oldPath, const QString &newPath);
virtual Type type() const { return Rename; }
virtual SftpOutgoingPacket &initialPacket(SftpOutgoingPacket &packet);
const QString oldPath;
const QString newPath;
};
struct SftpCreateLink : public AbstractSftpOperation
{
typedef QSharedPointer<SftpCreateLink> Ptr;
SftpCreateLink(SftpJobId jobId, const QString &filePath, const QString &target);
virtual Type type() const { return CreateLink; }
virtual SftpOutgoingPacket &initialPacket(SftpOutgoingPacket &packet);
const QString filePath;
const QString target;
};
struct AbstractSftpOperationWithHandle : public AbstractSftpOperation
{
typedef QSharedPointer<AbstractSftpOperationWithHandle> Ptr;
enum State { Inactive, OpenRequested, Open, CloseRequested };
AbstractSftpOperationWithHandle(SftpJobId jobId, const QString &remotePath);
~AbstractSftpOperationWithHandle();
const QString remotePath;
QByteArray remoteHandle;
State state;
bool hasError;
};
struct SftpListDir : public AbstractSftpOperationWithHandle
{
typedef QSharedPointer<SftpListDir> Ptr;
SftpListDir(SftpJobId jobId, const QString &path,
const QSharedPointer<SftpDownloadDir> &parentJob = QSharedPointer<SftpDownloadDir>());
virtual Type type() const { return ListDir; }
virtual SftpOutgoingPacket &initialPacket(SftpOutgoingPacket &packet);
const QSharedPointer<SftpDownloadDir> parentJob;
};
struct SftpCreateFile : public AbstractSftpOperationWithHandle
{
typedef QSharedPointer<SftpCreateFile> Ptr;
SftpCreateFile(SftpJobId jobId, const QString &path, SftpOverwriteMode mode);
virtual Type type() const { return CreateFile; }
virtual SftpOutgoingPacket &initialPacket(SftpOutgoingPacket &packet);
const SftpOverwriteMode mode;
};
struct AbstractSftpTransfer : public AbstractSftpOperationWithHandle
{
typedef QSharedPointer<AbstractSftpTransfer> Ptr;
AbstractSftpTransfer(SftpJobId jobId, const QString &remotePath,
const QSharedPointer<QIODevice> &localFile);
~AbstractSftpTransfer();
void calculateInFlightCount(quint32 chunkSize);
static const int MaxInFlightCount;
const QSharedPointer<QIODevice> localFile;
quint64 fileSize;
quint64 offset;
int inFlightCount;
bool statRequested;
};
struct SftpDownload : public AbstractSftpTransfer
{
typedef QSharedPointer<SftpDownload> Ptr;
SftpDownload(SftpJobId jobId, const QString &remotePath,
const QSharedPointer<QIODevice> &localFile, SftpOverwriteMode mode,
const QSharedPointer<SftpDownloadDir> &parentJob = QSharedPointer<SftpDownloadDir>());
virtual Type type() const { return Download; }
virtual SftpOutgoingPacket &initialPacket(SftpOutgoingPacket &packet);
QMap<quint32, quint64> offsets;
SftpJobId eofId;
SftpOverwriteMode mode;
const QSharedPointer<QSsh::Internal::SftpDownloadDir> parentJob;
};
struct SftpUploadFile : public AbstractSftpTransfer
{
typedef QSharedPointer<SftpUploadFile> Ptr;
SftpUploadFile(SftpJobId jobId, const QString &remotePath,
const QSharedPointer<QIODevice> &localFile, SftpOverwriteMode mode,
const QSharedPointer<SftpUploadDir> &parentJob = QSharedPointer<SftpUploadDir>());
virtual Type type() const { return UploadFile; }
virtual SftpOutgoingPacket &initialPacket(SftpOutgoingPacket &packet);
const QSharedPointer<SftpUploadDir> parentJob;
SftpOverwriteMode mode;
};
// Composite operation.
struct SftpUploadDir
{
typedef QSharedPointer<SftpUploadDir> Ptr;
struct Dir {
Dir(const QString &l, const QString &r) : localDir(l), remoteDir(r) {}
QString localDir;
QString remoteDir;
};
SftpUploadDir(SftpJobId jobId) : jobId(jobId), hasError(false) {}
~SftpUploadDir();
void setError()
{
hasError = true;
uploadsInProgress.clear();
mkdirsInProgress.clear();
}
const SftpJobId jobId;
bool hasError;
QList<SftpUploadFile::Ptr> uploadsInProgress;
QMap<SftpMakeDir::Ptr, Dir> mkdirsInProgress;
};
// Composite operation.
struct SftpDownloadDir
{
typedef QSharedPointer<SftpDownloadDir> Ptr;
struct Dir {
Dir() {}
Dir(const QString &l, const QString &r) : localDir(l), remoteDir(r) {}
QString localDir;
QString remoteDir;
};
SftpDownloadDir(SftpJobId jobId, SftpOverwriteMode mode)
: jobId(jobId), hasError(false), mode(mode) {}
~SftpDownloadDir() {}
void setError()
{
hasError = true;
downloadsInProgress.clear();
lsdirsInProgress.clear();
}
const SftpJobId jobId;
bool hasError;
SftpOverwriteMode mode;
QList<SftpDownload::Ptr> downloadsInProgress;
QMap<SftpListDir::Ptr, Dir> lsdirsInProgress;
};
} // namespace Internal
} // namespace QSsh
#endif // SFTPOPERATION_P_H

View file

@ -1,225 +0,0 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: http://www.qt-project.org/
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**************************************************************************/
#include "sftpoutgoingpacket_p.h"
#include "sshlogging_p.h"
#include "sshpacket_p.h"
#include <QtEndian>
#include <limits>
namespace QSsh {
namespace Internal {
namespace {
const quint32 DefaultAttributes = 0;
const quint32 SSH_FXF_READ = 0x00000001;
const quint32 SSH_FXF_WRITE = 0x00000002;
const quint32 SSH_FXF_APPEND = 0x00000004;
const quint32 SSH_FXF_CREAT = 0x00000008;
const quint32 SSH_FXF_TRUNC = 0x00000010;
const quint32 SSH_FXF_EXCL = 0x00000020;
}
SftpOutgoingPacket::SftpOutgoingPacket()
{
}
SftpOutgoingPacket &SftpOutgoingPacket::generateInit(quint32 version)
{
return init(SSH_FXP_INIT, 0).appendInt(version).finalize();
}
SftpOutgoingPacket &SftpOutgoingPacket::generateStat(const QString &path, quint32 requestId)
{
return init(SSH_FXP_LSTAT, requestId).appendString(path).finalize();
}
SftpOutgoingPacket &SftpOutgoingPacket::generateOpenDir(const QString &path,
quint32 requestId)
{
return init(SSH_FXP_OPENDIR, requestId).appendString(path).finalize();
}
SftpOutgoingPacket &SftpOutgoingPacket::generateReadDir(const QByteArray &handle,
quint32 requestId)
{
return init(SSH_FXP_READDIR, requestId).appendString(handle).finalize();
}
SftpOutgoingPacket &SftpOutgoingPacket::generateCloseHandle(const QByteArray &handle,
quint32 requestId)
{
return init(SSH_FXP_CLOSE, requestId).appendString(handle).finalize();
}
SftpOutgoingPacket &SftpOutgoingPacket::generateMkDir(const QString &path,
quint32 requestId)
{
return init(SSH_FXP_MKDIR, requestId).appendString(path)
.appendInt(DefaultAttributes).finalize();
}
SftpOutgoingPacket &SftpOutgoingPacket::generateRmDir(const QString &path,
quint32 requestId)
{
return init(SSH_FXP_RMDIR, requestId).appendString(path).finalize();
}
SftpOutgoingPacket &SftpOutgoingPacket::generateRm(const QString &path,
quint32 requestId)
{
return init(SSH_FXP_REMOVE, requestId).appendString(path).finalize();
}
SftpOutgoingPacket &SftpOutgoingPacket::generateRename(const QString &oldPath,
const QString &newPath, quint32 requestId)
{
return init(SSH_FXP_RENAME, requestId).appendString(oldPath)
.appendString(newPath).finalize();
}
SftpOutgoingPacket &SftpOutgoingPacket::generateOpenFileForWriting(const QString &path,
SftpOverwriteMode mode, quint32 permissions, quint32 requestId)
{
QList<quint32> attributes;
if (permissions != DefaultPermissions)
attributes << SSH_FILEXFER_ATTR_PERMISSIONS << permissions;
else
attributes << DefaultAttributes;
return generateOpenFile(path, Write, mode, attributes, requestId);
}
SftpOutgoingPacket &SftpOutgoingPacket::generateOpenFileForReading(const QString &path,
quint32 requestId)
{
// Note: Overwrite mode is irrelevant and will be ignored.
return generateOpenFile(path, Read, SftpSkipExisting, QList<quint32>() << DefaultAttributes,
requestId);
}
SftpOutgoingPacket &SftpOutgoingPacket::generateReadFile(const QByteArray &handle,
quint64 offset, quint32 length, quint32 requestId)
{
return init(SSH_FXP_READ, requestId).appendString(handle).appendInt64(offset)
.appendInt(length).finalize();
}
SftpOutgoingPacket &SftpOutgoingPacket::generateFstat(const QByteArray &handle,
quint32 requestId)
{
return init(SSH_FXP_FSTAT, requestId).appendString(handle).finalize();
}
SftpOutgoingPacket &SftpOutgoingPacket::generateWriteFile(const QByteArray &handle,
quint64 offset, const QByteArray &data, quint32 requestId)
{
return init(SSH_FXP_WRITE, requestId).appendString(handle)
.appendInt64(offset).appendString(data).finalize();
}
SftpOutgoingPacket &SftpOutgoingPacket::generateCreateLink(const QString &filePath,
const QString &target, quint32 requestId)
{
return init(SSH_FXP_SYMLINK, requestId).appendString(filePath).appendString(target).finalize();
}
SftpOutgoingPacket &SftpOutgoingPacket::generateOpenFile(const QString &path,
OpenType openType, SftpOverwriteMode mode, const QList<quint32> &attributes, quint32 requestId)
{
quint32 pFlags = 0;
switch (openType) {
case Read:
pFlags = SSH_FXF_READ;
break;
case Write:
pFlags = SSH_FXF_WRITE | SSH_FXF_CREAT;
switch (mode) {
case SftpOverwriteExisting: pFlags |= SSH_FXF_TRUNC; break;
case SftpAppendToExisting: pFlags |= SSH_FXF_APPEND; break;
case SftpSkipExisting: pFlags |= SSH_FXF_EXCL; break;
}
break;
}
init(SSH_FXP_OPEN, requestId).appendString(path).appendInt(pFlags);
foreach (const quint32 attribute, attributes)
appendInt(attribute);
return finalize();
}
SftpOutgoingPacket &SftpOutgoingPacket::init(SftpPacketType type,
quint32 requestId)
{
m_data.resize(TypeOffset + 1);
m_data[TypeOffset] = type;
if (type != SSH_FXP_INIT) {
appendInt(requestId);
qCDebug(sshLog, "Generating SFTP packet of type %d with request id %u", type, requestId);
}
return *this;
}
SftpOutgoingPacket &SftpOutgoingPacket::appendInt(quint32 val)
{
m_data.append(AbstractSshPacket::encodeInt(val));
return *this;
}
SftpOutgoingPacket &SftpOutgoingPacket::appendInt64(quint64 value)
{
m_data.append(AbstractSshPacket::encodeInt(value));
return *this;
}
SftpOutgoingPacket &SftpOutgoingPacket::appendString(const QString &string)
{
m_data.append(AbstractSshPacket::encodeString(string.toUtf8()));
return *this;
}
SftpOutgoingPacket &SftpOutgoingPacket::appendString(const QByteArray &string)
{
m_data += AbstractSshPacket::encodeString(string);
return *this;
}
SftpOutgoingPacket &SftpOutgoingPacket::finalize()
{
AbstractSshPacket::setLengthField(m_data);
return *this;
}
const quint32 SftpOutgoingPacket::DefaultPermissions = std::numeric_limits<quint32>::max();
} // namespace Internal
} // namespace QSsh

View file

@ -1,92 +0,0 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: http://www.qt-project.org/
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**************************************************************************/
#ifndef SFTPOUTGOINGPACKET_P_H
#define SFTPOUTGOINGPACKET_P_H
#include "sftppacket_p.h"
#include "sftpdefs.h"
namespace QSsh {
namespace Internal {
class SftpOutgoingPacket : public AbstractSftpPacket
{
public:
SftpOutgoingPacket();
SftpOutgoingPacket &generateInit(quint32 version);
SftpOutgoingPacket &generateStat(const QString &path, quint32 requestId);
SftpOutgoingPacket &generateOpenDir(const QString &path, quint32 requestId);
SftpOutgoingPacket &generateReadDir(const QByteArray &handle,
quint32 requestId);
SftpOutgoingPacket &generateCloseHandle(const QByteArray &handle,
quint32 requestId);
SftpOutgoingPacket &generateMkDir(const QString &path, quint32 requestId);
SftpOutgoingPacket &generateRmDir(const QString &path, quint32 requestId);
SftpOutgoingPacket &generateRm(const QString &path, quint32 requestId);
SftpOutgoingPacket &generateRename(const QString &oldPath,
const QString &newPath, quint32 requestId);
SftpOutgoingPacket &generateOpenFileForWriting(const QString &path,
SftpOverwriteMode mode, quint32 permissions, quint32 requestId);
SftpOutgoingPacket &generateOpenFileForReading(const QString &path,
quint32 requestId);
SftpOutgoingPacket &generateReadFile(const QByteArray &handle,
quint64 offset, quint32 length, quint32 requestId);
SftpOutgoingPacket &generateFstat(const QByteArray &handle,
quint32 requestId);
SftpOutgoingPacket &generateWriteFile(const QByteArray &handle,
quint64 offset, const QByteArray &data, quint32 requestId);
// Note: OpenSSH's SFTP server has a bug that reverses the filePath and target
// arguments, so this operation is not portable.
SftpOutgoingPacket &generateCreateLink(const QString &filePath, const QString &target,
quint32 requestId);
static const quint32 DefaultPermissions;
private:
static QByteArray encodeString(const QString &string);
enum OpenType { Read, Write };
SftpOutgoingPacket &generateOpenFile(const QString &path, OpenType openType,
SftpOverwriteMode mode, const QList<quint32> &attributes, quint32 requestId);
SftpOutgoingPacket &init(SftpPacketType type, quint32 requestId);
SftpOutgoingPacket &appendInt(quint32 value);
SftpOutgoingPacket &appendInt64(quint64 value);
SftpOutgoingPacket &appendString(const QString &string);
SftpOutgoingPacket &appendString(const QByteArray &string);
SftpOutgoingPacket &finalize();
};
} // namespace Internal
} // namespace QSsh
#endif // SFTPOUTGOINGPACKET_P_H

View file

@ -1,57 +0,0 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: http://www.qt-project.org/
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**************************************************************************/
#include "sftppacket_p.h"
#include "sshpacketparser_p.h"
namespace QSsh {
namespace Internal {
// There's no "standard" or negotiation between server and client for this, so
// just use the same as openssh's sftp implementation
const quint32 AbstractSftpPacket::MaxDataSize = 32768;
const quint32 AbstractSftpPacket::MaxPacketSize = 256 * 1024;
const int AbstractSftpPacket::TypeOffset = 4;
const int AbstractSftpPacket::RequestIdOffset = TypeOffset + 1;
const int AbstractSftpPacket::PayloadOffset = RequestIdOffset + 4;
AbstractSftpPacket::AbstractSftpPacket()
{
}
quint32 AbstractSftpPacket::requestId() const
{
return SshPacketParser::asUint32(m_data, RequestIdOffset);
}
} // namespace Internal
} // namespace QSsh

View file

@ -1,117 +0,0 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: http://www.qt-project.org/
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**************************************************************************/
#ifndef SFTPPACKET_P_H
#define SFTPPACKET_P_H
#include <QByteArray>
#include <QList>
#include <QString>
namespace QSsh {
namespace Internal {
enum SftpPacketType {
SSH_FXP_INIT = 1,
SSH_FXP_VERSION = 2,
SSH_FXP_OPEN = 3,
SSH_FXP_CLOSE = 4,
SSH_FXP_READ = 5,
SSH_FXP_WRITE = 6,
SSH_FXP_LSTAT = 7,
SSH_FXP_FSTAT = 8,
SSH_FXP_SETSTAT = 9,
SSH_FXP_FSETSTAT = 10,
SSH_FXP_OPENDIR = 11,
SSH_FXP_READDIR = 12,
SSH_FXP_REMOVE = 13,
SSH_FXP_MKDIR = 14,
SSH_FXP_RMDIR = 15,
SSH_FXP_REALPATH = 16,
SSH_FXP_STAT = 17,
SSH_FXP_RENAME = 18,
SSH_FXP_READLINK = 19,
SSH_FXP_SYMLINK = 20, // Removed from later protocol versions. Try not to use.
SSH_FXP_STATUS = 101,
SSH_FXP_HANDLE = 102,
SSH_FXP_DATA = 103,
SSH_FXP_NAME = 104,
SSH_FXP_ATTRS = 105,
SSH_FXP_EXTENDED = 200,
SSH_FXP_EXTENDED_REPLY = 201
};
enum SftpStatusCode {
SSH_FX_OK = 0,
SSH_FX_EOF = 1,
SSH_FX_NO_SUCH_FILE = 2,
SSH_FX_PERMISSION_DENIED = 3,
SSH_FX_FAILURE = 4,
SSH_FX_BAD_MESSAGE = 5,
SSH_FX_NO_CONNECTION = 6,
SSH_FX_CONNECTION_LOST = 7,
SSH_FX_OP_UNSUPPORTED = 8
};
enum SftpAttributeType {
SSH_FILEXFER_ATTR_SIZE = 0x00000001,
SSH_FILEXFER_ATTR_UIDGID = 0x00000002,
SSH_FILEXFER_ATTR_PERMISSIONS = 0x00000004,
SSH_FILEXFER_ATTR_ACMODTIME = 0x00000008,
SSH_FILEXFER_ATTR_EXTENDED = 0x80000000
};
class AbstractSftpPacket
{
public:
AbstractSftpPacket();
quint32 requestId() const;
const QByteArray &rawData() const { return m_data; }
SftpPacketType type() const { return static_cast<SftpPacketType>(m_data.at(TypeOffset)); }
static const quint32 MaxDataSize; // "Pure" data size per read/writepacket.
static const quint32 MaxPacketSize;
protected:
quint32 dataSize() const { return static_cast<quint32>(m_data.size()); }
static const int TypeOffset;
static const int RequestIdOffset;
static const int PayloadOffset;
QByteArray m_data;
};
} // namespace Internal
} // namespace QSsh
#endif // SFTPPACKET_P_H

View file

@ -1,66 +0,0 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: http://www.qt-project.org/
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**************************************************************************/
#ifndef SSH_GLOBAL_H
#define SSH_GLOBAL_H
#include <QtGlobal>
#include <QObject>
#ifdef Q_OS_IOS
class QProcess {
public:
QProcess(QObject *){}
enum ProcessChannel {
StandardOutput,
StandardError
};
};
#endif
#ifdef _MSC_VER
// For static cmake building removing dll export/import
# define QSSH_EXPORT
#else
#if defined(QTCSSH_LIBRARY)
# define QSSH_EXPORT Q_DECL_EXPORT
#else
# define QSSH_EXPORT Q_DECL_IMPORT
#endif
#endif
#define QSSH_PRINT_WARNING qWarning("Soft assert at %s:%d", __FILE__, __LINE__)
#define QSSH_ASSERT(cond) do { if (!(cond)) { QSSH_PRINT_WARNING; } } while (false)
#define QSSH_ASSERT_AND_RETURN(cond) do { if (!(cond)) { QSSH_PRINT_WARNING; return; } } while (false)
#define QSSH_ASSERT_AND_RETURN_VALUE(cond, value) do { if (!(cond)) { QSSH_PRINT_WARNING; return value; } } while (false)
#endif // SSH_GLOBAL_H

View file

@ -1,313 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "sshagent_p.h"
#include "sshlogging_p.h"
#include "sshpacket_p.h"
#include "sshpacketparser_p.h"
#include "ssh_global.h"
#include <QTimer>
#include <QtEndian>
#include <algorithm>
namespace QSsh {
namespace Internal {
// https://github.com/openssh/openssh-portable/blob/V_7_2/PROTOCOL.agent
enum PacketType {
SSH_AGENT_FAILURE = 5,
SSH2_AGENTC_REQUEST_IDENTITIES = 11,
SSH2_AGENTC_SIGN_REQUEST = 13,
SSH2_AGENT_IDENTITIES_ANSWER = 12,
SSH2_AGENT_SIGN_RESPONSE = 14,
};
// TODO: Remove once we require 5.7, where the endianness functions have a sane input type.
template<typename T> static T fromBigEndian(const QByteArray &ba)
{
return qFromBigEndian<T>(reinterpret_cast<const uchar *>(ba.constData()));
}
void SshAgent::refreshKeysImpl()
{
if (state() != Connected)
return;
const auto keysRequestIt = std::find_if(m_pendingRequests.constBegin(),
m_pendingRequests.constEnd(), [](const Request &r) { return r.isKeysRequest(); });
if (keysRequestIt != m_pendingRequests.constEnd()) {
qCDebug(sshLog) << "keys request already pending, not adding another one";
return;
}
qCDebug(sshLog) << "queueing keys request";
m_pendingRequests << Request();
sendNextRequest();
}
void SshAgent::requestSignatureImpl(const QByteArray &key, uint token)
{
if (state() != Connected)
return;
const QByteArray data = m_dataToSign.take(qMakePair(key, token));
QSSH_ASSERT(!data.isEmpty());
qCDebug(sshLog) << "queueing signature request";
m_pendingRequests.enqueue(Request(key, data, token));
sendNextRequest();
}
void SshAgent::sendNextRequest()
{
if (m_pendingRequests.isEmpty())
return;
if (m_outgoingPacket.isComplete())
return;
if (hasError())
return;
const Request &request = m_pendingRequests.head();
m_outgoingPacket = request.isKeysRequest() ? generateKeysPacket() : generateSigPacket(request);
sendPacket();
}
SshAgent::Packet SshAgent::generateKeysPacket()
{
qCDebug(sshLog) << "requesting keys from agent";
Packet p;
p.size = 1;
p.data += char(SSH2_AGENTC_REQUEST_IDENTITIES);
return p;
}
SshAgent::Packet SshAgent::generateSigPacket(const SshAgent::Request &request)
{
qCDebug(sshLog) << "requesting signature from agent for key" << request.key << "and token"
<< request.token;
Packet p;
p.data += char(SSH2_AGENTC_SIGN_REQUEST);
p.data += AbstractSshPacket::encodeString(request.key);
p.data += AbstractSshPacket::encodeString(request.dataToSign);
p.data += AbstractSshPacket::encodeInt(quint32(0));
p.size = p.data.count();
return p;
}
SshAgent::~SshAgent()
{
m_agentSocket.disconnect(this);
}
void SshAgent::storeDataToSign(const QByteArray &key, const QByteArray &data, uint token)
{
instance().m_dataToSign.insert(qMakePair(key, token), data);
}
void SshAgent::removeDataToSign(const QByteArray &key, uint token)
{
instance().m_dataToSign.remove(qMakePair(key, token));
}
SshAgent &QSsh::Internal::SshAgent::instance()
{
static SshAgent agent;
return agent;
}
SshAgent::SshAgent()
{
connect(&m_agentSocket, &QLocalSocket::connected, this, &SshAgent::handleConnected);
connect(&m_agentSocket, &QLocalSocket::disconnected, this, &SshAgent::handleDisconnected);
connect(&m_agentSocket, SIGNAL(error(QAbstractSocket::SocketError)), this,
SLOT(handleSocketError()));
connect(&m_agentSocket, &QLocalSocket::readyRead, this, &SshAgent::handleIncomingData);
QTimer::singleShot(0, this, &SshAgent::connectToServer);
}
void SshAgent::connectToServer()
{
const QByteArray serverAddress = qgetenv("SSH_AUTH_SOCK");
if (serverAddress.isEmpty()) {
qCDebug(sshLog) << "agent failure: socket address unknown";
m_error = tr("Cannot connect to ssh-agent: SSH_AUTH_SOCK is not set.");
emit errorOccurred();
return;
}
qCDebug(sshLog) << "connecting to ssh-agent socket" << serverAddress;
m_state = Connecting;
m_agentSocket.connectToServer(QString::fromLocal8Bit(serverAddress));
}
void SshAgent::handleConnected()
{
m_state = Connected;
qCDebug(sshLog) << "connection to ssh-agent established";
refreshKeys();
}
void SshAgent::handleDisconnected()
{
qCDebug(sshLog) << "lost connection to ssh-agent";
m_error = tr("Lost connection to ssh-agent for unknown reason.");
setDisconnected();
}
void SshAgent::handleSocketError()
{
qCDebug(sshLog) << "agent socket error" << m_agentSocket.error();
m_error = m_agentSocket.errorString();
setDisconnected();
}
void SshAgent::handleIncomingData()
{
qCDebug(sshLog) << "getting data from agent";
m_incomingData += m_agentSocket.readAll();
while (!hasError() && !m_incomingData.isEmpty()) {
if (m_incomingPacket.size == 0) {
if (m_incomingData.count() < int(sizeof m_incomingPacket.size))
break;
m_incomingPacket.size = fromBigEndian<quint32>(m_incomingData);
m_incomingData.remove(0, sizeof m_incomingPacket.size);
}
const int bytesToTake = qMin<quint32>(m_incomingPacket.size - m_incomingPacket.data.count(),
m_incomingData.count());
m_incomingPacket.data += m_incomingData.left(bytesToTake);
m_incomingData.remove(0, bytesToTake);
if (m_incomingPacket.isComplete())
handleIncomingPacket();
else
break;
}
}
void SshAgent::handleIncomingPacket()
{
try {
qCDebug(sshLog) << "received packet from agent:" << m_incomingPacket.data.toHex();
const char messageType = m_incomingPacket.data.at(0);
switch (messageType) {
case SSH2_AGENT_IDENTITIES_ANSWER:
handleIdentitiesPacket();
break;
case SSH2_AGENT_SIGN_RESPONSE:
handleSignaturePacket();
break;
case SSH_AGENT_FAILURE:
if (m_pendingRequests.isEmpty()) {
qCWarning(sshLog) << "unexpected failure message from agent";
} else {
const Request request = m_pendingRequests.dequeue();
if (request.isSignatureRequest()) {
qCWarning(sshLog) << "agent failed to sign message for key"
<< request.key.toHex();
emit signatureAvailable(request.key, QByteArray(), request.token);
} else {
qCWarning(sshLog) << "agent failed to retrieve key list";
if (m_keys.isEmpty()) {
m_error = tr("ssh-agent failed to retrieve keys.");
setDisconnected();
}
}
}
break;
default:
qCWarning(sshLog) << "unexpected message type from agent:" << messageType;
}
} catch (const SshPacketParseException &) {
qCWarning(sshLog()) << "received malformed packet from agent";
handleProtocolError();
}
m_incomingPacket.invalidate();
m_incomingPacket.size = 0;
m_outgoingPacket.invalidate();
sendNextRequest();
}
void SshAgent::handleIdentitiesPacket()
{
qCDebug(sshLog) << "got keys packet from agent";
if (m_pendingRequests.isEmpty() || !m_pendingRequests.dequeue().isKeysRequest()) {
qCDebug(sshLog) << "packet was not requested";
handleProtocolError();
return;
}
quint32 offset = 1;
const auto keyCount = SshPacketParser::asUint32(m_incomingPacket.data, &offset);
qCDebug(sshLog) << "packet contains" << keyCount << "keys";
QList<QByteArray> newKeys;
for (quint32 i = 0; i < keyCount; ++i) {
const QByteArray key = SshPacketParser::asString(m_incomingPacket.data, &offset);
quint32 keyOffset = 0;
const QByteArray algoName = SshPacketParser::asString(key, &keyOffset);
SshPacketParser::asString(key, &keyOffset); // rest of key blob
SshPacketParser::asString(m_incomingPacket.data, &offset); // comment
qCDebug(sshLog) << "adding key of type" << algoName;
newKeys << key;
}
m_keys = newKeys;
emit keysUpdated();
}
void SshAgent::handleSignaturePacket()
{
qCDebug(sshLog) << "got signature packet from agent";
if (m_pendingRequests.isEmpty()) {
qCDebug(sshLog) << "signature packet was not requested";
handleProtocolError();
return;
}
const Request request = m_pendingRequests.dequeue();
if (!request.isSignatureRequest()) {
qCDebug(sshLog) << "signature packet was not requested";
handleProtocolError();
return;
}
const QByteArray signature = SshPacketParser::asString(m_incomingPacket.data, 1);
qCDebug(sshLog) << "signature for key" << request.key.toHex() << "is" << signature.toHex();
emit signatureAvailable(request.key, signature, request.token);
}
void SshAgent::handleProtocolError()
{
m_error = tr("Protocol error when talking to ssh-agent.");
setDisconnected();
}
void SshAgent::setDisconnected()
{
m_state = Unconnected;
m_agentSocket.disconnect(this);
emit errorOccurred();
}
void SshAgent::sendPacket()
{
const quint32 sizeMsb = qToBigEndian(m_outgoingPacket.size);
m_agentSocket.write(reinterpret_cast<const char *>(&sizeMsb), sizeof sizeMsb);
m_agentSocket.write(m_outgoingPacket.data);
}
} // namespace Internal
} // namespace QSsh

View file

@ -1,125 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <QByteArray>
#include <QHash>
#include <QList>
#include <QLocalSocket>
#include <QObject>
#include <QPair>
#include <QQueue>
#include <QString>
namespace QSsh {
namespace Internal {
class SshAgent : public QObject
{
Q_OBJECT
public:
enum State { Unconnected, Connecting, Connected, };
~SshAgent();
static State state() { return instance().m_state; }
static bool hasError() { return !instance().m_error.isEmpty(); }
static QString errorString() { return instance().m_error; }
static QList<QByteArray> publicKeys() { return instance().m_keys; }
static void refreshKeys() { instance().refreshKeysImpl(); }
static void storeDataToSign(const QByteArray &key, const QByteArray &data, uint token);
static void removeDataToSign(const QByteArray &key, uint token);
static void requestSignature(const QByteArray &key, uint token) {
instance().requestSignatureImpl(key, token);
}
static SshAgent &instance();
signals:
void errorOccurred();
void keysUpdated();
// Empty signature means signing failure.
void signatureAvailable(const QByteArray &key, const QByteArray &signature, uint token);
private:
struct Request {
Request() { }
Request(const QByteArray &k, const QByteArray &d, uint t)
: key(k), dataToSign(d), token(t) { }
bool isKeysRequest() const { return !isSignatureRequest(); }
bool isSignatureRequest() const { return !key.isEmpty(); }
QByteArray key;
QByteArray dataToSign;
uint token = 0;
};
struct Packet {
bool isComplete() const { return size != 0 && int(size) == data.count(); }
void invalidate() { size = 0; data.clear(); }
quint32 size = 0;
QByteArray data;
};
SshAgent();
void connectToServer();
void refreshKeysImpl();
void requestSignatureImpl(const QByteArray &key, uint token);
void sendNextRequest();
Packet generateKeysPacket();
Packet generateSigPacket(const Request &request);
void handleConnected();
void handleDisconnected();
void handleSocketError();
void handleIncomingData();
void handleIncomingPacket();
void handleIdentitiesPacket();
void handleSignaturePacket();
void handleProtocolError();
void setDisconnected();
void sendPacket();
State m_state = Unconnected;
QString m_error;
QList<QByteArray> m_keys;
QHash<QPair<QByteArray, uint>, QByteArray> m_dataToSign;
QLocalSocket m_agentSocket;
QByteArray m_incomingData;
Packet m_incomingPacket;
Packet m_outgoingPacket;
QQueue<Request> m_pendingRequests;
};
} // namespace Internal
} // namespace QSsh

View file

@ -1,172 +0,0 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: http://www.qt-project.org/
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**************************************************************************/
#ifndef BYTEARRAYCONVERSIONS_P_H
#define BYTEARRAYCONVERSIONS_P_H
#include "sshcapabilities_p.h"
#include "sshexception_p.h"
#include <botan_all.h>
namespace QSsh {
namespace Internal {
inline const Botan::byte *convertByteArray(const QByteArray &a)
{
return reinterpret_cast<const Botan::byte *>(a.constData());
}
inline Botan::byte *convertByteArray(QByteArray &a)
{
return reinterpret_cast<Botan::byte *>(a.data());
}
inline QByteArray convertByteArray(const Botan::secure_vector<Botan::byte> &v)
{
return QByteArray(reinterpret_cast<const char *>(v.data()), static_cast<int>(v.size()));
}
inline QByteArray convertByteArray(const std::vector<uint8_t> &v)
{
return QByteArray(reinterpret_cast<const char *>(v.data()), v.size());
}
inline const char *botanKeyExchangeAlgoName(const QByteArray &rfcAlgoName)
{
if (rfcAlgoName == SshCapabilities::DiffieHellmanGroup1Sha1)
return "modp/ietf/1024";
if (rfcAlgoName == SshCapabilities::DiffieHellmanGroup14Sha1)
return "modp/ietf/2048";
if (rfcAlgoName == SshCapabilities::EcdhNistp256)
return "secp256r1";
if (rfcAlgoName == SshCapabilities::EcdhNistp384)
return "secp384r1";
if (rfcAlgoName == SshCapabilities::EcdhNistp521)
return "secp521r1";
throw SshClientException(SshInternalError, SSH_TR("Unexpected key exchange algorithm \"%1\"")
.arg(QString::fromLatin1(rfcAlgoName)));
}
inline const char *botanCipherAlgoName(const QByteArray &rfcAlgoName)
{
if (rfcAlgoName == SshCapabilities::CryptAlgoAes128Cbc) {
return "CBC(AES-128)";
}
if (rfcAlgoName == SshCapabilities::CryptAlgoAes128Ctr) {
return "CTR(AES-128)";
}
if (rfcAlgoName == SshCapabilities::CryptAlgo3DesCbc) {
return "CBC(TripleDES)";
}
if (rfcAlgoName == SshCapabilities::CryptAlgo3DesCtr) {
return "CTR(TripleDES)";
}
if (rfcAlgoName == SshCapabilities::CryptAlgoAes192Ctr) {
return "CBR(AES-192)";
}
if (rfcAlgoName == SshCapabilities::CryptAlgoAes256Ctr) {
return "CTR(AES-256)";
}
throw SshClientException(SshInternalError, SSH_TR("Unexpected cipher \"%1\"")
.arg(QString::fromLatin1(rfcAlgoName)));
}
inline const char *botanCryptAlgoName(const QByteArray &rfcAlgoName)
{
if (rfcAlgoName == SshCapabilities::CryptAlgoAes128Cbc
|| rfcAlgoName == SshCapabilities::CryptAlgoAes128Ctr) {
return "AES-128";
}
if (rfcAlgoName == SshCapabilities::CryptAlgo3DesCbc
|| rfcAlgoName == SshCapabilities::CryptAlgo3DesCtr) {
return "TripleDES";
}
if (rfcAlgoName == SshCapabilities::CryptAlgoAes192Ctr) {
return "AES-192";
}
if (rfcAlgoName == SshCapabilities::CryptAlgoAes256Ctr) {
return "AES-256";
}
throw SshClientException(SshInternalError, SSH_TR("Unexpected cipher \"%1\"")
.arg(QString::fromLatin1(rfcAlgoName)));
}
inline const char *botanEmsaAlgoName(const QByteArray &rfcAlgoName)
{
if (rfcAlgoName == SshCapabilities::PubKeyDss)
return "EMSA1(SHA-1)";
if (rfcAlgoName == SshCapabilities::PubKeyRsa)
return "EMSA3(SHA-1)";
if (rfcAlgoName == SshCapabilities::PubKeyEcdsa256)
return "EMSA1(SHA-256)";
if (rfcAlgoName == SshCapabilities::PubKeyEcdsa384)
return "EMSA1_BSI(SHA-384)";
if (rfcAlgoName == SshCapabilities::PubKeyEcdsa521)
return "EMSA1_BSI(SHA-512)";
throw SshClientException(SshInternalError, SSH_TR("Unexpected host key algorithm \"%1\"")
.arg(QString::fromLatin1(rfcAlgoName)));
}
inline const char *botanHMacAlgoName(const QByteArray &rfcAlgoName)
{
if (rfcAlgoName == SshCapabilities::HMacSha1)
return "SHA-1";
if (rfcAlgoName == SshCapabilities::HMacSha256)
return "SHA-256";
if (rfcAlgoName == SshCapabilities::HMacSha384)
return "SHA-384";
if (rfcAlgoName == SshCapabilities::HMacSha512)
return "SHA-512";
throw SshClientException(SshInternalError, SSH_TR("Unexpected hashing algorithm \"%1\"")
.arg(QString::fromLatin1(rfcAlgoName)));
}
inline quint32 botanHMacKeyLen(const QByteArray &rfcAlgoName)
{
if (rfcAlgoName == SshCapabilities::HMacSha1)
return 20;
if (rfcAlgoName == SshCapabilities::HMacSha256)
return 32;
if (rfcAlgoName == SshCapabilities::HMacSha384)
return 48;
if (rfcAlgoName == SshCapabilities::HMacSha512)
return 64;
throw SshClientException(SshInternalError, SSH_TR("Unexpected hashing algorithm \"%1\"")
.arg(QString::fromLatin1(rfcAlgoName)));
}
} // namespace Internal
} // namespace QSsh
#endif // BYTEARRAYCONVERSIONS_P_H

View file

@ -1,177 +0,0 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: http://www.qt-project.org/
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**************************************************************************/
#include "sshcapabilities_p.h"
#include "sshexception_p.h"
#include <QCoreApplication>
#include <QString>
namespace QSsh {
namespace Internal {
namespace {
QByteArray listAsByteArray(const QList<QByteArray> &list)
{
QByteArray array;
foreach(const QByteArray &elem, list)
array += elem + ',';
if (!array.isEmpty())
array.remove(array.count() - 1, 1);
return array;
}
} // anonymous namspace
const QByteArray SshCapabilities::DiffieHellmanGroup1Sha1("diffie-hellman-group1-sha1");
const QByteArray SshCapabilities::DiffieHellmanGroup14Sha1("diffie-hellman-group14-sha1");
const QByteArray SshCapabilities::EcdhKexNamePrefix("ecdh-sha2-nistp");
const QByteArray SshCapabilities::EcdhNistp256 = EcdhKexNamePrefix + "256";
const QByteArray SshCapabilities::EcdhNistp384 = EcdhKexNamePrefix + "384";
const QByteArray SshCapabilities::EcdhNistp521 = EcdhKexNamePrefix + "521";
const QList<QByteArray> SshCapabilities::KeyExchangeMethods = QList<QByteArray>()
<< SshCapabilities::EcdhNistp256
<< SshCapabilities::EcdhNistp384
<< SshCapabilities::EcdhNistp521
<< SshCapabilities::DiffieHellmanGroup1Sha1
<< SshCapabilities::DiffieHellmanGroup14Sha1;
const QByteArray SshCapabilities::PubKeyDss("ssh-dss");
const QByteArray SshCapabilities::PubKeyRsa("ssh-rsa");
const QByteArray SshCapabilities::PubKeyEcdsaPrefix("ecdsa-sha2-nistp");
const QByteArray SshCapabilities::PubKeyEcdsa256 = SshCapabilities::PubKeyEcdsaPrefix + "256";
const QByteArray SshCapabilities::PubKeyEcdsa384 = SshCapabilities::PubKeyEcdsaPrefix + "384";
const QByteArray SshCapabilities::PubKeyEcdsa521 = SshCapabilities::PubKeyEcdsaPrefix + "521";
const QList<QByteArray> SshCapabilities::PublicKeyAlgorithms = QList<QByteArray>()
<< SshCapabilities::PubKeyEcdsa256
<< SshCapabilities::PubKeyEcdsa384
<< SshCapabilities::PubKeyEcdsa521
<< SshCapabilities::PubKeyRsa
<< SshCapabilities::PubKeyDss;
const QByteArray SshCapabilities::CryptAlgo3DesCbc("3des-cbc");
const QByteArray SshCapabilities::CryptAlgo3DesCtr("3des-ctr");
const QByteArray SshCapabilities::CryptAlgoAes128Cbc("aes128-cbc");
const QByteArray SshCapabilities::CryptAlgoAes128Ctr("aes128-ctr");
const QByteArray SshCapabilities::CryptAlgoAes192Ctr("aes192-ctr");
const QByteArray SshCapabilities::CryptAlgoAes256Ctr("aes256-ctr");
const QList<QByteArray> SshCapabilities::EncryptionAlgorithms
= QList<QByteArray>() << SshCapabilities::CryptAlgoAes256Ctr
<< SshCapabilities::CryptAlgoAes192Ctr
<< SshCapabilities::CryptAlgoAes128Ctr
<< SshCapabilities::CryptAlgo3DesCtr
<< SshCapabilities::CryptAlgoAes128Cbc
<< SshCapabilities::CryptAlgo3DesCbc;
const QByteArray SshCapabilities::HMacSha1("hmac-sha1");
const QByteArray SshCapabilities::HMacSha196("hmac-sha1-96");
const QByteArray SshCapabilities::HMacSha256("hmac-sha2-256");
const QByteArray SshCapabilities::HMacSha384("hmac-sha2-384");
const QByteArray SshCapabilities::HMacSha512("hmac-sha2-512");
const QList<QByteArray> SshCapabilities::MacAlgorithms
= QList<QByteArray>() /* << SshCapabilities::HMacSha196 */
<< SshCapabilities::HMacSha256
<< SshCapabilities::HMacSha384
<< SshCapabilities::HMacSha512
<< SshCapabilities::HMacSha1;
const QList<QByteArray> SshCapabilities::CompressionAlgorithms
= QList<QByteArray>() << "none";
const QByteArray SshCapabilities::SshConnectionService("ssh-connection");
QList<QByteArray> SshCapabilities::commonCapabilities(const QList<QByteArray> &myCapabilities,
const QList<QByteArray> &serverCapabilities, const QByteArray &group)
{
QList<QByteArray> capabilities;
foreach (const QByteArray &myCapability, myCapabilities) {
if (serverCapabilities.contains(myCapability))
capabilities << myCapability;
}
if (!capabilities.isEmpty())
return capabilities;
throw SshServerException(SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
"Server and client capabilities do not match.",
QCoreApplication::translate("SshConnection",
"Server and client %1 capabilities don't match.\n"
"Client list: %2\n"
"Server list: %3")
.arg(QString::fromLatin1(group))
.arg(QString::fromLocal8Bit(listAsByteArray(myCapabilities).data()))
.arg(QString::fromLocal8Bit(listAsByteArray(serverCapabilities).data())));
}
QByteArray SshCapabilities::findBestMatch(const QList<QByteArray> &myCapabilities,
const QList<QByteArray> &serverCapabilities, const QByteArray &group)
{
return commonCapabilities(myCapabilities, serverCapabilities, group).first();
}
int SshCapabilities::ecdsaIntegerWidthInBytes(const QByteArray &ecdsaAlgo)
{
if (ecdsaAlgo == PubKeyEcdsa256)
return 32;
if (ecdsaAlgo == PubKeyEcdsa384)
return 48;
if (ecdsaAlgo == PubKeyEcdsa521)
return 66;
throw SshClientException(SshInternalError, SSH_TR("Unexpected ecdsa algorithm \"%1\"")
.arg(QString::fromLatin1(ecdsaAlgo)));
}
QByteArray SshCapabilities::ecdsaPubKeyAlgoForKeyWidth(int keyWidthInBytes)
{
if (keyWidthInBytes <= 32)
return PubKeyEcdsa256;
if (keyWidthInBytes <= 48)
return PubKeyEcdsa384;
if (keyWidthInBytes <= 66)
return PubKeyEcdsa521;
throw SshClientException(SshInternalError, SSH_TR("Unexpected ecdsa key size (%1 bytes)")
.arg(keyWidthInBytes));
}
const char *SshCapabilities::oid(const QByteArray &ecdsaAlgo)
{
if (ecdsaAlgo == PubKeyEcdsa256)
return "secp256r1";
if (ecdsaAlgo == PubKeyEcdsa384)
return "secp384r1";
if (ecdsaAlgo == PubKeyEcdsa521)
return "secp521r1";
throw SshClientException(SshInternalError, SSH_TR("Unexpected ecdsa algorithm \"%1\"")
.arg(QString::fromLatin1(ecdsaAlgo)));
}
} // namespace Internal
} // namespace QSsh

View file

@ -1,91 +0,0 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: http://www.qt-project.org/
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**************************************************************************/
#ifndef CAPABILITIES_P_H
#define CAPABILITIES_P_H
#include <QByteArray>
#include <QList>
namespace QSsh {
namespace Internal {
class SshCapabilities
{
public:
static const QByteArray DiffieHellmanGroup1Sha1;
static const QByteArray DiffieHellmanGroup14Sha1;
static const QByteArray EcdhKexNamePrefix;
static const QByteArray EcdhNistp256;
static const QByteArray EcdhNistp384;
static const QByteArray EcdhNistp521; // sic
static const QList<QByteArray> KeyExchangeMethods;
static const QByteArray PubKeyDss;
static const QByteArray PubKeyRsa;
static const QByteArray PubKeyEcdsaPrefix;
static const QByteArray PubKeyEcdsa256;
static const QByteArray PubKeyEcdsa384;
static const QByteArray PubKeyEcdsa521;
static const QList<QByteArray> PublicKeyAlgorithms;
static const QByteArray CryptAlgo3DesCbc;
static const QByteArray CryptAlgo3DesCtr;
static const QByteArray CryptAlgoAes128Cbc;
static const QByteArray CryptAlgoAes128Ctr;
static const QByteArray CryptAlgoAes192Ctr;
static const QByteArray CryptAlgoAes256Ctr;
static const QList<QByteArray> EncryptionAlgorithms;
static const QByteArray HMacSha1;
static const QByteArray HMacSha196;
static const QByteArray HMacSha256;
static const QByteArray HMacSha384;
static const QByteArray HMacSha512;
static const QList<QByteArray> MacAlgorithms;
static const QList<QByteArray> CompressionAlgorithms;
static const QByteArray SshConnectionService;
static QList<QByteArray> commonCapabilities(const QList<QByteArray> &myCapabilities,
const QList<QByteArray> &serverCapabilities, const QByteArray &group);
static QByteArray findBestMatch(const QList<QByteArray> &myCapabilities,
const QList<QByteArray> &serverCapabilities, const QByteArray &group);
static int ecdsaIntegerWidthInBytes(const QByteArray &ecdsaAlgo);
static QByteArray ecdsaPubKeyAlgoForKeyWidth(int keyWidthInBytes);
static const char *oid(const QByteArray &ecdsaAlgo);
};
} // namespace Internal
} // namespace QSsh
#endif // CAPABILITIES_P_H

View file

@ -1,277 +0,0 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: http://www.qt-project.org/
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**************************************************************************/
#include "sshchannel_p.h"
#include "sshincomingpacket_p.h"
#include "sshsendfacility_p.h"
#include "sshlogging_p.h"
#include <botan_all.h>
#include <QTimer>
namespace QSsh {
namespace Internal {
const quint32 NoChannel = 0xffffffffu;
AbstractSshChannel::AbstractSshChannel(quint32 channelId,
SshSendFacility &sendFacility)
: m_sendFacility(sendFacility),
m_localChannel(channelId), m_remoteChannel(NoChannel),
m_localWindowSize(initialWindowSize()), m_remoteWindowSize(0),
m_state(Inactive)
{
m_timeoutTimer.setTimerType(Qt::VeryCoarseTimer);
m_timeoutTimer.setSingleShot(true);
connect(&m_timeoutTimer, &QTimer::timeout, this, &AbstractSshChannel::timeout);
}
AbstractSshChannel::~AbstractSshChannel()
{
}
void AbstractSshChannel::setChannelState(ChannelState state)
{
m_state = state;
if (state == Closed)
closeHook();
}
void AbstractSshChannel::requestSessionStart()
{
// Note: We are just being paranoid here about the Botan exceptions,
// which are extremely unlikely to happen, because if there was a problem
// with our cryptography stuff, it would have hit us before, on
// establishing the connection.
try {
m_sendFacility.sendSessionPacket(m_localChannel, initialWindowSize(), maxPacketSize());
setChannelState(SessionRequested);
m_timeoutTimer.start(ReplyTimeout);
} catch (const std::exception &e) {
qCWarning(sshLog, "Botan error: %s", e.what());
closeChannel();
}
}
void AbstractSshChannel::sendData(const QByteArray &data)
{
try {
m_sendBuffer += data;
flushSendBuffer();
} catch (const std::exception &e) {
qCWarning(sshLog, "Botan error: %s", e.what());
closeChannel();
}
}
quint32 AbstractSshChannel::initialWindowSize()
{
return maxPacketSize();
}
quint32 AbstractSshChannel::maxPacketSize()
{
return 16 * 1024 * 1024;
}
void AbstractSshChannel::handleWindowAdjust(quint64 bytesToAdd)
{
checkChannelActive();
const quint64 newValue = m_remoteWindowSize + bytesToAdd;
if (newValue > 0xffffffffu) {
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
"Illegal window size requested.");
}
m_remoteWindowSize = newValue;
flushSendBuffer();
}
void AbstractSshChannel::flushSendBuffer()
{
while (true) {
const quint32 bytesToSend = qMin(m_remoteMaxPacketSize,
qMin<quint32>(m_remoteWindowSize, m_sendBuffer.size()));
if (bytesToSend == 0)
break;
const QByteArray &data = m_sendBuffer.left(bytesToSend);
m_sendFacility.sendChannelDataPacket(m_remoteChannel, data);
m_sendBuffer.remove(0, bytesToSend);
m_remoteWindowSize -= bytesToSend;
}
}
void AbstractSshChannel::handleOpenSuccess(quint32 remoteChannelId,
quint32 remoteWindowSize, quint32 remoteMaxPacketSize)
{
const ChannelState oldState = m_state;
switch (oldState) {
case CloseRequested: // closeChannel() was called while we were in SessionRequested state
case SessionRequested:
break; // Ok, continue.
default:
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
"Unexpected SSH_MSG_CHANNEL_OPEN_CONFIRMATION packet.");
}
m_timeoutTimer.stop();
qCDebug(sshLog, "Channel opened. remote channel id: %u, remote window size: %u, "
"remote max packet size: %u",
remoteChannelId, remoteWindowSize, remoteMaxPacketSize);
m_remoteChannel = remoteChannelId;
m_remoteWindowSize = remoteWindowSize;
m_remoteMaxPacketSize = remoteMaxPacketSize;
setChannelState(SessionEstablished);
if (oldState == CloseRequested)
closeChannel();
else
handleOpenSuccessInternal();
}
void AbstractSshChannel::handleOpenFailure(const QString &reason)
{
switch (m_state) {
case SessionRequested:
break; // Ok, continue.
case CloseRequested:
return; // Late server reply; we requested a channel close in the meantime.
default:
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
"Unexpected SSH_MSG_CHANNEL_OPEN_FAILURE packet.");
}
m_timeoutTimer.stop();
qCDebug(sshLog, "Channel open request failed for channel %u", m_localChannel);
handleOpenFailureInternal(reason);
}
void AbstractSshChannel::handleChannelEof()
{
if (m_state == Inactive || m_state == Closed) {
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
"Unexpected SSH_MSG_CHANNEL_EOF message.");
}
m_localWindowSize = 0;
emit eof();
}
void AbstractSshChannel::handleChannelClose()
{
qCDebug(sshLog, "Receiving CLOSE for channel %u", m_localChannel);
if (channelState() == Inactive || channelState() == Closed) {
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
"Unexpected SSH_MSG_CHANNEL_CLOSE message.");
}
closeChannel();
setChannelState(Closed);
}
void AbstractSshChannel::handleChannelData(const QByteArray &data)
{
const int bytesToDeliver = handleChannelOrExtendedChannelData(data);
handleChannelDataInternal(bytesToDeliver == data.size()
? data : data.left(bytesToDeliver));
}
void AbstractSshChannel::handleChannelExtendedData(quint32 type, const QByteArray &data)
{
const int bytesToDeliver = handleChannelOrExtendedChannelData(data);
handleChannelExtendedDataInternal(type, bytesToDeliver == data.size()
? data : data.left(bytesToDeliver));
}
void AbstractSshChannel::handleChannelRequest(const SshIncomingPacket &packet)
{
checkChannelActive();
const QByteArray &requestType = packet.extractChannelRequestType();
if (requestType == SshIncomingPacket::ExitStatusType)
handleExitStatus(packet.extractChannelExitStatus());
else if (requestType == SshIncomingPacket::ExitSignalType)
handleExitSignal(packet.extractChannelExitSignal());
else if (requestType != "eow@openssh.com") // Suppress warning for this one, as it's sent all the time.
qCWarning(sshLog, "Ignoring unknown request type '%s'", requestType.data());
}
int AbstractSshChannel::handleChannelOrExtendedChannelData(const QByteArray &data)
{
checkChannelActive();
const int bytesToDeliver = qMin<quint32>(data.size(), maxDataSize());
if (bytesToDeliver != data.size())
qCWarning(sshLog, "Misbehaving server does not respect local window, clipping.");
m_localWindowSize -= bytesToDeliver;
if (m_localWindowSize < maxPacketSize()) {
m_localWindowSize += maxPacketSize();
m_sendFacility.sendWindowAdjustPacket(m_remoteChannel, maxPacketSize());
}
return bytesToDeliver;
}
void AbstractSshChannel::closeChannel()
{
if (m_state == CloseRequested) {
m_timeoutTimer.stop();
} else if (m_state != Closed) {
if (m_state == Inactive) {
setChannelState(Closed);
} else {
const ChannelState oldState = m_state;
setChannelState(CloseRequested);
if (m_remoteChannel != NoChannel) {
m_sendFacility.sendChannelEofPacket(m_remoteChannel);
m_sendFacility.sendChannelClosePacket(m_remoteChannel);
} else {
QSSH_ASSERT(oldState == SessionRequested);
}
}
}
}
void AbstractSshChannel::checkChannelActive() const
{
if (channelState() == Inactive || channelState() == Closed)
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
"Channel not open.");
}
quint32 AbstractSshChannel::maxDataSize() const
{
return qMin(m_localWindowSize, maxPacketSize());
}
} // namespace Internal
} // namespace QSsh

View file

@ -1,125 +0,0 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: http://www.qt-project.org/
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**************************************************************************/
#ifndef SSHCHANNEL_P_H
#define SSHCHANNEL_P_H
#include <QByteArray>
#include <QObject>
#include <QString>
#include <QTimer>
namespace QSsh {
namespace Internal {
struct SshChannelExitSignal;
struct SshChannelExitStatus;
class SshIncomingPacket;
class SshSendFacility;
class AbstractSshChannel : public QObject
{
Q_OBJECT
public:
enum ChannelState {
Inactive, SessionRequested, SessionEstablished, CloseRequested, Closed
};
quint32 localChannelId() const { return m_localChannel; }
quint32 remoteChannel() const { return m_remoteChannel; }
virtual void handleChannelSuccess() = 0;
virtual void handleChannelFailure() = 0;
void handleOpenSuccess(quint32 remoteChannelId, quint32 remoteWindowSize,
quint32 remoteMaxPacketSize);
void handleOpenFailure(const QString &reason);
void handleWindowAdjust(quint64 bytesToAdd);
void handleChannelEof();
void handleChannelClose();
void handleChannelData(const QByteArray &data);
void handleChannelExtendedData(quint32 type, const QByteArray &data);
void handleChannelRequest(const SshIncomingPacket &packet);
void closeChannel();
virtual ~AbstractSshChannel();
static const int ReplyTimeout = 10000; // milli seconds
ChannelState channelState() const { return m_state; }
signals:
void timeout();
void eof();
protected:
AbstractSshChannel(quint32 channelId, SshSendFacility &sendFacility);
void setChannelState(ChannelState state);
void requestSessionStart();
void sendData(const QByteArray &data);
static quint32 initialWindowSize();
static quint32 maxPacketSize();
quint32 maxDataSize() const;
void checkChannelActive() const;
SshSendFacility &m_sendFacility;
QTimer m_timeoutTimer;
private:
virtual void handleOpenSuccessInternal() = 0;
virtual void handleOpenFailureInternal(const QString &reason) = 0;
virtual void handleChannelDataInternal(const QByteArray &data) = 0;
virtual void handleChannelExtendedDataInternal(quint32 type,
const QByteArray &data) = 0;
virtual void handleExitStatus(const SshChannelExitStatus &exitStatus) = 0;
virtual void handleExitSignal(const SshChannelExitSignal &signal) = 0;
virtual void closeHook() = 0;
void flushSendBuffer();
int handleChannelOrExtendedChannelData(const QByteArray &data);
const quint32 m_localChannel;
quint32 m_remoteChannel;
quint32 m_localWindowSize;
quint32 m_remoteWindowSize;
quint32 m_remoteMaxPacketSize;
ChannelState m_state;
QByteArray m_sendBuffer;
};
} // namespace Internal
} // namespace QSsh
#endif // SSHCHANNEL_P_H

View file

@ -1,412 +0,0 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: http://www.qt-project.org/
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**************************************************************************/
#include "sshchannelmanager_p.h"
#include "sftpchannel.h"
#include "sftpchannel_p.h"
#include "sshdirecttcpiptunnel.h"
#include "sshdirecttcpiptunnel_p.h"
#include "sshforwardedtcpiptunnel.h"
#include "sshforwardedtcpiptunnel_p.h"
#include "sshincomingpacket_p.h"
#include "sshlogging_p.h"
#include "sshremoteprocess.h"
#include "sshremoteprocess_p.h"
#include "sshsendfacility_p.h"
#include "sshtcpipforwardserver.h"
#include "sshtcpipforwardserver_p.h"
#include "sshx11channel_p.h"
#include "sshx11inforetriever_p.h"
#include <QList>
namespace QSsh {
namespace Internal {
SshChannelManager::SshChannelManager(SshSendFacility &sendFacility,
QObject *parent)
: QObject(parent), m_sendFacility(sendFacility), m_nextLocalChannelId(0)
{
}
void SshChannelManager::handleChannelRequest(const SshIncomingPacket &packet)
{
lookupChannel(packet.extractRecipientChannel())
->handleChannelRequest(packet);
}
void SshChannelManager::handleChannelOpen(const SshIncomingPacket &packet)
{
const SshChannelOpenGeneric channelOpen = packet.extractChannelOpen();
if (channelOpen.channelType == SshIncomingPacket::ForwardedTcpIpType) {
handleChannelOpenForwardedTcpIp(channelOpen);
return;
}
if (channelOpen.channelType == "x11") {
handleChannelOpenX11(channelOpen);
return;
}
try {
m_sendFacility.sendChannelOpenFailurePacket(channelOpen.commonData.remoteChannel,
SSH_OPEN_UNKNOWN_CHANNEL_TYPE, QByteArray());
} catch (const std::exception &e) {
qCWarning(sshLog, "Botan error: %s", e.what());
}
}
void SshChannelManager::handleChannelOpenFailure(const SshIncomingPacket &packet)
{
const SshChannelOpenFailure &failure = packet.extractChannelOpenFailure();
ChannelIterator it = lookupChannelAsIterator(failure.localChannel);
try {
it.value()->handleOpenFailure(failure.reasonString);
} catch (const SshServerException &e) {
removeChannel(it);
throw;
}
removeChannel(it);
}
void SshChannelManager::handleChannelOpenConfirmation(const SshIncomingPacket &packet)
{
const SshChannelOpenConfirmation &confirmation
= packet.extractChannelOpenConfirmation();
lookupChannel(confirmation.localChannel)->handleOpenSuccess(confirmation.remoteChannel,
confirmation.remoteWindowSize, confirmation.remoteMaxPacketSize);
}
void SshChannelManager::handleChannelSuccess(const SshIncomingPacket &packet)
{
lookupChannel(packet.extractRecipientChannel())->handleChannelSuccess();
}
void SshChannelManager::handleChannelFailure(const SshIncomingPacket &packet)
{
lookupChannel(packet.extractRecipientChannel())->handleChannelFailure();
}
void SshChannelManager::handleChannelWindowAdjust(const SshIncomingPacket &packet)
{
const SshChannelWindowAdjust adjust = packet.extractWindowAdjust();
lookupChannel(adjust.localChannel)->handleWindowAdjust(adjust.bytesToAdd);
}
void SshChannelManager::handleChannelData(const SshIncomingPacket &packet)
{
const SshChannelData &data = packet.extractChannelData();
lookupChannel(data.localChannel)->handleChannelData(data.data);
}
void SshChannelManager::handleChannelExtendedData(const SshIncomingPacket &packet)
{
const SshChannelExtendedData &data = packet.extractChannelExtendedData();
lookupChannel(data.localChannel)->handleChannelExtendedData(data.type, data.data);
}
void SshChannelManager::handleChannelEof(const SshIncomingPacket &packet)
{
AbstractSshChannel * const channel
= lookupChannel(packet.extractRecipientChannel(), true);
if (channel)
channel->handleChannelEof();
}
void SshChannelManager::handleChannelClose(const SshIncomingPacket &packet)
{
const quint32 channelId = packet.extractRecipientChannel();
ChannelIterator it = lookupChannelAsIterator(channelId, true);
if (it != m_channels.end()) {
it.value()->handleChannelClose();
removeChannel(it);
}
}
void SshChannelManager::handleRequestSuccess(const SshIncomingPacket &packet)
{
if (m_waitingForwardServers.isEmpty()) {
throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR,
"Unexpected request success packet.",
tr("Unexpected request success packet."));
}
SshTcpIpForwardServer::Ptr server = m_waitingForwardServers.takeFirst();
if (server->state() == SshTcpIpForwardServer::Closing) {
server->setClosed();
} else if (server->state() == SshTcpIpForwardServer::Initializing) {
quint16 port = server->port();
if (port == 0)
port = packet.extractRequestSuccess().bindPort;
server->setListening(port);
m_listeningForwardServers.append(server);
} else {
QSSH_ASSERT(false);
}
}
void SshChannelManager::handleRequestFailure(const SshIncomingPacket &packet)
{
Q_UNUSED(packet);
if (m_waitingForwardServers.isEmpty()) {
throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR,
"Unexpected request failure packet.",
tr("Unexpected request failure packet."));
}
SshTcpIpForwardServer::Ptr tunnel = m_waitingForwardServers.takeFirst();
tunnel->setClosed();
}
SshChannelManager::ChannelIterator SshChannelManager::lookupChannelAsIterator(quint32 channelId,
bool allowNotFound)
{
ChannelIterator it = m_channels.find(channelId);
if (it == m_channels.end() && !allowNotFound) {
throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR,
"Invalid channel id.",
tr("Invalid channel id %1").arg(channelId));
}
return it;
}
AbstractSshChannel *SshChannelManager::lookupChannel(quint32 channelId,
bool allowNotFound)
{
ChannelIterator it = lookupChannelAsIterator(channelId, allowNotFound);
return it == m_channels.end() ? nullptr : it.value();
}
QSsh::SshRemoteProcess::Ptr SshChannelManager::createRemoteProcess(const QByteArray &command)
{
SshRemoteProcess::Ptr proc(new SshRemoteProcess(command, m_nextLocalChannelId++, m_sendFacility));
insertChannel(proc->d, proc);
connect(proc->d, &SshRemoteProcessPrivate::destroyed, this, [this] {
m_x11ForwardingRequests.removeOne(static_cast<SshRemoteProcessPrivate *>(sender()));
});
connect(proc->d, &SshRemoteProcessPrivate::x11ForwardingRequested, this,
[this, proc = proc->d](const QString &displayName) {
if (!x11DisplayName().isEmpty()) {
if (x11DisplayName() != displayName) {
proc->failToStart(tr("Cannot forward to display %1 on SSH connection that is "
"already forwarding to display %2.")
.arg(displayName, x11DisplayName()));
return;
}
if (!m_x11DisplayInfo.cookie.isEmpty())
proc->startProcess(m_x11DisplayInfo);
else
m_x11ForwardingRequests << proc;
return;
}
m_x11DisplayInfo.displayName = displayName;
m_x11ForwardingRequests << proc;
auto * const x11InfoRetriever = new SshX11InfoRetriever(displayName, this);
const auto failureHandler = [this](const QString &errorMessage) {
for (SshRemoteProcessPrivate * const proc : qAsConst(m_x11ForwardingRequests))
proc->failToStart(errorMessage);
m_x11ForwardingRequests.clear();
};
connect(x11InfoRetriever, &SshX11InfoRetriever::failure, this, failureHandler);
const auto successHandler = [this](const X11DisplayInfo &displayInfo) {
m_x11DisplayInfo = displayInfo;
for (SshRemoteProcessPrivate * const proc : qAsConst(m_x11ForwardingRequests))
proc->startProcess(displayInfo);
m_x11ForwardingRequests.clear();
};
connect(x11InfoRetriever, &SshX11InfoRetriever::success, this, successHandler);
qCDebug(sshLog) << "starting x11 info retriever";
x11InfoRetriever->start();
});
return proc;
}
QSsh::SshRemoteProcess::Ptr SshChannelManager::createRemoteShell()
{
SshRemoteProcess::Ptr proc(new SshRemoteProcess(m_nextLocalChannelId++, m_sendFacility));
insertChannel(proc->d, proc);
return proc;
}
QSsh::SftpChannel::Ptr SshChannelManager::createSftpChannel()
{
SftpChannel::Ptr sftp(new SftpChannel(m_nextLocalChannelId++, m_sendFacility));
insertChannel(sftp->d, sftp);
return sftp;
}
SshDirectTcpIpTunnel::Ptr SshChannelManager::createDirectTunnel(const QString &originatingHost,
quint16 originatingPort, const QString &remoteHost, quint16 remotePort)
{
SshDirectTcpIpTunnel::Ptr tunnel(new SshDirectTcpIpTunnel(m_nextLocalChannelId++,
originatingHost, originatingPort, remoteHost, remotePort, m_sendFacility));
insertChannel(tunnel->d, tunnel);
return tunnel;
}
SshTcpIpForwardServer::Ptr SshChannelManager::createForwardServer(const QString &remoteHost,
quint16 remotePort)
{
SshTcpIpForwardServer::Ptr server(new SshTcpIpForwardServer(remoteHost, remotePort,
m_sendFacility));
connect(server.data(), &SshTcpIpForwardServer::stateChanged,
this, [this, server](SshTcpIpForwardServer::State state) {
switch (state) {
case SshTcpIpForwardServer::Closing:
m_listeningForwardServers.removeOne(server);
Q_FALLTHROUGH();
case SshTcpIpForwardServer::Initializing:
m_waitingForwardServers.append(server);
break;
case SshTcpIpForwardServer::Listening:
case SshTcpIpForwardServer::Inactive:
break;
}
});
return server;
}
void SshChannelManager::insertChannel(AbstractSshChannel *priv,
const QSharedPointer<QObject> &pub)
{
connect(priv, &AbstractSshChannel::timeout, this, &SshChannelManager::timeout);
m_channels.insert(priv->localChannelId(), priv);
m_sessions.insert(priv, pub);
}
void SshChannelManager::handleChannelOpenForwardedTcpIp(
const SshChannelOpenGeneric &channelOpenGeneric)
{
const SshChannelOpenForwardedTcpIp channelOpen
= SshIncomingPacket::extractChannelOpenForwardedTcpIp(channelOpenGeneric);
SshTcpIpForwardServer::Ptr server;
foreach (const SshTcpIpForwardServer::Ptr &candidate, m_listeningForwardServers) {
if (candidate->port() == channelOpen.remotePort
&& candidate->bindAddress().toUtf8() == channelOpen.remoteAddress) {
server = candidate;
break;
}
};
if (server.isNull()) {
// Apparently the server knows a remoteAddress we are not aware of. There are plenty of ways
// to make that happen: /etc/hosts on the server, different writings for localhost,
// different DNS servers, ...
// Rather than trying to figure that out, we just use the first listening forwarder with the
// same port.
foreach (const SshTcpIpForwardServer::Ptr &candidate, m_listeningForwardServers) {
if (candidate->port() == channelOpen.remotePort) {
server = candidate;
break;
}
};
}
if (server.isNull()) {
try {
m_sendFacility.sendChannelOpenFailurePacket(channelOpen.common.remoteChannel,
SSH_OPEN_ADMINISTRATIVELY_PROHIBITED,
QByteArray());
} catch (const std::exception &e) {
qCWarning(sshLog, "Botan error: %s", e.what());
}
return;
}
SshForwardedTcpIpTunnel::Ptr tunnel(new SshForwardedTcpIpTunnel(m_nextLocalChannelId++,
m_sendFacility));
tunnel->d->handleOpenSuccess(channelOpen.common.remoteChannel,
channelOpen.common.remoteWindowSize,
channelOpen.common.remoteMaxPacketSize);
tunnel->open(QIODevice::ReadWrite);
server->setNewConnection(tunnel);
insertChannel(tunnel->d, tunnel);
}
void SshChannelManager::handleChannelOpenX11(const SshChannelOpenGeneric &channelOpenGeneric)
{
qCDebug(sshLog) << "incoming X11 channel open request";
const SshChannelOpenX11 channelOpen
= SshIncomingPacket::extractChannelOpenX11(channelOpenGeneric);
if (m_x11DisplayInfo.cookie.isEmpty()) {
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
"Server attempted to open an unrequested X11 channel.");
}
SshX11Channel * const x11Channel = new SshX11Channel(m_x11DisplayInfo,
m_nextLocalChannelId++,
m_sendFacility);
x11Channel->setParent(this);
x11Channel->handleOpenSuccess(channelOpen.common.remoteChannel,
channelOpen.common.remoteWindowSize,
channelOpen.common.remoteMaxPacketSize);
insertChannel(x11Channel, QSharedPointer<QObject>());
}
int SshChannelManager::closeAllChannels(CloseAllMode mode)
{
int count = 0;
for (ChannelIterator it = m_channels.begin(); it != m_channels.end(); ++it) {
AbstractSshChannel * const channel = it.value();
QSSH_ASSERT(channel->channelState() != AbstractSshChannel::Closed);
if (channel->channelState() != AbstractSshChannel::CloseRequested) {
channel->closeChannel();
++count;
}
}
if (mode == CloseAllAndReset) {
m_channels.clear();
m_sessions.clear();
}
return count;
}
int SshChannelManager::channelCount() const
{
return m_channels.count();
}
void SshChannelManager::removeChannel(ChannelIterator it)
{
if (it == m_channels.end()) {
throw SshClientException(SshInternalError,
QLatin1String("Internal error: Unexpected channel lookup failure"));
}
const int removeCount = m_sessions.remove(it.value());
if (removeCount != 1) {
throw SshClientException(SshInternalError,
QString::fromLatin1("Internal error: Unexpected session count %1 for channel.")
.arg(removeCount));
}
m_channels.erase(it);
}
} // namespace Internal
} // namespace QSsh

View file

@ -1,117 +0,0 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: http://www.qt-project.org/
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**************************************************************************/
#ifndef SSHCHANNELLAYER_P_H
#define SSHCHANNELLAYER_P_H
#include "sshx11displayinfo_p.h"
#include <QHash>
#include <QObject>
#include <QSharedPointer>
namespace QSsh {
class SftpChannel;
class SshDirectTcpIpTunnel;
class SshRemoteProcess;
class SshTcpIpForwardServer;
namespace Internal {
class AbstractSshChannel;
struct SshChannelOpenGeneric;
class SshIncomingPacket;
class SshSendFacility;
class SshRemoteProcessPrivate;
class SshChannelManager : public QObject
{
Q_OBJECT
public:
SshChannelManager(SshSendFacility &sendFacility, QObject *parent);
QSharedPointer<SshRemoteProcess> createRemoteProcess(const QByteArray &command);
QSharedPointer<SshRemoteProcess> createRemoteShell();
QSharedPointer<SftpChannel> createSftpChannel();
QSharedPointer<SshDirectTcpIpTunnel> createDirectTunnel(const QString &originatingHost,
quint16 originatingPort, const QString &remoteHost, quint16 remotePort);
QSharedPointer<SshTcpIpForwardServer> createForwardServer(const QString &remoteHost,
quint16 remotePort);
int channelCount() const;
enum CloseAllMode { CloseAllRegular, CloseAllAndReset };
int closeAllChannels(CloseAllMode mode);
QString x11DisplayName() const { return m_x11DisplayInfo.displayName; }
void handleChannelRequest(const SshIncomingPacket &packet);
void handleChannelOpen(const SshIncomingPacket &packet);
void handleChannelOpenFailure(const SshIncomingPacket &packet);
void handleChannelOpenConfirmation(const SshIncomingPacket &packet);
void handleChannelSuccess(const SshIncomingPacket &packet);
void handleChannelFailure(const SshIncomingPacket &packet);
void handleChannelWindowAdjust(const SshIncomingPacket &packet);
void handleChannelData(const SshIncomingPacket &packet);
void handleChannelExtendedData(const SshIncomingPacket &packet);
void handleChannelEof(const SshIncomingPacket &packet);
void handleChannelClose(const SshIncomingPacket &packet);
void handleRequestSuccess(const SshIncomingPacket &packet);
void handleRequestFailure(const SshIncomingPacket &packet);
signals:
void timeout();
private:
typedef QHash<quint32, AbstractSshChannel *>::Iterator ChannelIterator;
ChannelIterator lookupChannelAsIterator(quint32 channelId,
bool allowNotFound = false);
AbstractSshChannel *lookupChannel(quint32 channelId,
bool allowNotFound = false);
void removeChannel(ChannelIterator it);
void insertChannel(AbstractSshChannel *priv,
const QSharedPointer<QObject> &pub);
void handleChannelOpenForwardedTcpIp(const SshChannelOpenGeneric &channelOpenGeneric);
void handleChannelOpenX11(const SshChannelOpenGeneric &channelOpenGeneric);
SshSendFacility &m_sendFacility;
QHash<quint32, AbstractSshChannel *> m_channels;
QHash<AbstractSshChannel *, QSharedPointer<QObject> > m_sessions;
quint32 m_nextLocalChannelId;
QList<QSharedPointer<SshTcpIpForwardServer>> m_waitingForwardServers;
QList<QSharedPointer<SshTcpIpForwardServer>> m_listeningForwardServers;
QList<SshRemoteProcessPrivate *> m_x11ForwardingRequests;
X11DisplayInfo m_x11DisplayInfo;
};
} // namespace Internal
} // namespace QSsh
#endif // SSHCHANNELLAYER_P_H

File diff suppressed because it is too large Load diff

View file

@ -1,298 +0,0 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: http://www.qt-project.org/
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**************************************************************************/
#ifndef SSHCONNECTION_H
#define SSHCONNECTION_H
#include "ssherrors.h"
#include "sshhostkeydatabase.h"
#include "ssh_global.h"
#include <QByteArray>
#include <QFlags>
#include <QMetaType>
#include <QObject>
#include <QSharedPointer>
#include <QString>
#include <QHostAddress>
#include <QUrl>
namespace QSsh {
class SftpChannel;
class SshDirectTcpIpTunnel;
class SshRemoteProcess;
class SshTcpIpForwardServer;
namespace Internal {
class SshConnectionPrivate;
} // namespace Internal
/*!
* \brief Flags that control various general behavior
*/
enum SshConnectionOption {
/// Set this to ignore the system defined proxy
SshIgnoreDefaultProxy = 0x1,
/// Fail instead of warn if the remote host violates the standard
SshEnableStrictConformanceChecks = 0x2,
/// Set the QAbstractSocket::LowDelayOption, which is the same as TCP_NODELAY
SshLowDelaySocket = 0x4
};
Q_DECLARE_FLAGS(SshConnectionOptions, SshConnectionOption)
/*!
* \brief How strict to be when checking the remote key
*/
enum SshHostKeyCheckingMode {
/// Ignore the remote key
SshHostKeyCheckingNone,
/// Fail connection if either there is no key stored for this host or the key is not the same as earlier
SshHostKeyCheckingStrict,
/// Allow connecting if there is no stored key for the host, but fail if the key has changed
SshHostKeyCheckingAllowNoMatch,
/// Continue connection if the key doesn't match the stored key for the host
SshHostKeyCheckingAllowMismatch
};
/*!
* \brief Class to use to specify parameters used during connection.
*/
class QSSH_EXPORT SshConnectionParameters
{
public:
/*!
* \brief What kinds of authentication to attempt
*/
enum AuthenticationType {
AuthenticationTypePassword, ///< Only attempt to connect using the password set with setPassword().
AuthenticationTypePublicKey, ///< Only attempt to authenticate with public key
/// Only attempt keyboard interactive authentication.
/// For now this only changes what to send to the server,
/// we will still just try to use the password set here.
AuthenticationTypeKeyboardInteractive,
/// Any method using the password set with setPassword().
/// Some servers disable \a "password", others disable \a "keyboard-interactive"
AuthenticationTypeTryAllPasswordBasedMethods,
/// ssh-agent authentication only
AuthenticationTypeAgent,
};
SshConnectionParameters();
/*!
* \brief Returns the hostname or IP set with setHost()
*/
QString host() const { return url.host(); }
/*!
* \brief Returns the port set with setPort()
*/
int port() const { return url.port(); }
/*!
* \brief Returns the username set with setUsername()
* \return
*/
QString userName() const { return url.userName(); }
/*!
* \brief Returns the password set with setPassword()
*/
QString password() const { return url.password(); }
/*!
* \brief Sets the hostname or IP to connect to
* \param host The remote host
*/
void setHost(const QString &host) { url.setHost(host); }
/*!
* \brief Sets the remote port to use
* \param port
*/
void setPort(int port) { url.setPort(port); }
/*!
* \brief Sets the username to use
* \param name Username
*/
void setUserName(const QString &name) { url.setUserName(name); }
/*!
* \brief Sets the password to attempt to use
* \param password
*/
void setPassword(const QString &password) { url.setPassword(password); }
QUrl url;
QString privateKeyFile;
int timeout; // In seconds.
AuthenticationType authenticationType;
SshConnectionOptions options;
SshHostKeyCheckingMode hostKeyCheckingMode;
SshHostKeyDatabasePtr hostKeyDatabase;
};
/// @cond
QSSH_EXPORT bool operator==(const SshConnectionParameters &p1, const SshConnectionParameters &p2);
QSSH_EXPORT bool operator!=(const SshConnectionParameters &p1, const SshConnectionParameters &p2);
/// @endcond
/*!
* \brief Network connection info.
*/
class QSSH_EXPORT SshConnectionInfo
{
public:
SshConnectionInfo() : localPort(0), peerPort(0) {}
SshConnectionInfo(const QHostAddress &la, quint16 lp, const QHostAddress &pa, quint16 pp)
: localAddress(la), localPort(lp), peerAddress(pa), peerPort(pp) {}
QHostAddress localAddress;
quint16 localPort;
QHostAddress peerAddress;
quint16 peerPort;
};
/*!
\class QSsh::SshConnection
\brief This class provides an SSH connection, implementing protocol version 2.0
See acquireConnection() which provides a pool mechanism for re-use.
It can spawn channels for remote execution and SFTP operations (version 3).
It operates asynchronously (non-blocking) and is not thread-safe.
*/
class QSSH_EXPORT SshConnection : public QObject
{
Q_OBJECT
public:
/*!
* \brief The current state of a connection
*/
enum State { Unconnected, Connecting, Connected };
/*!
* \param serverInfo serverInfo connection parameters
* \param parent Parent object.
*/
explicit SshConnection(const SshConnectionParameters &serverInfo, QObject *parent = nullptr);
void connectToHost();
void disconnectFromHost();
/*!
* \brief Current state of this connection
*/
State state() const;
/*!
* \brief Returns the error state of the connection
* \returns If there is no error, returns \ref SshNoError if the connection is OK
*/
SshError errorState() const;
QString errorString() const;
SshConnectionParameters connectionParameters() const;
SshConnectionInfo connectionInfo() const;
~SshConnection();
/*!
* \brief Use this to launch remote commands
* \param command The command to execute
*/
QSharedPointer<SshRemoteProcess> createRemoteProcess(const QByteArray &command);
/*!
* \brief Creates a remote interactive session with a shell
*/
QSharedPointer<SshRemoteProcess> createRemoteShell();
QSharedPointer<SftpChannel> createSftpChannel();
QSharedPointer<SshDirectTcpIpTunnel> createDirectTunnel(const QString &originatingHost,
quint16 originatingPort, const QString &remoteHost, quint16 remotePort);
QSharedPointer<SshTcpIpForwardServer> createForwardServer(const QString &remoteHost,
quint16 remotePort);
// -1 if an error occurred, number of channels closed otherwise.
int closeAllChannels();
int channelCount() const;
const QByteArray &hostKeyFingerprint() const;
/*!
* \brief The X11 display name used for X11 forwarding
* \return The name of the X11 display set for this connection
*/
QString x11DisplayName() const;
signals:
/*!
* \brief Emitted when ready for use
*/
void connected();
/*!
* \brief Emitted when the connection has been closed
*/
void disconnected();
/*!
* \brief Emitted when data has been received
* \param message The content of the data, same as the output you would get when running \a ssh on the command line
*/
void dataAvailable(const QString &message);
/*!
* \brief Emitted when an error occured
*/
void error(QSsh::SshError);
private:
Internal::SshConnectionPrivate *d;
};
} // namespace QSsh
Q_DECLARE_METATYPE(QSsh::SshConnectionParameters::AuthenticationType)
#endif // SSHCONNECTION_H

View file

@ -1,204 +0,0 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: http://www.qt-project.org/
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**************************************************************************/
#ifndef SSHCONNECTION_P_H
#define SSHCONNECTION_P_H
#include "sshconnection.h"
#include "sshexception_p.h"
#include "sshincomingpacket_p.h"
#include "sshsendfacility_p.h"
#include <QHash>
#include <QList>
#include <QQueue>
#include <QObject>
#include <QPair>
#include <QScopedPointer>
#include <QTimer>
QT_BEGIN_NAMESPACE
class QTcpSocket;
QT_END_NAMESPACE
namespace QSsh {
class SftpChannel;
class SshRemoteProcess;
class SshDirectTcpIpTunnel;
class SshTcpIpForwardServer;
namespace Internal {
class SshChannelManager;
// NOTE: When you add stuff here, don't forget to update m_packetHandlers.
enum SshStateInternal {
SocketUnconnected, // initial and after disconnect
SocketConnecting, // After connectToHost()
SocketConnected, // After socket's connected() signal
UserAuthServiceRequested,
WaitingForAgentKeys,
UserAuthRequested,
ConnectionEstablished // After service has been started
// ...
};
enum SshKeyExchangeState {
NoKeyExchange,
KexInitSent,
DhInitSent,
NewKeysSent,
KeyExchangeSuccess // After server's DH_REPLY message
};
class SshConnectionPrivate : public QObject
{
Q_OBJECT
friend class QSsh::SshConnection;
public:
SshConnectionPrivate(SshConnection *conn,
const SshConnectionParameters &serverInfo);
~SshConnectionPrivate();
void connectToHost();
void closeConnection(SshErrorCode sshError, SshError userError,
const QByteArray &serverErrorString, const QString &userErrorString);
QSharedPointer<SshRemoteProcess> createRemoteProcess(const QByteArray &command);
QSharedPointer<SshRemoteProcess> createRemoteShell();
QSharedPointer<SftpChannel> createSftpChannel();
QSharedPointer<SshDirectTcpIpTunnel> createDirectTunnel(const QString &originatingHost,
quint16 originatingPort, const QString &remoteHost, quint16 remotePort);
QSharedPointer<SshTcpIpForwardServer> createForwardServer(const QString &remoteHost,
quint16 remotePort);
SshStateInternal state() const { return m_state; }
SshError errorState() const { return m_error; }
QString errorString() const { return m_errorString; }
const QByteArray &hostKeyFingerprint() const { return m_hostFingerprint; }
signals:
void connected();
void disconnected();
void dataAvailable(const QString &message);
void error(QSsh::SshError);
private:
void handleSocketConnected();
void handleIncomingData();
void handleSocketError();
void handleSocketDisconnected();
void handleTimeout();
void sendKeepAlivePacket();
void handleAgentKeysUpdated();
void handleSignatureFromAgent(const QByteArray &key, const QByteArray &signature, uint token);
void tryAllAgentKeys();
void authenticateWithPublicKey();
void setAgentError();
void handleServerId();
void handlePackets();
void handleCurrentPacket();
void handleKeyExchangeInitPacket();
void handleKeyExchangeReplyPacket();
void handleNewKeysPacket();
void handleServiceAcceptPacket();
void handlePasswordExpiredPacket();
void handleUserAuthInfoRequestPacket();
void handleUserAuthSuccessPacket();
void handleUserAuthFailurePacket();
void handleUserAuthKeyOkPacket();
void handleUserAuthBannerPacket();
void handleUnexpectedPacket();
void handleGlobalRequest();
void handleDebugPacket();
void handleUnimplementedPacket();
void handleChannelRequest();
void handleChannelOpen();
void handleChannelOpenFailure();
void handleChannelOpenConfirmation();
void handleChannelSuccess();
void handleChannelFailure();
void handleChannelWindowAdjust();
void handleChannelData();
void handleChannelExtendedData();
void handleChannelEof();
void handleChannelClose();
void handleDisconnect();
void handleRequestSuccess();
void handleRequestFailure();
bool canUseSocket() const;
void createPrivateKey();
void sendData(const QByteArray &data);
uint tokenForAgent() const;
typedef void (SshConnectionPrivate::*PacketHandler)();
typedef QList<SshStateInternal> StateList;
void setupPacketHandlers();
void setupPacketHandler(SshPacketType type, const StateList &states,
PacketHandler handler);
typedef QPair<StateList, PacketHandler> HandlerInStates;
QHash<SshPacketType, HandlerInStates> m_packetHandlers;
static const quint64 InvalidSeqNr;
QTcpSocket *m_socket;
SshStateInternal m_state;
SshKeyExchangeState m_keyExchangeState;
SshIncomingPacket m_incomingPacket;
SshSendFacility m_sendFacility;
SshChannelManager * const m_channelManager;
const SshConnectionParameters m_connParams;
QByteArray m_incomingData;
SshError m_error;
QString m_errorString;
QScopedPointer<SshKeyExchange> m_keyExchange;
QByteArray m_hostFingerprint;
QTimer m_timeoutTimer;
QTimer m_keepAliveTimer;
bool m_ignoreNextPacket;
SshConnection *m_conn;
quint64 m_lastInvalidMsgSeqNr;
QByteArray m_serverId;
QByteArray m_agentSignature;
QQueue<QByteArray> m_pendingKeyChecks;
QByteArray m_agentKeyToUse;
bool m_serverHasSentDataBeforeId;
bool m_triedAllPasswordBasedMethods;
bool m_agentKeysUpToDate;
};
} // namespace Internal
} // namespace QSsh
#endif // SSHCONNECTION_P_H

View file

@ -1,276 +0,0 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: http://www.qt-project.org/
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**************************************************************************/
#include "sshconnectionmanager.h"
#include "sshconnection.h"
#include <QCoreApplication>
#include <QList>
#include <QMutex>
#include <QMutexLocker>
#include <QObject>
#include <QThread>
#include <QTimer>
namespace QSsh {
namespace Internal {
class UnaquiredConnection {
public:
UnaquiredConnection(SshConnection *conn) : connection(conn), scheduledForRemoval(false) {}
SshConnection *connection;
bool scheduledForRemoval;
};
bool operator==(UnaquiredConnection c1, UnaquiredConnection c2) {
return c1.connection == c2.connection;
}
bool operator!=(UnaquiredConnection c1, UnaquiredConnection c2) {
return !(c1 == c2);
}
class SshConnectionManager : public QObject
{
Q_OBJECT
public:
SshConnectionManager()
{
moveToThread(QCoreApplication::instance()->thread());
connect(&m_removalTimer, &QTimer::timeout,
this, &SshConnectionManager::removeInactiveConnections);
m_removalTimer.setTimerType(Qt::VeryCoarseTimer);
m_removalTimer.start(150000); // For a total timeout of five minutes.
}
~SshConnectionManager()
{
foreach (const UnaquiredConnection &connection, m_unacquiredConnections) {
disconnect(connection.connection, nullptr, this, nullptr);
delete connection.connection;
}
QSSH_ASSERT(m_acquiredConnections.isEmpty());
QSSH_ASSERT(m_deprecatedConnections.isEmpty());
}
SshConnection *acquireConnection(const SshConnectionParameters &sshParams)
{
QMutexLocker locker(&m_listMutex);
// Check in-use connections:
foreach (SshConnection * const connection, m_acquiredConnections) {
if (connection->connectionParameters() != sshParams)
continue;
if (connection->thread() != QThread::currentThread())
continue;
if (m_deprecatedConnections.contains(connection)) // we were asked to no longer use this one...
continue;
m_acquiredConnections.append(connection);
return connection;
}
// Check cached open connections:
foreach (const UnaquiredConnection &c, m_unacquiredConnections) {
SshConnection * const connection = c.connection;
if (connection->state() != SshConnection::Connected
|| connection->connectionParameters() != sshParams)
continue;
if (connection->thread() != QThread::currentThread()) {
if (connection->channelCount() != 0)
continue;
QMetaObject::invokeMethod(this, "switchToCallerThread",
Qt::BlockingQueuedConnection,
Q_ARG(SshConnection *, connection),
Q_ARG(QObject *, QThread::currentThread()));
}
m_unacquiredConnections.removeOne(c);
m_acquiredConnections.append(connection);
return connection;
}
// create a new connection:
SshConnection * const connection = new SshConnection(sshParams);
connect(connection, &SshConnection::disconnected,
this, &SshConnectionManager::cleanup);
m_acquiredConnections.append(connection);
return connection;
}
void releaseConnection(SshConnection *connection)
{
QMutexLocker locker(&m_listMutex);
const bool wasAquired = m_acquiredConnections.removeOne(connection);
QSSH_ASSERT_AND_RETURN(wasAquired);
if (m_acquiredConnections.contains(connection))
return;
bool doDelete = false;
connection->moveToThread(QCoreApplication::instance()->thread());
if (m_deprecatedConnections.removeOne(connection)
|| connection->state() != SshConnection::Connected) {
doDelete = true;
} else {
QSSH_ASSERT_AND_RETURN(!m_unacquiredConnections.contains(UnaquiredConnection(connection)));
// It can happen that two or more connections with the same parameters were acquired
// if the clients were running in different threads. Only keep one of them in
// such a case.
bool haveConnection = false;
foreach (const UnaquiredConnection &c, m_unacquiredConnections) {
if (c.connection->connectionParameters() == connection->connectionParameters()) {
haveConnection = true;
break;
}
}
if (!haveConnection) {
connection->closeAllChannels(); // Clean up after neglectful clients.
m_unacquiredConnections.append(UnaquiredConnection(connection));
} else {
doDelete = true;
}
}
if (doDelete) {
disconnect(connection, nullptr, this, nullptr);
m_deprecatedConnections.removeAll(connection);
connection->deleteLater();
}
}
void forceNewConnection(const SshConnectionParameters &sshParams)
{
QMutexLocker locker(&m_listMutex);
for (int i = 0; i < m_unacquiredConnections.count(); ++i) {
SshConnection * const connection = m_unacquiredConnections.at(i).connection;
if (connection->connectionParameters() == sshParams) {
disconnect(connection, nullptr, this, nullptr);
delete connection;
m_unacquiredConnections.removeAt(i);
break;
}
}
foreach (SshConnection * const connection, m_acquiredConnections) {
if (connection->connectionParameters() == sshParams) {
if (!m_deprecatedConnections.contains(connection))
m_deprecatedConnections.append(connection);
}
}
}
private:
Q_INVOKABLE void switchToCallerThread(SshConnection *connection, QObject *threadObj)
{
connection->moveToThread(qobject_cast<QThread *>(threadObj));
}
void cleanup()
{
QMutexLocker locker(&m_listMutex);
SshConnection *currentConnection = qobject_cast<SshConnection *>(sender());
if (!currentConnection)
return;
if (m_unacquiredConnections.removeOne(UnaquiredConnection(currentConnection))) {
disconnect(currentConnection, nullptr, this, nullptr);
currentConnection->deleteLater();
}
}
void removeInactiveConnections()
{
QMutexLocker locker(&m_listMutex);
for (int i = m_unacquiredConnections.count() - 1; i >= 0; --i) {
UnaquiredConnection &c = m_unacquiredConnections[i];
if (c.scheduledForRemoval) {
disconnect(c.connection, nullptr, this, nullptr);
c.connection->deleteLater();
m_unacquiredConnections.removeAt(i);
} else {
c.scheduledForRemoval = true;
}
}
}
private:
// We expect the number of concurrently open connections to be small.
// If that turns out to not be the case, we can still use a data
// structure with faster access.
QList<UnaquiredConnection> m_unacquiredConnections;
// Can contain the same connection more than once; this acts as a reference count.
QList<SshConnection *> m_acquiredConnections;
QList<SshConnection *> m_deprecatedConnections;
QMutex m_listMutex;
QTimer m_removalTimer;
};
} // namespace Internal
static QMutex instanceMutex;
static Internal::SshConnectionManager &instance()
{
static Internal::SshConnectionManager manager;
return manager;
}
SshConnection *acquireConnection(const SshConnectionParameters &sshParams)
{
QMutexLocker locker(&instanceMutex);
return instance().acquireConnection(sshParams);
}
void releaseConnection(SshConnection *connection)
{
QMutexLocker locker(&instanceMutex);
instance().releaseConnection(connection);
}
void forceNewConnection(const SshConnectionParameters &sshParams)
{
QMutexLocker locker(&instanceMutex);
instance().forceNewConnection(sshParams);
}
} // namespace QSsh
#include "sshconnectionmanager.moc"

View file

@ -1,63 +0,0 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: http://www.qt-project.org/
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**************************************************************************/
#ifndef SSHCONNECTIONMANAGER_H
#define SSHCONNECTIONMANAGER_H
#include "ssh_global.h"
namespace QSsh {
class SshConnection;
class SshConnectionParameters;
/*!
* \brief Creates a new connection or returns an existing one if there already is one with identical sshParams
* \param sshParams Parameters used during connection
* \return A connection
*/
QSSH_EXPORT SshConnection *acquireConnection(const SshConnectionParameters &sshParams);
/*!
* \brief Call this when you are done with a connection, might be disconnected and destroyed if there are no others who have called acquireConnection()
* \param connection The connection to be released
*/
QSSH_EXPORT void releaseConnection(SshConnection *connection);
/*!
* \brief Creates a new connection, unlike acquireConnection() it will not reuse an existing one.
* \param sshParams Parameters used during connection
* Make sure the next acquireConnection with the given parameters will return a new connection.
*/
QSSH_EXPORT void forceNewConnection(const SshConnectionParameters &sshParams);
} // namespace QSsh
#endif // SSHCONNECTIONMANAGER_H

View file

@ -1,456 +0,0 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: http://www.qt-project.org/
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**************************************************************************/
#include "sshcryptofacility_p.h"
#include "opensshkeyfilereader_p.h"
#include "sshbotanconversions_p.h"
#include "sshcapabilities_p.h"
#include "sshexception_p.h"
#include "sshkeyexchange_p.h"
#include "sshkeypasswordretriever_p.h"
#include "sshpacket_p.h"
#include "sshlogging_p.h"
#include <botan_all.h>
#include <QDebug>
#include <QList>
#include <string>
using namespace Botan;
namespace QSsh {
namespace Internal {
SshAbstractCryptoFacility::SshAbstractCryptoFacility()
: m_cipherBlockSize(0), m_macLength(0)
{
}
SshAbstractCryptoFacility::~SshAbstractCryptoFacility() {}
void SshAbstractCryptoFacility::clearKeys()
{
m_cipherBlockSize = 0;
m_macLength = 0;
m_sessionId.clear();
m_pipe.reset(nullptr);
m_hMac.reset(nullptr);
}
SshAbstractCryptoFacility::Mode SshAbstractCryptoFacility::getMode(const QByteArray &algoName)
{
if (algoName.endsWith("-ctr"))
return CtrMode;
if (algoName.endsWith("-cbc"))
return CbcMode;
throw SshClientException(SshInternalError, SSH_TR("Unexpected cipher \"%1\"")
.arg(QString::fromLatin1(algoName)));
}
void SshAbstractCryptoFacility::recreateKeys(const SshKeyExchange &kex)
{
checkInvariant();
if (m_sessionId.isEmpty())
m_sessionId = kex.h();
const QByteArray &rfcCryptAlgoName = cryptAlgoName(kex);
{ // Don't know how else to get this with the new botan API
std::unique_ptr<BlockCipher> cipher
= BlockCipher::create_or_throw(botanCryptAlgoName(rfcCryptAlgoName));
m_cipherBlockSize = static_cast<quint32>(cipher->block_size());
}
const QByteArray ivData = generateHash(kex, ivChar(), m_cipherBlockSize);
const InitializationVector iv(convertByteArray(ivData), m_cipherBlockSize);
Keyed_Filter * const cipherMode
= makeCipherMode(botanCipherAlgoName(rfcCryptAlgoName), getMode(rfcCryptAlgoName));
const quint32 keySize = static_cast<quint32>(cipherMode->key_spec().maximum_keylength());
const QByteArray cryptKeyData = generateHash(kex, keyChar(), keySize);
SymmetricKey cryptKey(convertByteArray(cryptKeyData), keySize);
cipherMode->set_key(cryptKey);
cipherMode->set_iv(iv);
m_pipe.reset(new Pipe(cipherMode));
m_macLength = botanHMacKeyLen(hMacAlgoName(kex));
const QByteArray hMacKeyData = generateHash(kex, macChar(), macLength());
SymmetricKey hMacKey(convertByteArray(hMacKeyData), macLength());
m_hMac = MessageAuthenticationCode::create_or_throw("HMAC(" + std::string(botanHMacAlgoName(hMacAlgoName(kex))) + ")");
m_hMac->set_key(hMacKey);
}
void SshAbstractCryptoFacility::convert(QByteArray &data, quint32 offset,
quint32 dataSize) const
{
Q_ASSERT(offset + dataSize <= static_cast<quint32>(data.size()));
checkInvariant();
// Session id empty => No key exchange has happened yet.
if (dataSize == 0 || m_sessionId.isEmpty())
return;
if (dataSize % cipherBlockSize() != 0) {
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
"Invalid packet size");
}
m_pipe->process_msg(reinterpret_cast<const byte *>(data.constData()) + offset,
dataSize);
// Can't use Pipe::LAST_MESSAGE because of a VC bug.
quint32 bytesRead = static_cast<quint32>(m_pipe->read(
reinterpret_cast<byte *>(data.data()) + offset, dataSize, m_pipe->message_count() - 1));
if (bytesRead != dataSize) {
throw SshClientException(SshInternalError,
QLatin1String("Internal error: Botan::Pipe::read() returned unexpected value"));
}
}
Keyed_Filter *SshAbstractCryptoFacility::makeCtrCipherMode(const QByteArray &cipher)
{
StreamCipher_Filter *filter = new StreamCipher_Filter(cipher.toStdString());
return filter;
}
QByteArray SshAbstractCryptoFacility::generateMac(const QByteArray &data,
quint32 dataSize) const
{
return m_sessionId.isEmpty()
? QByteArray()
: convertByteArray(m_hMac->process(reinterpret_cast<const byte *>(data.constData()),
dataSize));
}
QByteArray SshAbstractCryptoFacility::generateHash(const SshKeyExchange &kex,
char c, quint32 length)
{
const QByteArray &k = kex.k();
const QByteArray &h = kex.h();
QByteArray data(k);
data.append(h).append(c).append(m_sessionId);
SecureVector<byte> key
= kex.hash()->process(convertByteArray(data), data.size());
while (key.size() < length) {
secure_vector<byte> tmpKey;
tmpKey += secure_vector<byte>(k.begin(), k.end());
tmpKey += secure_vector<byte>(h.begin(), h.end());
tmpKey += key;
key += kex.hash()->process(tmpKey);
}
return QByteArray(reinterpret_cast<const char *>(key.data()), length);
}
void SshAbstractCryptoFacility::checkInvariant() const
{
Q_ASSERT(m_sessionId.isEmpty() == !m_pipe);
}
const QByteArray SshEncryptionFacility::PrivKeyFileStartLineRsa("-----BEGIN RSA PRIVATE KEY-----");
const QByteArray SshEncryptionFacility::PrivKeyFileStartLineDsa("-----BEGIN DSA PRIVATE KEY-----");
const QByteArray SshEncryptionFacility::PrivKeyFileEndLineRsa("-----END RSA PRIVATE KEY-----");
const QByteArray SshEncryptionFacility::PrivKeyFileEndLineDsa("-----END DSA PRIVATE KEY-----");
const QByteArray SshEncryptionFacility::PrivKeyFileStartLineEcdsa("-----BEGIN EC PRIVATE KEY-----");
const QByteArray SshEncryptionFacility::PrivKeyFileEndLineEcdsa("-----END EC PRIVATE KEY-----");
QByteArray SshEncryptionFacility::cryptAlgoName(const SshKeyExchange &kex) const
{
return kex.encryptionAlgo();
}
QByteArray SshEncryptionFacility::hMacAlgoName(const SshKeyExchange &kex) const
{
return kex.hMacAlgoClientToServer();
}
Keyed_Filter *SshEncryptionFacility::makeCipherMode(const QByteArray &cipher, const Mode mode)
{
if (mode == CtrMode) {
return new StreamCipher_Filter(cipher.toStdString());
}
qWarning() << "I haven't been able to test the CBC encryption modes, so if this files file a bug at https://github.com/sandsmark/QSsh";
Cipher_Mode_Filter *filter = new Cipher_Mode_Filter(
Cipher_Mode::create_or_throw(cipher.toStdString(), ENCRYPTION).release()); // We have to release, otherwise clang fails to link
return filter;
}
void SshEncryptionFacility::encrypt(QByteArray &data) const
{
convert(data, 0, data.size());
}
void SshEncryptionFacility::createAuthenticationKey(const QByteArray &privKeyFileContents)
{
if (privKeyFileContents == m_cachedPrivKeyContents)
return;
m_authKeyAlgoName.clear();
qCDebug(sshLog, "%s: Key not cached, reading", Q_FUNC_INFO);
QList<BigInt> pubKeyParams;
QList<BigInt> allKeyParams;
QString error1;
QString error2;
OpenSshKeyFileReader openSshReader(m_rng);
if (openSshReader.parseKey(privKeyFileContents)) {
m_authKeyAlgoName = openSshReader.keyType();
m_authKey.reset(openSshReader.privateKey().release());
pubKeyParams = openSshReader.publicParameters();
allKeyParams = openSshReader.allParameters();
} else if (!createAuthenticationKeyFromPKCS8(privKeyFileContents, pubKeyParams, allKeyParams,
error1)
&& !createAuthenticationKeyFromOpenSSL(privKeyFileContents, pubKeyParams, allKeyParams,
error2)) {
qCDebug(sshLog, "%s: %s\n\t%s\n", Q_FUNC_INFO, qPrintable(error1), qPrintable(error2));
throw SshClientException(SshKeyFileError, SSH_TR("Decoding of private key file failed: "
"Format not understood."));
}
foreach (const BigInt &b, allKeyParams) {
if (b.is_zero()) {
throw SshClientException(SshKeyFileError,
SSH_TR("Decoding of private key file failed: Invalid zero parameter."));
}
}
m_authPubKeyBlob = AbstractSshPacket::encodeString(m_authKeyAlgoName);
auto * const ecdsaKey = dynamic_cast<ECDSA_PrivateKey *>(m_authKey.data());
if (ecdsaKey) {
m_authPubKeyBlob += AbstractSshPacket::encodeString(m_authKeyAlgoName.mid(11)); // Without "ecdsa-sha2-" prefix.
m_authPubKeyBlob += AbstractSshPacket::encodeString(
convertByteArray(ecdsaKey->public_point().encode(PointGFp::UNCOMPRESSED)));
} else {
foreach (const BigInt &b, pubKeyParams)
m_authPubKeyBlob += AbstractSshPacket::encodeMpInt(b);
}
m_cachedPrivKeyContents = privKeyFileContents;
}
bool SshEncryptionFacility::createAuthenticationKeyFromPKCS8(const QByteArray &privKeyFileContents,
QList<BigInt> &pubKeyParams, QList<BigInt> &allKeyParams, QString &error)
{
try {
Pipe pipe;
pipe.process_msg(convertByteArray(privKeyFileContents), privKeyFileContents.size());
m_authKey.reset(PKCS8::load_key(pipe, m_rng, SshKeyPasswordRetriever::get_passphrase));
if (auto * const dsaKey = dynamic_cast<DSA_PrivateKey *>(m_authKey.data())) {
m_authKeyAlgoName = SshCapabilities::PubKeyDss;
pubKeyParams << dsaKey->group_p() << dsaKey->group_q()
<< dsaKey->group_g() << dsaKey->get_y();
allKeyParams << pubKeyParams << dsaKey->get_x();
} else if (auto * const rsaKey = dynamic_cast<RSA_PrivateKey *>(m_authKey.data())) {
m_authKeyAlgoName = SshCapabilities::PubKeyRsa;
pubKeyParams << rsaKey->get_e() << rsaKey->get_n();
allKeyParams << pubKeyParams << rsaKey->get_p() << rsaKey->get_q()
<< rsaKey->get_d();
} else if (auto * const ecdsaKey = dynamic_cast<ECDSA_PrivateKey *>(m_authKey.data())) {
const BigInt value = ecdsaKey->private_value();
m_authKeyAlgoName = SshCapabilities::ecdsaPubKeyAlgoForKeyWidth(
static_cast<int>(value.bytes()));
pubKeyParams << ecdsaKey->public_point().get_affine_x()
<< ecdsaKey->public_point().get_affine_y();
allKeyParams << pubKeyParams << value;
} else {
qCWarning(sshLog, "%s: Unexpected code flow, expected success or exception.",
Q_FUNC_INFO);
return false;
}
} catch (const std::exception &ex) {
error = QLatin1String(ex.what());
return false;
}
return true;
}
bool SshEncryptionFacility::createAuthenticationKeyFromOpenSSL(const QByteArray &privKeyFileContents,
QList<BigInt> &pubKeyParams, QList<BigInt> &allKeyParams, QString &error)
{
try {
bool syntaxOk = true;
QList<QByteArray> lines = privKeyFileContents.split('\n');
while (lines.last().isEmpty())
lines.removeLast();
if (lines.count() < 3) {
syntaxOk = false;
} else if (lines.first() == PrivKeyFileStartLineRsa) {
if (lines.last() != PrivKeyFileEndLineRsa)
syntaxOk = false;
else
m_authKeyAlgoName = SshCapabilities::PubKeyRsa;
} else if (lines.first() == PrivKeyFileStartLineDsa) {
if (lines.last() != PrivKeyFileEndLineDsa)
syntaxOk = false;
else
m_authKeyAlgoName = SshCapabilities::PubKeyDss;
} else if (lines.first() == PrivKeyFileStartLineEcdsa) {
if (lines.last() != PrivKeyFileEndLineEcdsa)
syntaxOk = false;
// m_authKeyAlgoName set below, as we don't know the size yet.
} else {
syntaxOk = false;
}
if (!syntaxOk) {
error = SSH_TR("Unexpected format.");
return false;
}
QByteArray privateKeyBlob;
for (int i = 1; i < lines.size() - 1; ++i)
privateKeyBlob += lines.at(i);
privateKeyBlob = QByteArray::fromBase64(privateKeyBlob);
BER_Decoder decoder(convertByteArray(privateKeyBlob), privateKeyBlob.size());
BER_Decoder sequence = decoder.start_cons(SEQUENCE);
size_t version;
sequence.decode (version);
const size_t expectedVersion = m_authKeyAlgoName.isEmpty() ? 1 : 0;
if (version != expectedVersion) {
error = SSH_TR("Key encoding has version %1, expected %2.")
.arg(version).arg(expectedVersion);
return false;
}
if (m_authKeyAlgoName == SshCapabilities::PubKeyDss) {
BigInt p, q, g, y, x;
sequence.decode (p).decode (q).decode (g).decode (y).decode (x);
DSA_PrivateKey * const dsaKey = new DSA_PrivateKey(m_rng, DL_Group(p, q, g), x);
m_authKey.reset(dsaKey);
pubKeyParams << p << q << g << y;
allKeyParams << pubKeyParams << x;
} else if (m_authKeyAlgoName == SshCapabilities::PubKeyRsa) {
BigInt p, q, e, d, n;
sequence.decode(n).decode(e).decode(d).decode(p).decode(q);
RSA_PrivateKey * const rsaKey = new RSA_PrivateKey(p, q, e, d, n);
m_authKey.reset(rsaKey);
pubKeyParams << e << n;
allKeyParams << pubKeyParams << p << q << d;
} else {
BigInt privKey;
sequence.decode_octet_string_bigint(privKey);
m_authKeyAlgoName = SshCapabilities::ecdsaPubKeyAlgoForKeyWidth(
static_cast<int>(privKey.bytes()));
const EC_Group group(SshCapabilities::oid(m_authKeyAlgoName));
auto * const key = new ECDSA_PrivateKey(m_rng, group, privKey);
m_authKey.reset(key);
pubKeyParams << key->public_point().get_affine_x()
<< key->public_point().get_affine_y();
allKeyParams << pubKeyParams << privKey;
}
sequence.discard_remaining();
sequence.verify_end();
} catch (const std::exception &ex) {
error = QLatin1String(ex.what());
return false;
}
return true;
}
QByteArray SshEncryptionFacility::authenticationAlgorithmName() const
{
Q_ASSERT(m_authKey);
return m_authKeyAlgoName;
}
QByteArray SshEncryptionFacility::authenticationKeySignature(const QByteArray &data) const
{
Q_ASSERT(m_authKey);
QScopedPointer<PK_Signer> signer(new PK_Signer(*m_authKey,
m_rng,
botanEmsaAlgoName(m_authKeyAlgoName)));
QByteArray dataToSign = AbstractSshPacket::encodeString(sessionId()) + data;
QByteArray signature
= convertByteArray(signer->sign_message(convertByteArray(dataToSign),
dataToSign.size(), m_rng));
if (m_authKeyAlgoName.startsWith(SshCapabilities::PubKeyEcdsaPrefix)) {
// The Botan output is not quite in the format that SSH defines.
const int halfSize = signature.count() / 2;
const BigInt r = BigInt::decode(convertByteArray(signature), halfSize);
const BigInt s = BigInt::decode(convertByteArray(signature.mid(halfSize)), halfSize);
signature = AbstractSshPacket::encodeMpInt(r) + AbstractSshPacket::encodeMpInt(s);
}
return AbstractSshPacket::encodeString(m_authKeyAlgoName)
+ AbstractSshPacket::encodeString(signature);
}
QByteArray SshEncryptionFacility::getRandomNumbers(int count) const
{
QByteArray data;
data.resize(count);
m_rng.randomize(convertByteArray(data), count);
return data;
}
SshEncryptionFacility::~SshEncryptionFacility() {}
QByteArray SshDecryptionFacility::cryptAlgoName(const SshKeyExchange &kex) const
{
return kex.decryptionAlgo();
}
QByteArray SshDecryptionFacility::hMacAlgoName(const SshKeyExchange &kex) const
{
return kex.hMacAlgoServerToClient();
}
Keyed_Filter *SshDecryptionFacility::makeCipherMode(const QByteArray &cipher, const Mode mode)
{
if (mode == CtrMode) {
return new StreamCipher_Filter(cipher.toStdString());
}
qWarning() << "I haven't been able to test the CBC decryption modes, so if this files file a bug at https://github.com/sandsmark/QSsh";
Cipher_Mode_Filter *filter = new Cipher_Mode_Filter(
Cipher_Mode::create_or_throw(cipher.toStdString(), DECRYPTION).release()); // We have to release, otherwise clang fails to link
return filter;
}
void SshDecryptionFacility::decrypt(QByteArray &data, quint32 offset,
quint32 dataSize) const
{
convert(data, offset, dataSize);
qCDebug(sshLog, "Decrypted data:");
const char * const start = data.constData() + offset;
const char * const end = start + dataSize;
for (const char *c = start; c < end; ++c)
qCDebug(sshLog) << "'" << *c << "' (0x" << (static_cast<int>(*c) & 0xff) << ")";
}
} // namespace Internal
} // namespace QSsh

View file

@ -1,144 +0,0 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: http://www.qt-project.org/
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**************************************************************************/
#ifndef SSHABSTRACTCRYPTOFACILITY_P_H
#define SSHABSTRACTCRYPTOFACILITY_P_H
#include <botan_all.h>
#include <QByteArray>
#include <QScopedPointer>
namespace QSsh {
namespace Internal {
class SshKeyExchange;
class SshAbstractCryptoFacility
{
public:
virtual ~SshAbstractCryptoFacility();
void clearKeys();
void recreateKeys(const SshKeyExchange &kex);
QByteArray generateMac(const QByteArray &data, quint32 dataSize) const;
quint32 cipherBlockSize() const { return m_cipherBlockSize; }
quint32 macLength() const { return m_macLength; }
QByteArray sessionId() const { return m_sessionId; }
bool isValid() const { return m_hMac && m_pipe; } // TODO: probably more, but this stops segfaulting
protected:
enum Mode { CbcMode, CtrMode };
SshAbstractCryptoFacility();
void convert(QByteArray &data, quint32 offset, quint32 dataSize) const;
Botan::Keyed_Filter *makeCtrCipherMode(const QByteArray &cipher);
private:
SshAbstractCryptoFacility(const SshAbstractCryptoFacility &);
SshAbstractCryptoFacility &operator=(const SshAbstractCryptoFacility &);
virtual QByteArray cryptAlgoName(const SshKeyExchange &kex) const = 0;
virtual QByteArray hMacAlgoName(const SshKeyExchange &kex) const = 0;
virtual Botan::Keyed_Filter *makeCipherMode(const QByteArray &cipher, const Mode mode) = 0;
virtual char ivChar() const = 0;
virtual char keyChar() const = 0;
virtual char macChar() const = 0;
QByteArray generateHash(const SshKeyExchange &kex, char c, quint32 length);
void checkInvariant() const;
static Mode getMode(const QByteArray &algoName);
QByteArray m_sessionId;
std::unique_ptr<Botan::Pipe> m_pipe;
std::unique_ptr<Botan::MessageAuthenticationCode> m_hMac;
quint32 m_cipherBlockSize;
quint32 m_macLength;
};
class SshEncryptionFacility : public SshAbstractCryptoFacility
{
public:
void encrypt(QByteArray &data) const;
void createAuthenticationKey(const QByteArray &privKeyFileContents);
QByteArray authenticationAlgorithmName() const;
QByteArray authenticationPublicKey() const { return m_authPubKeyBlob; }
QByteArray authenticationKeySignature(const QByteArray &data) const;
QByteArray getRandomNumbers(int count) const;
~SshEncryptionFacility();
private:
QByteArray cryptAlgoName(const SshKeyExchange &kex) const override;
QByteArray hMacAlgoName(const SshKeyExchange &kex) const override;
Botan::Keyed_Filter *makeCipherMode(const QByteArray &cipher, const Mode mode) override;
char ivChar() const override { return 'A'; }
char keyChar() const override { return 'C'; }
char macChar() const override { return 'E'; }
bool createAuthenticationKeyFromPKCS8(const QByteArray &privKeyFileContents,
QList<Botan::BigInt> &pubKeyParams, QList<Botan::BigInt> &allKeyParams, QString &error);
bool createAuthenticationKeyFromOpenSSL(const QByteArray &privKeyFileContents,
QList<Botan::BigInt> &pubKeyParams, QList<Botan::BigInt> &allKeyParams, QString &error);
static const QByteArray PrivKeyFileStartLineRsa;
static const QByteArray PrivKeyFileStartLineDsa;
static const QByteArray PrivKeyFileEndLineRsa;
static const QByteArray PrivKeyFileEndLineDsa;
static const QByteArray PrivKeyFileStartLineEcdsa;
static const QByteArray PrivKeyFileEndLineEcdsa;
QByteArray m_authKeyAlgoName;
QByteArray m_authPubKeyBlob;
QByteArray m_cachedPrivKeyContents;
QScopedPointer<Botan::Private_Key> m_authKey;
mutable Botan::AutoSeeded_RNG m_rng;
};
class SshDecryptionFacility : public SshAbstractCryptoFacility
{
public:
void decrypt(QByteArray &data, quint32 offset, quint32 dataSize) const;
private:
QByteArray cryptAlgoName(const SshKeyExchange &kex) const override;
QByteArray hMacAlgoName(const SshKeyExchange &kex) const override;
Botan::Keyed_Filter *makeCipherMode(const QByteArray &cipher, const Mode mode) override;
char ivChar() const override { return 'B'; }
char keyChar() const override { return 'D'; }
char macChar() const override { return 'F'; }
};
} // namespace Internal
} // namespace QSsh
#endif // SSHABSTRACTCRYPTOFACILITY_P_H

View file

@ -1,129 +0,0 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**************************************************************************/
#include "sshdirecttcpiptunnel.h"
#include "sshdirecttcpiptunnel_p.h"
#include "sshincomingpacket_p.h"
#include "sshlogging_p.h"
#include "sshsendfacility_p.h"
#include <QTimer>
namespace QSsh {
namespace Internal {
SshDirectTcpIpTunnelPrivate::SshDirectTcpIpTunnelPrivate(quint32 channelId,
const QString &originatingHost, quint16 originatingPort, const QString &remoteHost,
quint16 remotePort, SshSendFacility &sendFacility)
: SshTcpIpTunnelPrivate(channelId, sendFacility),
m_originatingHost(originatingHost),
m_originatingPort(originatingPort),
m_remoteHost(remoteHost),
m_remotePort(remotePort)
{
}
void SshDirectTcpIpTunnelPrivate::handleOpenSuccessInternal()
{
emit initialized();
}
} // namespace Internal
using namespace Internal;
SshDirectTcpIpTunnel::SshDirectTcpIpTunnel(quint32 channelId, const QString &originatingHost,
quint16 originatingPort, const QString &remoteHost, quint16 remotePort,
SshSendFacility &sendFacility)
: d(new SshDirectTcpIpTunnelPrivate(channelId, originatingHost, originatingPort, remoteHost,
remotePort, sendFacility))
{
d->init(this);
connect(d, &SshDirectTcpIpTunnelPrivate::initialized,
this, &SshDirectTcpIpTunnel::initialized, Qt::QueuedConnection);
}
SshDirectTcpIpTunnel::~SshDirectTcpIpTunnel()
{
delete d;
}
bool SshDirectTcpIpTunnel::atEnd() const
{
return QIODevice::atEnd() && d->m_data.isEmpty();
}
qint64 SshDirectTcpIpTunnel::bytesAvailable() const
{
return QIODevice::bytesAvailable() + d->m_data.count();
}
bool SshDirectTcpIpTunnel::canReadLine() const
{
return QIODevice::canReadLine() || d->m_data.contains('\n');
}
void SshDirectTcpIpTunnel::close()
{
d->closeChannel();
QIODevice::close();
}
void SshDirectTcpIpTunnel::initialize()
{
QSSH_ASSERT_AND_RETURN(d->channelState() == AbstractSshChannel::Inactive);
try {
QIODevice::open(QIODevice::ReadWrite);
d->m_sendFacility.sendDirectTcpIpPacket(d->localChannelId(), SshDirectTcpIpTunnelPrivate::initialWindowSize(),
SshDirectTcpIpTunnelPrivate::maxPacketSize(), d->m_remoteHost.toUtf8(), d->m_remotePort,
d->m_originatingHost.toUtf8(), d->m_originatingPort);
d->setChannelState(AbstractSshChannel::SessionRequested);
d->m_timeoutTimer.setTimerType(Qt::VeryCoarseTimer);
d->m_timeoutTimer.start(SshDirectTcpIpTunnelPrivate::ReplyTimeout);
} catch (const std::exception &e) { // Won't happen, but let's play it safe.
qCWarning(sshLog, "Botan error: %s", e.what());
d->closeChannel();
}
}
qint64 SshDirectTcpIpTunnel::readData(char *data, qint64 maxlen)
{
return d->readData(data, maxlen);
}
qint64 SshDirectTcpIpTunnel::writeData(const char *data, qint64 len)
{
return d->writeData(data, len);
}
} // namespace QSsh

View file

@ -1,89 +0,0 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**************************************************************************/
#ifndef SSHDIRECTTCPIPTUNNEL_H
#define SSHDIRECTTCPIPTUNNEL_H
#include "ssh_global.h"
#include <QIODevice>
#include <QSharedPointer>
namespace QSsh {
namespace Internal {
class SshChannelManager;
class SshDirectTcpIpTunnelPrivate;
class SshSendFacility;
class SshTcpIpTunnelPrivate;
} // namespace Internal
class QSSH_EXPORT SshDirectTcpIpTunnel : public QIODevice
{
Q_OBJECT
friend class Internal::SshChannelManager;
friend class Internal::SshTcpIpTunnelPrivate;
public:
typedef QSharedPointer<SshDirectTcpIpTunnel> Ptr;
~SshDirectTcpIpTunnel();
// QIODevice stuff
bool atEnd() const;
qint64 bytesAvailable() const;
bool canReadLine() const;
void close();
bool isSequential() const { return true; }
void initialize();
signals:
void initialized();
void error(const QString &reason);
private:
SshDirectTcpIpTunnel(quint32 channelId, const QString &originatingHost,
quint16 originatingPort, const QString &remoteHost, quint16 remotePort,
Internal::SshSendFacility &sendFacility);
// QIODevice stuff
qint64 readData(char *data, qint64 maxlen);
qint64 writeData(const char *data, qint64 len);
Internal::SshDirectTcpIpTunnelPrivate * const d;
};
} // namespace QSsh
#endif // SSHDIRECTTCPIPTUNNEL_H

View file

@ -1,68 +0,0 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**************************************************************************/
#ifndef DIRECTTCPIPCHANNEL_P_H
#define DIRECTTCPIPCHANNEL_P_H
#include "sshtcpiptunnel_p.h"
namespace QSsh {
class SshDirectTcpIpTunnel;
namespace Internal {
class SshDirectTcpIpTunnelPrivate : public SshTcpIpTunnelPrivate
{
Q_OBJECT
friend class QSsh::SshDirectTcpIpTunnel;
public:
explicit SshDirectTcpIpTunnelPrivate(quint32 channelId, const QString &originatingHost,
quint16 originatingPort, const QString &remoteHost, quint16 remotePort,
SshSendFacility &sendFacility);
signals:
void initialized();
private:
void handleOpenSuccessInternal();
const QString m_originatingHost;
const quint16 m_originatingPort;
const QString m_remoteHost;
const quint16 m_remotePort;
};
} // namespace Internal
} // namespace QSsh
#endif // DIRECTTCPIPCHANNEL_P_H

View file

@ -1,77 +0,0 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: http://www.qt-project.org/
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**************************************************************************/
#ifndef SSHERRORS_P_H
#define SSHERRORS_P_H
#include <QMetaType>
namespace QSsh {
/*!
* \brief SSH specific errors
*/
enum SshError {
/// No error has occured
SshNoError,
/// There was a network socket error
SshSocketError,
/// The connection timed out
SshTimeoutError,
/// There was an error communicating with the server
SshProtocolError,
/// There was a problem with the remote host key
SshHostKeyError,
/// We failed to read or parse the key file used for authentication
SshKeyFileError,
/// We failed to authenticate
SshAuthenticationError,
/// The server closed our connection
SshClosedByServerError,
/// The ssh-agent used for authenticating failed somehow
SshAgentError,
/// Something bad happened on the server
SshInternalError
};
} // namespace QSsh
Q_DECLARE_METATYPE(QSsh::SshError)
#endif // SSHERRORS_P_H

View file

@ -1,95 +0,0 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: http://www.qt-project.org/
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**************************************************************************/
#ifndef SSHEXCEPTION_P_H
#define SSHEXCEPTION_P_H
#include "ssherrors.h"
#include <QByteArray>
#include <QCoreApplication>
#include <QString>
#include <exception>
namespace QSsh {
namespace Internal {
enum SshErrorCode {
SSH_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT = 1,
SSH_DISCONNECT_PROTOCOL_ERROR = 2,
SSH_DISCONNECT_KEY_EXCHANGE_FAILED = 3,
SSH_DISCONNECT_RESERVED = 4,
SSH_DISCONNECT_MAC_ERROR = 5,
SSH_DISCONNECT_COMPRESSION_ERROR = 6,
SSH_DISCONNECT_SERVICE_NOT_AVAILABLE = 7,
SSH_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED = 8,
SSH_DISCONNECT_HOST_KEY_NOT_VERIFIABLE = 9,
SSH_DISCONNECT_CONNECTION_LOST = 10,
SSH_DISCONNECT_BY_APPLICATION = 11,
SSH_DISCONNECT_TOO_MANY_CONNECTIONS = 12,
SSH_DISCONNECT_AUTH_CANCELLED_BY_USER = 13,
SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE = 14,
SSH_DISCONNECT_ILLEGAL_USER_NAME = 15
};
#define SSH_TR(string) QCoreApplication::translate("SshConnection", string)
#define SSH_SERVER_EXCEPTION(error, errorString) \
SshServerException((error), (errorString), SSH_TR(errorString))
struct SshServerException : public std::exception
{
SshServerException(SshErrorCode error, const QByteArray &errorStringServer,
const QString &errorStringUser)
: error(error), errorStringServer(errorStringServer),
errorStringUser(errorStringUser) {}
const char *what() const noexcept override { return errorStringServer.constData(); }
const SshErrorCode error;
const QByteArray errorStringServer;
const QString errorStringUser;
};
struct SshClientException : public std::exception
{
SshClientException(SshError error, const QString &errorString)
: error(error), errorString(errorString), errorStringPrintable(errorString.toLocal8Bit()) {}
const char *what() const noexcept override { return errorStringPrintable.constData(); }
const SshError error;
const QString errorString;
const QByteArray errorStringPrintable;
};
} // namespace Internal
} // namespace QSsh
#endif // SSHEXCEPTION_P_H

View file

@ -1,100 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "sshforwardedtcpiptunnel.h"
#include "sshforwardedtcpiptunnel_p.h"
#include "sshlogging_p.h"
#include "sshsendfacility_p.h"
namespace QSsh {
namespace Internal {
SshForwardedTcpIpTunnelPrivate::SshForwardedTcpIpTunnelPrivate(quint32 channelId,
SshSendFacility &sendFacility) :
SshTcpIpTunnelPrivate(channelId, sendFacility)
{
setChannelState(SessionRequested);
}
void SshForwardedTcpIpTunnelPrivate::handleOpenSuccessInternal()
{
QSSH_ASSERT_AND_RETURN(channelState() == AbstractSshChannel::SessionEstablished);
try {
m_sendFacility.sendChannelOpenConfirmationPacket(remoteChannel(), localChannelId(),
initialWindowSize(), maxPacketSize());
} catch (const std::exception &e) { // Won't happen, but let's play it safe.
qCWarning(sshLog, "Botan error: %s", e.what());
closeChannel();
}
}
} // namespace Internal
using namespace Internal;
SshForwardedTcpIpTunnel::SshForwardedTcpIpTunnel(quint32 channelId, SshSendFacility &sendFacility) :
d(new SshForwardedTcpIpTunnelPrivate(channelId, sendFacility))
{
d->init(this);
}
SshForwardedTcpIpTunnel::~SshForwardedTcpIpTunnel()
{
delete d;
}
bool SshForwardedTcpIpTunnel::atEnd() const
{
return QIODevice::atEnd() && d->m_data.isEmpty();
}
qint64 SshForwardedTcpIpTunnel::bytesAvailable() const
{
return QIODevice::bytesAvailable() + d->m_data.count();
}
bool SshForwardedTcpIpTunnel::canReadLine() const
{
return QIODevice::canReadLine() || d->m_data.contains('\n');
}
void SshForwardedTcpIpTunnel::close()
{
d->closeChannel();
QIODevice::close();
}
qint64 SshForwardedTcpIpTunnel::readData(char *data, qint64 maxlen)
{
return d->readData(data, maxlen);
}
qint64 SshForwardedTcpIpTunnel::writeData(const char *data, qint64 len)
{
return d->writeData(data, len);
}
} // namespace QSsh

View file

@ -1,70 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "ssh_global.h"
#include <QIODevice>
#include <QSharedPointer>
namespace QSsh {
namespace Internal {
class SshChannelManager;
class SshForwardedTcpIpTunnelPrivate;
class SshSendFacility;
class SshTcpIpTunnelPrivate;
} // namespace Internal
class QSSH_EXPORT SshForwardedTcpIpTunnel : public QIODevice
{
Q_OBJECT
friend class Internal::SshChannelManager;
friend class Internal::SshTcpIpTunnelPrivate;
public:
typedef QSharedPointer<SshForwardedTcpIpTunnel> Ptr;
~SshForwardedTcpIpTunnel() override;
// QIODevice stuff
bool atEnd() const override;
qint64 bytesAvailable() const override;
bool canReadLine() const override;
void close() override;
bool isSequential() const override { return true; }
signals:
void error(const QString &reason);
private:
SshForwardedTcpIpTunnel(quint32 channelId, Internal::SshSendFacility &sendFacility);
// QIODevice stuff
qint64 readData(char *data, qint64 maxlen) override;
qint64 writeData(const char *data, qint64 len) override;
Internal::SshForwardedTcpIpTunnelPrivate * const d;
};
} // namespace QSsh

View file

@ -1,44 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "sshforwardedtcpiptunnel.h"
#include "sshtcpiptunnel_p.h"
namespace QSsh {
namespace Internal {
class SshForwardedTcpIpTunnelPrivate : public SshTcpIpTunnelPrivate
{
Q_OBJECT
friend class QSsh::SshForwardedTcpIpTunnel;
public:
SshForwardedTcpIpTunnelPrivate(quint32 channelId, SshSendFacility &sendFacility);
void handleOpenSuccessInternal() override;
};
} // namespace Internal
} // namespace QSsh

View file

@ -1,127 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://www.qt.io/licensing. For further information
** use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "sshhostkeydatabase.h"
#include "sshlogging_p.h"
#include <QByteArray>
#include <QCoreApplication>
#include <QDir>
#include <QFile>
#include <QHash>
#include <QString>
namespace QSsh {
class SshHostKeyDatabase::SshHostKeyDatabasePrivate
{
public:
QHash<QString, QByteArray> hostKeys;
};
SshHostKeyDatabase::SshHostKeyDatabase() : d(new SshHostKeyDatabasePrivate)
{
}
SshHostKeyDatabase::~SshHostKeyDatabase()
{
delete d;
}
bool SshHostKeyDatabase::load(const QString &filePath, QString *error)
{
QFile file(filePath);
if (!file.open(QIODevice::ReadOnly)) {
if (error) {
*error = QCoreApplication::translate("QSsh::Ssh",
"Failed to open key file \"%1\" for reading: %2")
.arg(QDir::toNativeSeparators(filePath), file.errorString());
}
return false;
}
d->hostKeys.clear();
const QByteArray content = file.readAll().trimmed();
if (content.isEmpty())
return true;
foreach (const QByteArray &line, content.split('\n')) {
const QList<QByteArray> &lineData = line.trimmed().split(' ');
if (lineData.count() != 2) {
qCDebug(Internal::sshLog, "Unexpected line \"%s\" in file \"%s\".", line.constData(),
qPrintable(filePath));
continue;
}
d->hostKeys.insert(QString::fromUtf8(lineData.first()),
QByteArray::fromHex(lineData.last()));
}
return true;
}
bool SshHostKeyDatabase::store(const QString &filePath, QString *error) const
{
QFile file(filePath);
if (!file.open(QIODevice::WriteOnly)) {
if (error) {
*error = QCoreApplication::translate("QSsh::Ssh",
"Failed to open key file \"%1\" for writing: %2")
.arg(QDir::toNativeSeparators(filePath), file.errorString());
}
return false;
}
file.resize(0);
for (auto it = d->hostKeys.constBegin(); it != d->hostKeys.constEnd(); ++it)
file.write(it.key().toUtf8() + ' ' + it.value().toHex() + '\n');
return true;
}
SshHostKeyDatabase::KeyLookupResult SshHostKeyDatabase::matchHostKey(const QString &hostName,
const QByteArray &key) const
{
auto it = d->hostKeys.constFind(hostName);
if (it == d->hostKeys.constEnd())
return KeyLookupNoMatch;
if (it.value() == key)
return KeyLookupMatch;
return KeyLookupMismatch;
}
void SshHostKeyDatabase::insertHostKey(const QString &hostName, const QByteArray &key)
{
d->hostKeys.insert(hostName, key);
}
QByteArray SshHostKeyDatabase::retrieveHostKey(const QString &hostName)
{
return d->hostKeys.value(hostName);
}
} // namespace QSsh

View file

@ -1,75 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://www.qt.io/licensing. For further information
** use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef SSHHOSTKEYDATABASE_H
#define SSHHOSTKEYDATABASE_H
#include "ssh_global.h"
#include <QSharedPointer>
QT_BEGIN_NAMESPACE
class QByteArray;
class QString;
QT_END_NAMESPACE
namespace QSsh {
class SshHostKeyDatabase;
/// Convenience typedef
typedef QSharedPointer<SshHostKeyDatabase> SshHostKeyDatabasePtr;
class QSSH_EXPORT SshHostKeyDatabase
{
friend class QSharedPointer<SshHostKeyDatabase>; // To give create() access to our constructor.
public:
enum KeyLookupResult {
KeyLookupMatch,
KeyLookupNoMatch,
KeyLookupMismatch
};
SshHostKeyDatabase();
~SshHostKeyDatabase();
bool load(const QString &filePath, QString *error = nullptr);
bool store(const QString &filePath, QString *error = nullptr) const;
KeyLookupResult matchHostKey(const QString &hostName, const QByteArray &key) const;
void insertHostKey(const QString &hostName, const QByteArray &key);
QByteArray retrieveHostKey(const QString &hostName);
private:
class SshHostKeyDatabasePrivate;
SshHostKeyDatabasePrivate * const d;
};
} // namespace QSsh
#endif // Include guard.

View file

@ -1,609 +0,0 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: http://www.qt-project.org/
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**************************************************************************/
#include "sshincomingpacket_p.h"
#include "ssh_global.h"
#include "sshbotanconversions_p.h"
#include "sshcapabilities_p.h"
#include "sshlogging_p.h"
namespace QSsh {
namespace Internal {
const QByteArray SshIncomingPacket::ExitStatusType("exit-status");
const QByteArray SshIncomingPacket::ExitSignalType("exit-signal");
const QByteArray SshIncomingPacket::ForwardedTcpIpType("forwarded-tcpip");
SshIncomingPacket::SshIncomingPacket() : m_serverSeqNr(0) { }
quint32 SshIncomingPacket::cipherBlockSize() const
{
return qMax(m_decrypter.cipherBlockSize(), 8U);
}
quint32 SshIncomingPacket::macLength() const
{
return m_decrypter.macLength();
}
void SshIncomingPacket::recreateKeys(const SshKeyExchange &keyExchange)
{
m_decrypter.recreateKeys(keyExchange);
}
void SshIncomingPacket::reset()
{
clear();
m_serverSeqNr = 0;
m_decrypter.clearKeys();
}
void SshIncomingPacket::consumeData(QByteArray &newData)
{
qCDebug(sshLog, "%s: current data size = %d, new data size = %d",
Q_FUNC_INFO, m_data.size(), newData.size());
if (isComplete() || newData.isEmpty())
return;
/*
* Until we have reached the minimum packet size, we cannot decrypt the
* length field.
*/
const quint32 minSize = minPacketSize();
if (currentDataSize() < minSize) {
const int bytesToTake
= qMin<quint32>(minSize - currentDataSize(), newData.size());
moveFirstBytes(m_data, newData, bytesToTake);
qCDebug(sshLog, "Took %d bytes from new data", bytesToTake);
if (currentDataSize() < minSize)
return;
}
if (4 + length() + macLength() < currentDataSize())
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, "Server sent invalid packet.");
const int bytesToTake
= qMin<quint32>(length() + 4 + macLength() - currentDataSize(),
newData.size());
moveFirstBytes(m_data, newData, bytesToTake);
qCDebug(sshLog, "Took %d bytes from new data", bytesToTake);
if (isComplete()) {
qCDebug(sshLog, "Message complete. Overall size: %u, payload size: %u",
m_data.size(), m_length - paddingLength() - 1);
decrypt();
++m_serverSeqNr;
}
}
void SshIncomingPacket::decrypt()
{
Q_ASSERT(isComplete());
const quint32 netDataLength = length() + 4;
m_decrypter.decrypt(m_data, cipherBlockSize(),
netDataLength - cipherBlockSize());
const QByteArray &mac = m_data.mid(netDataLength, macLength());
if (mac != generateMac(m_decrypter, m_serverSeqNr)) {
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_MAC_ERROR,
"Message authentication failed.");
}
}
void SshIncomingPacket::moveFirstBytes(QByteArray &target, QByteArray &source,
int n)
{
target.append(source.left(n));
source.remove(0, n);
}
SshKeyExchangeInit SshIncomingPacket::extractKeyExchangeInitData() const
{
Q_ASSERT(isComplete());
Q_ASSERT(type() == SSH_MSG_KEXINIT);
SshKeyExchangeInit exchangeData;
try {
quint32 offset = TypeOffset + 1;
std::memcpy(exchangeData.cookie, &m_data.constData()[offset],
sizeof exchangeData.cookie);
offset += sizeof exchangeData.cookie;
exchangeData.keyAlgorithms
= SshPacketParser::asNameList(m_data, &offset);
exchangeData.serverHostKeyAlgorithms
= SshPacketParser::asNameList(m_data, &offset);
exchangeData.encryptionAlgorithmsClientToServer
= SshPacketParser::asNameList(m_data, &offset);
exchangeData.encryptionAlgorithmsServerToClient
= SshPacketParser::asNameList(m_data, &offset);
exchangeData.macAlgorithmsClientToServer
= SshPacketParser::asNameList(m_data, &offset);
exchangeData.macAlgorithmsServerToClient
= SshPacketParser::asNameList(m_data, &offset);
exchangeData.compressionAlgorithmsClientToServer
= SshPacketParser::asNameList(m_data, &offset);
exchangeData.compressionAlgorithmsServerToClient
= SshPacketParser::asNameList(m_data, &offset);
exchangeData.languagesClientToServer
= SshPacketParser::asNameList(m_data, &offset);
exchangeData.languagesServerToClient
= SshPacketParser::asNameList(m_data, &offset);
exchangeData.firstKexPacketFollows
= SshPacketParser::asBool(m_data, &offset);
} catch (const SshPacketParseException &) {
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
"Key exchange failed: Server sent invalid SSH_MSG_KEXINIT packet.");
}
return exchangeData;
}
static void getHostKeySpecificReplyData(SshKeyExchangeReply &replyData,
const QByteArray &hostKeyAlgo, const QByteArray &input)
{
quint32 offset = 0;
if (hostKeyAlgo == SshCapabilities::PubKeyDss || hostKeyAlgo == SshCapabilities::PubKeyRsa) {
// DSS: p and q, RSA: e and n
replyData.hostKeyParameters << SshPacketParser::asBigInt(input, &offset);
replyData.hostKeyParameters << SshPacketParser::asBigInt(input, &offset);
// g and y
if (hostKeyAlgo == SshCapabilities::PubKeyDss) {
replyData.hostKeyParameters << SshPacketParser::asBigInt(input, &offset);
replyData.hostKeyParameters << SshPacketParser::asBigInt(input, &offset);
}
} else {
QSSH_ASSERT_AND_RETURN(hostKeyAlgo.startsWith(SshCapabilities::PubKeyEcdsaPrefix));
if (SshPacketParser::asString(input, &offset)
!= hostKeyAlgo.mid(11)) { // Without "ecdsa-sha2-" prefix.
throw SshPacketParseException();
}
replyData.q = SshPacketParser::asString(input, &offset);
}
}
static QByteArray &padToWidth(QByteArray &data, int targetWidth)
{
return data.prepend(QByteArray(targetWidth - data.count(), 0));
}
SshKeyExchangeReply SshIncomingPacket::extractKeyExchangeReply(const QByteArray &kexAlgo,
const QByteArray &hostKeyAlgo) const
{
Q_ASSERT(isComplete());
Q_ASSERT(type() == SSH_MSG_KEXDH_REPLY);
try {
SshKeyExchangeReply replyData;
quint32 topLevelOffset = TypeOffset + 1;
replyData.k_s = SshPacketParser::asString(m_data, &topLevelOffset);
quint32 k_sOffset = 0;
if (SshPacketParser::asString(replyData.k_s, &k_sOffset) != hostKeyAlgo)
throw SshPacketParseException();
getHostKeySpecificReplyData(replyData, hostKeyAlgo, replyData.k_s.mid(k_sOffset));
if (kexAlgo == SshCapabilities::DiffieHellmanGroup1Sha1
|| kexAlgo == SshCapabilities::DiffieHellmanGroup14Sha1) {
replyData.f = SshPacketParser::asBigInt(m_data, &topLevelOffset);
} else {
QSSH_ASSERT_AND_RETURN_VALUE(kexAlgo.startsWith(SshCapabilities::EcdhKexNamePrefix),
SshKeyExchangeReply());
replyData.q_s = SshPacketParser::asString(m_data, &topLevelOffset);
}
const QByteArray fullSignature = SshPacketParser::asString(m_data, &topLevelOffset);
quint32 sigOffset = 0;
if (SshPacketParser::asString(fullSignature, &sigOffset) != hostKeyAlgo)
throw SshPacketParseException();
replyData.signatureBlob = SshPacketParser::asString(fullSignature, &sigOffset);
if (hostKeyAlgo.startsWith(SshCapabilities::PubKeyEcdsaPrefix)) {
// Botan's PK_Verifier wants the signature in this format.
quint32 blobOffset = 0;
const Botan::BigInt r = SshPacketParser::asBigInt(replyData.signatureBlob, &blobOffset);
const Botan::BigInt s = SshPacketParser::asBigInt(replyData.signatureBlob, &blobOffset);
const int width = SshCapabilities::ecdsaIntegerWidthInBytes(hostKeyAlgo);
QByteArray encodedR = convertByteArray(Botan::BigInt::encode(r));
replyData.signatureBlob = padToWidth(encodedR, width);
QByteArray encodedS = convertByteArray(Botan::BigInt::encode(s));
replyData.signatureBlob += padToWidth(encodedS, width);
}
replyData.k_s.prepend(m_data.mid(TypeOffset + 1, 4));
return replyData;
} catch (const SshPacketParseException &) {
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
"Key exchange failed: "
"Server sent invalid key exchange reply packet.");
}
}
SshDisconnect SshIncomingPacket::extractDisconnect() const
{
Q_ASSERT(isComplete());
Q_ASSERT(type() == SSH_MSG_DISCONNECT);
SshDisconnect msg;
try {
quint32 offset = TypeOffset + 1;
msg.reasonCode = SshPacketParser::asUint32(m_data, &offset);
msg.description = SshPacketParser::asUserString(m_data, &offset);
msg.language = SshPacketParser::asString(m_data, &offset);
} catch (const SshPacketParseException &) {
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
"Invalid SSH_MSG_DISCONNECT.");
}
return msg;
}
SshUserAuthBanner SshIncomingPacket::extractUserAuthBanner() const
{
Q_ASSERT(isComplete());
Q_ASSERT(type() == SSH_MSG_USERAUTH_BANNER);
try {
SshUserAuthBanner msg;
quint32 offset = TypeOffset + 1;
msg.message = SshPacketParser::asUserString(m_data, &offset);
msg.language = SshPacketParser::asString(m_data, &offset);
return msg;
} catch (const SshPacketParseException &) {
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
"Invalid SSH_MSG_USERAUTH_BANNER.");
}
}
SshUserAuthInfoRequestPacket SshIncomingPacket::extractUserAuthInfoRequest() const
{
Q_ASSERT(isComplete());
Q_ASSERT(type() == SSH_MSG_USERAUTH_INFO_REQUEST);
try {
SshUserAuthInfoRequestPacket msg;
quint32 offset = TypeOffset + 1;
msg.name = SshPacketParser::asUserString(m_data, &offset);
msg.instruction = SshPacketParser::asUserString(m_data, &offset);
msg.languageTag = SshPacketParser::asString(m_data, &offset);
const quint32 promptCount = SshPacketParser::asUint32(m_data, &offset);
msg.prompts.reserve(promptCount);
msg.echos.reserve(promptCount);
for (quint32 i = 0; i < promptCount; ++i) {
msg.prompts << SshPacketParser::asUserString(m_data, &offset);
msg.echos << SshPacketParser::asBool(m_data, &offset);
}
return msg;
} catch (const SshPacketParseException &) {
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
"Invalid SSH_MSG_USERAUTH_INFO_REQUEST.");
}
}
SshUserAuthPkOkPacket SshIncomingPacket::extractUserAuthPkOk() const
{
Q_ASSERT(isComplete());
Q_ASSERT(type() == SSH_MSG_USERAUTH_PK_OK);
try {
SshUserAuthPkOkPacket msg;
quint32 offset = TypeOffset + 1;
msg.algoName= SshPacketParser::asString(m_data, &offset);
msg.keyBlob = SshPacketParser::asString(m_data, &offset);
return msg;
} catch (const SshPacketParseException &) {
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
"Invalid SSH_MSG_USERAUTH_PK_OK.");
}
}
SshDebug SshIncomingPacket::extractDebug() const
{
Q_ASSERT(isComplete());
Q_ASSERT(type() == SSH_MSG_DEBUG);
try {
SshDebug msg;
quint32 offset = TypeOffset + 1;
msg.display = SshPacketParser::asBool(m_data, &offset);
msg.message = SshPacketParser::asUserString(m_data, &offset);
msg.language = SshPacketParser::asString(m_data, &offset);
return msg;
} catch (const SshPacketParseException &) {
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
"Invalid SSH_MSG_DEBUG.");
}
}
SshRequestSuccess SshIncomingPacket::extractRequestSuccess() const
{
Q_ASSERT(isComplete());
Q_ASSERT(type() == SSH_MSG_REQUEST_SUCCESS);
try {
SshRequestSuccess msg;
quint32 offset = TypeOffset + 1;
msg.bindPort = SshPacketParser::asUint32(m_data, &offset);
return msg;
} catch (const SshPacketParseException &) {
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
"Invalid SSH_MSG_REQUEST_SUCCESS.");
}
}
SshUnimplemented SshIncomingPacket::extractUnimplemented() const
{
Q_ASSERT(isComplete());
Q_ASSERT(type() == SSH_MSG_UNIMPLEMENTED);
try {
SshUnimplemented msg;
quint32 offset = TypeOffset + 1;
msg.invalidMsgSeqNr = SshPacketParser::asUint32(m_data, &offset);
return msg;
} catch (const SshPacketParseException &) {
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
"Invalid SSH_MSG_UNIMPLEMENTED.");
}
}
SshChannelOpenGeneric SshIncomingPacket::extractChannelOpen() const
{
Q_ASSERT(isComplete());
Q_ASSERT(type() == SSH_MSG_CHANNEL_OPEN);
try {
SshChannelOpenGeneric channelOpen;
quint32 offset = TypeOffset + 1;
channelOpen.channelType = SshPacketParser::asString(m_data, &offset);
channelOpen.commonData.remoteChannel = SshPacketParser::asUint32(m_data, &offset);
channelOpen.commonData.remoteWindowSize = SshPacketParser::asUint32(m_data, &offset);
channelOpen.commonData.remoteMaxPacketSize = SshPacketParser::asUint32(m_data, &offset);
channelOpen.typeSpecificData = m_data.mid(offset, length() - paddingLength() - offset
+ int(sizeof m_length));
return channelOpen;
} catch (const SshPacketParseException &) {
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
"Server sent invalid SSH_MSG_CHANNEL_OPEN packet.");
}
}
SshChannelOpenForwardedTcpIp SshIncomingPacket::extractChannelOpenForwardedTcpIp(
const SshChannelOpenGeneric &genericData)
{
try {
SshChannelOpenForwardedTcpIp specificData;
specificData.common = genericData.commonData;
quint32 offset = 0;
specificData.remoteAddress = SshPacketParser::asString(genericData.typeSpecificData,
&offset);
specificData.remotePort = SshPacketParser::asUint32(genericData.typeSpecificData, &offset);
specificData.originatorAddress = SshPacketParser::asString(genericData.typeSpecificData,
&offset);
specificData.originatorPort = SshPacketParser::asUint32(genericData.typeSpecificData,
&offset);
return specificData;
} catch (const SshPacketParseException &) {
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
"Server sent invalid SSH_MSG_CHANNEL_OPEN packet.");
}
}
SshChannelOpenX11 SshIncomingPacket::extractChannelOpenX11(const SshChannelOpenGeneric &genericData)
{
try {
SshChannelOpenX11 specificData;
specificData.common = genericData.commonData;
quint32 offset = 0;
specificData.originatorAddress = SshPacketParser::asString(genericData.typeSpecificData,
&offset);
specificData.originatorPort = SshPacketParser::asUint32(genericData.typeSpecificData,
&offset);
return specificData;
} catch (const SshPacketParseException &) {
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
"Server sent invalid SSH_MSG_CHANNEL_OPEN packet.");
}
}
SshChannelOpenFailure SshIncomingPacket::extractChannelOpenFailure() const
{
Q_ASSERT(isComplete());
Q_ASSERT(type() == SSH_MSG_CHANNEL_OPEN_FAILURE);
SshChannelOpenFailure openFailure;
try {
quint32 offset = TypeOffset + 1;
openFailure.localChannel = SshPacketParser::asUint32(m_data, &offset);
openFailure.reasonCode = SshPacketParser::asUint32(m_data, &offset);
openFailure.reasonString = QString::fromLocal8Bit(SshPacketParser::asString(m_data, &offset));
openFailure.language = SshPacketParser::asString(m_data, &offset);
} catch (const SshPacketParseException &) {
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
"Server sent invalid SSH_MSG_CHANNEL_OPEN_FAILURE packet.");
}
return openFailure;
}
SshChannelOpenConfirmation SshIncomingPacket::extractChannelOpenConfirmation() const
{
Q_ASSERT(isComplete());
Q_ASSERT(type() == SSH_MSG_CHANNEL_OPEN_CONFIRMATION);
SshChannelOpenConfirmation confirmation;
try {
quint32 offset = TypeOffset + 1;
confirmation.localChannel = SshPacketParser::asUint32(m_data, &offset);
confirmation.remoteChannel = SshPacketParser::asUint32(m_data, &offset);
confirmation.remoteWindowSize = SshPacketParser::asUint32(m_data, &offset);
confirmation.remoteMaxPacketSize = SshPacketParser::asUint32(m_data, &offset);
} catch (const SshPacketParseException &) {
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
"Server sent invalid SSH_MSG_CHANNEL_OPEN_CONFIRMATION packet.");
}
return confirmation;
}
SshChannelWindowAdjust SshIncomingPacket::extractWindowAdjust() const
{
Q_ASSERT(isComplete());
Q_ASSERT(type() == SSH_MSG_CHANNEL_WINDOW_ADJUST);
SshChannelWindowAdjust adjust;
try {
quint32 offset = TypeOffset + 1;
adjust.localChannel = SshPacketParser::asUint32(m_data, &offset);
adjust.bytesToAdd = SshPacketParser::asUint32(m_data, &offset);
} catch (const SshPacketParseException &) {
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
"Invalid SSH_MSG_CHANNEL_WINDOW_ADJUST packet.");
}
return adjust;
}
SshChannelData SshIncomingPacket::extractChannelData() const
{
Q_ASSERT(isComplete());
Q_ASSERT(type() == SSH_MSG_CHANNEL_DATA);
SshChannelData data;
try {
quint32 offset = TypeOffset + 1;
data.localChannel = SshPacketParser::asUint32(m_data, &offset);
data.data = SshPacketParser::asString(m_data, &offset);
} catch (const SshPacketParseException &) {
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
"Invalid SSH_MSG_CHANNEL_DATA packet.");
}
return data;
}
SshChannelExtendedData SshIncomingPacket::extractChannelExtendedData() const
{
Q_ASSERT(isComplete());
Q_ASSERT(type() == SSH_MSG_CHANNEL_EXTENDED_DATA);
SshChannelExtendedData data;
try {
quint32 offset = TypeOffset + 1;
data.localChannel = SshPacketParser::asUint32(m_data, &offset);
data.type = SshPacketParser::asUint32(m_data, &offset);
data.data = SshPacketParser::asString(m_data, &offset);
} catch (const SshPacketParseException &) {
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
"Invalid SSH_MSG_CHANNEL_EXTENDED_DATA packet.");
}
return data;
}
SshChannelExitStatus SshIncomingPacket::extractChannelExitStatus() const
{
Q_ASSERT(isComplete());
Q_ASSERT(type() == SSH_MSG_CHANNEL_REQUEST);
SshChannelExitStatus exitStatus;
try {
quint32 offset = TypeOffset + 1;
exitStatus.localChannel = SshPacketParser::asUint32(m_data, &offset);
const QByteArray &type = SshPacketParser::asString(m_data, &offset);
Q_ASSERT(type == ExitStatusType);
Q_UNUSED(type);
if (SshPacketParser::asBool(m_data, &offset))
throw SshPacketParseException();
exitStatus.exitStatus = SshPacketParser::asUint32(m_data, &offset);
} catch (const SshPacketParseException &) {
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
"Invalid exit-status packet.");
}
return exitStatus;
}
SshChannelExitSignal SshIncomingPacket::extractChannelExitSignal() const
{
Q_ASSERT(isComplete());
Q_ASSERT(type() == SSH_MSG_CHANNEL_REQUEST);
SshChannelExitSignal exitSignal;
try {
quint32 offset = TypeOffset + 1;
exitSignal.localChannel = SshPacketParser::asUint32(m_data, &offset);
const QByteArray &type = SshPacketParser::asString(m_data, &offset);
Q_ASSERT(type == ExitSignalType);
Q_UNUSED(type);
if (SshPacketParser::asBool(m_data, &offset))
throw SshPacketParseException();
exitSignal.signal = SshPacketParser::asString(m_data, &offset);
exitSignal.coreDumped = SshPacketParser::asBool(m_data, &offset);
exitSignal.error = SshPacketParser::asUserString(m_data, &offset);
exitSignal.language = SshPacketParser::asString(m_data, &offset);
} catch (const SshPacketParseException &) {
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
"Invalid exit-signal packet.");
}
return exitSignal;
}
quint32 SshIncomingPacket::extractRecipientChannel() const
{
Q_ASSERT(isComplete());
try {
quint32 offset = TypeOffset + 1;
return SshPacketParser::asUint32(m_data, &offset);
} catch (const SshPacketParseException &) {
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
"Server sent invalid packet.");
}
}
QByteArray SshIncomingPacket::extractChannelRequestType() const
{
Q_ASSERT(isComplete());
Q_ASSERT(type() == SSH_MSG_CHANNEL_REQUEST);
try {
quint32 offset = TypeOffset + 1;
SshPacketParser::asUint32(m_data, &offset);
return SshPacketParser::asString(m_data, &offset);
} catch (const SshPacketParseException &) {
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
"Invalid SSH_MSG_CHANNEL_REQUEST packet.");
}
}
void SshIncomingPacket::calculateLength() const
{
Q_ASSERT(currentDataSize() >= minPacketSize());
qCDebug(sshLog, "Length field before decryption: %d-%d-%d-%d", m_data.at(0) & 0xff,
m_data.at(1) & 0xff, m_data.at(2) & 0xff, m_data.at(3) & 0xff);
m_decrypter.decrypt(m_data, 0, cipherBlockSize());
qCDebug(sshLog, "Length field after decryption: %d-%d-%d-%d", m_data.at(0) & 0xff, m_data.at(1) & 0xff, m_data.at(2) & 0xff, m_data.at(3) & 0xff);
qCDebug(sshLog, "message type = %d", m_data.at(TypeOffset));
m_length = SshPacketParser::asUint32(m_data, static_cast<quint32>(0));
qCDebug(sshLog, "decrypted length is %u", m_length);
}
} // namespace Internal
} // namespace QSsh

View file

@ -1,252 +0,0 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: http://www.qt-project.org/
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**************************************************************************/
#ifndef SSHINCOMINGPACKET_P_H
#define SSHINCOMINGPACKET_P_H
#include "sshpacket_p.h"
#include "sshcryptofacility_p.h"
#include "sshpacketparser_p.h"
#include <QStringList>
namespace QSsh {
namespace Internal {
class SshKeyExchange;
struct SshKeyExchangeInit
{
char cookie[16];
SshNameList keyAlgorithms;
SshNameList serverHostKeyAlgorithms;
SshNameList encryptionAlgorithmsClientToServer;
SshNameList encryptionAlgorithmsServerToClient;
SshNameList macAlgorithmsClientToServer;
SshNameList macAlgorithmsServerToClient;
SshNameList compressionAlgorithmsClientToServer;
SshNameList compressionAlgorithmsServerToClient;
SshNameList languagesClientToServer;
SshNameList languagesServerToClient;
bool firstKexPacketFollows;
};
struct SshKeyExchangeReply
{
QByteArray k_s;
QList<Botan::BigInt> hostKeyParameters; // DSS: p, q, g, y. RSA: e, n.
QByteArray q; // For ECDSA host keys only.
Botan::BigInt f; // For DH only.
QByteArray q_s; // For ECDH only.
QByteArray signatureBlob;
};
struct SshDisconnect
{
quint32 reasonCode;
QString description;
QByteArray language;
};
struct SshUserAuthBanner
{
QString message;
QByteArray language;
};
struct SshUserAuthPkOkPacket
{
QByteArray algoName;
QByteArray keyBlob;
};
struct SshUserAuthInfoRequestPacket
{
QString name;
QString instruction;
QByteArray languageTag;
QStringList prompts;
QList<bool> echos;
};
struct SshDebug
{
bool display;
QString message;
QByteArray language;
};
struct SshUnimplemented
{
quint32 invalidMsgSeqNr;
};
struct SshRequestSuccess
{
quint32 bindPort;
};
struct SshChannelOpenCommon
{
quint32 remoteChannel;
quint32 remoteWindowSize;
quint32 remoteMaxPacketSize;
};
struct SshChannelOpenGeneric
{
QByteArray channelType;
SshChannelOpenCommon commonData;
QByteArray typeSpecificData;
};
struct SshChannelOpenForwardedTcpIp
{
SshChannelOpenCommon common;
QByteArray remoteAddress;
quint32 remotePort;
QByteArray originatorAddress;
quint32 originatorPort;
};
struct SshChannelOpenX11
{
SshChannelOpenCommon common;
QByteArray originatorAddress;
quint32 originatorPort;
};
struct SshChannelOpenFailure
{
quint32 localChannel;
quint32 reasonCode;
QString reasonString;
QByteArray language;
};
struct SshChannelOpenConfirmation
{
quint32 localChannel;
quint32 remoteChannel;
quint32 remoteWindowSize;
quint32 remoteMaxPacketSize;
};
struct SshChannelWindowAdjust
{
quint32 localChannel;
quint32 bytesToAdd;
};
struct SshChannelData
{
quint32 localChannel;
QByteArray data;
};
struct SshChannelExtendedData
{
quint32 localChannel;
quint32 type;
QByteArray data;
};
struct SshChannelExitStatus
{
quint32 localChannel;
quint32 exitStatus;
};
struct SshChannelExitSignal
{
quint32 localChannel;
QByteArray signal;
bool coreDumped;
QString error;
QByteArray language;
};
class SshIncomingPacket : public AbstractSshPacket
{
public:
SshIncomingPacket();
void consumeData(QByteArray &data);
void recreateKeys(const SshKeyExchange &keyExchange);
void reset();
SshKeyExchangeInit extractKeyExchangeInitData() const;
SshKeyExchangeReply extractKeyExchangeReply(const QByteArray &kexAlgo,
const QByteArray &hostKeyAlgo) const;
SshDisconnect extractDisconnect() const;
SshUserAuthBanner extractUserAuthBanner() const;
SshUserAuthInfoRequestPacket extractUserAuthInfoRequest() const;
SshUserAuthPkOkPacket extractUserAuthPkOk() const;
SshDebug extractDebug() const;
SshRequestSuccess extractRequestSuccess() const;
SshUnimplemented extractUnimplemented() const;
SshChannelOpenGeneric extractChannelOpen() const;
static SshChannelOpenForwardedTcpIp extractChannelOpenForwardedTcpIp(
const SshChannelOpenGeneric &genericData);
static SshChannelOpenX11 extractChannelOpenX11(const SshChannelOpenGeneric &genericData);
SshChannelOpenFailure extractChannelOpenFailure() const;
SshChannelOpenConfirmation extractChannelOpenConfirmation() const;
SshChannelWindowAdjust extractWindowAdjust() const;
SshChannelData extractChannelData() const;
SshChannelExtendedData extractChannelExtendedData() const;
SshChannelExitStatus extractChannelExitStatus() const;
SshChannelExitSignal extractChannelExitSignal() const;
quint32 extractRecipientChannel() const;
QByteArray extractChannelRequestType() const;
quint32 serverSeqNr() const { return m_serverSeqNr; }
static const QByteArray ExitStatusType;
static const QByteArray ExitSignalType;
static const QByteArray ForwardedTcpIpType;
private:
virtual quint32 cipherBlockSize() const;
virtual quint32 macLength() const;
virtual void calculateLength() const;
void decrypt();
void moveFirstBytes(QByteArray &target, QByteArray &source, int n);
quint32 m_serverSeqNr;
SshDecryptionFacility m_decrypter;
};
} // namespace Internal
} // namespace QSsh
#endif // SSHINCOMINGPACKET_P_H

View file

@ -1,292 +0,0 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: http://www.qt-project.org/
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**************************************************************************/
#include "sshkeyexchange_p.h"
#include "ssh_global.h"
#include "sshbotanconversions_p.h"
#include "sshcapabilities_p.h"
#include "sshsendfacility_p.h"
#include "sshexception_p.h"
#include "sshincomingpacket_p.h"
#include "sshlogging_p.h"
#include <botan_all.h>
#ifdef CREATOR_SSH_DEBUG
#include <iostream>
#endif
#include <string>
using namespace Botan;
namespace QSsh {
namespace Internal {
namespace {
// For debugging
void printNameList(const char *listName, const SshNameList &list)
{
qCDebug(sshLog, "%s:", listName);
foreach (const QByteArray &name, list.names)
qCDebug(sshLog, "%s", name.constData());
}
void printData(const char *name, const QByteArray &data)
{
qCDebug(sshLog, "The client thinks the %s has length %d and is: %s", name, data.count(),
data.toHex().constData());
}
} // anonymous namespace
SshKeyExchange::SshKeyExchange(const SshConnectionParameters &connParams,
SshSendFacility &sendFacility)
: m_connParams(connParams), m_sendFacility(sendFacility)
{
}
SshKeyExchange::~SshKeyExchange() {}
void SshKeyExchange::sendKexInitPacket(const QByteArray &serverId)
{
m_serverId = serverId;
m_clientKexInitPayload = m_sendFacility.sendKeyExchangeInitPacket();
}
bool SshKeyExchange::sendDhInitPacket(const SshIncomingPacket &serverKexInit)
{
qCDebug(sshLog, "server requests key exchange");
serverKexInit.printRawBytes();
SshKeyExchangeInit kexInitParams
= serverKexInit.extractKeyExchangeInitData();
printNameList("Key Algorithms", kexInitParams.keyAlgorithms);
printNameList("Server Host Key Algorithms", kexInitParams.serverHostKeyAlgorithms);
printNameList("Encryption algorithms client to server", kexInitParams.encryptionAlgorithmsClientToServer);
printNameList("Encryption algorithms server to client", kexInitParams.encryptionAlgorithmsServerToClient);
printNameList("MAC algorithms client to server", kexInitParams.macAlgorithmsClientToServer);
printNameList("MAC algorithms server to client", kexInitParams.macAlgorithmsServerToClient);
printNameList("Compression algorithms client to server", kexInitParams.compressionAlgorithmsClientToServer);
printNameList("Compression algorithms client to server", kexInitParams.compressionAlgorithmsClientToServer);
printNameList("Languages client to server", kexInitParams.languagesClientToServer);
printNameList("Languages server to client", kexInitParams.languagesServerToClient);
qCDebug(sshLog, "First packet follows: %d", kexInitParams.firstKexPacketFollows);
m_kexAlgoName = SshCapabilities::findBestMatch(SshCapabilities::KeyExchangeMethods,
kexInitParams.keyAlgorithms.names,
"KeyExchange");
m_serverHostKeyAlgo = SshCapabilities::findBestMatch(SshCapabilities::PublicKeyAlgorithms,
kexInitParams.serverHostKeyAlgorithms.names, "HostKey");
determineHashingAlgorithm(kexInitParams, true);
determineHashingAlgorithm(kexInitParams, false);
m_encryptionAlgo
= SshCapabilities::findBestMatch(SshCapabilities::EncryptionAlgorithms,
kexInitParams.encryptionAlgorithmsClientToServer.names, "Encryption");
m_decryptionAlgo
= SshCapabilities::findBestMatch(SshCapabilities::EncryptionAlgorithms,
kexInitParams.encryptionAlgorithmsServerToClient.names, "Decryption");
SshCapabilities::findBestMatch(SshCapabilities::CompressionAlgorithms,
kexInitParams.compressionAlgorithmsClientToServer.names, "Compression Client to Server");
SshCapabilities::findBestMatch(SshCapabilities::CompressionAlgorithms,
kexInitParams.compressionAlgorithmsServerToClient.names, "Compression Server to Client");
AutoSeeded_RNG rng;
if (m_kexAlgoName.startsWith(SshCapabilities::EcdhKexNamePrefix)) {
m_ecdhKey.reset(new ECDH_PrivateKey(rng, EC_Group(botanKeyExchangeAlgoName(m_kexAlgoName))));
m_sendFacility.sendKeyEcdhInitPacket(convertByteArray(m_ecdhKey->public_value()));
} else {
m_dhKey.reset(new DH_PrivateKey(rng, DL_Group(botanKeyExchangeAlgoName(m_kexAlgoName))));
m_sendFacility.sendKeyDhInitPacket(m_dhKey->get_y());
}
m_serverKexInitPayload = serverKexInit.payLoad();
return kexInitParams.firstKexPacketFollows;
}
void SshKeyExchange::sendNewKeysPacket(const SshIncomingPacket &dhReply,
const QByteArray &clientId)
{
const SshKeyExchangeReply &reply
= dhReply.extractKeyExchangeReply(m_kexAlgoName, m_serverHostKeyAlgo);
if (m_dhKey && (reply.f <= 0 || reply.f >= m_dhKey->group_p())) {
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
"Server sent invalid f.");
}
QByteArray concatenatedData = AbstractSshPacket::encodeString(clientId);
concatenatedData += AbstractSshPacket::encodeString(m_serverId);
concatenatedData += AbstractSshPacket::encodeString(m_clientKexInitPayload);
concatenatedData += AbstractSshPacket::encodeString(m_serverKexInitPayload);
concatenatedData += reply.k_s;
printData("Client Id", AbstractSshPacket::encodeString(clientId));
printData("Server Id", AbstractSshPacket::encodeString(m_serverId));
printData("Client Payload", AbstractSshPacket::encodeString(m_clientKexInitPayload));
printData("Server payload", AbstractSshPacket::encodeString(m_serverKexInitPayload));
printData("K_S", reply.k_s);
AutoSeeded_RNG rng;
SecureVector<byte> encodedK;
if (m_dhKey) {
concatenatedData += AbstractSshPacket::encodeMpInt(m_dhKey->get_y());
concatenatedData += AbstractSshPacket::encodeMpInt(reply.f);
std::unique_ptr<PK_Ops::Key_Agreement> dhOp = m_dhKey->create_key_agreement_op(rng, "Raw", "base");
std::vector<byte> encodedF = BigInt::encode(reply.f);
encodedK = dhOp->agree(0, encodedF.data(), encodedF.size(), nullptr, 0);
printData("y", AbstractSshPacket::encodeMpInt(m_dhKey->get_y()));
printData("f", AbstractSshPacket::encodeMpInt(reply.f));
m_dhKey.reset();
} else {
Q_ASSERT(m_ecdhKey);
concatenatedData // Q_C.
+= AbstractSshPacket::encodeString(convertByteArray(m_ecdhKey->public_value()));
concatenatedData += AbstractSshPacket::encodeString(reply.q_s);
std::unique_ptr<PK_Ops::Key_Agreement> ecdhOp = m_ecdhKey->create_key_agreement_op(rng, "Raw", "base");
encodedK = ecdhOp->agree(0, convertByteArray(reply.q_s), reply.q_s.count(), nullptr, 0);
m_ecdhKey.reset();
}
// If we try to just use "BigInt::decode(encodedK)" clang fails to link
const BigInt k = BigInt::decode(encodedK.data(), encodedK.size());
m_k = AbstractSshPacket::encodeMpInt(k); // Roundtrip, as Botan encodes BigInts somewhat differently.
printData("K", m_k);
concatenatedData += m_k;
printData("Concatenated data", concatenatedData);
m_hash = HashFunction::create_or_throw(botanHMacAlgoName(hashAlgoForKexAlgo()));
const SecureVector<byte> &hashResult = m_hash->process(convertByteArray(concatenatedData),
concatenatedData.size());
m_h = convertByteArray(hashResult);
printData("H", m_h);
QScopedPointer<Public_Key> sigKey;
if (m_serverHostKeyAlgo == SshCapabilities::PubKeyDss) {
const DL_Group group(reply.hostKeyParameters.at(0), reply.hostKeyParameters.at(1),
reply.hostKeyParameters.at(2));
DSA_PublicKey * const dsaKey
= new DSA_PublicKey(group, reply.hostKeyParameters.at(3));
sigKey.reset(dsaKey);
} else if (m_serverHostKeyAlgo == SshCapabilities::PubKeyRsa) {
RSA_PublicKey * const rsaKey
= new RSA_PublicKey(reply.hostKeyParameters.at(1), reply.hostKeyParameters.at(0));
sigKey.reset(rsaKey);
} else {
QSSH_ASSERT_AND_RETURN(m_serverHostKeyAlgo.startsWith(SshCapabilities::PubKeyEcdsaPrefix));
const EC_Group domain(SshCapabilities::oid(m_serverHostKeyAlgo));
const PointGFp point = domain.OS2ECP(convertByteArray(reply.q), reply.q.count());
ECDSA_PublicKey * const ecdsaKey = new ECDSA_PublicKey(domain, point);
sigKey.reset(ecdsaKey);
}
const byte * const botanH = convertByteArray(m_h);
const Botan::byte * const botanSig = convertByteArray(reply.signatureBlob);
PK_Verifier verifier(*sigKey, botanEmsaAlgoName(m_serverHostKeyAlgo));
if (!verifier.verify_message(botanH, m_h.size(), botanSig, reply.signatureBlob.size())) {
throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
"Invalid signature in key exchange reply packet.");
}
checkHostKey(reply.k_s);
m_sendFacility.sendNewKeysPacket();
m_hostFingerprint = QByteArray::fromStdString(sigKey->fingerprint_public("SHA-256"));
}
QByteArray SshKeyExchange::hashAlgoForKexAlgo() const
{
if (m_kexAlgoName == SshCapabilities::EcdhNistp256)
return SshCapabilities::HMacSha256;
if (m_kexAlgoName == SshCapabilities::EcdhNistp384)
return SshCapabilities::HMacSha384;
if (m_kexAlgoName == SshCapabilities::EcdhNistp521)
return SshCapabilities::HMacSha512;
return SshCapabilities::HMacSha1;
}
void SshKeyExchange::determineHashingAlgorithm(const SshKeyExchangeInit &kexInit,
bool serverToClient)
{
QByteArray * const algo = serverToClient ? &m_s2cHMacAlgo : &m_c2sHMacAlgo;
const QList<QByteArray> &serverCapabilities = serverToClient
? kexInit.macAlgorithmsServerToClient.names
: kexInit.macAlgorithmsClientToServer.names;
*algo = SshCapabilities::findBestMatch(SshCapabilities::MacAlgorithms,
serverCapabilities,
"MacAlgorithms");
}
void SshKeyExchange::checkHostKey(const QByteArray &hostKey)
{
if (m_connParams.hostKeyCheckingMode == SshHostKeyCheckingNone) {
if (m_connParams.hostKeyDatabase)
m_connParams.hostKeyDatabase->insertHostKey(m_connParams.host(), hostKey);
return;
}
if (!m_connParams.hostKeyDatabase) {
throw SshClientException(SshInternalError,
SSH_TR("Host key database must exist "
"if host key checking is enabled."));
}
switch (m_connParams.hostKeyDatabase->matchHostKey(m_connParams.host(), hostKey)) {
case SshHostKeyDatabase::KeyLookupMatch:
return; // Nothing to do.
case SshHostKeyDatabase::KeyLookupMismatch:
if (m_connParams.hostKeyCheckingMode != SshHostKeyCheckingAllowMismatch)
throwHostKeyException();
break;
case SshHostKeyDatabase::KeyLookupNoMatch:
if (m_connParams.hostKeyCheckingMode == SshHostKeyCheckingStrict)
throwHostKeyException();
break;
}
m_connParams.hostKeyDatabase->insertHostKey(m_connParams.host(), hostKey);
}
void SshKeyExchange::throwHostKeyException()
{
throw SshServerException(SSH_DISCONNECT_HOST_KEY_NOT_VERIFIABLE, "Host key changed",
SSH_TR("Host key of machine \"%1\" has changed.")
.arg(m_connParams.host()));
}
} // namespace Internal
} // namespace QSsh

View file

@ -1,105 +0,0 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: http://www.qt-project.org/
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**************************************************************************/
#ifndef SSHKEYEXCHANGE_P_H
#define SSHKEYEXCHANGE_P_H
#include "sshconnection.h"
#include <QByteArray>
#include <QScopedPointer>
#include <memory>
namespace Botan {
class DH_PrivateKey;
class ECDH_PrivateKey;
class HashFunction;
}
namespace QSsh {
namespace Internal {
struct SshKeyExchangeInit;
class SshSendFacility;
class SshIncomingPacket;
class SshKeyExchange
{
public:
SshKeyExchange(const SshConnectionParameters &connParams, SshSendFacility &sendFacility);
~SshKeyExchange();
const QByteArray &hostKeyFingerprint() { return m_hostFingerprint; }
void sendKexInitPacket(const QByteArray &serverId);
// Returns true <=> the server sends a guessed package.
bool sendDhInitPacket(const SshIncomingPacket &serverKexInit);
void sendNewKeysPacket(const SshIncomingPacket &dhReply,
const QByteArray &clientId);
QByteArray k() const { return m_k; }
QByteArray h() const { return m_h; }
Botan::HashFunction *hash() const { return m_hash.get(); }
QByteArray encryptionAlgo() const { return m_encryptionAlgo; }
QByteArray decryptionAlgo() const { return m_decryptionAlgo; }
QByteArray hMacAlgoClientToServer() const { return m_c2sHMacAlgo; }
QByteArray hMacAlgoServerToClient() const { return m_s2cHMacAlgo; }
private:
QByteArray hashAlgoForKexAlgo() const;
void determineHashingAlgorithm(const SshKeyExchangeInit &kexInit, bool serverToClient);
void checkHostKey(const QByteArray &hostKey);
Q_NORETURN void throwHostKeyException();
QByteArray m_serverId;
QByteArray m_clientKexInitPayload;
QByteArray m_serverKexInitPayload;
QScopedPointer<Botan::DH_PrivateKey> m_dhKey;
QScopedPointer<Botan::ECDH_PrivateKey> m_ecdhKey;
QByteArray m_kexAlgoName;
QByteArray m_k;
QByteArray m_h;
QByteArray m_serverHostKeyAlgo;
QByteArray m_encryptionAlgo;
QByteArray m_decryptionAlgo;
QByteArray m_c2sHMacAlgo;
QByteArray m_s2cHMacAlgo;
std::unique_ptr<Botan::HashFunction> m_hash;
const SshConnectionParameters m_connParams;
SshSendFacility &m_sendFacility;
QByteArray m_hostFingerprint;
};
} // namespace Internal
} // namespace QSsh
#endif // SSHKEYEXCHANGE_P_H

View file

@ -1,233 +0,0 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: http://www.qt-project.org/
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**************************************************************************/
#include "sshkeygenerator.h"
#include "sshbotanconversions_p.h"
#include "sshcapabilities_p.h"
#include "ssh_global.h"
#include "sshpacket_p.h"
#include "sshlogging_p.h"
#include <botan_all.h>
#include <QDateTime>
#include <QInputDialog>
#include <string>
namespace QSsh {
using namespace Botan;
using namespace Internal;
SshKeyGenerator::SshKeyGenerator() : m_type(Rsa)
{
}
bool SshKeyGenerator::generateKeys(KeyType type, PrivateKeyFormat format, int keySize,
EncryptionMode encryptionMode)
{
m_type = type;
m_encryptionMode = encryptionMode;
try {
AutoSeeded_RNG rng;
KeyPtr key;
switch (m_type) {
case Rsa:
key = KeyPtr(new RSA_PrivateKey(rng, keySize));
break;
case Dsa:
key = KeyPtr(new DSA_PrivateKey(rng, DL_Group(rng, DL_Group::DSA_Kosherizer, keySize)));
break;
case Ecdsa: {
const QByteArray algo = SshCapabilities::ecdsaPubKeyAlgoForKeyWidth(keySize / 8);
key = KeyPtr(new ECDSA_PrivateKey(rng, EC_Group(SshCapabilities::oid(algo))));
break;
}
}
switch (format) {
case Pkcs8:
generatePkcs8KeyStrings(key, rng);
break;
case OpenSsl:
generateOpenSslKeyStrings(key);
break;
case Mixed:
default:
generatePkcs8KeyString(key, true, rng);
generateOpenSslPublicKeyString(key);
}
return true;
} catch (const std::exception &e) {
m_error = tr("Error generating key: %1").arg(QString::fromLocal8Bit(e.what()));
return false;
}
}
void SshKeyGenerator::generatePkcs8KeyStrings(const KeyPtr &key, RandomNumberGenerator &rng)
{
generatePkcs8KeyString(key, false, rng);
generatePkcs8KeyString(key, true, rng);
}
void SshKeyGenerator::generatePkcs8KeyString(const KeyPtr &key, bool privateKey,
RandomNumberGenerator &rng)
{
Pipe pipe;
pipe.start_msg();
QByteArray *keyData;
if (privateKey) {
QString password;
if (m_encryptionMode == DoOfferEncryption)
password = getPassword();
if (!password.isEmpty())
pipe.write(PKCS8::PEM_encode(*key, rng, password.toLocal8Bit().data()));
else
pipe.write(PKCS8::PEM_encode(*key));
keyData = &m_privateKey;
} else {
pipe.write(X509::PEM_encode(*key));
keyData = &m_publicKey;
}
pipe.end_msg();
keyData->resize(static_cast<int>(pipe.remaining(pipe.message_count() - 1)));
size_t readSize = pipe.read(convertByteArray(*keyData), keyData->size(),
pipe.message_count() - 1);
if (readSize != size_t(keyData->size())) {
qCWarning(sshLog, "Didn't manage to read in all key data, only read %lu bytes", readSize);
}
}
void SshKeyGenerator::generateOpenSslKeyStrings(const KeyPtr &key)
{
generateOpenSslPublicKeyString(key);
generateOpenSslPrivateKeyString(key);
}
void SshKeyGenerator::generateOpenSslPublicKeyString(const KeyPtr &key)
{
QList<BigInt> params;
QByteArray keyId;
QByteArray q;
switch (m_type) {
case Rsa: {
const QSharedPointer<RSA_PrivateKey> rsaKey = key.dynamicCast<RSA_PrivateKey>();
params << rsaKey->get_e() << rsaKey->get_n();
keyId = SshCapabilities::PubKeyRsa;
break;
}
case Dsa: {
const QSharedPointer<DSA_PrivateKey> dsaKey = key.dynamicCast<DSA_PrivateKey>();
params << dsaKey->group_p() << dsaKey->group_q() << dsaKey->group_g() << dsaKey->get_y();
keyId = SshCapabilities::PubKeyDss;
break;
}
case Ecdsa: {
const auto ecdsaKey = key.dynamicCast<ECDSA_PrivateKey>();
q = convertByteArray(ecdsaKey->public_point().encode(PointGFp::UNCOMPRESSED));
keyId = SshCapabilities::ecdsaPubKeyAlgoForKeyWidth(
static_cast<int>(ecdsaKey->private_value().bytes()));
break;
}
}
QByteArray publicKeyBlob = AbstractSshPacket::encodeString(keyId);
foreach (const BigInt &b, params)
publicKeyBlob += AbstractSshPacket::encodeMpInt(b);
if (!q.isEmpty()) {
publicKeyBlob += AbstractSshPacket::encodeString(keyId.mid(11)); // Without "ecdsa-sha2-" prefix.
publicKeyBlob += AbstractSshPacket::encodeString(q);
}
publicKeyBlob = publicKeyBlob.toBase64();
const QByteArray id = "QtCreator/"
+ QDateTime::currentDateTime().toString(Qt::ISODate).toUtf8();
m_publicKey = keyId + ' ' + publicKeyBlob + ' ' + id;
}
void SshKeyGenerator::generateOpenSslPrivateKeyString(const KeyPtr &key)
{
QList<BigInt> params;
const char *label = "";
switch (m_type) {
case Rsa: {
const QSharedPointer<RSA_PrivateKey> rsaKey
= key.dynamicCast<RSA_PrivateKey>();
params << rsaKey->get_n() << rsaKey->get_e() << rsaKey->get_d() << rsaKey->get_p()
<< rsaKey->get_q();
const BigInt dmp1 = rsaKey->get_d() % (rsaKey->get_p() - 1);
const BigInt dmq1 = rsaKey->get_d() % (rsaKey->get_q() - 1);
const BigInt iqmp = inverse_mod(rsaKey->get_q(), rsaKey->get_p());
params << dmp1 << dmq1 << iqmp;
label = "RSA PRIVATE KEY";
break;
}
case Dsa: {
const QSharedPointer<DSA_PrivateKey> dsaKey = key.dynamicCast<DSA_PrivateKey>();
params << dsaKey->group_p() << dsaKey->group_q() << dsaKey->group_g() << dsaKey->get_y()
<< dsaKey->get_x();
label = "DSA PRIVATE KEY";
break;
}
case Ecdsa:
params << key.dynamicCast<ECDSA_PrivateKey>()->private_value();
label = "EC PRIVATE KEY";
break;
}
DER_Encoder encoder;
encoder.start_cons(SEQUENCE).encode(size_t(0));
foreach (const BigInt &b, params)
encoder.encode(b);
encoder.end_cons();
m_privateKey = QByteArray(PEM_Code::encode (encoder.get_contents(), label).c_str());
}
QString SshKeyGenerator::getPassword() const
{
QInputDialog d;
d.setInputMode(QInputDialog::TextInput);
d.setTextEchoMode(QLineEdit::Password);
d.setWindowTitle(tr("Password for Private Key"));
d.setLabelText(tr("It is recommended that you secure your private key\n"
"with a password, which you can enter below."));
d.setOkButtonText(tr("Encrypt Key File"));
d.setCancelButtonText(tr("Do Not Encrypt Key File"));
int result = QDialog::Accepted;
QString password;
while (result == QDialog::Accepted && password.isEmpty()) {
result = d.exec();
password = d.textValue();
}
return result == QDialog::Accepted ? password : QString();
}
} // namespace QSsh

View file

@ -1,83 +0,0 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: http://www.qt-project.org/
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**************************************************************************/
#ifndef SSHKEYGENERATOR_H
#define SSHKEYGENERATOR_H
#include "ssh_global.h"
#include <QCoreApplication>
#include <QSharedPointer>
namespace Botan {
class Private_Key;
class RandomNumberGenerator;
}
namespace QSsh {
class QSSH_EXPORT SshKeyGenerator
{
Q_DECLARE_TR_FUNCTIONS(SshKeyGenerator)
public:
enum KeyType { Rsa, Dsa, Ecdsa };
enum PrivateKeyFormat { Pkcs8, OpenSsl, Mixed };
enum EncryptionMode { DoOfferEncryption, DoNotOfferEncryption }; // Only relevant for Pkcs8 format.
SshKeyGenerator();
bool generateKeys(KeyType type, PrivateKeyFormat format, int keySize,
EncryptionMode encryptionMode = DoOfferEncryption);
QString error() const { return m_error; }
QByteArray privateKey() const { return m_privateKey; }
QByteArray publicKey() const { return m_publicKey; }
KeyType type() const { return m_type; }
private:
typedef QSharedPointer<Botan::Private_Key> KeyPtr;
void generatePkcs8KeyStrings(const KeyPtr &key, Botan::RandomNumberGenerator &rng);
void generatePkcs8KeyString(const KeyPtr &key, bool privateKey,
Botan::RandomNumberGenerator &rng);
void generateOpenSslKeyStrings(const KeyPtr &key);
void generateOpenSslPrivateKeyString(const KeyPtr &key);
void generateOpenSslPublicKeyString(const KeyPtr &key);
QString getPassword() const;
QString m_error;
QByteArray m_publicKey;
QByteArray m_privateKey;
KeyType m_type;
EncryptionMode m_encryptionMode;
};
} // namespace QSsh
#endif // SSHKEYGENERATOR_H

View file

@ -1,60 +0,0 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: http://www.qt-project.org/
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**************************************************************************/
#include "sshkeypasswordretriever_p.h"
#include <QString>
#include <QApplication>
#include <QInputDialog>
#include <iostream>
namespace QSsh {
namespace Internal {
std::string SshKeyPasswordRetriever::get_passphrase()
{
const bool hasGui = dynamic_cast<QApplication *>(QApplication::instance());
if (hasGui) {
bool ok;
const QString &password = QInputDialog::getText(nullptr,
QCoreApplication::translate("QSsh::Ssh", "Password Required"),
QCoreApplication::translate("QSsh::Ssh", "Please enter the password for your private key."),
QLineEdit::Password, QString(), &ok);
return std::string(password.toLocal8Bit().data());
} else {
std::string password;
std::cout << "Please enter the password for your private key (set echo off beforehand!): " << std::flush;
std::cin >> password;
return password;
}
}
} // namespace Internal
} // namespace QSsh

View file

@ -1,47 +0,0 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: http://www.qt-project.org/
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**************************************************************************/
#ifndef KEYPASSWORDRETRIEVER_H
#define KEYPASSWORDRETRIEVER_H
#include <string>
namespace QSsh {
namespace Internal {
class SshKeyPasswordRetriever
{
public:
static std::string get_passphrase();
};
} // namespace Internal
} // namespace QSsh
#endif // KEYPASSWORDRETRIEVER_H

View file

@ -1,37 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms and
** conditions see http://www.qt.io/terms-conditions. For further information
** use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "sshlogging_p.h"
namespace QSsh {
namespace Internal {
Q_LOGGING_CATEGORY(sshLog, "qtc.ssh", QtWarningMsg)
} // namespace Internal
} // namespace QSsh

View file

@ -1,42 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms and
** conditions see http://www.qt.io/terms-conditions. For further information
** use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef SSHLOGGING_P_H
#define SSHLOGGING_P_H
#include <QLoggingCategory>
namespace QSsh {
namespace Internal {
Q_DECLARE_LOGGING_CATEGORY(sshLog)
} // namespace Internal
} // namespace QSsh
#endif // Include guard

View file

@ -1,420 +0,0 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: http://www.qt-project.org/
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**************************************************************************/
#include "sshoutgoingpacket_p.h"
#include "sshagent_p.h"
#include "sshcapabilities_p.h"
#include "sshcryptofacility_p.h"
#include "sshlogging_p.h"
#include "sshpacketparser_p.h"
#include <QtEndian>
namespace QSsh {
namespace Internal {
SshOutgoingPacket::SshOutgoingPacket(const SshEncryptionFacility &encrypter,
const quint32 &seqNr) : m_encrypter(encrypter), m_seqNr(seqNr)
{
}
quint32 SshOutgoingPacket::cipherBlockSize() const
{
return qMax(m_encrypter.cipherBlockSize(), 4U);
}
quint32 SshOutgoingPacket::macLength() const
{
return m_encrypter.macLength();
}
QByteArray SshOutgoingPacket::generateKeyExchangeInitPacket()
{
const QByteArray &supportedkeyExchangeMethods
= encodeNameList(SshCapabilities::KeyExchangeMethods);
const QByteArray &supportedPublicKeyAlgorithms
= encodeNameList(SshCapabilities::PublicKeyAlgorithms);
const QByteArray &supportedEncryptionAlgorithms
= encodeNameList(SshCapabilities::EncryptionAlgorithms);
const QByteArray &supportedMacAlgorithms
= encodeNameList(SshCapabilities::MacAlgorithms);
const QByteArray &supportedCompressionAlgorithms
= encodeNameList(SshCapabilities::CompressionAlgorithms);
const QByteArray &supportedLanguages = encodeNameList(QList<QByteArray>());
init(SSH_MSG_KEXINIT);
m_data += m_encrypter.getRandomNumbers(16);
m_data.append(supportedkeyExchangeMethods);
m_data.append(supportedPublicKeyAlgorithms);
m_data.append(supportedEncryptionAlgorithms)
.append(supportedEncryptionAlgorithms);
m_data.append(supportedMacAlgorithms).append(supportedMacAlgorithms);
m_data.append(supportedCompressionAlgorithms)
.append(supportedCompressionAlgorithms);
m_data.append(supportedLanguages).append(supportedLanguages);
appendBool(false); // No guessed packet.
m_data.append(QByteArray(4, 0)); // Reserved.
QByteArray payload = m_data.mid(PayloadOffset);
finalize();
return payload;
}
void SshOutgoingPacket::generateKeyDhInitPacket(const Botan::BigInt &e)
{
init(SSH_MSG_KEXDH_INIT).appendMpInt(e).finalize();
}
void SshOutgoingPacket::generateKeyEcdhInitPacket(const QByteArray &clientQ)
{
init(SSH_MSG_KEX_ECDH_INIT).appendString(clientQ).finalize();
}
void SshOutgoingPacket::generateNewKeysPacket()
{
init(SSH_MSG_NEWKEYS).finalize();
}
void SshOutgoingPacket::generateUserAuthServiceRequestPacket()
{
generateServiceRequest("ssh-userauth");
}
void SshOutgoingPacket::generateServiceRequest(const QByteArray &service)
{
init(SSH_MSG_SERVICE_REQUEST).appendString(service).finalize();
}
void SshOutgoingPacket::generateUserAuthByPasswordRequestPacket(const QByteArray &user,
const QByteArray &service, const QByteArray &pwd)
{
init(SSH_MSG_USERAUTH_REQUEST).appendString(user).appendString(service);
if (pwd.isEmpty())
appendString("none"); // RFC 4252, 5.2
else
appendString("password").appendBool(false).appendString(pwd);
finalize();
}
void SshOutgoingPacket::generateUserAuthByPublicKeyRequestPacket(const QByteArray &user,
const QByteArray &service, const QByteArray &key, const QByteArray &signature)
{
init(SSH_MSG_USERAUTH_REQUEST).appendString(user).appendString(service)
.appendString("publickey").appendBool(true);
if (!key.isEmpty()) {
appendString(SshPacketParser::asString(key, quint32(0)));
appendString(key);
appendString(signature);
} else {
appendString(m_encrypter.authenticationAlgorithmName());
appendString(m_encrypter.authenticationPublicKey());
const QByteArray &dataToSign = m_data.mid(PayloadOffset);
appendString(m_encrypter.authenticationKeySignature(dataToSign));
}
finalize();
}
void SshOutgoingPacket::generateQueryPublicKeyPacket(const QByteArray &user,
const QByteArray &service, const QByteArray &publicKey)
{
// Name extraction cannot fail, we already verified this when receiving the key
// from the agent.
const QByteArray algoName = SshPacketParser::asString(publicKey, quint32(0));
SshOutgoingPacket packetToSign(m_encrypter, m_seqNr);
packetToSign.init(SSH_MSG_USERAUTH_REQUEST).appendString(user).appendString(service)
.appendString("publickey").appendBool(true).appendString(algoName)
.appendString(publicKey);
const QByteArray &dataToSign
= encodeString(m_encrypter.sessionId()) + packetToSign.m_data.mid(PayloadOffset);
SshAgent::storeDataToSign(publicKey, dataToSign, qHash(m_encrypter.sessionId()));
init(SSH_MSG_USERAUTH_REQUEST).appendString(user).appendString(service)
.appendString("publickey").appendBool(false).appendString(algoName)
.appendString(publicKey).finalize();
}
void SshOutgoingPacket::generateUserAuthByKeyboardInteractiveRequestPacket(const QByteArray &user,
const QByteArray &service)
{
// RFC 4256, 3.1
init(SSH_MSG_USERAUTH_REQUEST).appendString(user).appendString(service)
.appendString("keyboard-interactive")
.appendString(QByteArray()) // Language tag. Deprecated and should be empty
.appendString(QByteArray()) // Submethods.
.finalize();
}
void SshOutgoingPacket::generateUserAuthInfoResponsePacket(const QStringList &responses)
{
// RFC 4256, 3.4
init(SSH_MSG_USERAUTH_INFO_RESPONSE).appendInt(responses.count());
foreach (const QString &response, responses)
appendString(response.toUtf8());
finalize();
}
void SshOutgoingPacket::generateRequestFailurePacket()
{
init(SSH_MSG_REQUEST_FAILURE).finalize();
}
void SshOutgoingPacket::generateIgnorePacket()
{
init(SSH_MSG_IGNORE).finalize();
}
void SshOutgoingPacket::generateInvalidMessagePacket()
{
init(SSH_MSG_INVALID).finalize();
}
void SshOutgoingPacket::generateSessionPacket(quint32 channelId,
quint32 windowSize, quint32 maxPacketSize)
{
init(SSH_MSG_CHANNEL_OPEN).appendString("session").appendInt(channelId)
.appendInt(windowSize).appendInt(maxPacketSize).finalize();
}
void SshOutgoingPacket::generateDirectTcpIpPacket(quint32 channelId, quint32 windowSize,
quint32 maxPacketSize, const QByteArray &remoteHost, quint32 remotePort,
const QByteArray &localIpAddress, quint32 localPort)
{
init(SSH_MSG_CHANNEL_OPEN).appendString("direct-tcpip").appendInt(channelId)
.appendInt(windowSize).appendInt(maxPacketSize).appendString(remoteHost)
.appendInt(remotePort).appendString(localIpAddress).appendInt(localPort).finalize();
}
void SshOutgoingPacket::generateTcpIpForwardPacket(const QByteArray &bindAddress, quint32 bindPort)
{
init(SSH_MSG_GLOBAL_REQUEST).appendString("tcpip-forward").appendBool(true)
.appendString(bindAddress).appendInt(bindPort).finalize();
}
void SshOutgoingPacket::generateCancelTcpIpForwardPacket(const QByteArray &bindAddress,
quint32 bindPort)
{
init(SSH_MSG_GLOBAL_REQUEST).appendString("cancel-tcpip-forward").appendBool(true)
.appendString(bindAddress).appendInt(bindPort).finalize();
}
void SshOutgoingPacket::generateEnvPacket(quint32 remoteChannel,
const QByteArray &var, const QByteArray &value)
{
init(SSH_MSG_CHANNEL_REQUEST).appendInt(remoteChannel).appendString("env")
.appendBool(false).appendString(var).appendString(value).finalize();
}
void SshOutgoingPacket::generateX11ForwardingPacket(quint32 remoteChannel,
const QByteArray &protocol, const QByteArray &cookie, quint32 screenNumber)
{
init(SSH_MSG_CHANNEL_REQUEST).appendInt(remoteChannel).appendString("x11-req")
.appendBool(false).appendBool(false).appendString(protocol)
.appendString(cookie).appendInt(screenNumber).finalize();
}
void SshOutgoingPacket::generatePtyRequestPacket(quint32 remoteChannel,
const SshPseudoTerminal &terminal)
{
init(SSH_MSG_CHANNEL_REQUEST).appendInt(remoteChannel)
.appendString("pty-req").appendBool(false)
.appendString(terminal.termType).appendInt(terminal.columnCount)
.appendInt(terminal.rowCount).appendInt(0).appendInt(0);
QByteArray modeString;
for (SshPseudoTerminal::ModeMap::ConstIterator it = terminal.modes.constBegin();
it != terminal.modes.constEnd(); ++it) {
modeString += char(it.key());
modeString += encodeInt(it.value());
}
modeString += char(0); // TTY_OP_END
appendString(modeString).finalize();
}
void SshOutgoingPacket::generateExecPacket(quint32 remoteChannel,
const QByteArray &command)
{
init(SSH_MSG_CHANNEL_REQUEST).appendInt(remoteChannel).appendString("exec")
.appendBool(true).appendString(command).finalize();
}
void SshOutgoingPacket::generateShellPacket(quint32 remoteChannel)
{
init(SSH_MSG_CHANNEL_REQUEST).appendInt(remoteChannel).appendString("shell")
.appendBool(true).finalize();
}
void SshOutgoingPacket::generateSftpPacket(quint32 remoteChannel)
{
init(SSH_MSG_CHANNEL_REQUEST).appendInt(remoteChannel)
.appendString("subsystem").appendBool(true).appendString("sftp")
.finalize();
}
void SshOutgoingPacket::generateWindowAdjustPacket(quint32 remoteChannel,
quint32 bytesToAdd)
{
init(SSH_MSG_CHANNEL_WINDOW_ADJUST).appendInt(remoteChannel)
.appendInt(bytesToAdd).finalize();
}
void SshOutgoingPacket::generateChannelDataPacket(quint32 remoteChannel,
const QByteArray &data)
{
init(SSH_MSG_CHANNEL_DATA).appendInt(remoteChannel).appendString(data)
.finalize();
}
void SshOutgoingPacket::generateChannelSignalPacket(quint32 remoteChannel,
const QByteArray &signalName)
{
init(SSH_MSG_CHANNEL_REQUEST).appendInt(remoteChannel)
.appendString("signal").appendBool(false).appendString(signalName)
.finalize();
}
void SshOutgoingPacket::generateChannelEofPacket(quint32 remoteChannel)
{
init(SSH_MSG_CHANNEL_EOF).appendInt(remoteChannel).finalize();
}
void SshOutgoingPacket::generateChannelClosePacket(quint32 remoteChannel)
{
init(SSH_MSG_CHANNEL_CLOSE).appendInt(remoteChannel).finalize();
}
void SshOutgoingPacket::generateChannelOpenConfirmationPacket(quint32 remoteChannel,
quint32 localChannel,
quint32 localWindowSize,
quint32 maxPacketSize)
{
init(SSH_MSG_CHANNEL_OPEN_CONFIRMATION).appendInt(remoteChannel).appendInt(localChannel)
.appendInt(localWindowSize).appendInt(maxPacketSize).finalize();
}
void SshOutgoingPacket::generateChannelOpenFailurePacket(quint32 remoteChannel, quint32 reason,
const QByteArray &reasonString)
{
init(SSH_MSG_CHANNEL_OPEN_FAILURE).appendInt(remoteChannel).appendInt(reason)
.appendString(reasonString).appendString(QByteArray()).finalize();
}
void SshOutgoingPacket::generateDisconnectPacket(SshErrorCode reason,
const QByteArray &reasonString)
{
init(SSH_MSG_DISCONNECT).appendInt(reason).appendString(reasonString)
.appendString(QByteArray()).finalize();
}
void SshOutgoingPacket::generateMsgUnimplementedPacket(quint32 serverSeqNr)
{
init(SSH_MSG_UNIMPLEMENTED).appendInt(serverSeqNr).finalize();
}
SshOutgoingPacket &SshOutgoingPacket::appendInt(quint32 val)
{
m_data.append(encodeInt(val));
return *this;
}
SshOutgoingPacket &SshOutgoingPacket::appendMpInt(const Botan::BigInt &number)
{
m_data.append(encodeMpInt(number));
return *this;
}
SshOutgoingPacket &SshOutgoingPacket::appendBool(bool b)
{
m_data += static_cast<char>(b);
return *this;
}
SshOutgoingPacket &SshOutgoingPacket::appendString(const QByteArray &string)
{
m_data.append(encodeString(string));
return *this;
}
SshOutgoingPacket &SshOutgoingPacket::init(SshPacketType type)
{
m_data.resize(TypeOffset + 1);
m_data[TypeOffset] = type;
return *this;
}
SshOutgoingPacket &SshOutgoingPacket::setPadding()
{
m_data += m_encrypter.getRandomNumbers(MinPaddingLength);
int padLength = MinPaddingLength;
const int divisor = sizeDivisor();
const int mod = m_data.size() % divisor;
padLength += divisor - mod;
m_data += m_encrypter.getRandomNumbers(padLength - MinPaddingLength);
m_data[PaddingLengthOffset] = padLength;
return *this;
}
SshOutgoingPacket &SshOutgoingPacket::encrypt()
{
const QByteArray &mac
= generateMac(m_encrypter, m_seqNr);
m_encrypter.encrypt(m_data);
m_data += mac;
return *this;
}
void SshOutgoingPacket::finalize()
{
setPadding();
setLengthField(m_data);
m_length = m_data.size() - 4;
qCDebug(sshLog, "Encrypting packet of type %u", m_data.at(TypeOffset));
encrypt();
qCDebug(sshLog, "Sending packet of size %d", rawData().count());
Q_ASSERT(isComplete());
}
int SshOutgoingPacket::sizeDivisor() const
{
return qMax(cipherBlockSize(), 8U);
}
QByteArray SshOutgoingPacket::encodeNameList(const QList<QByteArray> &list)
{
QByteArray data;
data.resize(4);
for (int i = 0; i < list.count(); ++i) {
if (i > 0)
data.append(',');
data.append(list.at(i));
}
AbstractSshPacket::setLengthField(data);
return data;
}
} // namespace Internal
} // namespace QSsh

View file

@ -1,125 +0,0 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: http://www.qt-project.org/
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**************************************************************************/
#ifndef SSHOUTGOINGPACKET_P_H
#define SSHOUTGOINGPACKET_P_H
#include "sshpacket_p.h"
#include "sshpseudoterminal.h"
#include <QStringList>
namespace QSsh {
namespace Internal {
class SshEncryptionFacility;
class SshOutgoingPacket : public AbstractSshPacket
{
public:
SshOutgoingPacket(const SshEncryptionFacility &encrypter,
const quint32 &seqNr);
QByteArray generateKeyExchangeInitPacket(); // Returns payload.
void generateKeyDhInitPacket(const Botan::BigInt &e);
void generateKeyEcdhInitPacket(const QByteArray &clientQ);
void generateNewKeysPacket();
void generateDisconnectPacket(SshErrorCode reason,
const QByteArray &reasonString);
void generateMsgUnimplementedPacket(quint32 serverSeqNr);
void generateUserAuthServiceRequestPacket();
void generateUserAuthByPasswordRequestPacket(const QByteArray &user,
const QByteArray &service, const QByteArray &pwd);
void generateUserAuthByPublicKeyRequestPacket(const QByteArray &user,
const QByteArray &service, const QByteArray &key, const QByteArray &signature);
void generateQueryPublicKeyPacket(const QByteArray &user, const QByteArray &service,
const QByteArray &publicKey);
void generateUserAuthByKeyboardInteractiveRequestPacket(const QByteArray &user,
const QByteArray &service);
void generateUserAuthInfoResponsePacket(const QStringList &responses);
void generateRequestFailurePacket();
void generateIgnorePacket();
void generateInvalidMessagePacket();
void generateSessionPacket(quint32 channelId, quint32 windowSize,
quint32 maxPacketSize);
void generateDirectTcpIpPacket(quint32 channelId, quint32 windowSize,
quint32 maxPacketSize, const QByteArray &remoteHost, quint32 remotePort,
const QByteArray &localIpAddress, quint32 localPort);
void generateTcpIpForwardPacket(const QByteArray &bindAddress, quint32 bindPort);
void generateCancelTcpIpForwardPacket(const QByteArray &bindAddress, quint32 bindPort);
void generateEnvPacket(quint32 remoteChannel, const QByteArray &var,
const QByteArray &value);
void generateX11ForwardingPacket(quint32 remoteChannel, const QByteArray &protocol,
const QByteArray &cookie, quint32 screenNumber);
void generatePtyRequestPacket(quint32 remoteChannel,
const SshPseudoTerminal &terminal);
void generateExecPacket(quint32 remoteChannel, const QByteArray &command);
void generateShellPacket(quint32 remoteChannel);
void generateSftpPacket(quint32 remoteChannel);
void generateWindowAdjustPacket(quint32 remoteChannel, quint32 bytesToAdd);
void generateChannelDataPacket(quint32 remoteChannel,
const QByteArray &data);
void generateChannelSignalPacket(quint32 remoteChannel,
const QByteArray &signalName);
void generateChannelEofPacket(quint32 remoteChannel);
void generateChannelClosePacket(quint32 remoteChannel);
void generateChannelOpenConfirmationPacket(quint32 remoteChannel, quint32 localChannel,
quint32 localWindowSize, quint32 maxPackeSize);
void generateChannelOpenFailurePacket(quint32 remoteChannel, quint32 reason,
const QByteArray &reasonString);
private:
virtual quint32 cipherBlockSize() const;
virtual quint32 macLength() const;
static QByteArray encodeNameList(const QList<QByteArray> &list);
void generateServiceRequest(const QByteArray &service);
SshOutgoingPacket &init(SshPacketType type);
SshOutgoingPacket &setPadding();
SshOutgoingPacket &encrypt();
void finalize();
SshOutgoingPacket &appendInt(quint32 val);
SshOutgoingPacket &appendString(const QByteArray &string);
SshOutgoingPacket &appendMpInt(const Botan::BigInt &number);
SshOutgoingPacket &appendBool(bool b);
int sizeDivisor() const;
const SshEncryptionFacility &m_encrypter;
const quint32 &m_seqNr;
};
} // namespace Internal
} // namespace QSsh
#endif // SSHOUTGOINGPACKET_P_H

View file

@ -1,159 +0,0 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: http://www.qt-project.org/
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**************************************************************************/
#include "sshpacket_p.h"
#include "sshcapabilities_p.h"
#include "sshcryptofacility_p.h"
#include "sshexception_p.h"
#include "sshlogging_p.h"
#include "sshpacketparser_p.h"
#include <QDebug>
#include <cctype>
namespace QSsh {
namespace Internal {
const quint32 AbstractSshPacket::PaddingLengthOffset = 4;
const quint32 AbstractSshPacket::PayloadOffset = PaddingLengthOffset + 1;
const quint32 AbstractSshPacket::TypeOffset = PayloadOffset;
const quint32 AbstractSshPacket::MinPaddingLength = 4;
static void printByteArray(const QByteArray &data)
{
qCDebug(sshLog, "%s", data.toHex().constData());
}
AbstractSshPacket::AbstractSshPacket() : m_length(0) { }
AbstractSshPacket::~AbstractSshPacket() {}
bool AbstractSshPacket::isComplete() const
{
if (currentDataSize() < minPacketSize())
return false;
return 4 + length() + macLength() == currentDataSize();
}
void AbstractSshPacket::clear()
{
m_data.clear();
m_length = 0;
}
SshPacketType AbstractSshPacket::type() const
{
Q_ASSERT(isComplete());
return static_cast<SshPacketType>(m_data.at(TypeOffset));
}
QByteArray AbstractSshPacket::payLoad() const
{
return QByteArray(m_data.constData() + PayloadOffset,
length() - paddingLength() - 1);
}
void AbstractSshPacket::printRawBytes() const
{
printByteArray(m_data);
}
QByteArray AbstractSshPacket::encodeString(const QByteArray &string)
{
QByteArray data;
data.resize(4);
data += string;
setLengthField(data);
return data;
}
QByteArray AbstractSshPacket::encodeMpInt(const Botan::BigInt &number)
{
if (number.is_zero())
return QByteArray(4, 0);
int stringLength = static_cast<int>(number.bytes());
const bool positiveAndMsbSet = number.sign() == Botan::BigInt::Positive
&& (number.byte_at(stringLength - 1) & 0x80);
if (positiveAndMsbSet)
++stringLength;
QByteArray data;
data.resize(4 + stringLength);
int pos = 4;
if (positiveAndMsbSet)
data[pos++] = '\0';
number.binary_encode(reinterpret_cast<Botan::byte *>(data.data()) + pos);
setLengthField(data);
return data;
}
int AbstractSshPacket::paddingLength() const
{
return m_data[PaddingLengthOffset];
}
quint32 AbstractSshPacket::length() const
{
//Q_ASSERT(currentDataSize() >= minPacketSize());
if (m_length == 0)
calculateLength();
return m_length;
}
void AbstractSshPacket::calculateLength() const
{
m_length = SshPacketParser::asUint32(m_data, static_cast<quint32>(0));
}
QByteArray AbstractSshPacket::generateMac(const SshAbstractCryptoFacility &crypt,
quint32 seqNr) const
{
const quint32 seqNrBe = qToBigEndian(seqNr);
QByteArray data(reinterpret_cast<const char *>(&seqNrBe), static_cast<int>(sizeof seqNrBe));
data += QByteArray(m_data.constData(), length() + 4);
return crypt.generateMac(data, data.size());
}
quint32 AbstractSshPacket::minPacketSize() const
{
return qMax<quint32>(cipherBlockSize(), 16) + macLength();
}
void AbstractSshPacket::setLengthField(QByteArray &data)
{
const quint32 length = qToBigEndian<quint32>(data.size() - 4);
data.replace(static_cast<qsizetype>(0), static_cast<qsizetype>(4),
reinterpret_cast<const char *>(&length), static_cast<qsizetype>(4));
}
} // namespace Internal
} // namespace QSsh

Some files were not shown because too many files have changed in this diff Show more