Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
SUSE:SLE-12-SP2:GA
kdump.2364
kdump-sftppacket.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File kdump-sftppacket.patch of Package kdump.2364
From: Petr Tesarik <ptesarik@suse.cz> Date: Wed, 15 Apr 2015 12:50:49 +0200 Subject: Class to encode/decode SFTP packets References: FATE#318874, bsc#917747 Patch-mainline: v0.8.16 Git-commit: 6854130651fc82a4055fe49e60be7e70a3458e6d Git-commit: bb2833a563182ae9e0d3f0dc68d9c49536f61a54 Git-commit: e8a8df2b30120d8130b6007e7b14a489bd61e79b Git-commit: 149dd520cc1a6419c1ec36a999c80072df74ec74 Git-commit: e7699507d1b2c54452687af22c155222f65a550a Git-commit: d49008c86d26836ad6fcdc967741bf8dd3970953 Git-commit: 1988f5798476edcde4ad7bb2c577e755ccf610ff Git-commit: c88dd77c52d591855a9f31217fcc43513d0e6d05 Git-commit: 920b35981bd0dcd4e7ada32d39bbd191f1d63281 Git-commit: 1854f1b84fe2bc95a7339f33ee5db34dc0af0320 Git-commit: 08c884ea6e9d9e0f537035be25cf6c37cc0dc269 Git-commit: 8c18a0bd9b7fefde98333ad97ee4ee4709465357 The sftp protocol is sufficiently flexible to allow saving makedumpfile's output directly, but the sftp client is not (it has no way to copy standard input to a target file). This is why kdumptool must implement the necessary protocol commands itself. The SFTPPacket class can be used both for creating client requests and for parsing server replies. Signed-off-by: Petr Tesarik <ptesarik@suse.cz> --- kdumptool/CMakeLists.txt | 5 + kdumptool/sshtransfer.cc | 83 +++++++++++++++++++ kdumptool/sshtransfer.h | 49 +++++++++++ kdumptool/testsftppacket.cc | 189 ++++++++++++++++++++++++++++++++++++++++++++ tests/CMakeLists.txt | 4 tests/testsftppacket.sh | 181 ++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 511 insertions(+) --- a/kdumptool/CMakeLists.txt +++ b/kdumptool/CMakeLists.txt @@ -149,3 +149,8 @@ add_executable(testurldecode testurldecode.cc ) target_link_libraries(testurldecode common ${EXTRA_LIBS}) + +add_executable(testsftppacket + testsftppacket.cc +) +target_link_libraries(testsftppacket common ${EXTRA_LIBS}) --- a/kdumptool/sshtransfer.cc +++ b/kdumptool/sshtransfer.cc @@ -20,6 +20,7 @@ #include <string> #include <cstdlib> #include <cerrno> +#include <stdint.h> #if HAVE_LIBSSH2 # include <libssh2.h> @@ -165,6 +166,88 @@ StringVector SSHTransfer::makeArgs(std:: } //}}} +//{{{ SFTPPacket --------------------------------------------------------------- + +/* -------------------------------------------------------------------------- */ +SFTPPacket::SFTPPacket(void) + : m_vector(sizeof(uint32_t)), + m_gpos(0) +{ +} + +/* -------------------------------------------------------------------------- */ +void SFTPPacket::addByteVector(ByteVector const &val) +{ + m_vector.insert(m_vector.end(), val.begin(), val.end()); +} + +/* -------------------------------------------------------------------------- */ +void SFTPPacket::addInt32(unsigned long val) +{ + int i; + for (i = sizeof(uint32_t) - 1; i >= 0; --i) + m_vector.push_back((val >> (i*8)) & 0xff); +} + +/* -------------------------------------------------------------------------- */ +unsigned long SFTPPacket::getInt32(void) +{ + size_t i; + unsigned long ret = 0UL; + for (i = 0; i < sizeof(uint32_t); ++i) { + ret <<= 8; + ret |= m_vector.at(m_gpos++); + } + return ret; +} + +/* -------------------------------------------------------------------------- */ +void SFTPPacket::addInt64(unsigned long long val) +{ + int i; + for (i = sizeof(uint64_t) - 1; i >= 0; --i) + m_vector.push_back((val >> (i*8)) & 0xff); +} + +/* -------------------------------------------------------------------------- */ +unsigned long long SFTPPacket::getInt64(void) +{ + size_t i; + unsigned long long ret = 0ULL; + for (i = 0; i < sizeof(uint64_t); ++i) { + ret <<= 8; + ret |= m_vector.at(m_gpos++); + } + return ret; +} + +/* -------------------------------------------------------------------------- */ +void SFTPPacket::addString(KString const &val) +{ + addInt32(val.length()); + m_vector.insert(m_vector.end(), val.begin(), val.end()); +} + +/* -------------------------------------------------------------------------- */ +std::string SFTPPacket::getString(void) +{ + unsigned long len = getInt32(); + ByteVector::iterator it = m_vector.begin() + m_gpos; + return string(it, it + len); +} + +/* -------------------------------------------------------------------------- */ +ByteVector const &SFTPPacket::update(void) +{ + uint_fast32_t len = m_vector.size() - sizeof(uint32_t); + m_vector[0] = (len >> 24) & 0xff; + m_vector[1] = (len >> 16) & 0xff; + m_vector[2] = (len >> 8) & 0xff; + m_vector[3] = (len ) & 0xff; + return m_vector; +} + +//}}} //{{{ SFTPTransfer ------------------------------------------------------------- #if HAVE_LIBSSH2 --- a/kdumptool/sshtransfer.h +++ b/kdumptool/sshtransfer.h @@ -72,6 +72,55 @@ class SSHTransfer : public URLTransfer { }; //}}} +//{{{ SFTPPacket --------------------------------------------------------------- + +/** + * Encode/decode an SFTP packet. + */ +class SFTPPacket { + + public: + + SFTPPacket(void); + + ByteVector const &data(void) const + throw () + { return m_vector; } + + ByteVector const &update(void); + + void setData(ByteVector const &val) + { + m_vector = val; + m_gpos = 0; + } + + void addByte(unsigned char val) + { m_vector.push_back(val); } + + void addByteVector(ByteVector const &val); + + void addInt32(unsigned long val); + + void addInt64(unsigned long long val); + + void addString(KString const &val); + + unsigned char getByte(void) + { return m_vector.at(m_gpos++); } + + unsigned long getInt32(void); + + unsigned long long getInt64(void); + + std::string getString(void); + + private: + ByteVector m_vector; + size_t m_gpos; +}; + +//}}} //{{{ SFTPTransfer ------------------------------------------------------------- #if HAVE_LIBSSH2 --- /dev/null +++ b/kdumptool/testsftppacket.cc @@ -0,0 +1,189 @@ +/* + * (c) 2015, Petr Tesarik <ptesarik@suse.de>, SUSE LINUX Products GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ +#include <iostream> +#include <cstdlib> + +#include "global.h" +#include "stringutil.h" +#include "sshtransfer.h" +#include "debug.h" + +using std::cout; +using std::cerr; +using std::setw; +using std::endl; + +// ----------------------------------------------------------------------------- +static void +dumpvec(ByteVector const &bv) +{ + cout << std::hex << std::setfill('0'); + ByteVector::const_iterator it = bv.begin(); + if (it != bv.end()) { + cout << setw(2) << unsigned(*it); + ++it; + } + while (it != bv.end()) { + cout << ' ' << setw(2) << unsigned(*it); + ++it; + } + cout << endl; +} + +// ----------------------------------------------------------------------------- +static unsigned long long +parseval(const char *str, unsigned maxdigits) +{ + unsigned long long ret = 0; + unsigned i; + + for (i = 0; i < maxdigits; ++i) { + if (!str[i]) + break; + ret <<= 4; + ret |= Stringutil::hex2int(str[i]); + } + if (str[i]) + throw KError(KString("Number too big: '") + str + "'"); + + return ret; +} + +// ----------------------------------------------------------------------------- +static ByteVector +parsevec(const char *str) +{ + ByteVector ret; + + while(*str) { + unsigned char byte; + byte = Stringutil::hex2int(*str++); + if (*str) { + byte <<= 4; + byte |= Stringutil::hex2int(*str++); + } + ret.push_back(byte); + } + return ret; +} + +// ----------------------------------------------------------------------------- +static void +getbyte(SFTPPacket &pkt) +{ + cout << std::hex << std::setfill('0') << setw(2) + << unsigned(pkt.getByte()) << endl; +} + +// ----------------------------------------------------------------------------- +static void +getint32(SFTPPacket &pkt) +{ + cout << std::hex << std::setfill('0') << setw(8) + << pkt.getInt32() << endl; +} + +// ----------------------------------------------------------------------------- +static void +getint64(SFTPPacket &pkt) +{ + cout << std::hex << std::setfill('0') << setw(16) + << pkt.getInt64() << endl; +} + +// ----------------------------------------------------------------------------- +static void +getstring(SFTPPacket &pkt) +{ + cout << pkt.getString() << endl; +} + +// ----------------------------------------------------------------------------- +int main(int argc, char *argv[]) +{ + Debug::debug()->setStderrLevel(Debug::DL_TRACE); + + try { + SFTPPacket pkt; + + int i; + for (i = 1; i < argc; ++i) { + char *arg = argv[i]; + + switch (arg[0]) { + case 'd': + if (arg[1]) + pkt.setData(parsevec(arg + 1)); + else + dumpvec(pkt.data()); + break; + + case 'u': + dumpvec(pkt.update()); + break; + + case 'b': + if (arg[1]) + pkt.addByte(parseval(arg + 1, 2)); + else + getbyte(pkt); + break; + + case 'w': + if (arg[1]) + pkt.addInt32(parseval(arg + 1, 8)); + else + getint32(pkt); + break; + + case 'l': + if (arg[1]) + pkt.addInt64(parseval(arg + 1, 16)); + else + getint64(pkt); + break; + + case 's': + if (arg[1]) + pkt.addString(arg + 1); + else + getstring(pkt); + break; + + case 'v': + if (arg[1]) + pkt.addByteVector(parsevec(arg + 1)); + break; + + case '\0': + // Ignore empty arguments + break; + + default: + throw KError("Invalid format specifier"); + } + } + + } catch(const std::exception &ex) { + cerr << "Fatal exception: " << ex.what() << endl; + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -64,3 +64,7 @@ ADD_TEST(process ADD_TEST(urldecode ${CMAKE_CURRENT_SOURCE_DIR}/testurldecode.sh ${CMAKE_BINARY_DIR}/kdumptool/testurldecode) + +ADD_TEST(sftppacket + ${CMAKE_CURRENT_SOURCE_DIR}/testsftppacket.sh + ${CMAKE_BINARY_DIR}/kdumptool/testsftppacket) --- /dev/null +++ b/tests/testsftppacket.sh @@ -0,0 +1,181 @@ +#!/bin/bash +# +# (c) 2014, Petr Tesarik <ptesarik@suse.de>, SUSE LINUX Products GmbH +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. +# + +# Check that results match expectation +# {{{ +function check() +{ + local arg="$1" + local expect="$2" + local result="$3" + if [ "$result" != "$expect" ] ; then + echo "failed packet: $arg" + echo "Expected:" + echo "$expect" + echo "Result:" + echo "$result" + errornumber=$(( errornumber + 1 )) + fi +} +# }}} + +# Add random byte to ARG and EXPECT +# {{{ +function add_random_byte() +{ + local ch=$(( $RANDOM % 256 )) + local hex=$( printf "%02x" $ch ) + ARG="$ARG$hex" + EXPECT="$EXPECT $hex" +} +# }}} + +# +# Program {{{ +# + +TESTPACKET=$1 +HEXDUMP="od -Ax -tx1" + +if [ -z "$TESTPACKET" ] ; then + echo "Usage: $0 testsftppacket" + exit 1 +fi + +errornumber=0 + +# TEST #1: Empty packet + +ARG="d" +EXPECT="00 00 00 00" +RESULT=$( "$TESTPACKET" $ARG ) +check "$ARG" "$EXPECT" "$RESULT" + +# TEST #2: Updated empty packet + +ARG="u" +EXPECT="00 00 00 00" +RESULT=$( "$TESTPACKET" $ARG ) +check "$ARG" "$EXPECT" "$RESULT" + +# TEST #3: Any 8-bit value +ARG="" +EXPECT="00 00 01 00" +i=0 +while [ $i -le 255 ] +do + ARG="$ARG "$(printf "b%02x" $i) + EXPECT="$EXPECT "$(printf "%02x" $i) + i=$(( $i + 1 )) +done +RESULT=$( "$TESTPACKET" $ARG u ) +check "$ARG" "$EXPECT" "$RESULT" + +# TEST #4: 100 random 32-bit values +ARG="" +EXPECT="00 00 01 90" # 4*100 in hex +i=0 +while [ $i -lt 100 ] +do + ARG="$ARG w" + add_random_byte # bits 0-7 + add_random_byte # bits 8-15 + add_random_byte # bits 16-23 + add_random_byte # bits 24-31 + + i=$(( $i + 1 )) +done +RESULT=$( "$TESTPACKET" $ARG u ) +check "$ARG" "$EXPECT" "$RESULT" + +# TEST #5: 100 random 64-bit values +ARG="" +EXPECT="00 00 03 20" # 8*100 in hex +i=0 +while [ $i -lt 100 ] +do + ARG="$ARG l" + add_random_byte # bits 0-7 + add_random_byte # bits 8-15 + add_random_byte # bits 16-23 + add_random_byte # bits 24-31 + add_random_byte # bits 32-39 + add_random_byte # bits 40-47 + add_random_byte # bits 48-55 + add_random_byte # bits 56-63 + + i=$(( $i + 1 )) +done +RESULT=$( "$TESTPACKET" $ARG u ) +check "$ARG" "$EXPECT" "$RESULT" + +# TEST #6: String +ARG="sHello, world!" +EXPECT="00 00 00 11 00 00 00 0d 48 65 6c 6c 6f 2c 20 77 6f 72 6c 64 21" +RESULT=$( "$TESTPACKET" "$ARG" u ) +check "$ARG" "$EXPECT" "$RESULT" + +# TEST #7: Vector +ARG="v0123456789abcdef u" +EXPECT="00 00 00 08 01 23 45 67 89 ab cd ef" +RESULT=$( "$TESTPACKET" $ARG ) +check "$ARG" "$EXPECT" "$RESULT" + +# TEST #8: Get byte - note that packet length field is still zero! +ARG="v0123456789abcdef b b b b b b b b b b b b" +EXPECT=$(echo -e "00\n00\n00\n00\n01\n23\n45\n67\n89\nab\ncd\nef") +RESULT=$( "$TESTPACKET" $ARG ) +check "$ARG" "$EXPECT" "$RESULT" + +# TEST #9: Get 32-bit integers - note that packet length field is zero! +ARG="v0123456789abcdef w w w" +EXPECT=$(echo -e "00000000\n01234567\n89abcdef") +RESULT=$( "$TESTPACKET" $ARG ) +check "$ARG" "$EXPECT" "$RESULT" + +# TEST #10: Get 64-bit integer - note that packet length field is zero! +ARG="v0123456789abcdef w l" +EXPECT=$(echo -e "00000000\n0123456789abcdef") +RESULT=$( "$TESTPACKET" $ARG ) +check "$ARG" "$EXPECT" "$RESULT" + +# TEST #11: Get string value +ARG="sHello! w s" +EXPECT=$(echo -e "00000000\nHello!") +RESULT=$( "$TESTPACKET" $ARG ) +check "$ARG" "$EXPECT" "$RESULT" + +# TEST #12: Set data - note the bogus packet length +ARG="dbadf1e1d0123456789abcdef d" +EXPECT="ba df 1e 1d 01 23 45 67 89 ab cd ef" +RESULT=$( "$TESTPACKET" $ARG ) +check "$ARG" "$EXPECT" "$RESULT" + +# TEST #13: Set data - note the updated packet length +ARG="dbadf1e1d0123456789abcdef u" +EXPECT="00 00 00 08 01 23 45 67 89 ab cd ef" +RESULT=$( "$TESTPACKET" $ARG ) +check "$ARG" "$EXPECT" "$RESULT" + +exit $errornumber + +# }}} + +# vim: set sw=4 ts=4 fdm=marker et: :collapseFolds=1:
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor