diff options
| author | Ed Tanous <ed.tanous@intel.com> | 2017-03-21 13:15:58 -0700 |
|---|---|---|
| committer | Ed Tanous <ed.tanous@intel.com> | 2017-03-21 13:15:58 -0700 |
| commit | 1ccd57c4a6cd397794bb81bbb043a364d02aab4f (patch) | |
| tree | 8dd4969e2394037121d751dc92b01a1749943e72 /src | |
| parent | c4771fb4cecd77272a72f3265d19096c83e5e8e9 (diff) | |
| download | bmcweb-1ccd57c4a6cd397794bb81bbb043a364d02aab4f.tar.gz bmcweb-1ccd57c4a6cd397794bb81bbb043a364d02aab4f.zip | |
incremental
Diffstat (limited to 'src')
| -rw-r--r-- | src/base64_test.cpp | 11 | ||||
| -rw-r--r-- | src/getvideo_main.cpp | 67 | ||||
| -rw-r--r-- | src/token_authorization_middleware.cpp | 15 | ||||
| -rw-r--r-- | src/udpclient.cpp | 99 | ||||
| -rw-r--r-- | src/webserver_main.cpp | 179 |
5 files changed, 305 insertions, 66 deletions
diff --git a/src/base64_test.cpp b/src/base64_test.cpp index 2758dfa..e21655e 100644 --- a/src/base64_test.cpp +++ b/src/base64_test.cpp @@ -47,7 +47,7 @@ TEST(Base64, DecodeRFC4648) { } // Tests using pathalogical cases for all escapings -TEST(Base64, NaugtyStrings) { +TEST(Base64, NaugtyStringsEncodeDecode) { std::string base64_string; std::string decoded_string; for (auto& str : naughty_strings) { @@ -56,3 +56,12 @@ TEST(Base64, NaugtyStrings) { EXPECT_EQ(str, decoded_string); } } + +// Tests using pathalogical cases for all escapings +TEST(Base64, NaugtyStringsPathological) { + std::string base64_string; + std::string decoded_string; + for (auto& str : naughty_strings) { + base64::base64_decode(str, base64_string); + } +}
\ No newline at end of file diff --git a/src/getvideo_main.cpp b/src/getvideo_main.cpp new file mode 100644 index 0000000..f73ee30 --- /dev/null +++ b/src/getvideo_main.cpp @@ -0,0 +1,67 @@ +#include <video.h> +#include <fstream> +#include <iostream> +#include <iomanip> + +namespace AstVideo { +class VideoPuller { + public: + VideoPuller() {} + + void initialize() { + std::cout << "Opening /dev/video\n"; + file.open("/dev/video", std::ios::out | std::ios::in | std::ios::binary); + if (!file.is_open()) { + std::cout << "Failed to open /dev/video\n"; + } + IMAGE_INFO image_info{}; + + file.write(reinterpret_cast<char*>(&image_info), sizeof(image_info)); + + file.read(reinterpret_cast<char*>(&image_info), sizeof(image_info)); + + if (file){ + std::cout << "Read succeeded\n"; + } + + auto pt = reinterpret_cast<char*>(&image_info); + + for(int i=0; i<sizeof(image_info); i++){ + std::cout << std::hex << std::setfill('0') << std::setw(2) << int(*(pt + i)) << " "; + } + + std::cout << "\n"; + + std::cout << "typedef struct _video_features {\n"; + std::cout << "short jpg_fmt: " << image_info.parameter.features.jpg_fmt << "\n"; + std::cout << "short lumin_tbl;" << image_info.parameter.features.lumin_tbl << "\n"; + std::cout << "short chrom_tbl;" << image_info.parameter.features.chrom_tbl << "\n"; + std::cout << "short tolerance_noise;" << image_info.parameter.features.tolerance_noise << "\n"; + std::cout << "int w;" << image_info.parameter.features.w << "\n"; + std::cout << "int h;" << image_info.parameter.features.h << "\n"; + //std::cout << "unsigned char *buf;" << image_info.parameter.features.buf << "\n"; + std::cout << "} FEATURES_TAG;\n"; + + std::cout << "typedef struct _image_info {"; + std::cout << "short do_image_refresh;" << image_info.do_image_refresh << "\n"; + std::cout << "char qc_valid;" << image_info.qc_valid << "\n"; + std::cout << "unsigned int len;" << image_info.len << "\n"; + std::cout << "int crypttype;" << image_info.crypttype << "\n"; + std::cout << "char cryptkey[16];" << image_info.cryptkey << "\n"; + std::cout << "union {\n"; + std::cout << " FEATURES_TAG features;\n"; + std::cout << " AST_CURSOR_TAG cursor_info;\n"; + std::cout << "} parameter;\n"; + std::cout << "} IMAGE_INFO;\n"; + std::cout << std::endl; + } + std::fstream file; +}; +} + +int main() { + AstVideo::VideoPuller p; + p.initialize(); + + return 1; +}
\ No newline at end of file diff --git a/src/token_authorization_middleware.cpp b/src/token_authorization_middleware.cpp index 40ade75..30d12c5 100644 --- a/src/token_authorization_middleware.cpp +++ b/src/token_authorization_middleware.cpp @@ -1,9 +1,9 @@ +#include <random> #include <unordered_map> - #include <boost/algorithm/string/predicate.hpp> #include <token_authorization_middleware.hpp> - +#include <crow/logging.h> #include <base64.hpp> namespace crow { @@ -17,16 +17,19 @@ void TokenAuthorizationMiddleware::before_handle(crow::request& req, response& r res.code = 401; res.end(); }; + + LOG(DEBUG) << "Got route " << req.url; + if (req.url == "/" || boost::starts_with(req.url, "/static/")){ //TODO this is total hackery to allow the login page to work before the user // is authenticated. Also, it will be quite slow for all pages instead of // a one time hit for the whitelist entries. // Ideally, this should be done in the url router handler, with tagged routes // for the whitelist entries. + // Another option would be to whitelist a minimal return; } - if (req.url == "/login") { if (req.method != HTTPMethod::POST){ return_unauthorized(); @@ -39,8 +42,10 @@ void TokenAuthorizationMiddleware::before_handle(crow::request& req, response& r } auto username = login_credentials["username"].s(); auto password = login_credentials["password"].s(); - + + // TODO(ed) pull real passwords from PAM if (username == "dude" && password == "dude"){ + //TODO(ed) the RNG should be initialized at start, not every time we want a token std::random_device rand; random_bytes_engine rbe; std::string token('a', 20); @@ -49,7 +54,6 @@ void TokenAuthorizationMiddleware::before_handle(crow::request& req, response& r base64::base64_encode(token, encoded_token); ctx.auth_token = encoded_token; this->auth_token2 = encoded_token; - } else { return_unauthorized(); return; @@ -82,6 +86,7 @@ void TokenAuthorizationMiddleware::before_handle(crow::request& req, response& r return_unauthorized(); return; } + // else let the request continue unharmed } } diff --git a/src/udpclient.cpp b/src/udpclient.cpp new file mode 100644 index 0000000..5f04a9a --- /dev/null +++ b/src/udpclient.cpp @@ -0,0 +1,99 @@ +// +// client.cpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +#include <array> +#include <boost/array.hpp> +#include <boost/asio.hpp> +#include <iostream> + +using boost::asio::ip::udp; + +int main(int argc, char* argv[]) { + try { + boost::asio::io_service io_service; + + udp::resolver resolver(io_service); + udp::resolver::query query(udp::v4(), "10.243.48.31", "623"); + udp::endpoint receiver_endpoint = *resolver.resolve(query); + + udp::socket socket(io_service); + socket.open(udp::v4()); + + std::string username = "root"; + std::string password = "two"; + uint8_t privilege_level = 4; + uint8_t seq_number = 1; + uint8_t command = 0x38; // AUTH_CAP_CMD + // std::array<uint8_t> ChannelAuthCap{0x80 | (0x0f & channel), + // privilege_level&0x0f}; + + uint8_t srcaddr = 0x81; // 0xC8? + uint8_t dstaddr = 0x20; + + uint8_t net_function = 0x06; + uint8_t lun = 0; + + uint8_t netfn_lun = static_cast<uint8_t>((net_function << 2) + lun); + uint8_t channel_number = + 0x0E + 0x80; // E is defined in spec as this channel + // 0x80 is requesting IPMI 2.0 + uint8_t byte1 = static_cast<uint8_t>(channel_number | 0x80); + boost::array<uint8_t, 2> payload{byte1, privilege_level}; + + int payload_sum = 0; + for (auto element : payload) { + payload_sum += element; + } + + uint8_t chk1 = (1 + ((~(dstaddr + netfn_lun)) & 0xff)) & 0xff; + uint8_t chk2 = srcaddr + (seq_number << 2) + command + payload_sum; + chk2 = (1 + ((~chk2) & 0xff)) & 0xff; + + uint8_t ptype = 0; + uint8_t session_id = 0; + + uint8_t seq_number2 = 0; + uint8_t seq_number_lun = seq_number << 2 + lun; + + uint8_t seq2 = 0xff; //???? + uint8_t rmcp_class = 0x07; + + std::vector<uint8_t> send_buf = { + 0x06, 0x00, seq2, + rmcp_class, 0x06, ptype, + session_id, seq_number2, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x09, + 0x00, dstaddr, netfn_lun, + chk1, srcaddr, seq_number_lun, + command, channel_number, privilege_level, + chk2}; + + for (auto character : send_buf) { + std::cout << std::hex << static_cast<unsigned>(character) << " "; + } + std::cout << std::endl; + socket.send_to(boost::asio::buffer(send_buf), receiver_endpoint); + + boost::array<unsigned char, 32> recv_buf; + udp::endpoint sender_endpoint; + size_t len = + socket.receive_from(boost::asio::buffer(recv_buf), sender_endpoint); + + for (auto character : recv_buf) { + std::cout << std::hex << static_cast<unsigned>(character) << " "; + } + + std::cout << std::endl; + } catch (std::exception& e) { + std::cerr << e.what() << std::endl; + } + + return 0; +}
\ No newline at end of file diff --git a/src/webserver_main.cpp b/src/webserver_main.cpp index c5c3eed..c55bd4d 100644 --- a/src/webserver_main.cpp +++ b/src/webserver_main.cpp @@ -20,6 +20,8 @@ #include "crow/utility.h" #include "crow/websocket.h" +#include "app_type.hpp" + #include "color_cout_g3_sink.hpp" #include "token_authorization_middleware.hpp" #include "webassets.hpp" @@ -40,7 +42,11 @@ static const std::string rfb_3_3_version_string = "RFB 003.003\n"; static const std::string rfb_3_7_version_string = "RFB 003.007\n"; static const std::string rfb_3_8_version_string = "RFB 003.008\n"; -enum class RfbAuthScheme : uint8_t { connection_failed = 0, no_authentication = 1, vnc_authentication = 2 }; +enum class RfbAuthScheme : uint8_t { + connection_failed = 0, + no_authentication = 1, + vnc_authentication = 2 +}; struct pixel_format_struct { boost::endian::big_uint8_t bits_per_pixel; @@ -163,12 +169,14 @@ std::string serialize(const framebuffer_update_message& msg) { serialized[i++] = 0; // Type serialized[i++] = 0; // Pad byte boost::endian::big_uint16_t number_of_rectangles; - std::memcpy(&serialized[i], &number_of_rectangles, sizeof(number_of_rectangles)); + std::memcpy(&serialized[i], &number_of_rectangles, + sizeof(number_of_rectangles)); i += sizeof(number_of_rectangles); for (const auto& rect : msg.rectangles) { // copy the first part of the struct - size_t buffer_size = sizeof(framebuffer_rectangle) - sizeof(std::vector<uint8_t>); + size_t buffer_size = + sizeof(framebuffer_rectangle) - sizeof(std::vector<uint8_t>); std::memcpy(&serialized[i], &rect, buffer_size); i += buffer_size; @@ -179,7 +187,13 @@ std::string serialize(const framebuffer_update_message& msg) { return serialized; } -enum class VncState { UNSTARTED, AWAITING_CLIENT_VERSION, AWAITING_CLIENT_AUTH_METHOD, AWAITING_CLIENT_INIT_MESSAGE, MAIN_LOOP }; +enum class VncState { + UNSTARTED, + AWAITING_CLIENT_VERSION, + AWAITING_CLIENT_AUTH_METHOD, + AWAITING_CLIENT_INIT_MESSAGE, + MAIN_LOOP +}; class connection_metadata { public: @@ -190,15 +204,17 @@ class connection_metadata { int main(int argc, char** argv) { auto worker(g3::LogWorker::createLogWorker()); - - auto handle = worker->addDefaultLogger(argv[0], "/tmp/"); + std::string logger_name("bmcweb"); + std::string folder("/tmp/"); + auto handle = worker->addDefaultLogger(logger_name, folder); g3::initializeLogging(worker.get()); - auto sink_handle = worker->addSink(std::make_unique<crow::ColorCoutSink>(), &crow::ColorCoutSink::ReceiveLogMessage); + auto sink_handle = worker->addSink(std::make_unique<crow::ColorCoutSink>(), + &crow::ColorCoutSink::ReceiveLogMessage); std::string ssl_pem_file("server.pem"); ensuressl::ensure_openssl_key_present_and_valid(ssl_pem_file); - crow::App<crow::TokenAuthorizationMiddleware> app; + BmcAppType app; crow::webassets::request_routes(app); crow::logger::setLogLevel(crow::LogLevel::INFO); @@ -213,7 +229,8 @@ int main(int argc, char** argv) { CROW_ROUTE(app, "/login") .methods("POST"_method)([&](const crow::request& req) { - auto auth_token = app.get_context<crow::TokenAuthorizationMiddleware>(req).auth_token; + auto auth_token = + app.get_context<crow::TokenAuthorizationMiddleware>(req).auth_token; crow::json::wvalue x; x["token"] = auth_token; @@ -262,21 +279,29 @@ int main(int argc, char** argv) { meta.vnc_state = VncState::AWAITING_CLIENT_VERSION; conn.send_binary(rfb_3_8_version_string); }) - .onclose([&](crow::websocket::connection& conn, const std::string& reason) { - - }) - .onmessage([&](crow::websocket::connection& conn, const std::string& data, bool is_binary) { + .onclose( + [&](crow::websocket::connection& conn, const std::string& reason) { + meta.vnc_state = VncState::UNSTARTED; + }) + .onmessage([&](crow::websocket::connection& conn, const std::string& data, + bool is_binary) { switch (meta.vnc_state) { case VncState::AWAITING_CLIENT_VERSION: { - std::cout << "Client sent: " << data; - if (data == rfb_3_8_version_string || data == rfb_3_7_version_string) { - std::string auth_types{1, (uint8_t)RfbAuthScheme::no_authentication}; + LOG(DEBUG) << "Client sent: " << data; + if (data == rfb_3_8_version_string || + data == rfb_3_7_version_string) { + std::string auth_types{1, + (uint8_t)RfbAuthScheme::no_authentication}; conn.send_binary(auth_types); meta.vnc_state = VncState::AWAITING_CLIENT_AUTH_METHOD; } else if (data == rfb_3_3_version_string) { - // TODO(ed) + // TODO(ed) Support older protocols + meta.vnc_state = VncState::UNSTARTED; + conn.close(); } else { - // TODO(ed) + // TODO(ed) Support older protocols + meta.vnc_state = VncState::UNSTARTED; + conn.close(); } } break; case VncState::AWAITING_CLIENT_AUTH_METHOD: { @@ -305,10 +330,12 @@ int main(int argc, char** argv) { server_init_msg.pixel_format.green_shift = 8; server_init_msg.pixel_format.blue_shift = 0; server_init_msg.name_length = 0; - std::cout << "size: " << sizeof(server_init_msg); - // TODO(ed) this is ugly. Crow should really have a span type interface + LOG(DEBUG) << "size: " << sizeof(server_init_msg); + // TODO(ed) this is ugly. Crow should really have a span type + // interface // to avoid the copy, but alas, today it does not. - std::string s(reinterpret_cast<char*>(&server_init_msg), sizeof(server_init_msg)); + std::string s(reinterpret_cast<char*>(&server_init_msg), + sizeof(server_init_msg)); LOG(DEBUG) << "s.size() " << s.size(); conn.send_binary(s); meta.vnc_state = VncState::MAIN_LOOP; @@ -316,7 +343,7 @@ int main(int argc, char** argv) { case VncState::MAIN_LOOP: { if (data.size() >= sizeof(client_to_server_message_type)) { auto type = static_cast<client_to_server_message_type>(data[0]); - std::cout << "Got type " << (uint32_t)type << "\n"; + LOG(DEBUG) << "Got type " << (uint32_t)type << "\n"; switch (type) { case client_to_server_message_type::set_pixel_format: { } break; @@ -325,21 +352,29 @@ int main(int argc, char** argv) { } break; case client_to_server_message_type::set_encodings: { } break; - case client_to_server_message_type::framebuffer_update_request: { - // Make sure the buffer is long enough to handle what we're about to do - if (data.size() >= sizeof(frame_buffer_update_request_message) + sizeof(client_to_server_message_type)) { - auto msg = reinterpret_cast<const frame_buffer_update_request_message*>(data.data() + sizeof(client_to_server_message_type)); - - std::cout << "framebuffer_update_request_message\n"; - std::cout << " incremental=" << msg->incremental << "\n"; - std::cout << " x=" << msg->x_position; - std::cout << " y=" << msg->y_position << "\n"; - std::cout << " width=" << msg->width; - std::cout << " height=" << msg->height << "\n"; + case client_to_server_message_type:: + framebuffer_update_request: { + // Make sure the buffer is long enough to handle what we're + // about to do + if (data.size() >= + sizeof(frame_buffer_update_request_message) + + sizeof(client_to_server_message_type)) { + auto msg = reinterpret_cast< + const frame_buffer_update_request_message*>( + data.data() + sizeof(client_to_server_message_type)); + + LOG(DEBUG) << "framebuffer_update_request_message\n"; + LOG(DEBUG) << " incremental=" << msg->incremental + << "\n"; + LOG(DEBUG) << " x=" << msg->x_position; + LOG(DEBUG) << " y=" << msg->y_position << "\n"; + LOG(DEBUG) << " width=" << msg->width; + LOG(DEBUG) << " height=" << msg->height << "\n"; framebuffer_update_message buffer_update_message; - // If the viewer is requesting a full update, force write of all + // If the viewer is requesting a full update, force write of + // all // pixels framebuffer_rectangle this_rect; @@ -347,20 +382,29 @@ int main(int argc, char** argv) { this_rect.y = msg->y_position; this_rect.width = msg->width; this_rect.height = msg->height; - this_rect.encoding = static_cast<uint8_t>(encoding_type::raw); - - this_rect.data.reserve(this_rect.width * this_rect.height * 4); - - for (unsigned int x_index = 0; x_index < this_rect.width; x_index++) { - for (unsigned int y_index = 0; y_index < this_rect.height; y_index++) { - this_rect.data.push_back(static_cast<uint8_t>(0)); // Blue - this_rect.data.push_back(static_cast<uint8_t>(0)); // Green - this_rect.data.push_back(static_cast<uint8_t>(x_index * 0xFF / msg->width)); // RED - this_rect.data.push_back(static_cast<uint8_t>(0)); // UNUSED + this_rect.encoding = + static_cast<uint8_t>(encoding_type::raw); + + this_rect.data.reserve(this_rect.width * this_rect.height * + 4); + + for (unsigned int x_index = 0; x_index < this_rect.width; + x_index++) { + for (unsigned int y_index = 0; y_index < this_rect.height; + y_index++) { + this_rect.data.push_back( + static_cast<uint8_t>(0)); // Blue + this_rect.data.push_back( + static_cast<uint8_t>(0)); // Green + this_rect.data.push_back(static_cast<uint8_t>( + x_index * 0xFF / msg->width)); // RED + this_rect.data.push_back( + static_cast<uint8_t>(0)); // UNUSED } } - buffer_update_message.rectangles.push_back(std::move(this_rect)); + buffer_update_message.rectangles.push_back( + std::move(this_rect)); auto serialized = serialize(buffer_update_message); conn.send_binary(serialized); @@ -397,23 +441,38 @@ int main(int argc, char** argv) { .onopen([&](crow::websocket::connection& conn) { }) - .onclose([&](crow::websocket::connection& conn, const std::string& reason) { + .onclose( + [&](crow::websocket::connection& conn, const std::string& reason) { - }) - .onmessage([&](crow::websocket::connection& conn, const std::string& data, bool is_binary) { + }) + .onmessage([&](crow::websocket::connection& conn, const std::string& data, + bool is_binary) { boost::asio::io_service io_service; - boost::asio::ip::udp::udp::socket socket(io_service, boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), 0)); - boost::asio::ip::udp::resolver resolver(io_service); - boost::asio::ip::udp::resolver::query query(boost::asio::ip::udp::v4(), "10.243.48.31", "623"); - boost::asio::ip::udp::resolver::iterator iter = resolver.resolve(query); - socket.send_to(boost::asio::buffer(data), *iter); - }); + using boost::asio::ip::udp; + udp::resolver resolver(io_service); + udp::resolver::query query(udp::v4(), "10.243.48.31", "623"); + udp::endpoint receiver_endpoint = *resolver.resolve(query); - auto rules = app.get_rules(); - for (auto& rule : rules) { - LOG(DEBUG) << "Static route: " << rule; - } + udp::socket socket(io_service); + socket.open(udp::v4()); + + socket.send_to(boost::asio::buffer(data), receiver_endpoint); + + std::array<char, 255> recv_buf; + + udp::endpoint sender_endpoint; + size_t len = + socket.receive_from(boost::asio::buffer(recv_buf), sender_endpoint); + // TODO(ed) THis is ugly. Find a way to not make a copy (ie, use + // std::string::data()) + std::string str(std::begin(recv_buf), std::end(recv_buf)); + LOG(DEBUG) << "Got " << str << "back \n"; + conn.send_binary(str); + + }); - // app.port(18080).ssl(std::move(get_ssl_context(ssl_pem_file))).concurrency(4).run(); - app.port(18080).concurrency(4).run(); + app.port(18080) + //.ssl(std::move(ensuressl::get_ssl_context(ssl_pem_file))) + .run(); + // app.port(18080).run(); } |

