diff options
| author | Ed Tanous <ed.tanous@intel.com> | 2017-08-15 09:37:42 -0700 |
|---|---|---|
| committer | Ed Tanous <ed.tanous@intel.com> | 2017-10-11 13:34:56 -0700 |
| commit | 911ac31759cb7b77a856af8806b4e064d50d7422 (patch) | |
| tree | c4b714fabb2b956936ab6dffc18d9ff418756cf4 /include | |
| parent | 8f0c0481d2280919b38a31656ba21a4347d12620 (diff) | |
| download | bmcweb-911ac31759cb7b77a856af8806b4e064d50d7422.tar.gz bmcweb-911ac31759cb7b77a856af8806b4e064d50d7422.zip | |
Large updates to webserver
Do not merge yet
Change-Id: I38c56844c1b0e3e8e5493c2705e62e6db7ee2102
Diffstat (limited to 'include')
| -rw-r--r-- | include/aspeed/JTABLES.H | 12 | ||||
| -rw-r--r-- | include/ast_jpeg_decoder.hpp | 342 | ||||
| -rw-r--r-- | include/ast_video_puller.hpp | 30 | ||||
| -rw-r--r-- | include/ast_video_types.hpp | 11 | ||||
| -rw-r--r-- | include/base64.hpp | 2 | ||||
| -rw-r--r-- | include/dbus_monitor.hpp | 82 | ||||
| -rw-r--r-- | include/dbus_singleton.hpp | 10 | ||||
| -rw-r--r-- | include/gzip_helper.hpp | 56 | ||||
| -rw-r--r-- | include/intel_oem.hpp | 33 | ||||
| -rw-r--r-- | include/openbmc_dbus_rest.hpp | 320 | ||||
| -rw-r--r-- | include/pam_authenticate.hpp | 86 | ||||
| -rw-r--r-- | include/redfish_v1.hpp | 93 | ||||
| -rw-r--r-- | include/security_headers_middleware.hpp | 34 | ||||
| -rw-r--r-- | include/ssl_key_handler.hpp | 86 | ||||
| -rw-r--r-- | include/test_utils.hpp | 6 | ||||
| -rw-r--r-- | include/token_authorization_middleware.hpp | 265 | ||||
| -rw-r--r-- | include/web_kvm.hpp | 41 | ||||
| -rw-r--r-- | include/webassets.hpp | 118 |
18 files changed, 1206 insertions, 421 deletions
diff --git a/include/aspeed/JTABLES.H b/include/aspeed/JTABLES.H index bff39e3..8f2d9f3 100644 --- a/include/aspeed/JTABLES.H +++ b/include/aspeed/JTABLES.H @@ -18,15 +18,15 @@ static const unsigned char *std_chrominance_qt; // Standard Huffman tables (cf. JPEG standard section K.3) */
-static const unsigned char std_dc_luminance_nrcodes[17] = {0, 0, 1, 5, 1, 1, 1, 1, 1,
- 1, 0, 0, 0, 0, 0, 0, 0};
+static const unsigned char std_dc_luminance_nrcodes[17] = {
+ 0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0};
static const unsigned char std_dc_luminance_values[12] = {0, 1, 2, 3, 4, 5,
- 6, 7, 8, 9, 10, 11};
+ 6, 7, 8, 9, 10, 11};
static const unsigned char std_dc_chrominance_nrcodes[17] = {
0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0};
static const unsigned char std_dc_chrominance_values[12] = {0, 1, 2, 3, 4, 5,
- 6, 7, 8, 9, 10, 11};
+ 6, 7, 8, 9, 10, 11};
static const unsigned char std_ac_luminance_nrcodes[17] = {
0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d};
@@ -284,7 +284,7 @@ static const unsigned char Tbl_000UV[64] = { 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185,
185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185};
-typedef struct {
+struct Huffman_table {
unsigned char Length[17]; // k =1-16 ; L[k] indicates the number of Huffman
// codes of length k
unsigned short int minor_code[17]; // indicates the value of the smallest
@@ -296,4 +296,4 @@ typedef struct { // Low nibble = size (in bits) of the coefficient which will be taken from the
// data stream
unsigned char Len[65536];
-} Huffman_table;
+};
diff --git a/include/ast_jpeg_decoder.hpp b/include/ast_jpeg_decoder.hpp index b5144ab..d2a482a 100644 --- a/include/ast_jpeg_decoder.hpp +++ b/include/ast_jpeg_decoder.hpp @@ -1,41 +1,23 @@ #pragma once -#include <string.h> +#include <ast_video_types.hpp> #include <array> #include <aspeed/JTABLES.H> -#include <ast_video_types.hpp> #include <cassert> #include <cstdint> +#include <cstring> #include <iostream> #include <vector> -/* -template <class T, class Compare> -constexpr const T &clamp(const T &v, const T &lo, const T &hi, Compare comp) { - return assert(!comp(hi, lo)), comp(v, lo) ? lo : comp(hi, v) ? hi : v; -} - -template <class T> -constexpr const T &clamp(const T &v, const T &lo, const T &hi) { - return clamp(v, lo, hi, std::less<>()); -} -*/ namespace AstVideo { struct COLOR_CACHE { - COLOR_CACHE() { - for (int i = 0; i < 4; i++) { - Index[i] = i; - } - Color[0] = 0x008080; - Color[1] = 0xFF8080; - Color[2] = 0x808080; - Color[3] = 0xC08080; - } + COLOR_CACHE() + : Color{0x008080, 0xFF8080, 0x808080, 0xC08080}, Index{0, 1, 2, 3} {} unsigned long Color[4]; unsigned char Index[4]; - unsigned char BitMapBits; + unsigned char BitMapBits{}; }; struct RGB { @@ -94,7 +76,7 @@ class AstJpegDecoder { float scalefactor[8] = {1.0f, 1.387039845f, 1.306562965f, 1.175875602f, 1.0f, 0.785694958f, 0.541196100f, 0.275899379f}; uint8_t j, row, col; - uint8_t tempQT[64]; + std::array<uint8_t, 64> tempQT{}; // Load quantization coefficients from JPG file, scale them for DCT and // reorder @@ -125,17 +107,20 @@ class AstJpegDecoder { std_luminance_qt = Tbl_100Y; break; } - set_quant_table(std_luminance_qt, (uint8_t)SCALEFACTOR, tempQT); + set_quant_table(std_luminance_qt, static_cast<uint8_t>(SCALEFACTOR), + tempQT); - for (j = 0; j <= 63; j++) quant_table[j] = tempQT[zigzag[j]]; + for (j = 0; j <= 63; j++) { + quant_table[j] = tempQT[zigzag[j]]; + } j = 0; - for (row = 0; row <= 7; row++) + for (row = 0; row <= 7; row++) { for (col = 0; col <= 7; col++) { - quant_table[j] = - (long)((quant_table[j] * scalefactor[row] * scalefactor[col]) * - 65536); + quant_table[j] = static_cast<long>( + (quant_table[j] * scalefactor[row] * scalefactor[col]) * 65536); j++; } + } byte_pos += 64; } @@ -143,7 +128,7 @@ class AstJpegDecoder { float scalefactor[8] = {1.0f, 1.387039845f, 1.306562965f, 1.175875602f, 1.0f, 0.785694958f, 0.541196100f, 0.275899379f}; uint8_t j, row, col; - uint8_t tempQT[64]; + std::array<uint8_t, 64> tempQT{}; // Load quantization coefficients from JPG file, scale them for DCT and // reorder from zig-zag order @@ -202,7 +187,8 @@ class AstJpegDecoder { break; } } - set_quant_table(std_chrominance_qt, (uint8_t)SCALEFACTORUV, tempQT); + set_quant_table(std_chrominance_qt, static_cast<uint8_t>(SCALEFACTORUV), + tempQT); for (j = 0; j <= 63; j++) { quant_table[j] = tempQT[zigzag[j]]; @@ -210,9 +196,8 @@ class AstJpegDecoder { j = 0; for (row = 0; row <= 7; row++) { for (col = 0; col <= 7; col++) { - quant_table[j] = - (long)((quant_table[j] * scalefactor[row] * scalefactor[col]) * - 65536); + quant_table[j] = static_cast<long>( + (quant_table[j] * scalefactor[row] * scalefactor[col]) * 65536); j++; } } @@ -223,7 +208,7 @@ class AstJpegDecoder { float scalefactor[8] = {1.0f, 1.387039845f, 1.306562965f, 1.175875602f, 1.0f, 0.785694958f, 0.541196100f, 0.275899379f}; uint8_t j, row, col; - uint8_t tempQT[64]; + std::array<uint8_t, 64> tempQT{}; // Load quantization coefficients from JPG file, scale them for DCT and // reorder @@ -255,17 +240,20 @@ class AstJpegDecoder { break; } // Note: pass ADVANCE SCALE FACTOR to sub-function in Dual-JPEG - set_quant_table(std_luminance_qt, (uint8_t)ADVANCESCALEFACTOR, tempQT); + set_quant_table(std_luminance_qt, static_cast<uint8_t>(ADVANCESCALEFACTOR), + tempQT); - for (j = 0; j <= 63; j++) quant_table[j] = tempQT[zigzag[j]]; + for (j = 0; j <= 63; j++) { + quant_table[j] = tempQT[zigzag[j]]; + } j = 0; - for (row = 0; row <= 7; row++) + for (row = 0; row <= 7; row++) { for (col = 0; col <= 7; col++) { - quant_table[j] = - (long)((quant_table[j] * scalefactor[row] * scalefactor[col]) * - 65536); + quant_table[j] = static_cast<long>( + (quant_table[j] * scalefactor[row] * scalefactor[col]) * 65536); j++; } + } byte_pos += 64; } @@ -274,7 +262,7 @@ class AstJpegDecoder { float scalefactor[8] = {1.0f, 1.387039845f, 1.306562965f, 1.175875602f, 1.0f, 0.785694958f, 0.541196100f, 0.275899379f}; uint8_t j, row, col; - uint8_t tempQT[64]; + std::array<uint8_t, 64> tempQT{}; // Load quantization coefficients from JPG file, scale them for DCT and // reorder @@ -335,17 +323,20 @@ class AstJpegDecoder { } } // Note: pass ADVANCE SCALE FACTOR to sub-function in Dual-JPEG - set_quant_table(std_chrominance_qt, (uint8_t)ADVANCESCALEFACTORUV, tempQT); + set_quant_table(std_chrominance_qt, + static_cast<uint8_t>(ADVANCESCALEFACTORUV), tempQT); - for (j = 0; j <= 63; j++) quant_table[j] = tempQT[zigzag[j]]; + for (j = 0; j <= 63; j++) { + quant_table[j] = tempQT[zigzag[j]]; + } j = 0; - for (row = 0; row <= 7; row++) + for (row = 0; row <= 7; row++) { for (col = 0; col <= 7; col++) { - quant_table[j] = - (long)((quant_table[j] * scalefactor[row] * scalefactor[col]) * - 65536); + quant_table[j] = static_cast<long>( + (quant_table[j] * scalefactor[row] * scalefactor[col]) * 65536); j++; } + } byte_pos += 64; } @@ -387,7 +378,8 @@ class AstJpegDecoder { inptr[DCTSIZE * 4] | inptr[DCTSIZE * 5] | inptr[DCTSIZE * 6] | inptr[DCTSIZE * 7]) == 0) { /* AC terms all zero */ - dcval = (int)((inptr[DCTSIZE * 0] * quantptr[DCTSIZE * 0]) >> 16); + dcval = static_cast<int>((inptr[DCTSIZE * 0] * quantptr[DCTSIZE * 0]) >> + 16); wsptr[DCTSIZE * 0] = dcval; wsptr[DCTSIZE * 1] = dcval; @@ -445,14 +437,14 @@ class AstJpegDecoder { tmp5 = tmp11 - tmp6; tmp4 = tmp10 + tmp5; - wsptr[DCTSIZE * 0] = (int)(tmp0 + tmp7); - wsptr[DCTSIZE * 7] = (int)(tmp0 - tmp7); - wsptr[DCTSIZE * 1] = (int)(tmp1 + tmp6); - wsptr[DCTSIZE * 6] = (int)(tmp1 - tmp6); - wsptr[DCTSIZE * 2] = (int)(tmp2 + tmp5); - wsptr[DCTSIZE * 5] = (int)(tmp2 - tmp5); - wsptr[DCTSIZE * 4] = (int)(tmp3 + tmp4); - wsptr[DCTSIZE * 3] = (int)(tmp3 - tmp4); + wsptr[DCTSIZE * 0] = (tmp0 + tmp7); + wsptr[DCTSIZE * 7] = (tmp0 - tmp7); + wsptr[DCTSIZE * 1] = (tmp1 + tmp6); + wsptr[DCTSIZE * 6] = (tmp1 - tmp6); + wsptr[DCTSIZE * 2] = (tmp2 + tmp5); + wsptr[DCTSIZE * 5] = (tmp2 - tmp5); + wsptr[DCTSIZE * 4] = (tmp3 + tmp4); + wsptr[DCTSIZE * 3] = (tmp3 - tmp4); inptr++; /* advance pointers to next column */ quantptr++; @@ -465,7 +457,7 @@ class AstJpegDecoder { //#define RANGE_MASK 1023; //2 bits wider than legal samples #define PASS1_BITS 0 -#define IDESCALE(x, n) ((int)((x) >> n)) +#define IDESCALE(x, n) ((int)((x) >> (n))) wsptr = workspace; for (ctr = 0; ctr < DCTSIZE; ctr++) { @@ -480,10 +472,10 @@ class AstJpegDecoder { */ /* Even part */ - tmp10 = ((int)wsptr[0] + (int)wsptr[4]); - tmp11 = ((int)wsptr[0] - (int)wsptr[4]); + tmp10 = (wsptr[0] + wsptr[4]); + tmp11 = (wsptr[0] - wsptr[4]); - tmp13 = ((int)wsptr[2] + (int)wsptr[6]); + tmp13 = (wsptr[2] + wsptr[6]); tmp12 = MULTIPLY((int)wsptr[2] - (int)wsptr[6], FIX_1_414213562) - tmp13; tmp0 = tmp10 + tmp13; @@ -493,10 +485,10 @@ class AstJpegDecoder { /* Odd part */ - z13 = (int)wsptr[5] + (int)wsptr[3]; - z10 = (int)wsptr[5] - (int)wsptr[3]; - z11 = (int)wsptr[1] + (int)wsptr[7]; - z12 = (int)wsptr[1] - (int)wsptr[7]; + z13 = wsptr[5] + wsptr[3]; + z10 = wsptr[5] - wsptr[3]; + z11 = wsptr[1] + wsptr[7]; + z12 = wsptr[1] - wsptr[7]; tmp7 = z11 + z13; /* phase 5 */ tmp11 = MULTIPLY(z11 - z13, FIX_1_414213562); /* 2*c4 */ @@ -538,7 +530,7 @@ class AstJpegDecoder { int nBlocksInMcu = 6; unsigned int pixel_x, pixel_y; - pByte = (struct RGB *)pBgr; + pByte = reinterpret_cast<struct RGB *>(pBgr); if (yuvmode == YuvMode::YUV444) { py = pYCbCr; pcb = pYCbCr + 64; @@ -566,7 +558,9 @@ class AstJpegDecoder { pos += WIDTH; } } else { - for (i = 0; i < nBlocksInMcu - 2; i++) py420[i] = pYCbCr + i * 64; + for (i = 0; i < nBlocksInMcu - 2; i++) { + py420[i] = pYCbCr + i * 64; + } pcb = pYCbCr + (nBlocksInMcu - 2) * 64; pcr = pcb + 64; @@ -606,7 +600,7 @@ class AstJpegDecoder { int nBlocksInMcu = 6; unsigned int pixel_x, pixel_y; - pByte = (struct RGB *)pBgr; + pByte = reinterpret_cast<struct RGB *>(pBgr); if (yuvmode == YuvMode::YUV444) { py = pYCbCr; pcb = pYCbCr + 64; @@ -633,7 +627,9 @@ class AstJpegDecoder { pos += WIDTH; } } else { - for (i = 0; i < nBlocksInMcu - 2; i++) py420[i] = pYCbCr + i * 64; + for (i = 0; i < nBlocksInMcu - 2; i++) { + py420[i] = pYCbCr + i * 64; + } pcb = pYCbCr + (nBlocksInMcu - 2) * 64; pcr = pcb + 64; @@ -697,7 +693,8 @@ class AstJpegDecoder { // YUVToRGB (txb, tyb, byTileYuv, (unsigned char *)outBuf); // YUVBuffer for YUV record - YUVToRGB(txb, tyb, byTileYuv, YUVBuffer.data(), (unsigned char *)outBuf); + YUVToRGB(txb, tyb, byTileYuv, YUVBuffer.data(), + reinterpret_cast<unsigned char *>(outBuf)); } void Decompress_2PASS(int txb, int tyb, char *outBuf, @@ -718,7 +715,8 @@ class AstJpegDecoder { process_Huffman_data_unit(CrDC_nr, CrAC_nr, &DCCr, 128); IDCT_transform(DCT_coeff + 128, ptr, QT_TableSelection + 1); - YUVToBuffer(txb, tyb, byTileYuv, YUVBuffer.data(), (unsigned char *)outBuf); + YUVToBuffer(txb, tyb, byTileYuv, YUVBuffer.data(), + reinterpret_cast<unsigned char *>(outBuf)); // YUVToRGB (txb, tyb, byTileYuv, (unsigned char *)outBuf); } @@ -738,7 +736,7 @@ class AstJpegDecoder { } } else { for (i = 0; i < 64; i++) { - Data = (int)lookKbits(VQ->BitMapBits); + Data = static_cast<int>(lookKbits(VQ->BitMapBits)); ptr[0] = (VQ->Color[VQ->Index[Data]] & 0xFF0000) >> 16; ptr[64] = (VQ->Color[VQ->Index[Data]] & 0x00FF00) >> 8; ptr[128] = VQ->Color[VQ->Index[Data]] & 0x0000FF; @@ -747,22 +745,27 @@ class AstJpegDecoder { } } // YUVToRGB (txb, tyb, byTileYuv, (unsigned char *)outBuf); - YUVToRGB(txb, tyb, byTileYuv, YUVBuffer.data(), (unsigned char *)outBuf); + YUVToRGB(txb, tyb, byTileYuv, YUVBuffer.data(), + reinterpret_cast<unsigned char *>(outBuf)); } - void MoveBlockIndex(void) { + void MoveBlockIndex() { if (yuvmode == YuvMode::YUV444) { txb++; - if (txb >= (int)(WIDTH / 8)) { + if (txb >= static_cast<int>(WIDTH / 8)) { tyb++; - if (tyb >= (int)(HEIGHT / 8)) tyb = 0; + if (tyb >= static_cast<int>(HEIGHT / 8)) { + tyb = 0; + } txb = 0; } } else { txb++; - if (txb >= (int)(WIDTH / 16)) { + if (txb >= static_cast<int>(WIDTH / 16)) { tyb++; - if (tyb >= (int)(HEIGHT / 16)) tyb = 0; + if (tyb >= static_cast<int>(HEIGHT / 16)) { + tyb = 0; + } txb = 0; } } @@ -782,13 +785,13 @@ class AstJpegDecoder { /* Cr=>G value is scaled-up -0.8125 * x */ /* Cb=>G value is scaled-up -0.390625 * x */ for (i = 0, x = -128; i < 256; i++, x++) { - m_CrToR[i] = (int)(FIX(1.597656) * x + nHalf) >> 16; - m_CbToB[i] = (int)(FIX(2.015625) * x + nHalf) >> 16; - m_CrToG[i] = (int)(-FIX(0.8125) * x + nHalf) >> 16; - m_CbToG[i] = (int)(-FIX(0.390625) * x + nHalf) >> 16; + m_CrToR[i] = (FIX(1.597656) * x + nHalf) >> 16; + m_CbToB[i] = (FIX(2.015625) * x + nHalf) >> 16; + m_CrToG[i] = (-FIX(0.8125) * x + nHalf) >> 16; + m_CbToG[i] = (-FIX(0.390625) * x + nHalf) >> 16; } for (i = 0, x = -16; i < 256; i++, x++) { - m_Y[i] = (int)(FIX(1.164) * x + nHalf) >> 16; + m_Y[i] = (FIX(1.164) * x + nHalf) >> 16; } // For Color Text Enchance Y Re-map. Recommend to disable in default /* @@ -823,17 +826,20 @@ class AstJpegDecoder { for (j = 1; j <= 16; j++) { HT->Length[j] = nrcode[j]; } - for (i = 0, k = 1; k <= 16; k++) + for (i = 0, k = 1; k <= 16; k++) { for (j = 0; j < HT->Length[k]; j++) { HT->V[WORD_hi_lo(k, j)] = value[i]; i++; } + } code = 0; for (k = 1; k <= 16; k++) { - HT->minor_code[k] = (unsigned short int)code; - for (j = 1; j <= HT->Length[k]; j++) code++; - HT->major_code[k] = (unsigned short int)(code - 1); + HT->minor_code[k] = static_cast<unsigned short int>(code); + for (j = 1; j <= HT->Length[k]; j++) { + code++; + } + HT->major_code[k] = static_cast<unsigned short int>(code - 1); code *= 2; if (HT->Length[k] == 0) { HT->minor_code[k] = 0xFFFF; @@ -846,10 +852,10 @@ class AstJpegDecoder { for (code_index = 1; code_index < 65535; code_index++) { if (code_index < Huff_code[i]) { - HT->Len[code_index] = (unsigned char)Huff_code[i + 1]; + HT->Len[code_index] = static_cast<unsigned char>(Huff_code[i + 1]); } else { i = i + 2; - HT->Len[code_index] = (unsigned char)Huff_code[i + 1]; + HT->Len[code_index] = static_cast<unsigned char>(Huff_code[i + 1]); } } } @@ -870,18 +876,24 @@ class AstJpegDecoder { /* Allocate and fill in the sample_range_limit table */ { int j; - rlimit_table = (unsigned char *)malloc(5 * 256L + 128); + rlimit_table = reinterpret_cast<unsigned char *>(malloc(5 * 256L + 128)); /* First segment of "simple" table: limit[x] = 0 for x < 0 */ memset((void *)rlimit_table, 0, 256); rlimit_table += 256; /* allow negative subscripts of simple table */ /* Main part of "simple" table: limit[x] = x */ - for (j = 0; j < 256; j++) rlimit_table[j] = j; + for (j = 0; j < 256; j++) { + rlimit_table[j] = j; + } /* End of simple table, rest of first half of post-IDCT table */ - for (j = 256; j < 640; j++) rlimit_table[j] = 255; + for (j = 256; j < 640; j++) { + rlimit_table[j] = 255; + } /* Second half of post-IDCT table */ memset((void *)(rlimit_table + 640), 0, 384); - for (j = 0; j < 128; j++) rlimit_table[j + 1024] = j; + for (j = 0; j < 128; j++) { + rlimit_table[j + 1024] = j; + } } inline unsigned short int WORD_hi_lo(uint8_t byte_high, uint8_t byte_low) { @@ -905,15 +917,16 @@ class AstJpegDecoder { huff_values = HTDC[DC_nr].V; // DC - k = HTDC[DC_nr].Len[(unsigned short int)(codebuf >> 16)]; + k = HTDC[DC_nr].Len[static_cast<unsigned short int>(codebuf >> 16)]; // river // tmp_Hcode=lookKbits(k); - tmp_Hcode = (unsigned short int)(codebuf >> (32 - k)); + tmp_Hcode = static_cast<unsigned short int>(codebuf >> (32 - k)); skipKbits(k); - size_val = huff_values[WORD_hi_lo(k, (uint8_t)(tmp_Hcode - min_code[k]))]; - if (size_val == 0) + size_val = huff_values[WORD_hi_lo( + k, static_cast<uint8_t>(tmp_Hcode - min_code[k]))]; + if (size_val == 0) { DCT_coeff[position + 0] = *previous_DC; - else { + } else { DCT_coeff[position + 0] = *previous_DC + getKbits(size_val); *previous_DC = DCT_coeff[position + 0]; } @@ -925,12 +938,12 @@ class AstJpegDecoder { nr = 1; // AC coefficient do { - k = HTAC[AC_nr].Len[(unsigned short int)(codebuf >> 16)]; - tmp_Hcode = (unsigned short int)(codebuf >> (32 - k)); + k = HTAC[AC_nr].Len[static_cast<unsigned short int>(codebuf >> 16)]; + tmp_Hcode = static_cast<unsigned short int>(codebuf >> (32 - k)); skipKbits(k); - byte_temp = - huff_values[WORD_hi_lo(k, (uint8_t)(tmp_Hcode - min_code[k]))]; + byte_temp = huff_values[WORD_hi_lo( + k, static_cast<uint8_t>(tmp_Hcode - min_code[k]))]; size_val = byte_temp & 0xF; count_0 = byte_temp >> 4; if (size_val == 0) { @@ -948,7 +961,7 @@ class AstJpegDecoder { unsigned short int lookKbits(uint8_t k) { unsigned short int revcode; - revcode = (unsigned short int)(codebuf >> (32 - k)); + revcode = static_cast<unsigned short int>(codebuf >> (32 - k)); return (revcode); } @@ -975,7 +988,7 @@ class AstJpegDecoder { // river // signed_wordvalue=lookKbits(k); - signed_wordvalue = (unsigned short int)(codebuf >> (32 - k)); + signed_wordvalue = static_cast<unsigned short int>(codebuf >> (32 - k)); if (((1L << (k - 1)) & signed_wordvalue) == 0) { // neg_pow2 was previously defined as the below. It seemed silly to keep // a table of values around for something @@ -1002,17 +1015,21 @@ class AstJpegDecoder { } void set_quant_table(const uint8_t *basic_table, uint8_t scale_factor, - uint8_t *newtable) + std::array<uint8_t, 64>& newtable) // Set quantization table and zigzag reorder it { uint8_t i; long temp; for (i = 0; i < 64; i++) { - temp = ((long)(basic_table[i] * 16) / scale_factor); + temp = (static_cast<long>(basic_table[i] * 16) / scale_factor); /* limit the values to the valid range */ - if (temp <= 0L) temp = 1L; - if (temp > 255L) temp = 255L; /* limit to baseline range if requested */ - newtable[zigzag[i]] = (uint8_t)temp; + if (temp <= 0L) { + temp = 1L; + } + if (temp > 255L) { + temp = 255L; /* limit to baseline range if requested */ + } + newtable[zigzag[i]] = static_cast<uint8_t>(temp); } } @@ -1053,17 +1070,17 @@ class AstJpegDecoder { Mapping = 0; // 0 or 1 if (yuvmode == YuvMode::YUV420) { - if (WIDTH % 16) { + if ((WIDTH % 16) != 0u) { WIDTH = WIDTH + 16 - (WIDTH % 16); } - if (HEIGHT % 16) { + if ((HEIGHT % 16) != 0u) { HEIGHT = HEIGHT + 16 - (HEIGHT % 16); } } else { - if (WIDTH % 8) { + if ((WIDTH % 8) != 0u) { WIDTH = WIDTH + 8 - (WIDTH % 8); } - if (HEIGHT % 8) { + if ((HEIGHT % 8) != 0u) { HEIGHT = HEIGHT + 8 - (HEIGHT % 8); } } @@ -1098,7 +1115,7 @@ class AstJpegDecoder { case JpgBlock::JPEG_NO_SKIP_CODE: updatereadbuf(&codebuf, &newbuf, BLOCK_AST2100_START_LENGTH, &newbits, buffer); - Decompress(txb, tyb, (char *)OutBuffer.data(), 0); + Decompress(txb, tyb, reinterpret_cast<char *>(OutBuffer.data()), 0); break; case JpgBlock::FRAME_END_CODE: return 0; @@ -1110,7 +1127,7 @@ class AstJpegDecoder { updatereadbuf(&codebuf, &newbuf, BLOCK_AST2100_SKIP_LENGTH, &newbits, buffer); - Decompress(txb, tyb, (char *)OutBuffer.data(), 0); + Decompress(txb, tyb, reinterpret_cast<char *>(OutBuffer.data()), 0); break; case JpgBlock::VQ_NO_SKIP_1_COLOR_CODE: updatereadbuf(&codebuf, &newbuf, BLOCK_AST2100_START_LENGTH, &newbits, @@ -1129,7 +1146,8 @@ class AstJpegDecoder { buffer); } } - VQ_Decompress(txb, tyb, (char *)OutBuffer.data(), 0, &Decode_Color); + VQ_Decompress(txb, tyb, reinterpret_cast<char *>(OutBuffer.data()), 0, + &Decode_Color); break; case JpgBlock::VQ_SKIP_1_COLOR_CODE: txb = (codebuf & 0x0FF00000) >> 20; @@ -1151,7 +1169,8 @@ class AstJpegDecoder { buffer); } } - VQ_Decompress(txb, tyb, (char *)OutBuffer.data(), 0, &Decode_Color); + VQ_Decompress(txb, tyb, reinterpret_cast<char *>(OutBuffer.data()), 0, + &Decode_Color); break; case JpgBlock::VQ_NO_SKIP_2_COLOR_CODE: @@ -1171,7 +1190,8 @@ class AstJpegDecoder { buffer); } } - VQ_Decompress(txb, tyb, (char *)OutBuffer.data(), 0, &Decode_Color); + VQ_Decompress(txb, tyb, reinterpret_cast<char *>(OutBuffer.data()), 0, + &Decode_Color); break; case JpgBlock::VQ_SKIP_2_COLOR_CODE: txb = (codebuf & 0x0FF00000) >> 20; @@ -1193,7 +1213,8 @@ class AstJpegDecoder { buffer); } } - VQ_Decompress(txb, tyb, (char *)OutBuffer.data(), 0, &Decode_Color); + VQ_Decompress(txb, tyb, reinterpret_cast<char *>(OutBuffer.data()), 0, + &Decode_Color); break; case JpgBlock::VQ_NO_SKIP_4_COLOR_CODE: @@ -1201,19 +1222,19 @@ class AstJpegDecoder { buffer); Decode_Color.BitMapBits = 2; - for (int i = 0; i < 4; i++) { - Decode_Color.Index[i] = ((codebuf >> 29) & VQ_INDEX_MASK); + for (unsigned char &i : Decode_Color.Index) { + i = ((codebuf >> 29) & VQ_INDEX_MASK); if (((codebuf >> 31) & VQ_HEADER_MASK) == VQ_NO_UPDATE_HEADER) { updatereadbuf(&codebuf, &newbuf, VQ_NO_UPDATE_LENGTH, &newbits, buffer); } else { - Decode_Color.Color[Decode_Color.Index[i]] = - ((codebuf >> 5) & VQ_COLOR_MASK); + Decode_Color.Color[i] = ((codebuf >> 5) & VQ_COLOR_MASK); updatereadbuf(&codebuf, &newbuf, VQ_UPDATE_LENGTH, &newbits, buffer); } } - VQ_Decompress(txb, tyb, (char *)OutBuffer.data(), 0, &Decode_Color); + VQ_Decompress(txb, tyb, reinterpret_cast<char *>(OutBuffer.data()), 0, + &Decode_Color); break; @@ -1225,19 +1246,19 @@ class AstJpegDecoder { buffer); Decode_Color.BitMapBits = 2; - for (int i = 0; i < 4; i++) { - Decode_Color.Index[i] = ((codebuf >> 29) & VQ_INDEX_MASK); + for (unsigned char &i : Decode_Color.Index) { + i = ((codebuf >> 29) & VQ_INDEX_MASK); if (((codebuf >> 31) & VQ_HEADER_MASK) == VQ_NO_UPDATE_HEADER) { updatereadbuf(&codebuf, &newbuf, VQ_NO_UPDATE_LENGTH, &newbits, buffer); } else { - Decode_Color.Color[Decode_Color.Index[i]] = - ((codebuf >> 5) & VQ_COLOR_MASK); + Decode_Color.Color[i] = ((codebuf >> 5) & VQ_COLOR_MASK); updatereadbuf(&codebuf, &newbuf, VQ_UPDATE_LENGTH, &newbits, buffer); } } - VQ_Decompress(txb, tyb, (char *)OutBuffer.data(), 0, &Decode_Color); + VQ_Decompress(txb, tyb, reinterpret_cast<char *>(OutBuffer.data()), 0, + &Decode_Color); break; case JpgBlock::JPEG_SKIP_PASS2_CODE: @@ -1246,7 +1267,8 @@ class AstJpegDecoder { updatereadbuf(&codebuf, &newbuf, BLOCK_AST2100_SKIP_LENGTH, &newbits, buffer); - Decompress_2PASS(txb, tyb, (char *)OutBuffer.data(), 2); + Decompress_2PASS(txb, tyb, reinterpret_cast<char *>(OutBuffer.data()), + 2); break; default: @@ -1277,41 +1299,41 @@ class AstJpegDecoder { #endif private: - YuvMode yuvmode; + YuvMode yuvmode{}; // WIDTH and HEIGHT are the modes your display used - unsigned long WIDTH; - unsigned long HEIGHT; - unsigned long USER_WIDTH; - unsigned long USER_HEIGHT; - unsigned char Y_selector; + unsigned long WIDTH{}; + unsigned long HEIGHT{}; + unsigned long USER_WIDTH{}; + unsigned long USER_HEIGHT{}; + unsigned char Y_selector{}; int SCALEFACTOR; int SCALEFACTORUV; int ADVANCESCALEFACTOR; int ADVANCESCALEFACTORUV; - int Mapping; - unsigned char UV_selector; - unsigned char advance_selector; - int byte_pos; // current byte position + int Mapping{}; + unsigned char UV_selector{}; + unsigned char advance_selector{}; + int byte_pos{}; // current byte position // quantization tables, no more than 4 quantization tables - std::array<std::array<long, 64>, 4> QT; + std::array<std::array<long, 64>, 4> QT{}; // DC huffman tables , no more than 4 (0..3) - std::array<Huffman_table, 4> HTDC; + std::array<Huffman_table, 4> HTDC{}; // AC huffman tables (0..3) - std::array<Huffman_table, 4> HTAC; - std::array<int, 256> m_CrToR; - std::array<int, 256> m_CbToB; - std::array<int, 256> m_CrToG; - std::array<int, 256> m_CbToG; - std::array<int, 256> m_Y; - unsigned long buffer_index; - uint32_t codebuf, newbuf, readbuf; - const unsigned char *std_luminance_qt; - const uint8_t *std_chrominance_qt; - - signed short int DCY, DCCb, DCCr; // Coeficientii DC pentru Y,Cb,Cr - signed short int DCT_coeff[384]; + std::array<Huffman_table, 4> HTAC{}; + std::array<int, 256> m_CrToR{}; + std::array<int, 256> m_CbToB{}; + std::array<int, 256> m_CrToG{}; + std::array<int, 256> m_CbToG{}; + std::array<int, 256> m_Y{}; + unsigned long buffer_index{}; + uint32_t codebuf{}, newbuf{}, readbuf{}; + const unsigned char *std_luminance_qt{}; + const uint8_t *std_chrominance_qt{}; + + signed short int DCY{}, DCCb{}, DCCr{}; // Coeficientii DC pentru Y,Cb,Cr + signed short int DCT_coeff[384]{}; // std::vector<signed short int> DCT_coeff; // Current DCT_coefficients // quantization table number for Y, Cb, Cr uint8_t YQ_nr = 0, CbQ_nr = 1, CrQ_nr = 1; @@ -1321,13 +1343,13 @@ class AstJpegDecoder { uint8_t YAC_nr = 0, CbAC_nr = 1, CrAC_nr = 1; int txb = 0; int tyb = 0; - int newbits; - uint8_t *rlimit_table; + int newbits{}; + uint8_t *rlimit_table{}; std::vector<RGB> YUVBuffer; // TODO(ed) this shouldn't exist. It is cruft that needs cleaning up - uint32_t *Buffer; + uint32_t *Buffer{}; public: std::vector<RGB> OutBuffer; }; -}
\ No newline at end of file +} // namespace AstVideo
\ No newline at end of file diff --git a/include/ast_video_puller.hpp b/include/ast_video_puller.hpp index 6575d7e..759aaeb 100644 --- a/include/ast_video_puller.hpp +++ b/include/ast_video_puller.hpp @@ -1,6 +1,6 @@ #pragma once -#include <assert.h> +#include <cassert> #include <ast_video_types.hpp> #include <iostream> #include <mutex> @@ -12,29 +12,29 @@ namespace AstVideo { // // Cursor struct is used in User Mode // -typedef struct _cursor_attribution_tag { +struct AST_CUR_ATTRIBUTION_TAG { unsigned int posX; unsigned int posY; unsigned int cur_width; unsigned int cur_height; unsigned int cur_type; // 0:mono 1:color 2:disappear cursor unsigned int cur_change_flag; -} AST_CUR_ATTRIBUTION_TAG; +}; // // For storing Cursor Information // -typedef struct _cursor_tag { +struct AST_CURSOR_TAG { AST_CUR_ATTRIBUTION_TAG attr; // unsigned char icon[MAX_CUR_OFFSETX*MAX_CUR_OFFSETY*2]; unsigned char *icon; //[64*64*2]; -} AST_CURSOR_TAG; +}; // // For select image format, i.e. 422 JPG420, 444 JPG444, lumin/chrom table, 0 // ~ 11, low to high // -typedef struct _video_features { +struct FEATURES_TAG { short jpg_fmt; // 422:JPG420, 444:JPG444 short lumin_tbl; short chrom_tbl; @@ -42,12 +42,12 @@ typedef struct _video_features { int w; int h; unsigned char *buf; -} FEATURES_TAG; +}; // // For configure video engine control registers // -typedef struct _image_info { +struct IMAGE_INFO { short do_image_refresh; // Action 0:motion 1:fullframe 2:quick cursor char qc_valid; // quick cursor enable/disable unsigned int len; @@ -57,7 +57,7 @@ typedef struct _image_info { FEATURES_TAG features; AST_CURSOR_TAG cursor_info; } parameter; -} IMAGE_INFO; +}; class SimpleVideoPuller { public: @@ -66,7 +66,7 @@ class SimpleVideoPuller { void initialize() { std::cout << "Opening /dev/video\n"; video_fd = open("/dev/video", O_RDWR); - if (!video_fd) { + if (video_fd == 0) { std::cout << "Failed to open /dev/video\n"; throw std::runtime_error("Failed to open /dev/video"); } @@ -117,16 +117,16 @@ class SimpleVideoPuller { } private: - int video_fd; + int video_fd{}; IMAGE_INFO image_info; }; #if defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) class AsyncVideoPuller { public: - typedef std::function<void(RawVideoBuffer &)> video_callback; + using video_callback = std::function<void (RawVideoBuffer &)>; - AsyncVideoPuller(boost::asio::io_service &io_service) + explicit AsyncVideoPuller(boost::asio::io_service &io_service) : image_info(), dev_video(io_service, open("/dev/video", O_RDWR)) { videobuf = std::make_shared<RawVideoBuffer>(); @@ -148,7 +148,7 @@ class AsyncVideoPuller { boost::asio::async_read( dev_video, mutable_buffer, [this](const boost::system::error_code &ec, std::size_t bytes_transferred) { - if (ec) { + if (ec != nullptr) { std::cerr << "Read failed with status " << ec << "\n"; } else { this->read_done(); @@ -182,4 +182,4 @@ class AsyncVideoPuller { std::vector<video_callback> callbacks; }; #endif // defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) -} +} // namespace AstVideo diff --git a/include/ast_video_types.hpp b/include/ast_video_types.hpp index 206a7ef..f5cfffd 100644 --- a/include/ast_video_types.hpp +++ b/include/ast_video_types.hpp @@ -1,5 +1,6 @@ #pragma once +#include <cstdint> #include <vector> namespace AstVideo { enum class YuvMode { YUV444 = 0, YUV420 = 1 }; @@ -7,12 +8,12 @@ enum class YuvMode { YUV444 = 0, YUV420 = 1 }; class RawVideoBuffer { public: RawVideoBuffer() : buffer(1024 * 1024 * 10, 0){}; - unsigned long height; - unsigned long width; - int y_selector; - int uv_selector; + unsigned long height{}; + unsigned long width{}; + int y_selector{}; + int uv_selector{}; YuvMode mode; // TODO(ed) determine a more appropriate buffer size std::vector<uint32_t> buffer; }; -}
\ No newline at end of file +} // namespace AstVideo
\ No newline at end of file diff --git a/include/base64.hpp b/include/base64.hpp index a40ab47..092189d 100644 --- a/include/base64.hpp +++ b/include/base64.hpp @@ -4,4 +4,4 @@ namespace base64 { bool base64_encode(const std::string &input, std::string &output); bool base64_decode(const std::string &input, std::string &output); -}
\ No newline at end of file +} // namespace base64
\ No newline at end of file diff --git a/include/dbus_monitor.hpp b/include/dbus_monitor.hpp new file mode 100644 index 0000000..0306183 --- /dev/null +++ b/include/dbus_monitor.hpp @@ -0,0 +1,82 @@ +#pragma once +#include <dbus/filter.hpp> +#include <dbus/match.hpp> +#include <dbus_singleton.hpp> +#include <crow/app.h> +#include <boost/container/flat_map.hpp> + +namespace crow { +namespace dbus_monitor { + +struct DbusWebsocketSession { + std::vector<std::unique_ptr<dbus::match>> matches; + std::vector<dbus::filter> filters; +}; + +static boost::container::flat_map<crow::websocket::connection*, + DbusWebsocketSession> + sessions; + +void on_property_update(dbus::filter& filter, boost::system::error_code ec, + dbus::message s) { + if (!ec) { + std::string object_name; + std::vector<std::pair<std::string, dbus::dbus_variant>> values; + s.unpack(object_name, values); + nlohmann::json j; + for (auto& value : values) { + boost::apply_visitor([&](auto val) { j[s.get_path()] = val; }, + value.second); + } + auto data_to_send = j.dump(); + + for (auto& session : sessions) { + session.first->send_text(data_to_send); + } + } + filter.async_dispatch([&](boost::system::error_code ec, dbus::message s) { + on_property_update(filter, ec, s); + }); +}; + +template <typename... Middlewares> +void request_routes(Crow<Middlewares...>& app) { + CROW_ROUTE(app, "/dbus_monitor") + .websocket() + .onopen([&](crow::websocket::connection& conn) { + std::string path_namespace(conn.req.url_params.get("path_namespace")); + if (path_namespace.empty()) { + conn.send_text( + nlohmann::json({"error", "Did not specify path_namespace"})); + conn.close("error"); + } + sessions[&conn] = DbusWebsocketSession(); + std::string match_string( + "type='signal'," + "interface='org.freedesktop.DBus.Properties'," + "path_namespace='" + + path_namespace + "'"); + sessions[&conn].matches.push_back(std::make_unique<dbus::match>( + crow::connections::system_bus, std::move(match_string))); + + sessions[&conn].filters.emplace_back( + crow::connections::system_bus, [path_namespace](dbus::message m) { + return m.get_member() == "PropertiesChanged" && + boost::starts_with(m.get_path(), path_namespace); + }); + auto& this_filter = sessions[&conn].filters.back(); + this_filter.async_dispatch( + [&](boost::system::error_code ec, dbus::message s) { + on_property_update(this_filter, ec, s); + }); + + }) + .onclose([&](crow::websocket::connection& conn, + const std::string& reason) { sessions.erase(&conn); }) + .onmessage([&](crow::websocket::connection& conn, const std::string& data, + bool is_binary) { + CROW_LOG_ERROR << "Got unexpected message from client on sensorws"; + }); +} +} // namespace redfish +} // namespace crow diff --git a/include/dbus_singleton.hpp b/include/dbus_singleton.hpp new file mode 100644 index 0000000..e2fd2d6 --- /dev/null +++ b/include/dbus_singleton.hpp @@ -0,0 +1,10 @@ +#pragma once +#include <dbus/connection.hpp> + +namespace crow { +namespace connections { + +static std::shared_ptr<dbus::connection> system_bus; + +} // namespace dbus +} // namespace crow
\ No newline at end of file diff --git a/include/gzip_helper.hpp b/include/gzip_helper.hpp new file mode 100644 index 0000000..9b7d253 --- /dev/null +++ b/include/gzip_helper.hpp @@ -0,0 +1,56 @@ +#pragma once + +#include <zlib.h> +#include <cstring> +#include <string> + +inline bool gzip_inflate(const std::string& compressedBytes, + std::string& uncompressedBytes) { + if (compressedBytes.empty()) { + uncompressedBytes = compressedBytes; + return true; + } + + uncompressedBytes.clear(); + + unsigned half_length = compressedBytes.size() / 2; + + z_stream strm{}; + + // The following line is nolint because we're declaring away constness. + // It's not clear why the input buffers on zlib aren't const, so this is a + // bit of a cheat for the moment + strm.next_in = (Bytef*)compressedBytes.data(); // NOLINT + strm.avail_in = compressedBytes.size(); + strm.total_out = 0; + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + + bool done = false; + + if (inflateInit2(&strm, (16 + MAX_WBITS)) != Z_OK) { + return false; + } + + while (!done) { + // If our output buffer is too small + if (strm.total_out >= uncompressedBytes.size()) { + uncompressedBytes.resize(uncompressedBytes.size() + half_length); + } + + strm.next_out = + (Bytef*)(uncompressedBytes.data() + strm.total_out); // NOLINT + strm.avail_out = + ((uLong)uncompressedBytes.size() - strm.total_out); // NOLINT + + // Inflate another chunk. + int err = inflate(&strm, Z_SYNC_FLUSH); + if (err == Z_STREAM_END) { + done = true; + } else if (err != Z_OK) { + break; + } + } + + return inflateEnd(&strm) == Z_OK; +}
\ No newline at end of file diff --git a/include/intel_oem.hpp b/include/intel_oem.hpp new file mode 100644 index 0000000..e821807 --- /dev/null +++ b/include/intel_oem.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include <dbus_singleton.hpp> +#include <fstream> +#include <crow/app.h> + +namespace crow { +namespace intel_oem { + +template <typename... Middlewares> +void request_routes(Crow<Middlewares...>& app) { + CROW_ROUTE(app, "/intel/firmwareupload") + .methods("POST"_method)([](const crow::request& req) { + std::string filepath("/tmp/fw_update_image"); + std::ofstream out(filepath, std::ofstream::out | std::ofstream::binary | + std::ofstream::trunc); + out << req.body; + out.close(); + + auto m = dbus::message::new_call( + {"xyz.openbmc_project.fwupdate1.server", + "/xyz/openbmc_project/fwupdate1", "xyz.openbmc_project.fwupdate1"}, + "start"); + + m.pack(std::string("file://") + filepath); + crow::connections::system_bus->send(m); + nlohmann::json j; + j["status"] = "Upload Successful"; + return j; + }); +} +} // namespace redfish +} // namespace crow diff --git a/include/openbmc_dbus_rest.hpp b/include/openbmc_dbus_rest.hpp new file mode 100644 index 0000000..9348808 --- /dev/null +++ b/include/openbmc_dbus_rest.hpp @@ -0,0 +1,320 @@ +#include <crow/app.h> + +#include <tinyxml2.h> +#include <dbus/connection.hpp> +#include <dbus/endpoint.hpp> +#include <dbus/filter.hpp> +#include <dbus/match.hpp> +#include <dbus/message.hpp> +#include <dbus_singleton.hpp> + +namespace crow { +namespace openbmc_mapper { +std::atomic<std::size_t> outstanding_async_calls(0); +nlohmann::json object_paths; + +void introspect_objects(crow::response &res, std::string process_name, + std::string path) { + dbus::endpoint introspect_endpoint( + process_name, path, "org.freedesktop.DBus.Introspectable", "Introspect"); + outstanding_async_calls++; + crow::connections::system_bus->async_method_call( + [&, process_name{std::move(process_name)}, object_path{std::move(path)} ]( + const boost::system::error_code ec, + const std::string &introspect_xml) { + outstanding_async_calls--; + if (ec) { + std::cerr << "Introspect call failed with error: " << ec.message() + << " on process: " << process_name + << " path: " << object_path << "\n"; + + } else { + object_paths.push_back({{"path", object_path}}); + + tinyxml2::XMLDocument doc; + + doc.Parse(introspect_xml.c_str()); + tinyxml2::XMLNode *pRoot = doc.FirstChildElement("node"); + if (pRoot == nullptr) { + std::cerr << "XML document failed to parse " << process_name << " " + << path << "\n"; + + } else { + tinyxml2::XMLElement *node = pRoot->FirstChildElement("node"); + while (node != nullptr) { + std::string child_path = node->Attribute("name"); + std::string newpath; + if (object_path != "/") { + newpath += object_path; + } + newpath += "/" + child_path; + // intropect the subobjects as well + introspect_objects(res, process_name, newpath); + + node = node->NextSiblingElement("node"); + } + } + } + // if we're the last outstanding caller, finish the request + if (outstanding_async_calls == 0) { + nlohmann::json j{{"status", "ok"}, + {"bus_name", process_name}, + {"objects", object_paths}}; + + res.write(j.dump()); + object_paths.clear(); + res.end(); + } + }, + introspect_endpoint); +} + +template <typename... Middlewares> +void request_routes(Crow<Middlewares...> &app) { + CROW_ROUTE(app, "/bus/").methods("GET"_method)([](const crow::request &req) { + return nlohmann::json{{"busses", {{{"name", "system"}}}}, {"status", "ok"}}; + + }); + + CROW_ROUTE(app, "/bus/system/") + .methods("GET"_method)([](const crow::request &req, crow::response &res) { + crow::connections::system_bus->async_method_call( + [&](const boost::system::error_code ec, + std::vector<std::string> &names) { + std::sort(names.begin(), names.end()); + if (ec) { + res.code = 500; + } else { + nlohmann::json j{{"status", "ok"}}; + auto &objects_sub = j["objects"]; + for (auto &name : names) { + objects_sub.push_back({{"name", name}}); + } + + res.write(j.dump()); + } + + res.end(); + + }, + {"org.freedesktop.DBus", "/", "org.freedesktop.DBus", "ListNames"}); + + }); + + CROW_ROUTE(app, "/bus/system/<str>/") + .methods("GET"_method)([](const crow::request &req, crow::response &res, + const std::string &connection) { + // Can only do one call at a time (for now) + if (outstanding_async_calls == 0) { + // TODO(ed) sanitize paths + introspect_objects(res, connection, "/"); + } else { + nlohmann::json j{{"status", "failed"}}; + res.code = 500; + res.write(j.dump()); + res.end(); + } + }); + + CROW_ROUTE(app, "/bus/system/<str>/<path>") + .methods("GET"_method)([](const crow::request &req, crow::response &res, + const std::string &process_name, + const std::string &requested_path) { + + std::vector<std::string> strs; + boost::split(strs, requested_path, boost::is_any_of("/")); + std::string object_path; + std::string interface_name; + std::string method_name; + auto it = strs.begin(); + if (it == strs.end()) { + object_path = "/"; + } + while (it != strs.end()) { + // Check if segment contains ".". If it does, it must be an + // interface + if ((*it).find(".") != std::string::npos) { + break; + // THis check is neccesary as the trailing slash gets parsed as part + // of our <path> specifier above, which causes the normal trailing + // backslash redirector to fail. + } else if (!it->empty()) { + object_path += "/" + *it; + } + it++; + } + if (it != strs.end()) { + interface_name = *it; + it++; + + // after interface, we might have a method name + if (it != strs.end()) { + method_name = *it; + it++; + } + } + if (it != strs.end()) { + // if there is more levels past the method name, something went + // wrong, throw an error + res.code = 404; + res.end(); + return; + } + dbus::endpoint introspect_endpoint( + process_name, object_path, "org.freedesktop.DBus.Introspectable", + "Introspect"); + if (interface_name.empty()) { + crow::connections::system_bus->async_method_call( + [ + &, process_name{std::move(process_name)}, + object_path{std::move(object_path)} + ](const boost::system::error_code ec, + const std::string &introspect_xml) { + if (ec) { + std::cerr + << "Introspect call failed with error: " << ec.message() + << " on process: " << process_name + << " path: " << object_path << "\n"; + + } else { + tinyxml2::XMLDocument doc; + + doc.Parse(introspect_xml.c_str()); + tinyxml2::XMLNode *pRoot = doc.FirstChildElement("node"); + if (pRoot == nullptr) { + std::cerr << "XML document failed to parse " << process_name + << " " << object_path << "\n"; + res.write(nlohmann::json{{"status", "XML parse error"}}); + res.code = 500; + } else { + nlohmann::json interfaces_array = nlohmann::json::array(); + tinyxml2::XMLElement *interface = + pRoot->FirstChildElement("interface"); + + while (interface != nullptr) { + std::string iface_name = interface->Attribute("name"); + interfaces_array.push_back({{"name", iface_name}}); + + interface = interface->NextSiblingElement("interface"); + } + nlohmann::json j{{"status", "ok"}, + {"bus_name", process_name}, + {"interfaces", interfaces_array}, + {"object_path", object_path}}; + res.write(j.dump()); + } + } + res.end(); + }, + introspect_endpoint); + } else { + crow::connections::system_bus->async_method_call( + [ + &, process_name{std::move(process_name)}, + interface_name{std::move(interface_name)}, + object_path{std::move(object_path)} + ](const boost::system::error_code ec, + const std::string &introspect_xml) { + if (ec) { + std::cerr + << "Introspect call failed with error: " << ec.message() + << " on process: " << process_name + << " path: " << object_path << "\n"; + + } else { + tinyxml2::XMLDocument doc; + + doc.Parse(introspect_xml.c_str()); + tinyxml2::XMLNode *pRoot = doc.FirstChildElement("node"); + if (pRoot == nullptr) { + std::cerr << "XML document failed to parse " << process_name + << " " << object_path << "\n"; + res.code = 500; + + } else { + tinyxml2::XMLElement *node = + pRoot->FirstChildElement("node"); + + // if we know we're the only call, build the json directly + nlohmann::json methods_array = nlohmann::json::array(); + nlohmann::json signals_array = nlohmann::json::array(); + tinyxml2::XMLElement *interface = + pRoot->FirstChildElement("interface"); + + while (interface != nullptr) { + std::string iface_name = interface->Attribute("name"); + + if (iface_name == interface_name) { + tinyxml2::XMLElement *methods = + interface->FirstChildElement("method"); + while (methods != nullptr) { + nlohmann::json args_array = nlohmann::json::array(); + tinyxml2::XMLElement *arg = + methods->FirstChildElement("arg"); + while (arg != nullptr) { + args_array.push_back( + {{"name", arg->Attribute("name")}, + {"type", arg->Attribute("type")}, + {"direction", arg->Attribute("direction")}}); + arg = arg->NextSiblingElement("arg"); + } + methods_array.push_back( + {{"name", methods->Attribute("name")}, + {"uri", "/bus/system/" + process_name + + object_path + "/" + interface_name + + "/" + methods->Attribute("name")}, + {"args", args_array}}); + methods = methods->NextSiblingElement("method"); + } + tinyxml2::XMLElement *signals = + interface->FirstChildElement("signal"); + while (signals != nullptr) { + nlohmann::json args_array = nlohmann::json::array(); + + tinyxml2::XMLElement *arg = + signals->FirstChildElement("arg"); + while (arg != nullptr) { + std::string name = arg->Attribute("name"); + std::string type = arg->Attribute("type"); + args_array.push_back({ + {"name", name}, {"type", type}, + }); + arg = arg->NextSiblingElement("arg"); + } + signals_array.push_back( + {{"name", signals->Attribute("name")}, + {"args", args_array}}); + signals = signals->NextSiblingElement("signal"); + } + + nlohmann::json j{ + {"status", "ok"}, + {"bus_name", process_name}, + {"interface", interface_name}, + {"methods", methods_array}, + {"object_path", object_path}, + {"properties", nlohmann::json::object()}, + {"signals", signals_array}}; + + res.write(j.dump()); + break; + } + + interface = interface->NextSiblingElement("interface"); + } + if (interface == nullptr) { + // if we got to the end of the list and never found a + // match, throw 404 + res.code = 404; + } + } + } + res.end(); + }, + introspect_endpoint); + } + + }); +} +} // namespace openbmc_mapper +} // namespace crow diff --git a/include/pam_authenticate.hpp b/include/pam_authenticate.hpp index 153dbc7..0825dd6 100644 --- a/include/pam_authenticate.hpp +++ b/include/pam_authenticate.hpp @@ -1,20 +1,28 @@ +#pragma once + #include <security/pam_appl.h> +#include <cstring> // function used to get user input inline int pam_function_conversation(int num_msg, const struct pam_message** msg, struct pam_response** resp, void* appdata_ptr) { - char* pass = (char*)malloc(strlen((char*)appdata_ptr) + 1); - strcpy(pass, (char*)appdata_ptr); - - int i; + if (appdata_ptr == nullptr) { + return PAM_AUTH_ERR; + } + auto* pass = reinterpret_cast<char*>( + malloc(std::strlen(reinterpret_cast<char*>(appdata_ptr)) + 1)); + std::strcpy(pass, reinterpret_cast<char*>(appdata_ptr)); - *resp = (pam_response*)calloc(num_msg, sizeof(struct pam_response)); + *resp = reinterpret_cast<pam_response*>( + calloc(num_msg, sizeof(struct pam_response))); - for (i = 0; i < num_msg; ++i) { + for (int i = 0; i < num_msg; ++i) { /* Ignore all PAM messages except prompting for hidden input */ - if (msg[i]->msg_style != PAM_PROMPT_ECHO_OFF) continue; + if (msg[i]->msg_style != PAM_PROMPT_ECHO_OFF) { + continue; + } /* Assume PAM is only prompting for the password as hidden input */ resp[i]->resp = pass; @@ -23,43 +31,39 @@ inline int pam_function_conversation(int num_msg, return PAM_SUCCESS; } -class PamAuthenticator { - public: - inline bool authenticate(const std::string& username, - const std::string& password) { - const struct pam_conv local_conversation = {pam_function_conversation, - (char*)password.c_str()}; - pam_handle_t* local_auth_handle = NULL; // this gets set by pam_start - - int retval; - retval = pam_start("su", username.c_str(), &local_conversation, - &local_auth_handle); - - if (retval != PAM_SUCCESS) { - //printf("pam_start returned: %d\n ", retval); - return false; - } +inline bool pam_authenticate_user(const std::string& username, + const std::string& password) { + const struct pam_conv local_conversation = { + pam_function_conversation, const_cast<char*>(password.c_str())}; + pam_handle_t* local_auth_handle = NULL; // this gets set by pam_start - retval = pam_authenticate(local_auth_handle, - PAM_SILENT | PAM_DISALLOW_NULL_AUTHTOK); + if (pam_start("su", username.c_str(), &local_conversation, + &local_auth_handle) != PAM_SUCCESS) { + return false; + } + int retval = pam_authenticate(local_auth_handle, + PAM_SILENT | PAM_DISALLOW_NULL_AUTHTOK); - if (retval != PAM_SUCCESS) { - if (retval == PAM_AUTH_ERR) { - //printf("Authentication failure.\n"); - } else { - //printf("pam_authenticate returned %d\n", retval); - } - return false; + if (retval != PAM_SUCCESS) { + if (retval == PAM_AUTH_ERR) { + // printf("Authentication failure.\n"); + } else { + // printf("pam_authenticate returned %d\n", retval); } + pam_end(local_auth_handle, PAM_SUCCESS); + return false; + } - //printf("Authenticated.\n"); - retval = pam_end(local_auth_handle, retval); - - if (retval != PAM_SUCCESS) { - //printf("pam_end returned\n"); - return false; - } + /* check that the account is healthy */ + if (pam_acct_mgmt(local_auth_handle, PAM_DISALLOW_NULL_AUTHTOK) != + PAM_SUCCESS) { + pam_end(local_auth_handle, PAM_SUCCESS); + return false; + } - return true; + if (pam_end(local_auth_handle, PAM_SUCCESS) != PAM_SUCCESS) { + return false; } -};
\ No newline at end of file + + return true; +} diff --git a/include/redfish_v1.hpp b/include/redfish_v1.hpp index c302a68..73ed84e 100644 --- a/include/redfish_v1.hpp +++ b/include/redfish_v1.hpp @@ -1,9 +1,24 @@ +#pragma once + #include <crow/app.h> + +#include <dbus/connection.hpp> +#include <dbus/endpoint.hpp> +#include <dbus/filter.hpp> +#include <dbus/match.hpp> +#include <dbus/message.hpp> +#include <fstream> + namespace crow { namespace redfish { template <typename... Middlewares> void request_routes(Crow<Middlewares...>& app) { + + // noop for now + return; + + CROW_ROUTE(app, "/redfish/").methods("GET"_method)([]() { return nlohmann::json{{"v1", "/redfish/v1/"}}; }); @@ -28,6 +43,28 @@ void request_routes(Crow<Middlewares...>& app) { }; }); + CROW_ROUTE(app, "/redfish/v1/Chassis").methods("GET"_method)([]() { + std::vector<std::string> entities; + std::ifstream f("~/system.json"); + nlohmann::json input; + input << f; + for (auto it = input.begin(); it != input.end(); it++) { + auto value = it.value(); + if (value["type"] == "Chassis") { + std::string str = value["name"]; + entities.emplace_back(str); + } + } + auto ret = nlohmann::json{ + {"@odata.context", + "/redfish/v1/$metadata#ChassisCollection.ChassisCollection"}, + {"@odata.id", "/redfish/v1/Chassis"}, + {"@odata.type", "#ChassisCollection.ChassisCollection"}, + {"Name", "Chassis Collection"}, + {"Members@odata.count", entities.size()}}; + return ret; + }); + CROW_ROUTE(app, "/redfish/v1/AccountService").methods("GET"_method)([]() { return nlohmann::json{ {"@odata.context", @@ -38,6 +75,7 @@ void request_routes(Crow<Middlewares...>& app) { {"Name", "Account Service"}, {"Description", "BMC User Accounts"}, {"Status", + // TODO(ed) health rollup {{"State", "Enabled"}, {"Health", "OK"}, {"HealthRollup", "OK"}}}, {"ServiceEnabled", true}, {"MinPasswordLength", 1}, @@ -47,22 +85,41 @@ void request_routes(Crow<Middlewares...>& app) { }; }); - CROW_ROUTE(app, "/redfish/v1/AccountService/Accounts/") - .methods("GET"_method)([]() { - return nlohmann::json{ - {"@odata.context", - "/redfish/v1/" - "$metadata#ManagerAccountCollection.ManagerAccountCollection"}, - {"@odata.id", "/redfish/v1/AccountService/Accounts"}, - {"@odata.type", - "#ManagerAccountCollection.ManagerAccountCollection"}, - {"Name", "Accounts Collection"}, - {"Description", "BMC User Accounts"}, - {"Members@odata.count", 3}, - {"Members", - {{{"@odata.id", "/redfish/v1/AccountService/Accounts/1"}}, - {{"@odata.id", "/redfish/v1/AccountService/Accounts/2"}}, - {{"@odata.id", "/redfish/v1/AccountService/Accounts/3"}}}}}; + CROW_ROUTE(app, "/redfish/v1/AccountService/Accounts") + .methods("GET"_method)([](const crow::request& req, crow::response& res) { + boost::asio::io_service io; + auto bus = std::make_shared<dbus::connection>(io, dbus::bus::session); + dbus::endpoint user_list("org.openbmc.UserManager", + "/org/openbmc/UserManager/Users", + "org.openbmc.Enrol", "UserList"); + bus->async_method_call( + [&](const boost::system::error_code ec, + const std::vector<std::string>& users) { + if (ec) { + res.code = 500; + } else { + nlohmann::json return_json{ + {"@odata.context", + "/redfish/v1/" + "$metadata#ManagerAccountCollection." + "ManagerAccountCollection"}, + {"@odata.id", "/redfish/v1/AccountService/Accounts"}, + {"@odata.type", + "#ManagerAccountCollection.ManagerAccountCollection"}, + {"Name", "Accounts Collection"}, + {"Description", "BMC User Accounts"}, + {"Members@odata.count", users.size()}}; + nlohmann::json member_array; + int user_index = 0; + for (auto& user : users) { + member_array.push_back( + {{"@odata.id", "/redfish/v1/AccountService/Accounts/" + + std::to_string(++user_index)}}); + } + return_json["Members"] = member_array; + } + res.end(); + }, user_list); }); CROW_ROUTE(app, "/redfish/v1/AccountService/Accounts/<int>/") @@ -84,5 +141,5 @@ void request_routes(Crow<Middlewares...>& app) { {{"@odata.id", "/redfish/v1/AccountService/Roles/NoAccess"}}}}}}; }); } -} -}
\ No newline at end of file +} // namespace redfish +} // namespace crow diff --git a/include/security_headers_middleware.hpp b/include/security_headers_middleware.hpp index 19644f4..e12395a 100644 --- a/include/security_headers_middleware.hpp +++ b/include/security_headers_middleware.hpp @@ -4,34 +4,28 @@ #include <crow/http_response.h> namespace crow { -static const std::string strict_transport_security_key = - "Strict-Transport-Security"; -static const std::string strict_transport_security_value = +static const char* strict_transport_security_key = "Strict-Transport-Security"; +static const char* strict_transport_security_value = "max-age=31536000; includeSubdomains; preload"; -static const std::string ua_compatability_key = "X-UA-Compatible"; -static const std::string ua_compatability_value = "IE=11"; +static const char* ua_compatability_key = "X-UA-Compatible"; +static const char* ua_compatability_value = "IE=11"; -static const std::string xframe_key = "X-Frame-Options"; -static const std::string xframe_value = "DENY"; +static const char* xframe_key = "X-Frame-Options"; +static const char* xframe_value = "DENY"; -static const std::string xss_key = "X-XSS-Protection"; -static const std::string xss_value = "1; mode=block"; - -static const std::string content_security_key = "X-Content-Security-Policy"; -static const std::string content_security_value = "default-src 'self'"; +static const char* xss_key = "X-XSS-Protection"; +static const char* xss_value = "1; mode=block"; +static const char* content_security_key = "X-Content-Security-Policy"; +static const char* content_security_value = "default-src 'self'"; struct SecurityHeadersMiddleware { struct context {}; - void before_handle(crow::request& req, - response& res, - context& ctx) {} + void before_handle(crow::request& req, response& res, context& ctx) {} - void after_handle(request& /*req*/, - response& res, - context& ctx) { + void after_handle(request& req, response& res, context& ctx) { /* TODO(ed) these should really check content types. for example, X-UA-Compatible header doesn't make sense when retrieving a JSON or @@ -43,6 +37,8 @@ struct SecurityHeadersMiddleware { res.add_header(xframe_key, xframe_value); res.add_header(xss_key, xss_value); res.add_header(content_security_key, content_security_value); + res.add_header("Access-Control-Allow-Origin", "http://localhost:8085"); + res.add_header("Access-Control-Allow-Credentials", "true"); } }; -}
\ No newline at end of file +} // namespace crow diff --git a/include/ssl_key_handler.hpp b/include/ssl_key_handler.hpp index 4948025..2a1a852 100644 --- a/include/ssl_key_handler.hpp +++ b/include/ssl_key_handler.hpp @@ -15,11 +15,11 @@ #include <boost/asio.hpp> namespace ensuressl { -static void init_openssl(void); -static void cleanup_openssl(void); -static EVP_PKEY *create_rsa_key(void); -static EVP_PKEY *create_ec_key(void); -static void handle_openssl_error(void); +static void init_openssl(); +static void cleanup_openssl(); +static EVP_PKEY *create_rsa_key(); +static EVP_PKEY *create_ec_key(); +static void handle_openssl_error(); inline bool verify_openssl_key_cert(const std::string &filepath) { bool private_key_valid = false; @@ -31,9 +31,9 @@ inline bool verify_openssl_key_cert(const std::string &filepath) { if (file != NULL) { EVP_PKEY *pkey = PEM_read_PrivateKey(file, NULL, NULL, NULL); int rc; - if (pkey) { + if (pkey != nullptr) { RSA *rsa = EVP_PKEY_get1_RSA(pkey); - if (rsa) { + if (rsa != nullptr) { std::cout << "Found an RSA key\n"; if (RSA_check_key(rsa) == 1) { // private_key_valid = true; @@ -43,12 +43,13 @@ inline bool verify_openssl_key_cert(const std::string &filepath) { RSA_free(rsa); } else { EC_KEY *ec = EVP_PKEY_get1_EC_KEY(pkey); - if (ec) { + if (ec != nullptr) { std::cout << "Found an EC key\n"; if (EC_KEY_check_key(ec) == 1) { private_key_valid = true; } else { - std::cerr << "Key not valid error number " << ERR_get_error() << "\n"; + std::cerr << "Key not valid error number " << ERR_get_error() + << "\n"; } EC_KEY_free(ec); } @@ -56,7 +57,7 @@ inline bool verify_openssl_key_cert(const std::string &filepath) { if (private_key_valid) { X509 *x509 = PEM_read_X509(file, NULL, NULL, NULL); - if (!x509) { + if (x509 == nullptr) { std::cout << "error getting x509 cert " << ERR_get_error() << "\n"; } else { rc = X509_verify(x509, pkey); @@ -64,7 +65,7 @@ inline bool verify_openssl_key_cert(const std::string &filepath) { cert_valid = true; } else { std::cerr << "Error in verifying private key signature " - << ERR_get_error() << "\n"; + << ERR_get_error() << "\n"; } } } @@ -86,12 +87,12 @@ inline void generate_ssl_certificate(const std::string &filepath) { std::cerr << "Generating EC key\n"; EVP_PKEY *pRsaPrivKey = create_ec_key(); - if (pRsaPrivKey) { + if (pRsaPrivKey != nullptr) { std::cerr << "Generating x509 Certificate\n"; // Use this code to directly generate a certificate X509 *x509; x509 = X509_new(); - if (x509) { + if (x509 != nullptr) { // Get a random number from the RNG for the certificate serial number // If this is not random, regenerating certs throws broswer errors std::random_device rd; @@ -111,12 +112,15 @@ inline void generate_ssl_certificate(const std::string &filepath) { X509_NAME *name; name = X509_get_subject_name(x509); - X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC, (unsigned char *)"US", + X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC, + reinterpret_cast<const unsigned char *>("US"), -1, -1, 0); - X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC, - (unsigned char *)"Intel BMC", -1, -1, 0); - X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, - (unsigned char *)"testhost", -1, -1, 0); + X509_NAME_add_entry_by_txt( + name, "O", MBSTRING_ASC, + reinterpret_cast<const unsigned char *>("Intel BMC"), -1, -1, 0); + X509_NAME_add_entry_by_txt( + name, "CN", MBSTRING_ASC, + reinterpret_cast<const unsigned char *>("testhost"), -1, -1, 0); // set the CSR options X509_set_issuer_name(x509, name); @@ -125,7 +129,7 @@ inline void generate_ssl_certificate(const std::string &filepath) { pFile = fopen(filepath.c_str(), "wt"); - if (pFile) { + if (pFile != nullptr) { PEM_write_PrivateKey(pFile, pRsaPrivKey, NULL, NULL, 0, 0, NULL); PEM_write_X509(pFile, x509); @@ -143,7 +147,7 @@ inline void generate_ssl_certificate(const std::string &filepath) { // cleanup_openssl(); } -EVP_PKEY *create_rsa_key(void) { +EVP_PKEY *create_rsa_key() { RSA *pRSA = NULL; #if OPENSSL_VERSION_NUMBER < 0x00908000L pRSA = RSA_generate_key(2048, RSA_3, NULL, NULL); @@ -152,7 +156,8 @@ EVP_PKEY *create_rsa_key(void) { #endif EVP_PKEY *pKey = EVP_PKEY_new(); - if (pRSA && pKey && EVP_PKEY_assign_RSA(pKey, pRSA)) { + if ((pRSA != nullptr) && (pKey != nullptr) && + EVP_PKEY_assign_RSA(pKey, pRSA)) { /* pKey owns pRSA from now */ if (RSA_check_key(pRSA) <= 0) { fprintf(stderr, "RSA_check_key failed.\n"); @@ -162,11 +167,11 @@ EVP_PKEY *create_rsa_key(void) { } } else { handle_openssl_error(); - if (pRSA) { + if (pRSA != nullptr) { RSA_free(pRSA); pRSA = NULL; } - if (pKey) { + if (pKey != nullptr) { EVP_PKEY_free(pKey); pKey = NULL; } @@ -174,17 +179,17 @@ EVP_PKEY *create_rsa_key(void) { return pKey; } -EVP_PKEY *create_ec_key(void) { +EVP_PKEY *create_ec_key() { EVP_PKEY *pKey = NULL; int eccgrp = 0; eccgrp = OBJ_txt2nid("prime256v1"); EC_KEY *myecc = EC_KEY_new_by_curve_name(eccgrp); - if (myecc) { + if (myecc != nullptr) { EC_KEY_set_asn1_flag(myecc, OPENSSL_EC_NAMED_CURVE); EC_KEY_generate_key(myecc); pKey = EVP_PKEY_new(); - if (pKey) { + if (pKey != nullptr) { if (EVP_PKEY_assign_EC_KEY(pKey, myecc)) { /* pKey owns pRSA from now */ if (EC_KEY_check_key(myecc) <= 0) { @@ -196,15 +201,15 @@ EVP_PKEY *create_ec_key(void) { return pKey; } -void init_openssl(void) { - #if OPENSSL_VERSION_NUMBER < 0x10100000L - SSL_load_error_strings(); - OpenSSL_add_all_algorithms(); - RAND_load_file("/dev/urandom", 1024); +void init_openssl() { +#if OPENSSL_VERSION_NUMBER < 0x10100000L + SSL_load_error_strings(); + OpenSSL_add_all_algorithms(); + RAND_load_file("/dev/urandom", 1024); #endif } -void cleanup_openssl(void) { +void cleanup_openssl() { CRYPTO_cleanup_all_ex_data(); ERR_free_strings(); #if OPENSSL_VERSION_NUMBER < 0x10100000L @@ -213,7 +218,7 @@ void cleanup_openssl(void) { EVP_cleanup(); } -void handle_openssl_error(void) { ERR_print_errors_fp(stderr); } +void handle_openssl_error() { ERR_print_errors_fp(stderr); } inline void ensure_openssl_key_present_and_valid(const std::string &filepath) { bool pem_file_valid = false; @@ -225,7 +230,8 @@ inline void ensure_openssl_key_present_and_valid(const std::string &filepath) { } } -boost::asio::ssl::context get_ssl_context(std::string ssl_pem_file) { +inline boost::asio::ssl::context get_ssl_context( + const std::string &ssl_pem_file) { boost::asio::ssl::context m_ssl_context{boost::asio::ssl::context::sslv23}; m_ssl_context.set_options(boost::asio::ssl::context::default_workarounds | boost::asio::ssl::context::no_sslv2 | @@ -249,7 +255,7 @@ boost::asio::ssl::context get_ssl_context(std::string ssl_pem_file) { } // From mozilla "compatibility" - std::string ciphers = + std::string mozilla_compatibility_ciphers = "ECDHE-ECDSA-CHACHA20-POLY1305:" "ECDHE-RSA-CHACHA20-POLY1305:" "ECDHE-ECDSA-AES128-GCM-SHA256:" @@ -283,7 +289,7 @@ boost::asio::ssl::context get_ssl_context(std::string ssl_pem_file) { "!DSS"; // From mozilla "modern" - std::string modern_ciphers = + std::string mozilla_modern_ciphers = "ECDHE-ECDSA-AES256-GCM-SHA384:" "ECDHE-RSA-AES256-GCM-SHA384:" "ECDHE-ECDSA-CHACHA20-POLY1305:" @@ -295,14 +301,14 @@ boost::asio::ssl::context get_ssl_context(std::string ssl_pem_file) { "ECDHE-ECDSA-AES128-SHA256:" "ECDHE-RSA-AES128-SHA256"; - std::string lighttp_ciphers = "AES128+EECDH:AES128+EDH:!aNULL:!eNULL"; + std::string aes_only_ciphers = "AES128+EECDH:AES128+EDH:!aNULL:!eNULL"; - if (SSL_CTX_set_cipher_list(m_ssl_context.native_handle(), lighttp_ciphers.c_str()) != - 1) { + if (SSL_CTX_set_cipher_list(m_ssl_context.native_handle(), + mozilla_compatibility_ciphers.c_str()) != 1) { CROW_LOG_ERROR << "Error setting cipher list\n"; } return m_ssl_context; } -} +} // namespace ensuressl #endif
\ No newline at end of file diff --git a/include/test_utils.hpp b/include/test_utils.hpp deleted file mode 100644 index eb990d5..0000000 --- a/include/test_utils.hpp +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once - -#include <string> - -bool gzipInflate(const std::string& compressedBytes, - std::string& uncompressedBytes);
\ No newline at end of file diff --git a/include/token_authorization_middleware.hpp b/include/token_authorization_middleware.hpp index 2d1edcd..eebd4f0 100644 --- a/include/token_authorization_middleware.hpp +++ b/include/token_authorization_middleware.hpp @@ -1,32 +1,32 @@ #pragma once +#include <base64.hpp> +#include <pam_authenticate.hpp> +#include <webassets.hpp> +#include <random> +#include <crow/app.h> #include <crow/http_request.h> #include <crow/http_response.h> #include <boost/container/flat_set.hpp> -#include <base64.hpp> - -#include <pam_authenticate.hpp> - namespace crow { +namespace TokenAuthorization { struct User {}; using random_bytes_engine = - std::independent_bits_engine<std::default_random_engine, CHAR_BIT, - unsigned char>; - -template <class AuthenticationFunction> -struct TokenAuthorization { - private: - random_bytes_engine rbe; + std::independent_bits_engine<std::random_device, CHAR_BIT, unsigned char>; +class Middleware { public: - struct context { - // std::string auth_token; + Middleware() { + for (auto& route : crow::webassets::routes) { + allowed_routes.emplace(route); + } + allowed_routes.emplace("/login"); }; - TokenAuthorization(){}; + struct context {}; void before_handle(crow::request& req, response& res, context& ctx) { auto return_unauthorized = [&req, &res]() { @@ -34,100 +34,64 @@ struct TokenAuthorization { res.end(); }; - auto return_bad_request = [&req, &res]() { - res.code = 400; - res.end(); - }; - - auto return_internal_error = [&req, &res]() { - res.code = 500; - res.end(); - }; - - if (req.url == "/" || boost::starts_with(req.url, "/static/")) { + if (allowed_routes.find(req.url.c_str()) != allowed_routes.end()) { // 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 for based page - // that didn't load the full angular UI until after login - return; - } - - if (req.url == "/login") { - if (req.method != HTTPMethod::POST) { - return_unauthorized(); - return; - } else { - std::string username; - std::string password; - try { - auto login_credentials = nlohmann::json::parse(req.body); - username = login_credentials["username"]; - password = login_credentials["password"]; - } catch (...) { - return_bad_request(); - return; - } - - auto p = AuthenticationFunction(); - if (p.authenticate(username, password)) { - nlohmann::json x; - - std::string token('a', 20); - // TODO(ed) for some reason clang-tidy finds a divide by zero error in - // cstdlibc here commented out for now. Needs investigation - std::generate(std::begin(token), std::end(token), - std::ref(rbe)); // NOLINT - std::string encoded_token; - base64::base64_encode(token, encoded_token); - // ctx.auth_token = encoded_token; - this->auth_token2.insert(encoded_token); - - nlohmann::json ret{{"token", encoded_token}}; - - res.write(ret.dump()); - res.add_header("Content-Type", "application/json"); - res.end(); - } else { + // should be done in the url router handler, with tagged routes for the + // whitelist entries. Another option would be to whitelist a minimal form + // based page that didn't load the full angular UI until after login + } else { + // Normal, non login, non static file request + // Check for an authorization header, reject if not present + std::string auth_key; + if (req.headers.count("Authorization") == 1) { + std::string auth_header = req.get_header_value("Authorization"); + // If the user is attempting any kind of auth other than token, reject + if (!boost::starts_with(auth_header, "Token ")) { return_unauthorized(); return; } + auth_key = auth_header.substr(6); + } else { + int count = req.headers.count("Cookie"); + if (count == 1) { + auto& cookie_value = req.get_header_value("Cookie"); + auto start_index = cookie_value.find("SESSION="); + if (start_index != std::string::npos) { + start_index += 8; + auto end_index = cookie_value.find(";", start_index); + if (end_index == std::string::npos) { + end_index = cookie_value.size() - 1; + } + auth_key = + cookie_value.substr(start_index, end_index - start_index + 1); + } + } } - - } else { // Normal, non login, non static file request - // Check to make sure we're logged in - if (this->auth_token2.empty()) { - return_unauthorized(); - return; - } - // Check for an authorization header, reject if not present - if (req.headers.count("Authorization") != 1) { - return_unauthorized(); + if (auth_key.empty()) { + res.code = 400; + res.end(); return; } + std::cout << "auth_key=" << auth_key << "\n"; - std::string auth_header = req.get_header_value("Authorization"); - // If the user is attempting any kind of auth other than token, reject - if (!boost::starts_with(auth_header, "Token ")) { - return_unauthorized(); - return; + for (auto& token : this->auth_tokens) { + std::cout << "token=" << token << "\n"; } - std::string auth_key = auth_header.substr(6); + // TODO(ed), use span here instead of constructing a new string - if (this->auth_token2.find(auth_key) == this->auth_token2.end()) { + if (this->auth_tokens.find(auth_key) == this->auth_tokens.end()) { return_unauthorized(); return; } if (req.url == "/logout") { - this->auth_token2.erase(auth_key); + this->auth_tokens.erase(auth_key); res.code = 200; res.end(); return; } - // else let the request continue unharmed } } @@ -136,9 +100,128 @@ struct TokenAuthorization { // Do nothing } - private: - boost::container::flat_set<std::string> auth_token2; + boost::container::flat_set<std::string> auth_tokens; + boost::container::flat_set<std::string> allowed_routes; + random_bytes_engine rbe; }; -using TokenAuthorizationMiddleware = TokenAuthorization<PamAuthenticator>; -}
\ No newline at end of file +// TODO(ed) see if there is a better way to allow middlewares to request routes. +// Possibly an init function on first construction? +template <typename... Middlewares> +void request_routes(Crow<Middlewares...>& app) { + static_assert(black_magic::contains<TokenAuthorization::Middleware, + Middlewares...>::value, + "TokenAuthorization middleware must be enabled in app to use " + "auth routes"); + CROW_ROUTE(app, "/login") + .methods( + "POST"_method)([&](const crow::request& req, crow::response& res) { + std::string content_type; + auto content_type_it = req.headers.find("content-type"); + if (content_type_it != req.headers.end()) { + content_type = content_type_it->second; + boost::algorithm::to_lower(content_type); + } + std::string username; + std::string password; + bool looks_like_ibm = false; + // Check if auth was provided by a payload + if (content_type == "application/json") { + try { + auto login_credentials = nlohmann::json::parse(req.body); + // check for username/password in the root object + // THis method is how intel APIs authenticate + auto user_it = login_credentials.find("username"); + auto pass_it = login_credentials.find("password"); + if (user_it != login_credentials.end() && + pass_it != login_credentials.end()) { + username = user_it->get<const std::string>(); + password = pass_it->get<const std::string>(); + } else { + // Openbmc appears to push a data object that contains the same + // keys (username and password), attempt to use that + auto data_it = login_credentials.find("data"); + if (data_it != login_credentials.end()) { + // Some apis produce an array of value ["username", "password"] + if (data_it->is_array()) { + if (data_it->size() == 2) { + username = (*data_it)[0].get<const std::string>(); + password = (*data_it)[1].get<const std::string>(); + looks_like_ibm = true; + } + } else if (data_it->is_object()) { + auto user_it = data_it->find("username"); + auto pass_it = data_it->find("password"); + if (user_it != data_it->end() && pass_it != data_it->end()) { + username = user_it->get<const std::string>(); + password = pass_it->get<const std::string>(); + } + } + } + } + } catch (...) { + // TODO(ed) figure out how to not throw on a bad json parse + res.code = 400; + res.end(); + return; + } + } else { + // check if auth was provided as a query string + auto user_it = req.headers.find("username"); + auto pass_it = req.headers.find("password"); + if (user_it != req.headers.end() && pass_it != req.headers.end()) { + username = user_it->second; + password = pass_it->second; + } + } + + if (!username.empty() && !password.empty()) { + if (!pam_authenticate_user(username, password)) { + res.code = 401; + } else { + // THis should be a multiple of 3 to make sure that base64 doesn't + // end with an equals sign at the end. we could strip it off + // afterward + std::string token(30, 'a'); + // TODO(ed) for some reason clang-tidy finds a divide by zero + // error in cstdlibc here commented out for now. + // Needs investigation + auto& m = app.template get_middleware<Middleware>(); + std::generate(std::begin(token), std::end(token), + std::ref(m.rbe)); // NOLINT + std::string encoded_token; + if (!base64::base64_encode(token, encoded_token)) { + res.code = 500; + } else { + + m.auth_tokens.insert(encoded_token); + if (looks_like_ibm) { + // IBM requires a very specific login structure, and doesn't + // actually look at the status code. TODO(ed).... Fix that + // upstream + nlohmann::json ret{ + {"data", "User '" + username + "' logged in"}, + {"message", "200 OK"}, + {"status", "ok"}}; + res.add_header( + "Set-Cookie", + "SESSION=" + encoded_token + "; Secure; HttpOnly"); + res.write(ret.dump()); + } else { + // if content type is json, assume json token + nlohmann::json ret{{"token", encoded_token}}; + + res.write(ret.dump()); + res.add_header("Content-Type", "application/json"); + } + } + } + + } else { + res.code = 400; + } + res.end(); + }); +} +} // namespaec TokenAuthorization +} // namespace crow
\ No newline at end of file diff --git a/include/web_kvm.hpp b/include/web_kvm.hpp index 3d33347..82cb488 100644 --- a/include/web_kvm.hpp +++ b/include/web_kvm.hpp @@ -119,20 +119,20 @@ enum class encoding_type : uint32_t { }; struct framebuffer_rectangle { - boost::endian::big_uint16_t x; - boost::endian::big_uint16_t y; - boost::endian::big_uint16_t width; - boost::endian::big_uint16_t height; - boost::endian::big_uint32_t encoding; + boost::endian::big_uint16_t x{}; + boost::endian::big_uint16_t y{}; + boost::endian::big_uint16_t width{}; + boost::endian::big_uint16_t height{}; + boost::endian::big_uint32_t encoding{}; std::vector<uint8_t> data; }; struct framebuffer_update_msg { - boost::endian::big_uint8_t message_type; + boost::endian::big_uint8_t message_type{}; std::vector<framebuffer_rectangle> rectangles; }; -std::string serialize(const framebuffer_update_msg& msg) { +inline std::string serialize(const framebuffer_update_msg& msg) { // calculate the size of the needed vector for serialization size_t vector_size = 4; for (const auto& rect : msg.rectangles) { @@ -174,12 +174,12 @@ enum class VncState { class connection_metadata { public: - connection_metadata(void) : vnc_state(VncState::UNSTARTED){}; + connection_metadata() {}; - VncState vnc_state; + VncState vnc_state{VncState::UNSTARTED}; }; -typedef std::vector<connection_metadata> meta_list; +using meta_list = std::vector<connection_metadata>; meta_list connection_states(10); connection_metadata meta; @@ -235,7 +235,7 @@ void request_routes(Crow<Middlewares...>& app) { } break; case VncState::AWAITING_CLIENT_INIT_msg: { // Now send the server initialization - server_initialization_msg server_init_msg; + server_initialization_msg server_init_msg{}; server_init_msg.framebuffer_width = 800; server_init_msg.framebuffer_height = 600; server_init_msg.pixel_format.bits_per_pixel = 32; @@ -261,8 +261,8 @@ void request_routes(Crow<Middlewares...>& app) { case VncState::MAIN_LOOP: { if (data.size() >= sizeof(client_to_server_msg_type)) { auto type = static_cast<client_to_server_msg_type>(data[0]); - std::cout << "Received client message type " << (uint32_t)type - << "\n"; + std::cout << "Received client message type " + << static_cast<std::size_t>(type) << "\n"; switch (type) { case client_to_server_msg_type::set_pixel_format: { } break; @@ -277,7 +277,9 @@ void request_routes(Crow<Middlewares...>& app) { if (data.size() >= sizeof(frame_buffer_update_req) + sizeof(client_to_server_msg_type)) { auto msg = reinterpret_cast<const frame_buffer_update_req*>( - data.data() + sizeof(client_to_server_msg_type)); + data.data() + // NOLINT + sizeof(client_to_server_msg_type)); + // TODO(ed) find a better way to do this deserialization // Todo(ed) lifecycle of the video puller and decoder // should be @@ -302,10 +304,11 @@ void request_routes(Crow<Middlewares...>& app) { this_rect.encoding = static_cast<uint8_t>(encoding_type::raw); std::cout << "Encoding is " << this_rect.encoding; - this_rect.data.reserve(this_rect.width * this_rect.height * - 4); + this_rect.data.reserve( + static_cast<std::size_t>(this_rect.width) * + static_cast<std::size_t>(this_rect.height) * 4); std::cout << "Width " << out.width << " Height " - << out.height; + << out.height; for (int i = 0; i < out.width * out.height; i++) { auto& pixel = d.OutBuffer[i]; @@ -349,5 +352,5 @@ void request_routes(Crow<Middlewares...>& app) { }); } -} -}
\ No newline at end of file +} // namespace kvm +} // namespace crow
\ No newline at end of file diff --git a/include/webassets.hpp b/include/webassets.hpp new file mode 100644 index 0000000..988af76 --- /dev/null +++ b/include/webassets.hpp @@ -0,0 +1,118 @@ +#pragma once + +#include <experimental/filesystem> +#include <fstream> +#include <string> +#include <crow/app.h> +#include <crow/http_request.h> +#include <crow/http_response.h> +#include <crow/routing.h> +#include <boost/algorithm/string/replace.hpp> +#include <boost/container/flat_set.hpp> + +namespace crow { +namespace webassets { + +namespace filesystem = std::experimental::filesystem; +static const char* gzip_string = "gzip"; +static const char* none_string = "none"; +static const char* if_none_match_string = "If-None-Match"; +static const char* content_encoding_string = "Content-Encoding"; +static const char* content_type_string = "Content-Type"; +static const char* etag_string = "ETag"; + +static boost::container::flat_set<std::string> routes; + +template <typename... Middlewares> +void request_routes(Crow<Middlewares...>& app) { + const static boost::container::flat_map<const char*, const char*> content_types{ + {{".css", "text/css;charset=UTF-8"}, + {".html", "text/html;charset=UTF-8"}, + {".js", "text/html;charset=UTF-8"}, + {".png", "image/png;charset=UTF-8"}, + {".woff", "application/x-font-woff"}, + {".woff2", "application/x-font-woff2"}, + {".ttf", "application/x-font-ttf"}, + {".svg", "image/svg+xml"}, + {".eot", "application/vnd.ms-fontobject"}, + // dev tools don't care about map type, setting to json causes + // browser to show as text + // https://stackoverflow.com/questions/19911929/what-mime-type-should-i-use-for-javascript-source-map-files + {".map", "application/json"}}}; + auto rootpath = filesystem::path("/usr/share/www/"); + auto dir_iter = filesystem::recursive_directory_iterator(rootpath); + for (auto& dir : dir_iter) { + auto absolute_path = dir.path(); + auto relative_path = filesystem::path( + absolute_path.string().substr(rootpath.string().size() - 1)); + // make sure we don't recurse into certain directories + // note: maybe check for is_directory() here as well... + if (filesystem::is_directory(dir)) { + // don't recurse into hidden directories or symlinks + if (boost::starts_with(dir.path().filename().string(), ".") || + filesystem::is_symlink(dir)) { + dir_iter.disable_recursion_pending(); + } + } else if (filesystem::is_regular_file(dir)) { + auto webpath = relative_path; + bool is_gzip = false; + if (relative_path.extension() == ".gz") { + webpath = webpath.replace_extension(""); + is_gzip = true; + } + + if (webpath.filename() == "index.html") { + webpath = webpath.parent_path(); + } + + routes.insert(webpath.string()); + + std::string absolute_path_str = absolute_path.string(); + const char* content_type = nullptr; + auto content_type_it = + content_types.find(relative_path.extension().c_str()); + if (content_type_it != content_types.end()) { + content_type = content_type_it->second; + } + app.route_dynamic(std::string(webpath.string()))( + [is_gzip, absolute_path_str, content_type](const crow::request& req, + crow::response& res) { + if (is_gzip) { + res.add_header(content_encoding_string, gzip_string); + } else { + res.add_header(content_encoding_string, none_string); + } + // std::string sha1("a576dc96a5c605b28afb032f3103630d61ac1068"); + // res.add_header(etag_string, sha1); + + // if (req.get_header_value(if_none_match_string) == sha1) { + // res.code = 304; + //} else { + // res.code = 200; + // TODO, if you have a browser from the dark ages that doesn't + // support + // gzip, unzip it before sending based on Accept-Encoding header + // res.add_header(content_encoding_string, gzip_string); + if (content_type != nullptr) { + res.add_header(content_type_string, content_type); + } + // res.set_header("Cache-Control", "public, max-age=86400"); + std::ifstream inf(absolute_path_str); + if (!inf) { + CROW_LOG_DEBUG << "failed to read file"; + res.code = 400; + res.end(); + return; + } + + std::string body{std::istreambuf_iterator<char>(inf), + std::istreambuf_iterator<char>()}; + + res.body = body; + res.end(); + }); + } + } +} +} // namespace webassets +} // namespace crow
\ No newline at end of file |

