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 (SshPacketParseException &) { throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, "Invalid SSH_FXP_NAME packet."); } }
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 (SshPacketParseException &) { throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, "Invalid SSH_MSG_DEBUG."); } }
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 (SshPacketParseException &) { throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, "Invalid SSH_FXP_STATUS packet."); } }
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); }
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 (SshPacketParseException &) { throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, "Invalid SSH_MSG_CHANNEL_EXTENDED_DATA packet."); } return data; }
void SshIncomingPacket::consumeData(QByteArray &newData) { #ifdef CREATOR_SSH_DEBUG qDebug("%s: current data size = %d, new data size = %d", Q_FUNC_INFO, m_data.size(), newData.size()); #endif 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); #ifdef CREATOR_SSH_DEBUG qDebug("Took %d bytes from new data", bytesToTake); #endif 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); #ifdef CREATOR_SSH_DEBUG qDebug("Took %d bytes from new data", bytesToTake); #endif if (isComplete()) { #ifdef CREATOR_SSH_DEBUG qDebug("Message complete. Overall size: %u, payload size: %u", m_data.size(), m_length - paddingLength() - 1); #endif decrypt(); ++m_serverSeqNr; } }
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 (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 (SshPacketParseException &) { throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, "Server sent invalid SSH_MSG_CHANNEL_OPEN_CONFIRMATION packet."); } return confirmation; }
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 (SshPacketParseException &) { throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, "Invalid SSH_MSG_DISCONNECT."); } return msg; }
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 (SshPacketParseException &) { throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, "Invalid exit-status packet."); } return exitStatus; }
void SftpChannelPrivate::handleServerVersion() { checkChannelActive(); if (m_sftpState != InitSent) { throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, "Unexpected SSH_FXP_VERSION packet."); } #ifdef CREATOR_SSH_DEBUG qDebug("sftp init received"); #endif const quint32 serverVersion = m_incomingPacket.extractServerVersion(); if (serverVersion != ProtocolVersion) { emit initializationFailed(tr("Protocol version mismatch: Expected %1, got %2") .arg(serverVersion).arg(ProtocolVersion)); closeChannel(); } else { m_sftpState = Initialized; emit initialized(); } }
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 (SshPacketParseException &) { throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_KEY_EXCHANGE_FAILED, "Key exchange failed: Server sent invalid SSH_MSG_KEXINIT packet."); } return exchangeData; }
SshKeyExchangeReply SshIncomingPacket::extractKeyExchangeReply(const QByteArray &pubKeyAlgo) const { Q_ASSERT(isComplete()); Q_ASSERT(type() == SSH_MSG_KEXDH_REPLY); try { SshKeyExchangeReply replyData; quint32 offset = TypeOffset + 1; const quint32 k_sLength = SshPacketParser::asUint32(m_data, &offset); if (offset + k_sLength > currentDataSize()) throw SshPacketParseException(); replyData.k_s = m_data.mid(offset - 4, k_sLength + 4); if (SshPacketParser::asString(m_data, &offset) != pubKeyAlgo) throw SshPacketParseException(); // DSS: p and q, RSA: e and n replyData.parameters << SshPacketParser::asBigInt(m_data, &offset); replyData.parameters << SshPacketParser::asBigInt(m_data, &offset); // g and y if (pubKeyAlgo == SshCapabilities::PubKeyDss) { replyData.parameters << SshPacketParser::asBigInt(m_data, &offset); replyData.parameters << SshPacketParser::asBigInt(m_data, &offset); } replyData.f = SshPacketParser::asBigInt(m_data, &offset); offset += 4; if (SshPacketParser::asString(m_data, &offset) != pubKeyAlgo) throw SshPacketParseException(); replyData.signatureBlob = SshPacketParser::asString(m_data, &offset); return replyData; } catch (SshPacketParseException &) { throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_KEY_EXCHANGE_FAILED, "Key exchange failed: " "Server sent invalid SSH_MSG_KEXDH_REPLY packet."); } }
void SftpIncomingPacket::consumeData(QByteArray &newData) { #ifdef CREATOR_SSH_DEBUG qDebug("%s: current data size = %d, new data size = %d", Q_FUNC_INFO, m_data.size(), newData.size()); #endif 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())); }
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 (SshPacketParseException &) { throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, "Invalid exit-signal packet."); } return exitSignal; }
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 (SshPacketParseException &) { throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, "Invalid SSH_MSG_USERAUTH_INFO_REQUEST."); } }
void SshChannelManager::handleChannelOpen(const SshIncomingPacket &) { throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, "Server tried to open channel on client."); }
void AbstractSshChannel::checkChannelActive() { if (channelState() == Inactive || channelState() == Closed) throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, "Channel not open."); }
void SshDirectTcpIpTunnelPrivate::handleChannelSuccess() { throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, "Unexpected SSH_MSG_CHANNEL_SUCCESS message."); }
void SshDirectTcpIpTunnelPrivate::handleChannelFailure() { throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, "Unexpected SSH_MSG_CHANNEL_FAILURE message."); }