From 497745ad31c90545b288e2845049e0ce474bcbe2 Mon Sep 17 00:00:00 2001 From: gcontini <1121667+gcontini@users.noreply.github.com> Date: 周六, 19 10月 2019 10:10:45 +0800 Subject: [PATCH] Merge branch 'feature/code_review_and_refactor' into develop --- src/library/locate/EnvironmentVarData.hpp | 29 src/library/api/datatypes.h | 49 src/library/locate/ExternalDefinition.hpp | 30 src/library/os/os.h | 10 src/library/locate/EnvironmentVarLocation.hpp | 27 src/library/locate/LocatorStrategy.cpp | 23 test/functional/generate-license.h | 4 test/functional/CMakeLists.txt | 30 test/functional/hijiaking_test.cpp | 6 src/library/locate/LocatorFactory.hpp | 32 src/tools/license-generator/license-generator.h | 13 src/library/locate/ApplicationFolder.cpp | 56 test/library/LicenseLocator_test.cpp | 217 +++ CONTRIBUTING.md | 9 test/functional/volid_test.cpp | 10 README.md | 2 src/tools/license-generator/CMakeLists.txt | 3 src/library/LicenseReader.cpp | 334 +--- src/library/locate/CMakeLists.txt | 18 src/library/base/FileUtils.hpp | 22 src/library/locate/ExternalDefinition.cpp | 76 + .gitignore | 6 src/library/base/base64.h | 140 -- src/library/api/license++.h | 44 src/tools/license-generator/license-generator.cpp | 141 + test/functional/generate-license.cpp | 3 src/library/locate/EnvironmentVarData.cpp | 67 + src/library/base/base64.c | 133 ++ src/library/locate/LocatorStrategy.hpp | 60 + src/library/base/CMakeLists.txt | 2 test/library/CMakeLists.txt | 54 src/library/base/EventRegistry.h | 56 src/library/base/base.h | 6 src/library/locate/ApplicationFolder.hpp | 28 src/library/locate/LocatorFactory.cpp | 46 test/functional/standard-license_test.cpp | 50 test/license-generator/license-generator_test.cpp | 5 test/library/EventRegistry_test.cpp | 41 src/library/base/StringUtils.cpp | 49 src/library/CMakeLists.txt | 10 src/library/base/FileUtils.cpp | 69 + test/functional/date_test.cpp | 26 src/library/base/EventRegistry.cpp | 190 ++- test/library/LicenseReader_test.cpp | 95 + example/example.cpp | 77 src/library/license++.cpp | 29 /dev/null | 13 src/library/locate/EnvironmentVarLocation.cpp | 46 src/library/LicenseReader.hpp | 84 + src/library/base/StringUtils.h | 21 src/tools/base_lib/win/CryptoHelperWindows.h | 92 src/build_properties.h.in | 14 example/CMakeLists.txt | 5 src/tools/base_lib/win/CryptoHelperWindows.cpp | 788 ++++++------ 54 files changed, 2,318 insertions(+), 1,172 deletions(-) diff --git a/.gitignore b/.gitignore index 6cd6db1..7165b6c 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,9 @@ *.so *.dylib +#Visual studio files +.vs + # Compiled Static libraries *.lai *.la @@ -21,4 +24,5 @@ .cproject .settings .project -*.out \ No newline at end of file +*.out +/Default/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9cd24af..32db051 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -18,7 +18,8 @@ * **Use a clear and descriptive title** for the issue to identify the problem. * **Describe the exact steps which reproduce the problem** in as many details as possible. For example, start by explaining how are you using Open License Manager. -* **Provide specific examples to demonstrate the steps**. Include links to files or GitHub projects, or licenses, which can cause the bug. If you're providing code snippets in the issue, use [Markdown code blocks](https://help.github.com/articles/markdown-basics/#multiple-lines). The best way to report a bug is to **design a test** to demonstrate it. +* **Provide specific examples to demonstrate the steps**. Include links to files or GitHub projects, or licenses, which can cause the bug. If you're providing code snippets in the issue, use [Markdown code blocks](https://help.github.com/articles/markdown-basics/#multiple-lines). +* **Provide a boost unit test to demonstrate the bug**. The best way to report a bug, and to have it fixed **forever** is to design a test to demonstrate it. * **If you're reporting that Open License Manager crashed**, include a crash dump and the associated message. * **Label the issue as bug.** @@ -79,8 +80,8 @@ ##### Don't * Don't reformat the code following your personal likes, it introduce a lot of "noise" and makes very hard to merge. - * Very large pull requests with few comments, no corresponding issue will probably be rejected. - * We understand that the project is still in a very alpha stage and a rearrangement is needed, however we would like to discuss it with you before we take project changing decision. - * We can't break current functionality, user established habits without documenting the change. + * Very large pull requests with few comments, no corresponding issue explaining what's it about will probably be rejected. + * We understand that the project is still in a very alpha stage and a rearrangement is needed, however we would like to discuss it with you before we take project changing decision. Please contact the project maintainer at `contini.mailing[AT]gmail.com` if you have time and plan to do a large contribution. + * Even it it's in alpha stage it's used ( _by some really courageous people!_ ) in production. We can't break current functionality, user established habits without documenting the change. \ No newline at end of file diff --git a/README.md b/README.md index 3b096d7..72838b4 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [](https://travis-ci.org/open-license-manager/open-license-manager) [](http://github.com/badges/stability-badges)[](https://opensource.org/licenses/BSD-3-Clause) -A copy protection, licensing software written in C/C++ for Windows and Linux. +A copy protection, licensing software written in C++ for Windows and Linux (with a simple C api for use in C projects). It allows to protect the software you develop from unauthorized copies, limit the usage in time, to a specific set of machines, or prevent the usage in diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index cbd53b6..87016f4 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -1,4 +1,3 @@ -#cmake_minimum_required(VERSION 3.0) cmake_minimum_required(VERSION 2.8.11) link_directories ( "${CMAKE_CURRENT_SOURCE_DIR}/../install/lib" ) @@ -10,7 +9,7 @@ SET(CMAKE_FIND_LIBRARY_SUFFIXES .lib ) else(MSVC) set(CMAKE_FIND_LIBRARY_SUFFIXES .a .so) -set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s -Wl,--exclude-libs,liblicensepp_static.a") +set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s -Wl,--exclude-libs,liblicensecc_static.a") find_package(OpenSSL REQUIRED) endif(MSVC) @@ -18,7 +17,7 @@ add_executable(example example.cpp) -target_link_libraries(example licensepp_static os base tools_base) +target_link_libraries(example licensecc_static os base tools_base) if(NOT MSVC) target_link_libraries(example crypto pthread dl z) diff --git a/example/example.cpp b/example/example.cpp index 45370dd..2379d6a 100644 --- a/example/example.cpp +++ b/example/example.cpp @@ -2,55 +2,46 @@ #include <map> #include "api/license++.h" #include "pc-identifiers.h" -#include "ini/SimpleIni.h" using namespace std; -int main(int argc, char *argv[]) -{ - map<EVENT_TYPE, string> stringByEventType; - stringByEventType[LICENSE_OK ] = "OK "; - stringByEventType[LICENSE_FILE_NOT_FOUND ] = "license file not found "; - stringByEventType[LICENSE_SERVER_NOT_FOUND ] = "license server can't be contacted "; - stringByEventType[ENVIRONMENT_VARIABLE_NOT_DEFINED] = "environment variable not defined "; - stringByEventType[FILE_FORMAT_NOT_RECOGNIZED ] = "license file has invalid format (not .ini file) "; - stringByEventType[LICENSE_MALFORMED ] = "some mandatory field are missing, or data can't be fully read. "; - stringByEventType[PRODUCT_NOT_LICENSED ] = "this product was not licensed "; - stringByEventType[PRODUCT_EXPIRED ] = "license expired "; - stringByEventType[LICENSE_CORRUPTED ] = "license signature didn't match with current license "; - stringByEventType[IDENTIFIERS_MISMATCH ] = "Calculated identifier and the one provided in license didn't match"; - stringByEventType[LICENSE_FILE_FOUND ] = "license file not found "; - stringByEventType[LICENSE_VERIFIED ] = "license verified "; - - const string licLocation("example.lic"); - - LicenseInfo licenseInfo; - LicenseLocation licenseLocation; - licenseLocation.openFileNearModule = false; - licenseLocation.licenseFileLocation = licLocation.c_str(); - licenseLocation.environmentVariableName = ""; - EVENT_TYPE result = acquire_license("example", licenseLocation, &licenseInfo); - PcSignature signature; - FUNCTION_RETURN generate_ok = generate_user_pc_signature(signature, DEFAULT); +int main(int argc, char *argv[]) { + map<EVENT_TYPE, string> stringByEventType; + stringByEventType[LICENSE_OK] = "OK "; + stringByEventType[LICENSE_FILE_NOT_FOUND] = "license file not found "; + stringByEventType[LICENSE_SERVER_NOT_FOUND] = "license server can't be contacted "; + stringByEventType[ENVIRONMENT_VARIABLE_NOT_DEFINED] = "environment variable not defined "; + stringByEventType[FILE_FORMAT_NOT_RECOGNIZED] = "license file has invalid format (not .ini file) "; + stringByEventType[LICENSE_MALFORMED] = "some mandatory field are missing, or data can't be fully read. "; + stringByEventType[PRODUCT_NOT_LICENSED] = "this product was not licensed "; + stringByEventType[PRODUCT_EXPIRED] = "license expired "; + stringByEventType[LICENSE_CORRUPTED] = "license signature didn't match with current license "; + stringByEventType[IDENTIFIERS_MISMATCH] = "Calculated identifier and the one provided in license didn't match"; - if (result == LICENSE_OK && licenseInfo.linked_to_pc) { - CSimpleIniA ini; - SI_Error rc = ini.LoadFile(licLocation.c_str()); - string IDinLicense = ini.GetValue("example", "client_signature", ""); - if (IDinLicense == "") { - cout << "No client signature in license file, generate license with -s <id>"; + LicenseInfo licenseInfo; + EVENT_TYPE result = acquire_license("example", nullptr, &licenseInfo); + + if (result == LICENSE_OK) { + //for this example we want to link the license to the execution hardware. + if (licenseInfo.linked_to_pc) { + cout + << "No client signature in license file, generate license with -s <id>"; result = IDENTIFIERS_MISMATCH; - } else if (IDinLicense != signature) { - result = IDENTIFIERS_MISMATCH; + } else { + cout << "license OK" << endl; + } + } + if (result != LICENSE_OK) { + cout << "license ERROR :" << endl; + cout << " " << stringByEventType[result].c_str() << endl; + if (result == IDENTIFIERS_MISMATCH) { + PcSignature signature; + FUNCTION_RETURN generate_ok = generate_user_pc_signature(signature, + DEFAULT); + cout << "the pc signature is :" << endl; + cout << " " << signature << endl; } } - if (result != LICENSE_OK) { - cout << "license ERROR :" << endl; - cout << " " << stringByEventType[result].c_str() << endl; - cout << "the pc signature is :" << endl; - cout << " " << signature << endl; - } - else - cout << "license OK" << endl; + return result; } diff --git a/src/build_properties.h.in b/src/build_properties.h.in index 240ff99..a15ef5e 100644 --- a/src/build_properties.h.in +++ b/src/build_properties.h.in @@ -1,12 +1,24 @@ #ifndef BUILD_PROPERTIES_H_ #define BUILD_PROPERTIES_H_ +//License retrieval configuration +#define FIND_LICENSE_NEAR_MODULE 1 +#define FIND_LICENSE_WITH_ENV_VAR 1 + +#define LICENSE_LOCATION_ENV_VAR "LICENSE_LOCATION" +#define LICENSE_DATA_ENV_VAR "LICENSE_DATA" + +//Internal data structures limits +#define MAX_LICENSE_LENGTH 256*1024 + +//Build locations and parameters #define PROJECT_INT_VERSION @LICENSECC_INT_VERSION@ #define PROJECT_VERSION "@LICENSECC_VERSION@" #define PROJECT_BINARY_DIR "@CMAKE_BINARY_DIR@" #define PROJECT_SRC_DIR "@CMAKE_CURRENT_LIST_DIR@" #define PROJECT_BASE_DIR "@CMAKE_SOURCE_DIR@" #define PROJECT_TEST_SRC_DIR "@CMAKE_SOURCE_DIR@/test" -#define PROJECT_TEST_TEMP_DIR "Testing/Temporary" +#define PROJECT_TEST_TEMP_DIR "@CMAKE_BINARY_DIR@/Testing/Temporary" #define BUILD_TYPE "@CMAKE_BUILD_TYPE@" + #endif diff --git a/src/library/CMakeLists.txt b/src/library/CMakeLists.txt index d1f0813..0589736 100644 --- a/src/library/CMakeLists.txt +++ b/src/library/CMakeLists.txt @@ -1,20 +1,24 @@ add_subdirectory("os") add_subdirectory("base") add_subdirectory("ini") +add_subdirectory("locate") -ADD_LIBRARY(licensepp_static STATIC + +ADD_LIBRARY(licensecc_static STATIC license++.cpp LicenseReader.cpp pc-identifiers.c ) target_link_libraries( - licensepp_static + licensecc_static ini + locators os + base ) -install(TARGETS licensepp_static ARCHIVE DESTINATION lib) +install(TARGETS licensecc_static ARCHIVE DESTINATION lib) install(FILES api/datatypes.h api/license++.h DESTINATION include/api) install(FILES base/base.h DESTINATION include/base) install(FILES pc-identifiers.h DESTINATION include/) diff --git a/src/library/LicenseReader.cpp b/src/library/LicenseReader.cpp index 9927426..84de09d 100644 --- a/src/library/LicenseReader.cpp +++ b/src/library/LicenseReader.cpp @@ -2,7 +2,7 @@ * LicenseReader.cpp * * Created on: Mar 30, 2014 - * + * */ #ifdef _WIN32 @@ -10,6 +10,7 @@ #else # include <unistd.h> #endif + #include <cstring> #include <ctime> #include <vector> @@ -17,24 +18,27 @@ #include <iterator> #include <fstream> #include <sstream> + #include <stdlib.h> #include <math.h> + #include "pc-identifiers.h" -#include "LicenseReader.h" +#include "build_properties.h" +#include "public-key.h" +#include "LicenseReader.hpp" #include "base/StringUtils.h" #include "base/logger.h" -#include "public-key.h" -#include <build_properties.h> +#include "locate/LocatorFactory.hpp" namespace license { const char *FullLicenseInfo::UNUSED_TIME = "0000-00-00"; -FullLicenseInfo::FullLicenseInfo(const string& source, const string& product, - const string& license_signature, int licenseVersion, string from_date, - string to_date, const string& client_signature, +FullLicenseInfo::FullLicenseInfo(const string &source, const string &product, + const string &license_signature, int licenseVersion, string from_date, + string to_date, const string &client_signature, unsigned int from_sw_version, unsigned int to_sw_version, - const string& extra_data) : + const string &extra_data) : source(source), product(product), // license_signature(license_signature), license_version(licenseVersion), // from_date(from_date), to_date(to_date), // @@ -48,38 +52,45 @@ extra_data(extra_data) { } -EventRegistry FullLicenseInfo::validate(int sw_version) { - EventRegistry er; +bool FullLicenseInfo::validate(int sw_version, + EventRegistry &eventRegistryOut) { os_initialize(); const FUNCTION_RETURN sigVer = verifySignature(printForSign().c_str(), license_signature.c_str()); - const bool sigVerified = sigVer == FUNC_RET_OK; - if (sigVerified) { - er.addEvent(LICENSE_VERIFIED, SVRT_INFO); + bool is_valid = (sigVer == FUNC_RET_OK); + if (is_valid) { + eventRegistryOut.addEvent(SIGNATURE_VERIFIED, source); } else { - er.addEvent(LICENSE_CORRUPTED, SVRT_ERROR); + eventRegistryOut.addEvent(LICENSE_CORRUPTED, source); } if (has_expiry) { + cout<<source<<endl; const time_t now = time(nullptr); if (expires_on() < now) { - er.addEvent(PRODUCT_EXPIRED, SVRT_ERROR, ""); +/* + eventRegistryOut.addEvent(PRODUCT_EXPIRED, source.c_str(), + string("Expired on: " + this->to_date).c_str());*/ + eventRegistryOut.addEvent(PRODUCT_EXPIRED, source.c_str(),nullptr); + is_valid = false; } if (valid_from() > now) { - er.addEvent(PRODUCT_EXPIRED, SVRT_ERROR); + /*eventRegistryOut.addEvent(PRODUCT_EXPIRED, source.c_str(), + string("Valid from " + this->from_date).c_str());*/ + eventRegistryOut.addEvent(PRODUCT_EXPIRED, source.c_str(),nullptr); + is_valid = false; } } if (has_client_sig) { PcSignature str_code; - strncpy(str_code, client_signature.c_str(), sizeof(str_code)-1); + strncpy(str_code, client_signature.c_str(), sizeof(str_code) - 1); const EVENT_TYPE event = validate_pc_signature(str_code); - if (event != LICENSE_OK) { - er.addEvent(event, SVRT_ERROR); - } + eventRegistryOut.addEvent(event, source); + is_valid = is_valid && (event == LICENSE_OK); } - return er; + return is_valid; } -void FullLicenseInfo::toLicenseInfo(LicenseInfo* license) const { +void FullLicenseInfo::toLicenseInfo(LicenseInfo *license) const { if (license != nullptr) { strncpy(license->proprietary_data, extra_data.c_str(), PROPRIETARY_DATA_SIZE); @@ -91,225 +102,106 @@ license->days_left = 999999; } else { strncpy(license->expiry_date, to_date.c_str(), 11); - const double secs = difftime( - seconds_from_epoch(to_date.c_str()), - time(nullptr)); + const double secs = difftime(seconds_from_epoch(to_date.c_str()), + time(nullptr)); license->days_left = round(secs / (60 * 60 * 24)); } } } -LicenseReader::LicenseReader(const LicenseLocation& licenseLocation) : - licenseLocation(licenseLocation) { +LicenseReader::LicenseReader(const LicenseLocation* licenseLocation) : + licenseLocation(licenseLocation) { } EventRegistry LicenseReader::readLicenses(const string &product, - vector<FullLicenseInfo>& licenseInfoOut) { + vector<FullLicenseInfo> &licenseInfoOut) { vector<string> diskFiles; - EventRegistry result = getLicenseDiskFiles(diskFiles); - if (!result.isGood()) { - return result; + vector<unique_ptr<locate::LocatorStrategy>> locator_strategies; + FUNCTION_RETURN ret = locate::LocatorFactory::get_active_strategies( + locator_strategies, licenseLocation); + EventRegistry eventRegistry; + if (ret != FUNC_RET_OK) { + eventRegistry.addEvent(LICENSE_FILE_NOT_FOUND); + eventRegistry.turnWarningsIntoErrors(); + return eventRegistry; } - bool loadAtLeastOneFile = false; - bool atLeastOneProductLicensed = false; + bool atLeastOneLicenseComplete = false; - CSimpleIniA ini; - for (auto it = diskFiles.begin(); it != diskFiles.end(); it++) { - ini.Reset(); - const SI_Error rc = ini.LoadFile((*it).c_str()); - if (rc < 0) { - result.addEvent(FILE_FORMAT_NOT_RECOGNIZED, SVRT_WARN, *it); + for (unique_ptr<locate::LocatorStrategy> &locator : locator_strategies) { + vector<string> licenseLocations = locator->license_locations( + eventRegistry); + if (licenseLocations.size() == 0) { continue; - } else { - loadAtLeastOneFile = true; } - const char* productNamePtr = product.c_str(); - const int sectionSize = ini.GetSectionSize(productNamePtr); - if (sectionSize <= 0) { - result.addEvent(PRODUCT_NOT_LICENSED, SVRT_WARN, *it); - continue; - } else { - atLeastOneProductLicensed = true; + CSimpleIniA ini; + for (auto it = licenseLocations.begin(); it != licenseLocations.end(); + it++) { + ini.Reset(); + string license = locator->retrieve_license_content((*it).c_str()); + const SI_Error rc = ini.LoadData(license.c_str(), license.size()); + if (rc < 0) { + eventRegistry.addEvent(FILE_FORMAT_NOT_RECOGNIZED, *it); + continue; + } + const char *productNamePtr = product.c_str(); + const int sectionSize = ini.GetSectionSize(productNamePtr); + if (sectionSize <= 0) { + eventRegistry.addEvent(PRODUCT_NOT_LICENSED, *it); + continue; + } else { + eventRegistry.addEvent(PRODUCT_FOUND, *it); + } + /* + * sw_version_from = (optional int) + * sw_version_to = (optional int) + * from_date = YYYY-MM-DD (optional) + * to_date = YYYY-MM-DD (optional) + * client_signature = XXXX-XXXX-XXXX-XXXX (optional string 16) + * license_signature = XXXXXXXXXX (mandatory, 1024) + * application_data = xxxxxxxxx (optional string 16) + */ + const char *license_signature = ini.GetValue(productNamePtr, + "license_signature", nullptr); + long license_version = ini.GetLongValue(productNamePtr, + "license_version", -1); + if (license_signature != nullptr && license_version > 0) { + const string from_date = trim_copy( + ini.GetValue(productNamePtr, "from_date", + FullLicenseInfo::UNUSED_TIME)); + const string to_date = trim_copy( + ini.GetValue(productNamePtr, "to_date", + FullLicenseInfo::UNUSED_TIME)); + string client_signature = trim_copy( + ini.GetValue(productNamePtr, "client_signature", "")); + /*client_signature.erase( + std::remove(client_signature.begin(), client_signature.end(), '-'), + client_signature.end());*/ + const int from_sw_version = ini.GetLongValue(productNamePtr, + "from_sw_version", + FullLicenseInfo::UNUSED_SOFTWARE_VERSION); + const int to_sw_version = ini.GetLongValue(productNamePtr, + "to_sw_version", + FullLicenseInfo::UNUSED_SOFTWARE_VERSION); + string extra_data = trim_copy( + ini.GetValue(productNamePtr, "extra_data", "")); + FullLicenseInfo licInfo(*it, product, license_signature, + (int) license_version, from_date, to_date, + client_signature, from_sw_version, to_sw_version, + extra_data); + licenseInfoOut.push_back(licInfo); + atLeastOneLicenseComplete = true; + } else { + eventRegistry.addEvent(LICENSE_MALFORMED, *it); + } } - /* - * sw_version_from = (optional int) - * sw_version_to = (optional int) - * from_date = YYYY-MM-DD (optional) - * to_date = YYYY-MM-DD (optional) - * client_signature = XXXX-XXXX-XXXX-XXXX (optional string 16) - * license_signature = XXXXXXXXXX (mandatory, 1024) - * application_data = xxxxxxxxx (optional string 16) - */ - const char * license_signature = ini.GetValue(productNamePtr, - "license_signature", nullptr); - long license_version = ini.GetLongValue(productNamePtr, - "license_version", -1); - if (license_signature != nullptr && license_version > 0) { - const string from_date = trim_copy( - ini.GetValue(productNamePtr, "from_date", - FullLicenseInfo::UNUSED_TIME)); - const string to_date = trim_copy( - ini.GetValue(productNamePtr, "to_date", - FullLicenseInfo::UNUSED_TIME)); - string client_signature = trim_copy( - ini.GetValue(productNamePtr, "client_signature", "")); - /*client_signature.erase( - std::remove(client_signature.begin(), client_signature.end(), '-'), - client_signature.end());*/ - const int from_sw_version = ini.GetLongValue(productNamePtr, - "from_sw_version", - FullLicenseInfo::UNUSED_SOFTWARE_VERSION); - const int to_sw_version = ini.GetLongValue(productNamePtr, - "to_sw_version", FullLicenseInfo::UNUSED_SOFTWARE_VERSION); - string extra_data = trim_copy( - ini.GetValue(productNamePtr, "extra_data", "")); - FullLicenseInfo licInfo(*it, product, license_signature, - (int) license_version, from_date, to_date, client_signature, - from_sw_version, to_sw_version, extra_data); - licenseInfoOut.push_back(licInfo); - atLeastOneLicenseComplete = true; - } else { - result.addEvent(LICENSE_MALFORMED, SVRT_WARN, *it); - } - } - if (!loadAtLeastOneFile) { - result.turnEventIntoError(FILE_FORMAT_NOT_RECOGNIZED); - } - if (!atLeastOneProductLicensed) { - result.turnEventIntoError(PRODUCT_NOT_LICENSED); } if (!atLeastOneLicenseComplete) { - result.turnEventIntoError(LICENSE_MALFORMED); - } - return result; -} - -bool LicenseReader::findLicenseWithExplicitLocation(vector<string>& diskFiles, - EventRegistry& eventRegistry) { -//bool hasFileLocation = false; - bool licenseFoundWithExplicitLocation = false; - if (licenseLocation.licenseFileLocation != nullptr - && licenseLocation.licenseFileLocation[0] != '\0') { - //hasFileLocation = true; - const string varName(licenseLocation.licenseFileLocation); - const vector<string> declared_positions = splitLicensePositions(varName); - vector<string> existing_pos = filterExistingFiles(declared_positions); - if (existing_pos.size() > 0) { - if (existing_pos.size() > 0) { - licenseFoundWithExplicitLocation = true; - for (auto it = existing_pos.begin(); it != existing_pos.end(); - ++it) { - diskFiles.push_back(*it); - eventRegistry.addEvent(LICENSE_FILE_FOUND, SVRT_INFO, *it); - } - } - } else { - eventRegistry.addEvent(LICENSE_FILE_NOT_FOUND, SVRT_WARN, varName); - } - } - return licenseFoundWithExplicitLocation; -} - -bool LicenseReader::findFileWithEnvironmentVariable(vector<string>& diskFiles, - EventRegistry& eventRegistry) { - bool licenseFileFoundWithEnvVariable = false; - if (licenseLocation.environmentVariableName != nullptr - && licenseLocation.environmentVariableName[0] != '\0') { - const string varName(licenseLocation.environmentVariableName); - if (varName.length() > 0) { - //var name is passed in by the calling application. - char* env_var_value = getenv(varName.c_str()); - if (env_var_value != nullptr && env_var_value[0] != '\0') { - const vector<string> declared_positions = splitLicensePositions( - string(env_var_value)); - vector<string> existing_pos = filterExistingFiles( - declared_positions); - if (existing_pos.size() > 0) { - licenseFileFoundWithEnvVariable = true; - for (auto it = existing_pos.begin(); - it != existing_pos.end(); ++it) { - diskFiles.push_back(*it); - eventRegistry.addEvent(LICENSE_FILE_FOUND, SVRT_INFO, - *it); - } - } else { - eventRegistry.addEvent(LICENSE_FILE_NOT_FOUND, SVRT_WARN, - env_var_value); - } - } else { - eventRegistry.addEvent(ENVIRONMENT_VARIABLE_NOT_DEFINED, - SVRT_WARN); - } - } else { - eventRegistry.addEvent(ENVIRONMENT_VARIABLE_NOT_DEFINED, SVRT_WARN); - } - } - return licenseFileFoundWithEnvVariable; -} - -EventRegistry LicenseReader::getLicenseDiskFiles(vector<string>& diskFiles) { - EventRegistry eventRegistry; - const bool licenseFoundWithExplicitLocation = findLicenseWithExplicitLocation( - diskFiles, eventRegistry); - bool foundNearModule = false; - if (licenseLocation.openFileNearModule) { - char fname[MAX_PATH] = { 0 }; - const FUNCTION_RETURN fret = getModuleName(fname); - if (fret == FUNC_RET_OK) { - const string temptativeLicense = string(fname) + ".lic"; - ifstream f(temptativeLicense.c_str()); - if (f.good()) { - foundNearModule = true; - diskFiles.push_back(temptativeLicense); - eventRegistry.addEvent(LICENSE_FILE_FOUND, SVRT_INFO, - temptativeLicense); - } else { - eventRegistry.addEvent(LICENSE_FILE_NOT_FOUND, SVRT_WARN, - temptativeLicense); - } - f.close(); - } else { - LOG_WARN("Error determining module name."); - } - } - const bool licenseFileFoundWithEnvVariable = findFileWithEnvironmentVariable( - diskFiles, eventRegistry); - - if (!foundNearModule && !licenseFoundWithExplicitLocation - && !licenseFileFoundWithEnvVariable) { - eventRegistry.turnEventIntoError(ENVIRONMENT_VARIABLE_NOT_DEFINED); - eventRegistry.turnEventIntoError(LICENSE_FILE_NOT_FOUND); + eventRegistry.turnWarningsIntoErrors(); } return eventRegistry; } -vector<string> LicenseReader::filterExistingFiles( - vector<string> licensePositions) { - vector<string> existingFiles; - for (auto it = licensePositions.begin(); it != licensePositions.end(); - it++) { - ifstream f(it->c_str()); - if (f.good()) { - existingFiles.push_back(*it); - } - f.close(); - } - return existingFiles; -} - -vector<string> LicenseReader::splitLicensePositions(string licensePositions) { - std::stringstream streamToSplit(licensePositions); - std::string segment; - std::vector<string> seglist; - - while (std::getline(streamToSplit, segment, ';')) { - seglist.push_back(segment); - } - return seglist; -} - LicenseReader::~LicenseReader() { - } string FullLicenseInfo::printForSign() const { @@ -336,7 +228,7 @@ } -void FullLicenseInfo::printAsIni(ostream & a_ostream) const { +void FullLicenseInfo::printAsIni(ostream &a_ostream) const { CSimpleIniA ini; string result; const string product = toupper_copy(trim_copy(this->product)); diff --git a/src/library/LicenseReader.h b/src/library/LicenseReader.h deleted file mode 100644 index 0d70f2f..0000000 --- a/src/library/LicenseReader.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * LicenseReader.h - * - * Created on: Mar 30, 2014 - * - */ - -#ifndef LICENSEREADER_H_ -#define LICENSEREADER_H_ - -#include "api/datatypes.h" -#include "base/EventRegistry.h" -#include "os/os.h" -#define SI_SUPPORT_IOSTREAMS -#include "ini/SimpleIni.h" -#include <string> -#include <ctime> -namespace license { - -using namespace std; - -class FullLicenseInfo { -public: - string source; - string product; - string license_signature; - int license_version; - string from_date; - string to_date; - bool has_expiry; - unsigned int from_sw_version; - unsigned int to_sw_version; - bool has_versions; - string client_signature; - bool has_client_sig; - string extra_data; - - static const char* UNUSED_TIME; - static const unsigned int UNUSED_SOFTWARE_VERSION = 0; - - FullLicenseInfo(const string& source, const string& product, - const string& license_signature, int licenseVersion, - string from_date = UNUSED_TIME, - string to_date = UNUSED_TIME, // - const string& client_signature = "", // - unsigned int from_sw_version = UNUSED_SOFTWARE_VERSION, - unsigned int to_sw_version = UNUSED_SOFTWARE_VERSION, - const string& extra_data = ""); - string printForSign() const; - void printAsIni(ostream & a_ostream) const; - void toLicenseInfo(LicenseInfo* license) const; - EventRegistry validate(int sw_version); - time_t expires_on() const; - time_t valid_from() const; -}; -/** - * This class it is responsible to read the licenses from the disk - * (in future from network) examining all the possible LicenseLocation - * positions. - * - * Each section of the ini file represents a product. - * <pre> - * [product] - * sw_version_from = (optional int) - * sw_version_to = (optional int) - * from_date = YYYY-MM-DD (optional) - * to_date = YYYY-MM-DD (optional) - * client_signature = XXXXXXXX (optional string 16) - * license_signature = XXXXXXXXXX (mandatory, 1024) - * application_data = xxxxxxxxx (optional string 16) - * license_version = 100 (mandatory int) - * </pre> - */ -class LicenseReader { -private: - const LicenseLocation licenseLocation; - EventRegistry getLicenseDiskFiles(vector<string>& diskFiles); - vector<string> filterExistingFiles(vector<string> licensePositions); - vector<string> splitLicensePositions(string licensePositions); - bool findLicenseWithExplicitLocation(vector<string>& diskFiles, - EventRegistry& eventRegistry); - bool findFileWithEnvironmentVariable(vector<string>& diskFiles, - EventRegistry& eventRegistry); - -public: - LicenseReader(const LicenseLocation& licenseLocation); - EventRegistry readLicenses(const string &product, - vector<FullLicenseInfo>& licenseInfoOut); - virtual ~LicenseReader(); -}; -} -#endif /* LICENSEREADER_H_ */ diff --git a/src/library/LicenseReader.hpp b/src/library/LicenseReader.hpp new file mode 100644 index 0000000..661bd05 --- /dev/null +++ b/src/library/LicenseReader.hpp @@ -0,0 +1,84 @@ +/* + * LicenseReader.h + * + * Created on: Mar 30, 2014 + * + */ + +#ifndef LICENSEREADER_H_ +#define LICENSEREADER_H_ +#include <string> +#include <ctime> + +#define SI_SUPPORT_IOSTREAMS +#include "api/datatypes.h" +#include "base/EventRegistry.h" +#include "os/os.h" +#include "ini/SimpleIni.h" + +namespace license { + +class FullLicenseInfo { +public: + std::string source; + std::string product; + std::string license_signature; + int license_version; + std::string from_date; + std::string to_date; + bool has_expiry; + unsigned int from_sw_version; + unsigned int to_sw_version; + bool has_versions; + std::string client_signature; + bool has_client_sig; + std::string extra_data; + + static const char* UNUSED_TIME; + static const unsigned int UNUSED_SOFTWARE_VERSION = 0; + + FullLicenseInfo(const std::string& source, const std::string& product, + const std::string& license_signature, int licenseVersion, + std::string from_date = UNUSED_TIME, + std::string to_date = UNUSED_TIME, // + const std::string& client_signature = "", // + unsigned int from_sw_version = UNUSED_SOFTWARE_VERSION, + unsigned int to_sw_version = UNUSED_SOFTWARE_VERSION, + const std::string& extra_data = ""); + std::string printForSign() const; + void printAsIni(std::ostream & a_ostream) const; + void toLicenseInfo(LicenseInfo* license) const; + bool validate(int sw_version, EventRegistry& eventRegistryOut); + time_t expires_on() const; + time_t valid_from() const; +}; + +/** + * This class it is responsible to read the licenses from the disk + * (in future from network) examining all the possible LicenseLocation + * positions. + * + * Each section of the ini file represents a product. + * <pre> + * [product] + * sw_version_from = (optional int) + * sw_version_to = (optional int) + * from_date = YYYY-MM-DD (optional) + * to_date = YYYY-MM-DD (optional) + * client_signature = XXXXXXXX (optional std::string 16) + * license_signature = XXXXXXXXXX (mandatory, 1024) + * application_data = xxxxxxxxx (optional std::string 16) + * license_version = 100 (mandatory int) + * </pre> + */ +class LicenseReader { +private: + const LicenseLocation* licenseLocation; +public: + LicenseReader(const LicenseLocation* licenseLocation); + EventRegistry readLicenses(const std::string &product, + std::vector<FullLicenseInfo>& licenseInfoOut); + virtual ~LicenseReader(); +}; +} +#endif /* LICENSEREADER_H_ */ diff --git a/src/library/api/Licensepp-features.h b/src/library/api/Licensepp-features.h deleted file mode 100644 index 88e41ab..0000000 --- a/src/library/api/Licensepp-features.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef LICENSEPP_FEATURES_H_ -#define LICENSEPP_FEATURES_H_ - -#include "license++.h" -#ifdef __cplusplus -extern "C" { -#endif - -enum FEATURE_NAMES { - FEATURE1, -} - -#endif diff --git a/src/library/api/datatypes.h b/src/library/api/datatypes.h index ed30576..439f477 100644 --- a/src/library/api/datatypes.h +++ b/src/library/api/datatypes.h @@ -13,32 +13,38 @@ #ifdef __unix__ #define DllExport +#ifndef MAX_PATH + #define MAX_PATH 1024 +#endif #else #include <windows.h> #define DllExport __declspec( dllexport ) #endif -#define ENVIRONMENT_VAR_NAME_MAX 64 + #define PC_IDENTIFIER_SIZE 18 #define PROPRIETARY_DATA_SIZE 16 +#define AUDIT_EVENT_NUM 5 #define LICENESE_INT_VERSION 110 #define LICENSEPP_VERSION "1.1.0" typedef enum { - LICENSE_OK = 0, //OK + LICENSE_OK = 0, //OK LICENSE_FILE_NOT_FOUND = 1, //license file not found LICENSE_SERVER_NOT_FOUND = 2, //license server can't be contacted ENVIRONMENT_VARIABLE_NOT_DEFINED = 3, //environment variable not defined - FILE_FORMAT_NOT_RECOGNIZED = 4, //license file has invalid format (not .ini file) - LICENSE_MALFORMED = 5, //some mandatory field are missing, or data can't be fully read. + FILE_FORMAT_NOT_RECOGNIZED = 4, //license file has invalid format (not .ini file) + LICENSE_MALFORMED = 5, //some mandatory field are missing, or data can't be fully read. PRODUCT_NOT_LICENSED = 6, //this product was not licensed PRODUCT_EXPIRED = 7, - LICENSE_CORRUPTED = 8,//License signature didn't match with current license - IDENTIFIERS_MISMATCH = 9, //Calculated identifier and the one provided in license didn't match + LICENSE_CORRUPTED = 8, //License signature didn't match with current license + IDENTIFIERS_MISMATCH = 9, //Calculated identifier and the one provided in license didn't match - LICENSE_FILE_FOUND = 100, - LICENSE_VERIFIED = 101 + LICENSE_SPECIFIED = 100, //license location was specified + LICENSE_FOUND = 101, //License file has been found or license data has been located + PRODUCT_FOUND = 102, //License has been loaded and the declared product has been found + SIGNATURE_VERIFIED = 103 } EVENT_TYPE; @@ -53,23 +59,40 @@ typedef struct { SEVERITY severity; EVENT_TYPE event_type; - char param1[256]; + /** + * License file name or location where the license is stored. + */ + char license_reference[MAX_PATH]; char param2[256]; } AuditEvent; +/** + * This structure contains informations on the raw license data. Software authors + * can specify the location of the license file or its full content. + * + * Can be NULL, in this case OpenLicenseManager will try to figure out the + * license file location on its own. + */ typedef struct { + /** + * A list of absolute path separated by ';' containing the eventual location + * of the license files. Can be NULL. + */ const char *licenseFileLocation; - const char *environmentVariableName; - bool openFileNearModule; + /** + * The application can provide the full license content through this string. + * It can be both in encoded form (base64) or in plain. It's optional. + */ + const char *licenseData; } LicenseLocation; typedef struct { /** * Detailed reason of success/failure. Reasons for a failure can be * multiple (for instance, license expired and signature not verified). - * Only the last 5 are reported. + * Only the last AUDIT_EVENT_NUM are reported. */ - AuditEvent status[5]; + AuditEvent status[AUDIT_EVENT_NUM]; /** * Eventual expiration date of the software, * can be '\0' if the software don't expire diff --git a/src/library/api/license++.h b/src/library/api/license++.h index faece34..ef1fbb6 100644 --- a/src/library/api/license++.h +++ b/src/library/api/license++.h @@ -3,22 +3,9 @@ /* * This include file is the public api di License++ - * You should include this file if your software don't plan to use - * the part of the library dealing with features. - * Otherwise licensepp-features.h should be included. - */ +*/ #ifdef __cplusplus extern "C" { -#endif - -#ifdef __unix__ -#define DllExport -#ifndef MAX_PATH - #define MAX_PATH 1024 -#endif -#else -#include <windows.h> -#define DllExport __declspec( dllexport ) #endif #include "datatypes.h" @@ -35,30 +22,37 @@ */ void identify_pc(IDENTIFICATION_STRATEGY pc_id_method, char chbuffer[PC_IDENTIFIER_SIZE + 1]); -/* - * The optional parameter License contains the information the program that uses the library - * should display: + + +/** + * This method is used to request the use of one license for a product. + * In case of local license it's used to check if the product is licensed. + * [In case of network licenses this will decrease the count of the available + * licenses] * - * @return true if successful. False if there are errors. - * @param licenseLocation[in] licenseLocation, either the name of the file + * @return LICENSE_OK(0) if successful. Other values if there are errors. + * @param productName[in] + * a vendor defined string containing the name of the product we want to request. + * @param licenseLocation[in] otpional, can be NULL. + * licenseLocation, either the name of the file * or the name of the environment variable should be !='\0' - * @param license[out] optional, can be NULL. + * @param license[out] optional, can be NULL, if set it will return extra informations about the license. */ EVENT_TYPE acquire_license(const char * productName, - LicenseLocation licenseLocation, LicenseInfo* license); + const LicenseLocation* licenseLocation, LicenseInfo* license); /** * Do nothing for now, useful for network licenses. * Should be called from time to time to confirm we're still using the - * slicense. + * license. */ -EVENT_TYPE confirm_license(char * productName, - LicenseLocation licenseLocation); +EVENT_TYPE confirm_license(char * featureName, + LicenseLocation* licenseLocation); /** * Do nothing for now, useful for network licenses. */ -EVENT_TYPE release_license(char * productName, +EVENT_TYPE release_license(char * featureName, LicenseLocation licenseLocation); #ifdef __cplusplus diff --git a/src/library/base/CMakeLists.txt b/src/library/base/CMakeLists.txt index 6dc0c98..0a61fdf 100644 --- a/src/library/base/CMakeLists.txt +++ b/src/library/base/CMakeLists.txt @@ -1,7 +1,9 @@ ADD_LIBRARY(base STATIC EventRegistry.cpp StringUtils.cpp + FileUtils.cpp logger.c + base64.c ) add_dependencies( base public_key ) diff --git a/src/library/base/EventRegistry.cpp b/src/library/base/EventRegistry.cpp index cd3c58f..ec9d4c1 100644 --- a/src/library/base/EventRegistry.cpp +++ b/src/library/base/EventRegistry.cpp @@ -2,106 +2,151 @@ * EventRegistry.cpp * * Created on: Mar 30, 2014 - * + * */ -#include "EventRegistry.h" #include <cstddef> #include <string.h> #include <algorithm> +#include <map> +#include <iostream> -using namespace std; +#include "EventRegistry.h" +#define LIC_ID_NOT_DEFINED "UNDEF" namespace license { +using namespace std; + +const map<EVENT_TYPE, int> PROGRESS_BY_EVENT_TYPE = { { LICENSE_SPECIFIED, 0 }, + { LICENSE_FOUND, 1 }, { PRODUCT_FOUND, 2 }, { SIGNATURE_VERIFIED, 3 }, { + LICENSE_OK, 4 } }; + EventRegistry::EventRegistry() { + current_validation_step = -1; } -EventRegistry& operator<<(EventRegistry& eventRegistry, - AuditEvent& securityEvent) { +EventRegistry& operator<<(EventRegistry &eventRegistry, + AuditEvent &securityEvent) { eventRegistry.logs.push_back(securityEvent); return eventRegistry; } -EventRegistry& operator<<(EventRegistry& eventRegistry1, - EventRegistry& otherRegistry) { +EventRegistry& operator<<(EventRegistry &eventRegistry1, + EventRegistry &otherRegistry) { eventRegistry1.append(otherRegistry); return eventRegistry1; } -void EventRegistry::append(const EventRegistry& eventRegistry) { +ostream& operator<<(std::ostream &out, const EventRegistry &er) { + out << string("EventReg[step:") << er.current_validation_step + << ",events:{"; + for (auto &it : er.logs) { + out << "[ev:" << it.event_type << ",sev:" << it.severity << "ref:" + << it.license_reference << "]"; + } + out << "]"; + return out; +} + +void EventRegistry::append(const EventRegistry &eventRegistry) { logs.insert(logs.end(), eventRegistry.logs.begin(), eventRegistry.logs.end()); } -void EventRegistry::turnLastEventIntoError() { - if (logs.size() > 0) { - logs.back().severity = SVRT_ERROR; +AuditEvent const* EventRegistry::getLastFailure() const { + const AuditEvent *result = nullptr; + if (logs.size() == 0) { + return result; + } + //try to find a failure between the licenses who progressed the most + if (mostAdvancedLogIdx_by_LicenseId.size() > 0) { + for (auto const &mostAdvLogIter : mostAdvancedLogIdx_by_LicenseId) { + const AuditEvent ¤tLog = logs[mostAdvLogIter.second]; + if (currentLog.severity == SVRT_ERROR) { + result = &(currentLog); + break; + } + } + } + if (result == nullptr) { + auto it = logs.end(); + do { + --it; + if (it->severity == SVRT_ERROR) { + result = &(*it); + break; + } + } while (it != logs.begin()); + } + return result; +} + +void EventRegistry::addEvent(EVENT_TYPE event, + const std::string &licenseLocationId) { + addEvent(event, licenseLocationId.c_str(), nullptr); +} + +void EventRegistry::addEvent(EVENT_TYPE event, const char *licenseLocationId, + const char *info) { + AuditEvent audit; + auto eventIterator = PROGRESS_BY_EVENT_TYPE.find(event); + bool successEvent = (eventIterator != PROGRESS_BY_EVENT_TYPE.end()); + audit.severity = successEvent ? SVRT_INFO : SVRT_WARN; + audit.event_type = event; + if (licenseLocationId == nullptr) { + strcpy(audit.license_reference, LIC_ID_NOT_DEFINED); + } else { + strncpy(audit.license_reference, licenseLocationId, MAX_PATH); + } + if (info == nullptr) { + audit.param2[0] = '\0'; + } else { + strncpy(audit.param2, info, 255); + } + logs.push_back(audit); +//udpate the status of the log + if (successEvent) { + int step = eventIterator->second; + if (step > current_validation_step) { + mostAdvancedLogIdx_by_LicenseId.clear(); + current_validation_step = step; + } + + if (step == current_validation_step) { + mostAdvancedLogIdx_by_LicenseId[audit.license_reference] = + logs.size() - 1; + } + } else if (mostAdvancedLogIdx_by_LicenseId.find(audit.license_reference) + != mostAdvancedLogIdx_by_LicenseId.end()) { + mostAdvancedLogIdx_by_LicenseId[audit.license_reference] = logs.size() + - 1; } } -bool EventRegistry::turnEventIntoError(EVENT_TYPE event) { +bool EventRegistry::turnWarningsIntoErrors() { bool eventFound = false; - for (auto it = logs.begin(); it != logs.end(); ++it) { - if (it->event_type == event) { - it->severity = SVRT_ERROR; - eventFound = true; + if (mostAdvancedLogIdx_by_LicenseId.size() > 0) { + for (auto const &mostAdvLogIter : mostAdvancedLogIdx_by_LicenseId) { + AuditEvent ¤tLog = logs[mostAdvLogIter.second]; + if (currentLog.severity == SVRT_WARN + || currentLog.severity == SVRT_ERROR) { + currentLog.severity = SVRT_ERROR; + eventFound = true; + } + } + } + if (!eventFound) { + for (auto it = logs.begin(); it != logs.end(); ++it) { + if (it->severity == SVRT_WARN) { + it->severity = SVRT_ERROR; + eventFound = true; + } } } return eventFound; } -AuditEvent const * EventRegistry::getLastFailure() const { - const AuditEvent* result = nullptr; - if (logs.size() == 0) { - return result; - } - auto it = logs.end(); - do { - --it; - if (it->severity == SVRT_ERROR) { - result = &(*it); - break; - } - } while (it != logs.begin()); - return result; - -} - -bool EventRegistry::isGood() const { - bool isGood = true; - for (auto it = logs.begin(); it != logs.end(); ++it) { - if (it->severity == SVRT_ERROR) { - isGood = false; - break; - } - } - return isGood; -} - -void EventRegistry::addError(EVENT_TYPE event) { - this->addEvent(event, SVRT_ERROR); -} - -void EventRegistry::addEvent(EVENT_TYPE event, SEVERITY severity) { - AuditEvent audit; - audit.severity = severity; - audit.event_type = event; - audit.param1[0] = '\0'; - audit.param2[0] = '\0'; - logs.push_back(audit); -} - -void EventRegistry::addEvent(EVENT_TYPE event, SEVERITY severity, - const string& eventParameter) { - AuditEvent audit; - audit.severity = severity; - audit.event_type = event; - strncpy(audit.param1, eventParameter.c_str(), 255); - audit.param2[0] = '\0'; - logs.push_back(audit); -} - -bool EventRegistry::turnErrosIntoWarnings() { +bool EventRegistry::turnErrorsIntoWarnings() { bool eventFound = false; for (auto it = logs.begin(); it != logs.end(); ++it) { if (it->severity == SVRT_ERROR) { @@ -112,9 +157,14 @@ return eventFound; } -void EventRegistry::exportLastEvents(AuditEvent* auditEvents, int nlogs) { +void EventRegistry::exportLastEvents(AuditEvent *auditEvents, int nlogs) { const int sizeToCopy = min(nlogs, (int) logs.size()); - std::copy(logs.begin(), logs.begin() + sizeToCopy, auditEvents); + std::copy(logs.end() - sizeToCopy, logs.end(), auditEvents); } + +bool EventRegistry::isGood() const { + return getLastFailure() == nullptr; +} + } diff --git a/src/library/base/EventRegistry.h b/src/library/base/EventRegistry.h index d86ea77..f5fec62 100644 --- a/src/library/base/EventRegistry.h +++ b/src/library/base/EventRegistry.h @@ -2,7 +2,7 @@ * EventRegistry.h * * Created on: Mar 30, 2014 - * + * */ #ifndef EVENTREGISTRY_H_ @@ -10,43 +10,51 @@ #include "../api/datatypes.h" #include <vector> +#include <map> +#include <set> #include <string> namespace license { -using namespace std; -/* -AuditEvent error_event_builder(EVENT_TYPE event); -AuditEvent audit_event_builder(EVENT_TYPE event, SEVERITY severity); -AuditEvent audit_event_builder(EVENT_TYPE event, SEVERITY severity, - const string& eventParameter);*/ +/** + * Tracks the events relative to a license and provide explanation regarding + * failures to verify licenses. + */ class EventRegistry { private: friend EventRegistry& operator<<(EventRegistry&, AuditEvent&); friend EventRegistry& operator<<(EventRegistry&, EventRegistry&); - //TODO change into map - vector<AuditEvent> logs; - //Forbid copy - //EventRegistry(const EventRegistry& that) = delete; + friend std::ostream & operator << (std::ostream &out, const EventRegistry &er); + + std::vector<AuditEvent> logs; + /** + * For every license keep track of the events who progressed most + * in the validation process + */ + std::map<std::string,int> mostAdvancedLogIdx_by_LicenseId; + int current_validation_step; + public: EventRegistry(); //operator << - void append(const EventRegistry& eventRegistry); - void turnLastEventIntoError(); - bool turnEventIntoError(EVENT_TYPE event); - bool turnErrosIntoWarnings(); + void append(const EventRegistry &eventRegistry); /** + * Turn the event warning for the license with the most advanced status + * into an error. + */ + bool turnWarningsIntoErrors(); + bool turnErrorsIntoWarnings(); + bool isGood() const; + /** + * Return the last failure (event with warn or error status) + * for the license with the most advanced status. * @return NULL if no failures are found. */ - AuditEvent const * getLastFailure() const; - bool isGood() const; - - void addError(EVENT_TYPE event); - void addEvent(EVENT_TYPE event, SEVERITY severity); - void addEvent(EVENT_TYPE event, SEVERITY severity, - const string& eventParameter); - void exportLastEvents(AuditEvent* auditEvents,int nlogs); - + AuditEvent const* getLastFailure() const; + void addEvent(EVENT_TYPE event, const std::string &licenseLocationId); + void addEvent(EVENT_TYPE event, const char *licenseLocationId = nullptr, + const char *info = nullptr); + void exportLastEvents(AuditEvent *auditEvents, int nlogs); }; } #endif /* EVENTREGISTRY_H_ */ diff --git a/src/library/base/FileUtils.cpp b/src/library/base/FileUtils.cpp new file mode 100644 index 0000000..f8fcc20 --- /dev/null +++ b/src/library/base/FileUtils.cpp @@ -0,0 +1,69 @@ +/* + * FileUtils.cpp + * + * Created on: Oct 8, 2019 + * Author: devel + */ + +#include <fstream> +#include <string> +#include <cerrno> +#include <iostream> +#include <algorithm> + +#include "FileUtils.hpp" + +namespace license { +using namespace std; + +vector<string> filter_existing_files(const vector<string> &fileList, + EventRegistry& registry,const char* extraData) { + vector<string> existingFiles; + for (auto it = fileList.begin(); it != fileList.end(); it++) { + registry.addEvent(LICENSE_SPECIFIED,it->c_str(), extraData); + ifstream f(it->c_str()); + if (f.good()) { + existingFiles.push_back(*it); + registry.addEvent(LICENSE_FOUND,it->c_str(),extraData); + } else { + registry.addEvent(LICENSE_FILE_NOT_FOUND,it->c_str(), extraData); + } + f.close(); + } + return existingFiles; +} + +string get_file_contents(const char *filename, size_t max_size) { + ifstream in(filename, std::ios::binary); + if (in) { + string contents; + size_t index = in.seekg(0, ios::end).tellg(); + size_t limited_size = min(index, max_size); + contents.resize(limited_size); + in.seekg(0, ios::beg); + in.read(&contents[0], limited_size); + return contents; + } + throw(errno); +} + +string remove_extension(const string& path) { + if (path == "." || path == "..") { + return path; + } + size_t dotpos = path.find_last_of("."); + //no dot + if (dotpos == string::npos) { + return path; + } + //find the last path separator + size_t pathsep_pos = path.find_last_of("\\/"); + if (pathsep_pos == string::npos) { + return (dotpos == 0 ? path : path.substr(0, dotpos)); + } else if(pathsep_pos >= dotpos +1) { + return path; + } + return path.substr(0, dotpos); +} + +} diff --git a/src/library/base/FileUtils.hpp b/src/library/base/FileUtils.hpp new file mode 100644 index 0000000..e6f9e9e --- /dev/null +++ b/src/library/base/FileUtils.hpp @@ -0,0 +1,22 @@ +/* + * FileUtils.h + * + * Created on: Apr 8, 2019 + * + */ + +#ifndef FILEUTILS_H_ +#define FILEUTILS_H_ +#include <string> +#include <vector> +#include "EventRegistry.h" + +namespace license { + +std::vector<std::string> filter_existing_files(const std::vector<std::string>& fileList,EventRegistry& registry, const char* extraData); +std::string get_file_contents(const char *filename,size_t max_size); +std::string remove_extension(const std::string& path); + +} /* namespace license */ + +#endif diff --git a/src/library/base/StringUtils.cpp b/src/library/base/StringUtils.cpp index a635b47..cf9da96 100644 --- a/src/library/base/StringUtils.cpp +++ b/src/library/base/StringUtils.cpp @@ -2,16 +2,18 @@ * StringUtils.cpp * * Created on: Apr 8, 2014 - * + * */ #include <cctype> //toupper -#include "StringUtils.h" #include <iostream> #include <string> +#include <sstream> #include <cstring> #include <algorithm> #include <stdexcept> +#include <regex> +#include "StringUtils.h" #ifdef _WIN32 #include <time.h> //mktime under windows @@ -20,7 +22,7 @@ namespace license { using namespace std; -string trim_copy(const string& string_to_trim) { +string trim_copy(const string &string_to_trim) { std::string::const_iterator it = string_to_trim.begin(); while (it != string_to_trim.end() && isspace(*it)) it++; @@ -32,13 +34,13 @@ return std::string(it, rit.base()); } -string toupper_copy(const string& lowercase) { +string toupper_copy(const string &lowercase) { string cp(lowercase); - std::transform(cp.begin(), cp.end(), cp.begin(), (int (*)(int))toupper); + std::transform(cp.begin(), cp.end(), cp.begin(), (int (*)(int)) toupper); return cp; } -time_t seconds_from_epoch(const char* timeString) { +time_t seconds_from_epoch(const char *timeString) { int year, month, day; tm tm; if (strlen(timeString) == 8) { @@ -47,14 +49,16 @@ throw invalid_argument("Date not recognized"); } } else if (strlen(timeString) == 10) { - const int nfield = sscanf(timeString, "%4d-%2d-%2d", &year, &month, &day); + const int nfield = sscanf(timeString, "%4d-%2d-%2d", &year, &month, + &day); if (nfield != 3) { - const int nfield = sscanf(timeString, "%4d/%2d/%2d", &year, &month, &day); + const int nfield = sscanf(timeString, "%4d/%2d/%2d", &year, &month, + &day); if (nfield != 3) { throw invalid_argument("Date not recognized"); } } - } else{ + } else { throw invalid_argument("Date not recognized"); } tm.tm_isdst = -1; @@ -68,4 +72,31 @@ tm.tm_wday = -1; return mktime(&tm); } + +const vector<string> split_string(const string &licensePositions, + char splitchar) { + std::stringstream streamToSplit(licensePositions); + std::string segment; + std::vector<string> seglist; + + while (std::getline(streamToSplit, segment, splitchar)) { + seglist.push_back(segment); + } + return seglist; +} + +const static regex iniSection("\\[.*?\\]"); +const static regex b64( + "^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$"); + +FILE_FORMAT identify_format(const string &license) { + FILE_FORMAT result = UNKNOWN; + if (regex_match(license, b64)) { + result = BASE64; + } else if (regex_search(license, iniSection)) { + result = INI; + } + return result; +} + } /* namespace license */ diff --git a/src/library/base/StringUtils.h b/src/library/base/StringUtils.h index bbb9ce3..dee0526 100644 --- a/src/library/base/StringUtils.h +++ b/src/library/base/StringUtils.h @@ -2,12 +2,15 @@ * StringUtils.h * * Created on: Apr 8, 2014 - * + * */ #ifndef STRINGUTILS_H_ #define STRINGUTILS_H_ + +#include <bits/types/time_t.h> #include <string> +#include <vector> namespace license { using namespace std; @@ -23,6 +26,20 @@ string toupper_copy(const string& lowercase); time_t seconds_from_epoch(const char* s); -} /* namespace license */ + +/** + * Split a string on a given character + */ +const vector<string> split_string(const string& stringToBeSplit, const char splitchar); + +typedef enum { + INI, BASE64, UNKNOWN +} FILE_FORMAT; + +FILE_FORMAT identify_format(const string& license); + +} + +/* namespace license */ #endif /* STRINGUTILS_H_ */ diff --git a/src/library/base/base.h b/src/library/base/base.h index 6ad0bc6..898688f 100644 --- a/src/library/base/base.h +++ b/src/library/base/base.h @@ -1,7 +1,6 @@ #ifndef BASE_H_ #define BASE_H_ - #ifdef __cplusplus extern "C" { #endif @@ -29,11 +28,6 @@ #endif /* #define _DEBUG */ - -#define cmax(a,b) \ - ({ __typeof__ (a) _a = (a); \ - __typeof__ (b) _b = (b); \ - _a > _b ? _a : _b; }) #define cmin(a,b) \ ({ __typeof__ (a) _a = (a); \ diff --git a/src/library/base/base64.c b/src/library/base/base64.c new file mode 100644 index 0000000..4d17d33 --- /dev/null +++ b/src/library/base/base64.c @@ -0,0 +1,133 @@ +#include <stdio.h> +#include <stdlib.h> + +const static char* b64 = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +// maps A=>0,B=>1.. +const static unsigned char unb64[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //10 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //20 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //30 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //40 + 0, 0, 0, 62, 0, 0, 0, 63, 52, 53, //50 + 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, //60 + 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, //70 + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, //80 + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, //90 + 25, 0, 0, 0, 0, 0, 0, 26, 27, 28, //100 + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, //110 + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, //120 + 49, 50, 51, 0, 0, 0, 0, 0, 0, 0, //130 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //140 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //150 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //160 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //170 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //180 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //190 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //200 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //210 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //220 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //230 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //240 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //250 + 0, 0, 0, 0, 0, 0, }; // This array has 255 elements + +//review api +char* base64(const void* binaryData, int len, int *flen) { + const unsigned char* bin = (const unsigned char*) binaryData; + char* res; + + int rc = 0; // result counter + int byteNo; // I need this after the loop + + int modulusLen = len % 3; + int pad = ((modulusLen & 1) << 1) + ((modulusLen & 2) >> 1); // 2 gives 1 and 1 gives 2, but 0 gives 0. + + *flen = 4 * (len + pad) / 3; + res = (char*) malloc(*flen + 1); // and one for the null + if (!res) { + puts("ERROR: base64 could not allocate enough memory."); + puts("I must stop because I could not get enough"); + return 0; + } + + for (byteNo = 0; byteNo <= len - 3; byteNo += 3) { + unsigned char BYTE0 = bin[byteNo]; + unsigned char BYTE1 = bin[byteNo + 1]; + unsigned char BYTE2 = bin[byteNo + 2]; + res[rc++] = b64[BYTE0 >> 2]; + res[rc++] = b64[((0x3 & BYTE0) << 4) + (BYTE1 >> 4)]; + res[rc++] = b64[((0x0f & BYTE1) << 2) + (BYTE2 >> 6)]; + res[rc++] = b64[0x3f & BYTE2]; + } + + if (pad == 2) { + res[rc++] = b64[bin[byteNo] >> 2]; + res[rc++] = b64[(0x3 & bin[byteNo]) << 4]; + res[rc++] = '='; + res[rc++] = '='; + } else if (pad == 1) { + res[rc++] = b64[bin[byteNo] >> 2]; + res[rc++] = b64[((0x3 & bin[byteNo]) << 4) + (bin[byteNo + 1] >> 4)]; + res[rc++] = b64[(0x0f & bin[byteNo + 1]) << 2]; + res[rc++] = '='; + } + + res[rc] = 0; // NULL TERMINATOR! ;) + return res; +} + +unsigned char* unbase64(const char* ascii, int len, int *flen) { + const unsigned char *safeAsciiPtr = (const unsigned char*) ascii; + unsigned char *bin; + int cb = 0; + int charNo; + int pad = 0; + + if (len < 2) { // 2 accesses below would be OOB. + // catch empty string, return NULL as result. + puts( + "ERROR: You passed an invalid base64 string (too short). You get NULL back."); + *flen = 0; + return 0; + } + if (safeAsciiPtr[len - 1] == '=') + ++pad; + if (safeAsciiPtr[len - 2] == '=') + ++pad; + + *flen = 3 * len / 4 - pad; + bin = (unsigned char*) malloc(*flen); + if (!bin) { + puts("ERROR: unbase64 could not allocate enough memory."); + puts("I must stop because I could not get enough"); + return 0; + } + + for (charNo = 0; charNo <= len - 4 - pad; charNo += 4) { + int A = unb64[safeAsciiPtr[charNo]]; + int B = unb64[safeAsciiPtr[charNo + 1]]; + int C = unb64[safeAsciiPtr[charNo + 2]]; + int D = unb64[safeAsciiPtr[charNo + 3]]; + + bin[cb++] = (A << 2) | (B >> 4); + bin[cb++] = (B << 4) | (C >> 2); + bin[cb++] = (C << 6) | (D); + } + + if (pad == 1) { + int A = unb64[safeAsciiPtr[charNo]]; + int B = unb64[safeAsciiPtr[charNo + 1]]; + int C = unb64[safeAsciiPtr[charNo + 2]]; + + bin[cb++] = (A << 2) | (B >> 4); + bin[cb++] = (B << 4) | (C >> 2); + } else if (pad == 2) { + int A = unb64[safeAsciiPtr[charNo]]; + int B = unb64[safeAsciiPtr[charNo + 1]]; + + bin[cb++] = (A << 2) | (B >> 4); + } + + return bin; +} diff --git a/src/library/base/base64.h b/src/library/base/base64.h index 27f49cd..9a353df 100644 --- a/src/library/base/base64.h +++ b/src/library/base/base64.h @@ -31,140 +31,14 @@ #ifndef BASE64_H #define BASE64_H -#include <stdio.h> -#include <stdlib.h> +#ifdef __cplusplus +extern "C" { +#endif -const static char* b64 = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +unsigned char* unbase64(const char* ascii, int len, int *flen); +char* base64(const void* binaryData, int len, int *flen); -// maps A=>0,B=>1.. -const static unsigned char unb64[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //10 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //20 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //30 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //40 - 0, 0, 0, 62, 0, 0, 0, 63, 52, 53, //50 - 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, //60 - 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, //70 - 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, //80 - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, //90 - 25, 0, 0, 0, 0, 0, 0, 26, 27, 28, //100 - 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, //110 - 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, //120 - 49, 50, 51, 0, 0, 0, 0, 0, 0, 0, //130 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //140 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //150 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //160 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //170 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //180 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //190 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //200 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //210 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //220 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //230 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //240 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //250 - 0, 0, 0, 0, 0, 0, }; // This array has 255 elements - -// Converts binary data of length=len to base64 characters. -// Length of the resultant string is stored in flen -// (you must pass pointer flen). -char* base64(const void* binaryData, int len, int *flen) { - const unsigned char* bin = (const unsigned char*) binaryData; - char* res; - - int rc = 0; // result counter - int byteNo; // I need this after the loop - - int modulusLen = len % 3; - int pad = ((modulusLen & 1) << 1) + ((modulusLen & 2) >> 1); // 2 gives 1 and 1 gives 2, but 0 gives 0. - - *flen = 4 * (len + pad) / 3; - res = (char*) malloc(*flen + 1); // and one for the null - if (!res) { - puts("ERROR: base64 could not allocate enough memory."); - puts("I must stop because I could not get enough"); - return 0; - } - - for (byteNo = 0; byteNo <= len - 3; byteNo += 3) { - unsigned char BYTE0 = bin[byteNo]; - unsigned char BYTE1 = bin[byteNo + 1]; - unsigned char BYTE2 = bin[byteNo + 2]; - res[rc++] = b64[BYTE0 >> 2]; - res[rc++] = b64[((0x3 & BYTE0) << 4) + (BYTE1 >> 4)]; - res[rc++] = b64[((0x0f & BYTE1) << 2) + (BYTE2 >> 6)]; - res[rc++] = b64[0x3f & BYTE2]; - } - - if (pad == 2) { - res[rc++] = b64[bin[byteNo] >> 2]; - res[rc++] = b64[(0x3 & bin[byteNo]) << 4]; - res[rc++] = '='; - res[rc++] = '='; - } else if (pad == 1) { - res[rc++] = b64[bin[byteNo] >> 2]; - res[rc++] = b64[((0x3 & bin[byteNo]) << 4) + (bin[byteNo + 1] >> 4)]; - res[rc++] = b64[(0x0f & bin[byteNo + 1]) << 2]; - res[rc++] = '='; - } - - res[rc] = 0; // NULL TERMINATOR! ;) - return res; +#ifdef __cplusplus } - -unsigned char* unbase64(const char* ascii, int len, int *flen) { - const unsigned char *safeAsciiPtr = (const unsigned char*) ascii; - unsigned char *bin; - int cb = 0; - int charNo; - int pad = 0; - - if (len < 2) { // 2 accesses below would be OOB. - // catch empty string, return NULL as result. - puts( - "ERROR: You passed an invalid base64 string (too short). You get NULL back."); - *flen = 0; - return 0; - } - if (safeAsciiPtr[len - 1] == '=') - ++pad; - if (safeAsciiPtr[len - 2] == '=') - ++pad; - - *flen = 3 * len / 4 - pad; - bin = (unsigned char*) malloc(*flen); - if (!bin) { - puts("ERROR: unbase64 could not allocate enough memory."); - puts("I must stop because I could not get enough"); - return 0; - } - - for (charNo = 0; charNo <= len - 4 - pad; charNo += 4) { - int A = unb64[safeAsciiPtr[charNo]]; - int B = unb64[safeAsciiPtr[charNo + 1]]; - int C = unb64[safeAsciiPtr[charNo + 2]]; - int D = unb64[safeAsciiPtr[charNo + 3]]; - - bin[cb++] = (A << 2) | (B >> 4); - bin[cb++] = (B << 4) | (C >> 2); - bin[cb++] = (C << 6) | (D); - } - - if (pad == 1) { - int A = unb64[safeAsciiPtr[charNo]]; - int B = unb64[safeAsciiPtr[charNo + 1]]; - int C = unb64[safeAsciiPtr[charNo + 2]]; - - bin[cb++] = (A << 2) | (B >> 4); - bin[cb++] = (B << 4) | (C >> 2); - } else if (pad == 2) { - int A = unb64[safeAsciiPtr[charNo]]; - int B = unb64[safeAsciiPtr[charNo + 1]]; - - bin[cb++] = (A << 2) | (B >> 4); - } - - return bin; -} - +#endif #endif diff --git a/src/library/license++.cpp b/src/library/license++.cpp index f9cc7c7..b702d51 100644 --- a/src/library/license++.cpp +++ b/src/library/license++.cpp @@ -1,6 +1,6 @@ //============================================================================ // Name : license-manager-cpp.cpp -// Author : +// Author : // Version : // Copyright : BSD //============================================================================ @@ -9,8 +9,11 @@ #include <stdio.h> #include <stdlib.h> #include <cstring> +#include <iostream> + #include "api/license++.h" -#include "LicenseReader.h" + +#include "LicenseReader.hpp" using namespace std; void print_error(char out_buffer[256], LicenseInfo* licenseInfo) { @@ -39,7 +42,7 @@ } EVENT_TYPE acquire_license(const char * product, - LicenseLocation licenseLocation, LicenseInfo* license) { + const LicenseLocation* licenseLocation, LicenseInfo* licenseInfoOut) { license::LicenseReader lr = license::LicenseReader(licenseLocation); vector<license::FullLicenseInfo> licenses; license::EventRegistry er = lr.readLicenses(string(product), licenses); @@ -48,28 +51,32 @@ vector<license::FullLicenseInfo> licenses_with_errors; vector<license::FullLicenseInfo> licenses_ok; for (auto it = licenses.begin(); it != licenses.end(); it++) { - license::EventRegistry validation_er = it->validate(0); - if (validation_er.isGood()) { + bool valid = it->validate(0,er); + if (valid) { licenses_ok.push_back(*it); } else { licenses_with_errors.push_back(*it); } - er.append(validation_er); } if (licenses_ok.size() > 0) { - er.turnErrosIntoWarnings(); + er.turnErrorsIntoWarnings(); result = LICENSE_OK; - mergeLicenses(licenses_ok, license); + mergeLicenses(licenses_ok, licenseInfoOut); } else { + er.turnWarningsIntoErrors(); result = er.getLastFailure()->event_type; - mergeLicenses(licenses_with_errors, license); + mergeLicenses(licenses_with_errors, licenseInfoOut); } } else { + er.turnWarningsIntoErrors(); result = er.getLastFailure()->event_type; } - if (license != nullptr) { - er.exportLastEvents(license->status, 5); +#ifdef _DEBUG + cout << er <<endl; +#endif + if (licenseInfoOut != nullptr) { + er.exportLastEvents(licenseInfoOut->status, AUDIT_EVENT_NUM); } return result; } diff --git a/src/library/locate/ApplicationFolder.cpp b/src/library/locate/ApplicationFolder.cpp new file mode 100644 index 0000000..b1fb0e3 --- /dev/null +++ b/src/library/locate/ApplicationFolder.cpp @@ -0,0 +1,56 @@ +/* + * ApplicationFolder.cpp + * + * Created on: Oct 12, 2019 + * Author: Gabriele Contini + */ +#include <fstream> +#include <sstream> +#include <string> + +#include <build_properties.h> + +#include "../base/logger.h" +#include "../api/datatypes.h" +#include "../base/base.h" +#include "../base/EventRegistry.h" +#include "../base/FileUtils.hpp" +#include "../os/os.h" +#include "ApplicationFolder.hpp" +#include <iostream> + +namespace license { +namespace locate { +using namespace std; + +ApplicationFolder::ApplicationFolder() : + LocatorStrategy("ApplicationFolder") { +} + +ApplicationFolder::~ApplicationFolder() { +} + +const vector<string> ApplicationFolder::license_locations( + EventRegistry &eventRegistry) { + vector<string> diskFiles; + char fname[MAX_PATH] = { 0 }; + const FUNCTION_RETURN fret = getModuleName(fname); + if (fret == FUNC_RET_OK) { + const string module_name = remove_extension(fname); + const string temptativeLicense = string(module_name) + ".lic"; + ifstream f(temptativeLicense.c_str()); + if (f.good()) { + diskFiles.push_back(temptativeLicense); + eventRegistry.addEvent(LICENSE_FOUND, temptativeLicense.c_str()); + } else { + eventRegistry.addEvent(LICENSE_FILE_NOT_FOUND, temptativeLicense.c_str()); + } + f.close(); + } else { + LOG_WARN("Error determining module name."); + } + return diskFiles; +} + +} +} /* namespace license */ diff --git a/src/library/locate/ApplicationFolder.hpp b/src/library/locate/ApplicationFolder.hpp new file mode 100644 index 0000000..649d8da --- /dev/null +++ b/src/library/locate/ApplicationFolder.hpp @@ -0,0 +1,28 @@ +/* + * ApplicationFolder.h + * + * Created on: Oct 6, 2019 + * Author: devel + */ + +#ifndef SRC_LIBRARY_RETRIEVERS_APPLICATIONFOLDER_H_ +#define SRC_LIBRARY_RETRIEVERS_APPLICATIONFOLDER_H_ + +#include <string> + +#include "LocatorStrategy.hpp" + +namespace license { +namespace locate { + +class ApplicationFolder: public LocatorStrategy { +public: + ApplicationFolder(); + virtual const std::vector<std::string> license_locations(EventRegistry& eventRegistry); + virtual ~ApplicationFolder(); +}; + +} +} /* namespace license */ + +#endif /* SRC_LIBRARY_RETRIEVERS_APPLICATIONFOLDER_H_ */ diff --git a/src/library/locate/CMakeLists.txt b/src/library/locate/CMakeLists.txt new file mode 100644 index 0000000..4314fbd --- /dev/null +++ b/src/library/locate/CMakeLists.txt @@ -0,0 +1,18 @@ + +ADD_LIBRARY(locators STATIC + ApplicationFolder.cpp + EnvironmentVarLocation.cpp + EnvironmentVarData.cpp + ExternalDefinition.cpp + LocatorStrategy.cpp + LocatorFactory.cpp +) + +add_dependencies( locators os base ) + +target_link_libraries( + locators + os + base +) + diff --git a/src/library/locate/EnvironmentVarData.cpp b/src/library/locate/EnvironmentVarData.cpp new file mode 100644 index 0000000..616b948 --- /dev/null +++ b/src/library/locate/EnvironmentVarData.cpp @@ -0,0 +1,67 @@ +/* + * EnvironmentVarData.cpp + * + * Created on: Oct 12, 2019 + * Author: Gabriele Contini + */ + +#include "EnvironmentVarData.hpp" + +#include <build_properties.h> +#include <cstdlib> +#include <regex> +#include <string> +#include <vector> + +#include "../api/datatypes.h" +#include "../base/base64.h" +#include "../base/EventRegistry.h" +#include "../base/StringUtils.h" + +namespace license { +namespace locate { + +using namespace std; + +EnvironmentVarData::EnvironmentVarData() : + LocatorStrategy("EnvironmentVarData") { +} + +EnvironmentVarData::~EnvironmentVarData() { +} + +const vector<string> EnvironmentVarData::license_locations( + EventRegistry &eventRegistry) { + vector<string> diskFiles; + char *env_var_value = getenv(LICENSE_DATA_ENV_VAR); + if (env_var_value != nullptr && env_var_value[0] != '\0') { + eventRegistry.addEvent(LICENSE_SPECIFIED, LICENSE_LOCATION_ENV_VAR); + FILE_FORMAT licenseFormat = identify_format(env_var_value); + if (licenseFormat == UNKNOWN) { + eventRegistry.addEvent(LICENSE_MALFORMED, LICENSE_LOCATION_ENV_VAR); + } else { + diskFiles.push_back(LICENSE_LOCATION_ENV_VAR); + isBase64 = (licenseFormat == BASE64); + } + } else { + eventRegistry.addEvent(ENVIRONMENT_VARIABLE_NOT_DEFINED, + LICENSE_LOCATION_ENV_VAR); + } + return diskFiles; +} + +const std::string EnvironmentVarData::retrieve_license_content( + const std::string &licenseLocation) const { + string tmpVal = getenv(LICENSE_LOCATION_ENV_VAR); + if (isBase64) { + int flen = 0; + unsigned char *raw = unbase64(tmpVal.c_str(), tmpVal.length(), &flen); + string str = string(reinterpret_cast<char*>(raw)); + free(raw); + return str; + } + return tmpVal; +} + +} +} diff --git a/src/library/locate/EnvironmentVarData.hpp b/src/library/locate/EnvironmentVarData.hpp new file mode 100644 index 0000000..5698975 --- /dev/null +++ b/src/library/locate/EnvironmentVarData.hpp @@ -0,0 +1,29 @@ +/* + * EnvironmentVarLocation.h + * + * Created on: Oct 6, 2019 + * Author: devel + */ + +#ifndef SRC_LIBRARY_LOCATE_ENVIRONMENTVARDATA_H_ +#define SRC_LIBRARY_LOCATE_ENVIRONMENTVARDATA_H_ + +#include "LocatorStrategy.hpp" + +namespace license { +namespace locate { +class EnvironmentVarData: public LocatorStrategy { +private: + bool isBase64 = false; + +public: + EnvironmentVarData(); + virtual const std::vector<std::string> license_locations(EventRegistry& eventRegistr); + virtual const std::string retrieve_license_content(const std::string &licenseLocation) const; + virtual ~EnvironmentVarData(); +}; + +} +} + +#endif diff --git a/src/library/locate/EnvironmentVarLocation.cpp b/src/library/locate/EnvironmentVarLocation.cpp new file mode 100644 index 0000000..a904b9a --- /dev/null +++ b/src/library/locate/EnvironmentVarLocation.cpp @@ -0,0 +1,46 @@ +/* + * EnvironmentVarLocation.cpp + * + * Created on: Oct 12, 2019 + * Author: Gabriele Contini + */ + +#include <build_properties.h> + +#include "../base/FileUtils.hpp" +#include "../base/StringUtils.h" +#include "EnvironmentVarLocation.hpp" + +namespace license { +namespace locate { +using namespace std; + +EnvironmentVarLocation::EnvironmentVarLocation() : + LocatorStrategy("EnvironmentVarLocation") { +} + +EnvironmentVarLocation::~EnvironmentVarLocation() { +} + +const vector<string> EnvironmentVarLocation::license_locations( + EventRegistry &eventRegistry) { + vector<string> licenseFileFoundWithEnvVariable; + + const string varName(LICENSE_LOCATION_ENV_VAR); + if (varName.length() > 0) { + //var name is defined in header files. + char *env_var_value = getenv(LICENSE_LOCATION_ENV_VAR); + if (env_var_value != nullptr && env_var_value[0] != '\0') { + const vector<string> declared_positions = license::split_string( + string(env_var_value), ';'); + licenseFileFoundWithEnvVariable = license::filter_existing_files( + declared_positions, eventRegistry, LICENSE_LOCATION_ENV_VAR); + } else { + eventRegistry.addEvent(ENVIRONMENT_VARIABLE_NOT_DEFINED); + } + } + return licenseFileFoundWithEnvVariable; +} + +} +} diff --git a/src/library/locate/EnvironmentVarLocation.hpp b/src/library/locate/EnvironmentVarLocation.hpp new file mode 100644 index 0000000..b2f9b6a --- /dev/null +++ b/src/library/locate/EnvironmentVarLocation.hpp @@ -0,0 +1,27 @@ +/* + * EnvironmentVarLocation.h + * + * Created on: Oct 6, 2019 + * Author: devel + */ + +#ifndef SRC_LIBRARY_LOCATE_ENVIRONMENTVARLOCATION_H_ +#define SRC_LIBRARY_LOCATE_ENVIRONMENTVARLOCATION_H_ + +#include "LocatorStrategy.hpp" + +namespace license { +namespace locate { + +class EnvironmentVarLocation: public LocatorStrategy { + +public: + EnvironmentVarLocation(); + virtual const std::vector<std::string> license_locations(EventRegistry& eventRegistry); + virtual ~EnvironmentVarLocation(); +}; + +} +} + +#endif /* SRC_LIBRARY_LOCATE_ENVIRONMENTVARLOCATION_H_ */ diff --git a/src/library/locate/ExternalDefinition.cpp b/src/library/locate/ExternalDefinition.cpp new file mode 100644 index 0000000..ec0428f --- /dev/null +++ b/src/library/locate/ExternalDefinition.cpp @@ -0,0 +1,76 @@ +/* + * ExplicitDefinition.cpp + * + * Created on: Oct 12, 2019 + * Author: Gabriele Contini + */ + +#include <stdlib.h> +#include <cstring> +#include <string> +#include <vector> + +#include "../api/datatypes.h" +#include "../base/base64.h" +#include "../base/EventRegistry.h" +#include "../base/FileUtils.hpp" +#include "../base/StringUtils.h" + +#include "ExternalDefinition.hpp" + +namespace license { +namespace locate { +using namespace std; + +ExternalDefinition::ExternalDefinition(const LicenseLocation *location) : + LocatorStrategy("ExternalDefinition"), m_location(location) { +} + +ExternalDefinition::~ExternalDefinition() { +} + +const std::vector<std::string> ExternalDefinition::license_locations( + EventRegistry &eventRegistry) { + vector<string> existing_pos; + if (m_location->licenseData != nullptr + && m_location->licenseData[0] != '\0') { + eventRegistry.addEvent(LICENSE_SPECIFIED, get_strategy_name()); + FILE_FORMAT licenseFormat = identify_format(m_location->licenseData); + + if (licenseFormat == UNKNOWN) { + eventRegistry.addEvent(LICENSE_MALFORMED, get_strategy_name()); + } else { + existing_pos.push_back(get_strategy_name()); + licenseDataIsBase64 = (licenseFormat == BASE64); + } + } + if (m_location->licenseFileLocation != nullptr + && strlen(m_location->licenseFileLocation) > 0) { + const vector<string> declared_positions = license::split_string( + m_location->licenseFileLocation, ';'); + existing_pos = license::filter_existing_files(declared_positions, + eventRegistry, get_strategy_name().c_str()); + } + return existing_pos; +} + +const std::string ExternalDefinition::retrieve_license_content( + const std::string &licenseLocation) const { + if (licenseLocation == get_strategy_name()) { + if (licenseDataIsBase64) { + int flen = 0; + unsigned char *raw = unbase64(m_location->licenseData, + strlen(m_location->licenseData), &flen); + string str = string(reinterpret_cast<char*>(raw)); + free(raw); + return str; + } else { + return m_location->licenseData; + } + } else { + return LocatorStrategy::retrieve_license_content(licenseLocation); + } +} + +} /* namespace locate */ +} /* namespace license */ diff --git a/src/library/locate/ExternalDefinition.hpp b/src/library/locate/ExternalDefinition.hpp new file mode 100644 index 0000000..c70775a --- /dev/null +++ b/src/library/locate/ExternalDefinition.hpp @@ -0,0 +1,30 @@ +/* + * ExplicitDefinition.hpp + * + * Created on: Oct 12, 2019 + * Author: devel + */ + +#ifndef SRC_LIBRARY_LOCATE_EXTERNALDEFINITION_HPP_ +#define SRC_LIBRARY_LOCATE_EXTERNALDEFINITION_HPP_ + +#include "LocatorStrategy.hpp" + +namespace license { +namespace locate { + +class ExternalDefinition: public LocatorStrategy { +private: + const LicenseLocation* m_location; + bool licenseDataIsBase64 = false; +public: + ExternalDefinition(const LicenseLocation* location); + virtual const std::vector<std::string> license_locations(EventRegistry& eventRegistry); + virtual const std::string retrieve_license_content(const std::string &licenseLocation) const; + virtual ~ExternalDefinition(); +}; + +} /* namespace locate */ +} /* namespace license */ + +#endif /* SRC_LIBRARY_LOCATE_EXTERNALDEFINITION_HPP_ */ diff --git a/src/library/locate/LocatorFactory.cpp b/src/library/locate/LocatorFactory.cpp new file mode 100644 index 0000000..1b45752 --- /dev/null +++ b/src/library/locate/LocatorFactory.cpp @@ -0,0 +1,46 @@ +/* + * LocatorFactory.cpp + * + * Created on: Oct 13, 2019 + * Author: Gabriele Contini + */ + +#include "build_properties.h" + +#include "LocatorStrategy.hpp" +#include "LocatorFactory.hpp" +#include "ApplicationFolder.hpp" +#include "EnvironmentVarData.hpp" +#include "EnvironmentVarLocation.hpp" +#include "ExternalDefinition.hpp" + +namespace license { +namespace locate { + +FUNCTION_RETURN LocatorFactory::get_active_strategies( + std::vector<std::unique_ptr<LocatorStrategy>> &strategies, + const LicenseLocation *locationHint) { +#if(FIND_LICENSE_NEAR_MODULE) + strategies.push_back( + std::unique_ptr<LocatorStrategy>( + (LocatorStrategy*) new ApplicationFolder())); +#endif +#if(FIND_LICENSE_WITH_ENV_VAR) + strategies.push_back( + std::unique_ptr<LocatorStrategy>( + (LocatorStrategy*) new EnvironmentVarLocation())); + strategies.push_back( + std::unique_ptr<LocatorStrategy>( + (LocatorStrategy*) new EnvironmentVarData())); +#endif + if (locationHint != nullptr) { + strategies.push_back( + std::unique_ptr<LocatorStrategy>( + (LocatorStrategy*) new ExternalDefinition(locationHint))); + } + return strategies.size() > 0 ? FUNC_RET_OK : FUNC_RET_NOT_AVAIL; + +} + +} +} diff --git a/src/library/locate/LocatorFactory.hpp b/src/library/locate/LocatorFactory.hpp new file mode 100644 index 0000000..6f1cd30 --- /dev/null +++ b/src/library/locate/LocatorFactory.hpp @@ -0,0 +1,32 @@ +#ifndef RETRIEVE_FACTORY_H_ +#define RETRIEVE_FACTORY_H_ + +#include <cstddef> +#include <string> +#include <vector> + +#include "../base/base.h" +#include "../api/datatypes.h" +#include "LocatorStrategy.hpp" + +namespace license { +namespace locate { + +class LocatorFactory { +private: + inline LocatorFactory() { + } + inline ~LocatorFactory() { + } +public: + + static FUNCTION_RETURN get_active_strategies( + std::vector<std::unique_ptr<LocatorStrategy>> &strategiesOut, + const LicenseLocation *locationHint); + +}; + +} +} + +#endif diff --git a/src/library/locate/LocatorStrategy.cpp b/src/library/locate/LocatorStrategy.cpp new file mode 100644 index 0000000..e1319b2 --- /dev/null +++ b/src/library/locate/LocatorStrategy.cpp @@ -0,0 +1,23 @@ +/* + * EnvironmentVarLocation.cpp + * + * Created on: Oct 12, 2019 + * Author: Gabriele Contini + */ + +#include <build_properties.h> + +#include "../base/FileUtils.hpp" +#include "LocatorStrategy.hpp" + +namespace license { +namespace locate { +using namespace std; + +const string LocatorStrategy::retrieve_license_content( + const string &licenseLocation) const { + return get_file_contents(licenseLocation.c_str(), MAX_LICENSE_LENGTH); +} + +} +} diff --git a/src/library/locate/LocatorStrategy.hpp b/src/library/locate/LocatorStrategy.hpp new file mode 100644 index 0000000..278c6a3 --- /dev/null +++ b/src/library/locate/LocatorStrategy.hpp @@ -0,0 +1,60 @@ +#ifndef RETRIEVER_H_ +#define RETRIEVER_H_ + +#include <memory> +#include <cstddef> +#include <string> +#include <vector> + +#include "../base/EventRegistry.h" + +namespace license { +namespace locate { +/** + * This class provides a common interface to find and retrieve + * licenses from different sources and positions. + * + * Usage: + * <ol> + * <li> call licenseLocations to get a list of available locations (the returned format is defined by the class, it's usually the file name)</li> + * <li> iterate over the returned vector and call retrieveLicense to get the content of the license</li> + * </ol> + */ +class LocatorStrategy { +protected: + const std::string m_strategy_name; + inline LocatorStrategy(const std::string &strategyName) : + m_strategy_name(strategyName) { + } +public: + + virtual const std::string get_strategy_name() const { + return m_strategy_name; + } + /** + * Try to find licenses + * @param eventRegistry + * @return + * A list of identifiers for call retrieve_license_content. + */ + virtual const std::vector<std::string> license_locations( + EventRegistry &eventRegistry) = 0; + + /** + * Default implementation is to retrieve the license from file. + * Subclasses may override it. + * @param licenseLocationId + * String that identifies the license. It is usually the file name + * but can be whatever is understood by the class + * @return + * a string containing the license data in INI format. + */ + virtual const std::string retrieve_license_content( + const std::string &licenseLocationId) const; + inline virtual ~LocatorStrategy() { + } +}; + +} +} +#endif diff --git a/src/library/os/os.h b/src/library/os/os.h index 7eea3eb..1371786 100644 --- a/src/library/os/os.h +++ b/src/library/os/os.h @@ -2,7 +2,7 @@ * os-dependent.hpp * * Created on: Mar 29, 2014 - * + * */ #ifndef OS_DEPENDENT_HPP_ @@ -79,6 +79,14 @@ FUNCTION_RETURN verifySignature(const char* stringToVerify, const char* signatureB64); +#ifdef _WIN32 +#define SETENV(VAR,VAL) _putenv_s(VAR, VAL); +#define UNSETENV(P) _putenv_s(P, ""); +#else +#define SETENV(VAR,VAL) setenv(VAR, VAL, 1); +#define UNSETENV(P) unsetenv(P); +#endif + #ifdef __cplusplus } #endif diff --git a/src/tools/base_lib/win/CryptoHelperWindows.cpp b/src/tools/base_lib/win/CryptoHelperWindows.cpp index 99e0b12..ff40457 100644 --- a/src/tools/base_lib/win/CryptoHelperWindows.cpp +++ b/src/tools/base_lib/win/CryptoHelperWindows.cpp @@ -1,394 +1,394 @@ -/* - * CryptoHelperWindows.cpp - * - * Created on: Sep 14, 2014 - * - */ - -#include <sstream> -#include <vector> -#include <string> -#include "CryptoHelperWindows.h" -// The RSA public-key key exchange algorithm -#define ENCRYPT_ALGORITHM CALG_RSA_SIGN -// The high order WORD 0x0200 (decimal 512) -// determines the key length in bits. -#define KEYLENGTH 0x02000000 -#pragma comment(lib, "crypt32.lib") - -namespace license { - -CryptoHelperWindows::CryptoHelperWindows() { - m_hCryptProv = NULL; - m_hCryptKey = NULL; - if (!CryptAcquireContext(&m_hCryptProv, "license_sign", NULL , PROV_RSA_FULL, 0)) { - // If the key container cannot be opened, try creating a new - // container by specifying a container name and setting the - // CRYPT_NEWKEYSET flag. - DWORD lastError = GetLastError(); - printf("Error in CryptAcquireContext (1) 0x%08x \n", lastError); - if (NTE_BAD_KEYSET == lastError) { - if (!CryptAcquireContext(&m_hCryptProv, "license_sign", NULL , PROV_RSA_FULL, CRYPT_NEWKEYSET)) { - printf("Warn in CryptAcquireContext: acquiring new user keyset failed 0x%08x, trying less secure mackine keyset \n", GetLastError()); - //maybe access to protected storage disabled. Try with machine keys (less secure) - if (!CryptAcquireContext(&m_hCryptProv, "license_sign", NULL, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET)) { - printf("Error in CryptAcquireContext (2) 0x%08x \n", GetLastError()); - if (!CryptAcquireContext(&m_hCryptProv, "license_sign", NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET|CRYPT_MACHINE_KEYSET)) { - printf("Error in CryptAcquireContext (3): acquiring new keyset(machine) failed 0x%08x \n", GetLastError()); - throw logic_error(""); - } - } - } - } else { - printf(" Error in CryptAcquireContext (4) 0x%08x \n", lastError); - throw logic_error(""); - } - } - -} - -/** - This method calls the CryptGenKey function to get a handle to an - - exportable key-pair. The key-pair is generated with the RSA public-key - key exchange algorithm using Microsoft Enhanced Cryptographic Provider. - */ -void CryptoHelperWindows::generateKeyPair() { - HRESULT hr = S_OK; - DWORD dwErrCode; - // If the handle to key container is NULL, fail. - if (m_hCryptProv == NULL) - throw logic_error("Cryptocontext not correctly initialized"); - // Release a previously acquired handle to key-pair. - if (m_hCryptKey) - m_hCryptKey = NULL; - // Call the CryptGenKey method to get a handle - // to a new exportable key-pair. - if (!CryptGenKey(m_hCryptProv, ENCRYPT_ALGORITHM, - KEYLENGTH | CRYPT_EXPORTABLE, &m_hCryptKey)) { - dwErrCode = GetLastError(); - throw logic_error( - string("Error generating keys ") - + to_string(static_cast<long long>(dwErrCode))); - } - //double check the key is really generated - if(m_hCryptKey == NULL) { - dwErrCode = GetLastError(); - throw logic_error( - string("Error generating keys (2)") - + to_string(static_cast<long long>(dwErrCode))); - } -} - -/* This method calls the CryptExportKey function to get the Public key - in a string suitable for C source inclusion. - */ -const string CryptoHelperWindows::exportPublicKey() const { - HRESULT hr = S_OK; - DWORD dwErrCode; - DWORD dwBlobLen; - BYTE *pbKeyBlob = nullptr; - stringstream ss; - // If the handle to key container is NULL, fail. - if (m_hCryptKey == NULL) - throw logic_error("call GenerateKey first."); - // This call here determines the length of the key - // blob. - if (!CryptExportKey(m_hCryptKey, - NULL, PUBLICKEYBLOB, 0, nullptr, &dwBlobLen)) { - dwErrCode = GetLastError(); - throw logic_error( - string("Error calculating size of public key ") - + to_string(static_cast<long long>(dwErrCode))); - } - // Allocate memory for the pbKeyBlob. - if ((pbKeyBlob = new BYTE[dwBlobLen]) == nullptr) { - throw logic_error(string("Out of memory exporting public key ")); - } - // Do the actual exporting into the key BLOB. - if (!CryptExportKey(m_hCryptKey, - NULL, PUBLICKEYBLOB, 0, pbKeyBlob, &dwBlobLen)) { - delete pbKeyBlob; - dwErrCode = GetLastError(); - throw logic_error( - string("Error exporting public key ") - + to_string(static_cast<long long>(dwErrCode))); - } else { - ss << "\t"; - for (unsigned int i = 0; i < dwBlobLen; i++) { - if (i != 0) { - ss << ", "; - if (i % 10 == 0) { - ss << "\\" << endl << "\t"; - } - } - ss << to_string(static_cast<long long>(pbKeyBlob[i])); - } - delete pbKeyBlob; - } - return ss.str(); -} - -CryptoHelperWindows::~CryptoHelperWindows() { - if (m_hCryptProv) { - CryptReleaseContext(m_hCryptProv, 0); - m_hCryptProv = NULL; - } - if (m_hCryptKey) - m_hCryptKey = NULL; -} - -//-------------------------------------------------------------------- -// This method calls the CryptExportKey function to get the Private key -// in a byte array. The byte array is allocated on the heap and the size -// of this is returned to the caller. The caller is responsible for releasing // this memory using a delete call. -//-------------------------------------------------------------------- -const string CryptoHelperWindows::exportPrivateKey() const { - HRESULT hr = S_OK; - DWORD dwErrCode; - DWORD dwBlobLen; - BYTE *pbKeyBlob; - stringstream ss; - // If the handle to key container is NULL, fail. - if (m_hCryptKey == NULL) - throw logic_error(string("call GenerateKey first.")); - // This call here determines the length of the key - // blob. - if (!CryptExportKey(m_hCryptKey, - NULL, PRIVATEKEYBLOB, 0, nullptr, &dwBlobLen)) { - dwErrCode = GetLastError(); - throw logic_error( - string("Error calculating size of private key ") - + to_string(static_cast<long long>(dwErrCode))); - } - // Allocate memory for the pbKeyBlob. - if ((pbKeyBlob = new BYTE[dwBlobLen]) == nullptr) { - throw logic_error(string("Out of memory exporting private key ")); - } - - // Do the actual exporting into the key BLOB. - if (!CryptExportKey(m_hCryptKey, - NULL, PRIVATEKEYBLOB, 0, pbKeyBlob, &dwBlobLen)) { - delete pbKeyBlob; - dwErrCode = GetLastError(); - throw logic_error( - string("Error exporting private key ") - + to_string(static_cast<long long>(dwErrCode))); - } else { - ss << "\t"; - for (unsigned int i = 0; i < dwBlobLen; i++) { - if (i != 0) { - ss << ", "; - if (i % 15 == 0) { - ss << "\\" << endl << "\t"; - } - } - ss << to_string(static_cast<long long>(pbKeyBlob[i])); - } - delete pbKeyBlob; - } - return ss.str(); -} - -void CryptoHelperWindows::printHash(HCRYPTHASH *hHash) const { - BYTE *pbHash; - DWORD dwHashLen; - DWORD dwHashLenSize = sizeof(DWORD); - char *hashStr; - unsigned int i; - - if (CryptGetHashParam(*hHash, HP_HASHSIZE, (BYTE*) &dwHashLen, - &dwHashLenSize, 0)) { - pbHash = (BYTE*) malloc(dwHashLen); - hashStr = (char*) malloc(dwHashLen * 2 + 1); - if (CryptGetHashParam(*hHash, HP_HASHVAL, pbHash, &dwHashLen, 0)) { - for (i = 0; i < dwHashLen; i++) { - sprintf(&hashStr[i * 2], "%02x", pbHash[i]); - } - printf("hash To be signed: %s \n", hashStr); - } - free(pbHash); - free(hashStr); - } -} - -const string CryptoHelperWindows::signString(const void *privateKey, - size_t pklen, const string &license) const { - BYTE *pbBuffer = (BYTE*) license.c_str(); - const DWORD dwBufferLen = (DWORD) strlen((char*) pbBuffer); - HCRYPTHASH hHash; - - HCRYPTKEY hKey; - BYTE *pbSignature; - DWORD dwSigLen; - DWORD strLen; - - //------------------------------------------------------------------- - // Acquire a cryptographic provider context handle. - - if (!CryptImportKey(m_hCryptProv, (const BYTE*) privateKey, (DWORD) pklen, - 0, 0, &hKey)) { - throw logic_error( - string("Error in importing the PrivateKey ") - + to_string(static_cast<long long>(GetLastError()))); - } - - //------------------------------------------------------------------- - // Create the hash object. - - if (CryptCreateHash(m_hCryptProv, CALG_SHA1, 0, 0, &hHash)) { - printf("Hash object created. \n"); - } else { - CryptDestroyKey(hKey); - throw logic_error(string("Error during CryptCreateHash.")); - } - //------------------------------------------------------------------- - // Compute the cryptographic hash of the buffer. - - if (CryptHashData(hHash, pbBuffer, dwBufferLen, 0)) { -#ifdef _DEBUG - printf("Length of data to be hashed: %d \n", dwBufferLen); - printHash(&hHash); -#endif - } else { - throw logic_error(string("Error during CryptHashData.")); - } - //------------------------------------------------------------------- - // Determine the size of the signature and allocate memory. - - dwSigLen = 0; - if (CryptSignHash(hHash, AT_SIGNATURE, nullptr, 0, nullptr, &dwSigLen)) { - printf("Signature length %d found.\n", dwSigLen); - } else { - throw logic_error(string("Error during CryptSignHash.")); - } - //------------------------------------------------------------------- - // Allocate memory for the signature buffer. - - if (pbSignature = (BYTE*) malloc(dwSigLen)) { - printf("Memory allocated for the signature.\n"); - } else { - throw logic_error(string("Out of memory.")); - } - //------------------------------------------------------------------- - // Sign the hash object. - - if (CryptSignHash(hHash, AT_SIGNATURE, nullptr, 0, pbSignature, - &dwSigLen)) { - printf("pbSignature is the signature length. %d\n", dwSigLen); - } else { - throw logic_error(string("Error during CryptSignHash.")); - } - //------------------------------------------------------------------- - // Destroy the hash object. - - CryptDestroyHash(hHash); - CryptDestroyKey(hKey); - - CryptBinaryToString(pbSignature, dwSigLen, - CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, nullptr, &strLen); - vector<char> buffer(strLen); - CryptBinaryToString(pbSignature, dwSigLen, - CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, &buffer[0], &strLen); - - //------------------------------------------------------------------- - // In the second phase, the hash signature is verified. - // This would most often be done by a different user in a - // separate program. The hash, signature, and the PUBLICKEYBLOB - // would be read from a file, an email message, - // or some other source. - - // Here, the original pbBuffer, pbSignature, szDescription. - // pbKeyBlob, and their lengths are used. - - // The contents of the pbBuffer must be the same data - // that was originally signed. - - //------------------------------------------------------------------- - // Get the public key of the user who created the digital signature - // and import it into the CSP by using CryptImportKey. This returns - // a handle to the public key in hPubKey. - - /*if (CryptImportKey( - hProv, - pbKeyBlob, - dwBlobLen, - 0, - 0, - &hPubKey)) - { - printf("The key has been imported.\n"); - } - else - { - MyHandleError("Public key import failed."); - } - //------------------------------------------------------------------- - // Create a new hash object. - - if (CryptCreateHash( - hProv, - CALG_MD5, - 0, - 0, - &hHash)) - { - printf("The hash object has been recreated. \n"); - } - else - { - MyHandleError("Error during CryptCreateHash."); - } - //------------------------------------------------------------------- - // Compute the cryptographic hash of the buffer. - - if (CryptHashData( - hHash, - pbBuffer, - dwBufferLen, - 0)) - { - printf("The new hash has been created.\n"); - } - else - { - MyHandleError("Error during CryptHashData."); - } - //------------------------------------------------------------------- - // Validate the digital signature. - - if (CryptVerifySignature( - hHash, - pbSignature, - dwSigLen, - hPubKey, - NULL, - 0)) - { - printf("The signature has been verified.\n"); - } - else - { - printf("Signature not validated!\n"); - } - //------------------------------------------------------------------- - // Free memory to be used to store signature. - - - - //------------------------------------------------------------------- - // Destroy the hash object. - - - - //------------------------------------------------------------------- - // Release the provider handle. - - /*if (hProv) - CryptReleaseContext(hProv, 0);*/ - if (pbSignature) { - free(pbSignature); - } - return string(&buffer[0]); -} -} /* namespace license */ +/* + * CryptoHelperWindows.cpp + * + * Created on: Sep 14, 2014 + * + */ + +#include <sstream> +#include <vector> +#include <string> +#include "CryptoHelperWindows.h" +// The RSA public-key key exchange algorithm +#define ENCRYPT_ALGORITHM CALG_RSA_SIGN +// The high order WORD 0x0200 (decimal 512) +// determines the key length in bits. +#define KEYLENGTH 0x02000000 +#pragma comment(lib, "crypt32.lib") + +namespace license { + +CryptoHelperWindows::CryptoHelperWindows() { + m_hCryptProv = NULL; + m_hCryptKey = NULL; + if (!CryptAcquireContext(&m_hCryptProv, "license_sign", NULL , PROV_RSA_FULL, 0)) { + // If the key container cannot be opened, try creating a new + // container by specifying a container name and setting the + // CRYPT_NEWKEYSET flag. + DWORD lastError = GetLastError(); + printf("Error in CryptAcquireContext (1) 0x%08x \n", lastError); + if (NTE_BAD_KEYSET == lastError) { + if (!CryptAcquireContext(&m_hCryptProv, "license_sign", NULL , PROV_RSA_FULL, CRYPT_NEWKEYSET)) { + printf("Warn in CryptAcquireContext: acquiring new user keyset failed 0x%08x, trying less secure mackine keyset \n", GetLastError()); + //maybe access to protected storage disabled. Try with machine keys (less secure) + if (!CryptAcquireContext(&m_hCryptProv, "license_sign", NULL, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET)) { + printf("Error in CryptAcquireContext (2) 0x%08x \n", GetLastError()); + if (!CryptAcquireContext(&m_hCryptProv, "license_sign", NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET|CRYPT_MACHINE_KEYSET)) { + printf("Error in CryptAcquireContext (3): acquiring new keyset(machine) failed 0x%08x \n", GetLastError()); + throw logic_error(""); + } + } + } + } else { + printf(" Error in CryptAcquireContext (4) 0x%08x \n", lastError); + throw logic_error(""); + } + } + +} + +/** + This method calls the CryptGenKey function to get a handle to an + + exportable key-pair. The key-pair is generated with the RSA public-key + key exchange algorithm using Microsoft Enhanced Cryptographic Provider. + */ +void CryptoHelperWindows::generateKeyPair() { + HRESULT hr = S_OK; + DWORD dwErrCode; + // If the handle to key container is NULL, fail. + if (m_hCryptProv == NULL) + throw logic_error("Cryptocontext not correctly initialized"); + // Release a previously acquired handle to key-pair. + if (m_hCryptKey) + m_hCryptKey = NULL; + // Call the CryptGenKey method to get a handle + // to a new exportable key-pair. + if (!CryptGenKey(m_hCryptProv, ENCRYPT_ALGORITHM, + KEYLENGTH | CRYPT_EXPORTABLE, &m_hCryptKey)) { + dwErrCode = GetLastError(); + throw logic_error( + string("Error generating keys ") + + to_string(static_cast<long long>(dwErrCode))); + } + //double check the key is really generated + if(m_hCryptKey == NULL) { + dwErrCode = GetLastError(); + throw logic_error( + string("Error generating keys (2)") + + to_string(static_cast<long long>(dwErrCode))); + } +} + +/* This method calls the CryptExportKey function to get the Public key + in a string suitable for C source inclusion. + */ +const string CryptoHelperWindows::exportPublicKey() const { + HRESULT hr = S_OK; + DWORD dwErrCode; + DWORD dwBlobLen; + BYTE *pbKeyBlob = nullptr; + stringstream ss; + // If the handle to key container is NULL, fail. + if (m_hCryptKey == NULL) + throw logic_error("call GenerateKey first."); + // This call here determines the length of the key + // blob. + if (!CryptExportKey(m_hCryptKey, + NULL, PUBLICKEYBLOB, 0, nullptr, &dwBlobLen)) { + dwErrCode = GetLastError(); + throw logic_error( + string("Error calculating size of public key ") + + to_string(static_cast<long long>(dwErrCode))); + } + // Allocate memory for the pbKeyBlob. + if ((pbKeyBlob = new BYTE[dwBlobLen]) == nullptr) { + throw logic_error(string("Out of memory exporting public key ")); + } + // Do the actual exporting into the key BLOB. + if (!CryptExportKey(m_hCryptKey, + NULL, PUBLICKEYBLOB, 0, pbKeyBlob, &dwBlobLen)) { + delete pbKeyBlob; + dwErrCode = GetLastError(); + throw logic_error( + string("Error exporting public key ") + + to_string(static_cast<long long>(dwErrCode))); + } else { + ss << "\t"; + for (unsigned int i = 0; i < dwBlobLen; i++) { + if (i != 0) { + ss << ", "; + if (i % 10 == 0) { + ss << "\\" << endl << "\t"; + } + } + ss << to_string(static_cast<long long>(pbKeyBlob[i])); + } + delete pbKeyBlob; + } + return ss.str(); +} + +CryptoHelperWindows::~CryptoHelperWindows() { + if (m_hCryptProv) { + CryptReleaseContext(m_hCryptProv, 0); + m_hCryptProv = NULL; + } + if (m_hCryptKey) + m_hCryptKey = NULL; +} + +//-------------------------------------------------------------------- +// This method calls the CryptExportKey function to get the Private key +// in a byte array. The byte array is allocated on the heap and the size +// of this is returned to the caller. The caller is responsible for releasing // this memory using a delete call. +//-------------------------------------------------------------------- +const string CryptoHelperWindows::exportPrivateKey() const { + HRESULT hr = S_OK; + DWORD dwErrCode; + DWORD dwBlobLen; + BYTE *pbKeyBlob; + stringstream ss; + // If the handle to key container is NULL, fail. + if (m_hCryptKey == NULL) + throw logic_error(string("call GenerateKey first.")); + // This call here determines the length of the key + // blob. + if (!CryptExportKey(m_hCryptKey, + NULL, PRIVATEKEYBLOB, 0, nullptr, &dwBlobLen)) { + dwErrCode = GetLastError(); + throw logic_error( + string("Error calculating size of private key ") + + to_string(static_cast<long long>(dwErrCode))); + } + // Allocate memory for the pbKeyBlob. + if ((pbKeyBlob = new BYTE[dwBlobLen]) == nullptr) { + throw logic_error(string("Out of memory exporting private key ")); + } + + // Do the actual exporting into the key BLOB. + if (!CryptExportKey(m_hCryptKey, + NULL, PRIVATEKEYBLOB, 0, pbKeyBlob, &dwBlobLen)) { + delete pbKeyBlob; + dwErrCode = GetLastError(); + throw logic_error( + string("Error exporting private key ") + + to_string(static_cast<long long>(dwErrCode))); + } else { + ss << "\t"; + for (unsigned int i = 0; i < dwBlobLen; i++) { + if (i != 0) { + ss << ", "; + if (i % 15 == 0) { + ss << "\\" << endl << "\t"; + } + } + ss << to_string(static_cast<long long>(pbKeyBlob[i])); + } + delete pbKeyBlob; + } + return ss.str(); +} + +void CryptoHelperWindows::printHash(HCRYPTHASH *hHash) const { + BYTE *pbHash; + DWORD dwHashLen; + DWORD dwHashLenSize = sizeof(DWORD); + char *hashStr; + unsigned int i; + + if (CryptGetHashParam(*hHash, HP_HASHSIZE, (BYTE*) &dwHashLen, + &dwHashLenSize, 0)) { + pbHash = (BYTE*) malloc(dwHashLen); + hashStr = (char*) malloc(dwHashLen * 2 + 1); + if (CryptGetHashParam(*hHash, HP_HASHVAL, pbHash, &dwHashLen, 0)) { + for (i = 0; i < dwHashLen; i++) { + sprintf(&hashStr[i * 2], "%02x", pbHash[i]); + } + printf("hash To be signed: %s \n", hashStr); + } + free(pbHash); + free(hashStr); + } +} + +const string CryptoHelperWindows::signString(const void *privateKey, + size_t pklen, const string &license) const { + BYTE *pbBuffer = (BYTE*) license.c_str(); + const DWORD dwBufferLen = (DWORD) strlen((char*) pbBuffer); + HCRYPTHASH hHash; + + HCRYPTKEY hKey; + BYTE *pbSignature; + DWORD dwSigLen; + DWORD strLen; + + //------------------------------------------------------------------- + // Acquire a cryptographic provider context handle. + + if (!CryptImportKey(m_hCryptProv, (const BYTE*) privateKey, (DWORD) pklen, + 0, 0, &hKey)) { + throw logic_error( + string("Error in importing the PrivateKey ") + + to_string(static_cast<long long>(GetLastError()))); + } + + //------------------------------------------------------------------- + // Create the hash object. + + if (CryptCreateHash(m_hCryptProv, CALG_SHA1, 0, 0, &hHash)) { + printf("Hash object created. \n"); + } else { + CryptDestroyKey(hKey); + throw logic_error(string("Error during CryptCreateHash.")); + } + //------------------------------------------------------------------- + // Compute the cryptographic hash of the buffer. + + if (CryptHashData(hHash, pbBuffer, dwBufferLen, 0)) { +#ifdef _DEBUG + printf("Length of data to be hashed: %d \n", dwBufferLen); + printHash(&hHash); +#endif + } else { + throw logic_error(string("Error during CryptHashData.")); + } + //------------------------------------------------------------------- + // Determine the size of the signature and allocate memory. + + dwSigLen = 0; + if (CryptSignHash(hHash, AT_SIGNATURE, nullptr, 0, nullptr, &dwSigLen)) { + printf("Signature length %d found.\n", dwSigLen); + } else { + throw logic_error(string("Error during CryptSignHash.")); + } + //------------------------------------------------------------------- + // Allocate memory for the signature buffer. + + if (pbSignature = (BYTE*) malloc(dwSigLen)) { + printf("Memory allocated for the signature.\n"); + } else { + throw logic_error(string("Out of memory.")); + } + //------------------------------------------------------------------- + // Sign the hash object. + + if (CryptSignHash(hHash, AT_SIGNATURE, nullptr, 0, pbSignature, + &dwSigLen)) { + printf("pbSignature is the signature length. %d\n", dwSigLen); + } else { + throw logic_error(string("Error during CryptSignHash.")); + } + //------------------------------------------------------------------- + // Destroy the hash object. + + CryptDestroyHash(hHash); + CryptDestroyKey(hKey); + + CryptBinaryToString(pbSignature, dwSigLen, + CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, nullptr, &strLen); + vector<char> buffer(strLen); + CryptBinaryToString(pbSignature, dwSigLen, + CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, &buffer[0], &strLen); + + //------------------------------------------------------------------- + // In the second phase, the hash signature is verified. + // This would most often be done by a different user in a + // separate program. The hash, signature, and the PUBLICKEYBLOB + // would be read from a file, an email message, + // or some other source. + + // Here, the original pbBuffer, pbSignature, szDescription. + // pbKeyBlob, and their lengths are used. + + // The contents of the pbBuffer must be the same data + // that was originally signed. + + //------------------------------------------------------------------- + // Get the public key of the user who created the digital signature + // and import it into the CSP by using CryptImportKey. This returns + // a handle to the public key in hPubKey. + + /*if (CryptImportKey( + hProv, + pbKeyBlob, + dwBlobLen, + 0, + 0, + &hPubKey)) + { + printf("The key has been imported.\n"); + } + else + { + MyHandleError("Public key import failed."); + } + //------------------------------------------------------------------- + // Create a new hash object. + + if (CryptCreateHash( + hProv, + CALG_MD5, + 0, + 0, + &hHash)) + { + printf("The hash object has been recreated. \n"); + } + else + { + MyHandleError("Error during CryptCreateHash."); + } + //------------------------------------------------------------------- + // Compute the cryptographic hash of the buffer. + + if (CryptHashData( + hHash, + pbBuffer, + dwBufferLen, + 0)) + { + printf("The new hash has been created.\n"); + } + else + { + MyHandleError("Error during CryptHashData."); + } + //------------------------------------------------------------------- + // Validate the digital signature. + + if (CryptVerifySignature( + hHash, + pbSignature, + dwSigLen, + hPubKey, + NULL, + 0)) + { + printf("The signature has been verified.\n"); + } + else + { + printf("Signature not validated!\n"); + } + //------------------------------------------------------------------- + // Free memory to be used to store signature. + + + + //------------------------------------------------------------------- + // Destroy the hash object. + + + + //------------------------------------------------------------------- + // Release the provider handle. + + /*if (hProv) + CryptReleaseContext(hProv, 0);*/ + if (pbSignature) { + free(pbSignature); + } + return string(&buffer[0]); +} +} /* namespace license */ diff --git a/src/tools/base_lib/win/CryptoHelperWindows.h b/src/tools/base_lib/win/CryptoHelperWindows.h index a432e27..b4e7594 100644 --- a/src/tools/base_lib/win/CryptoHelperWindows.h +++ b/src/tools/base_lib/win/CryptoHelperWindows.h @@ -1,46 +1,46 @@ -/* - * CryptoHelperWindows.h - * - * Created on: Sep 14, 2014 - * - */ - -#ifndef CRYPTOHELPERWINDOWS_H_ -#define CRYPTOHELPERWINDOWS_H_ - -//#define _WIN32_WINNT 0x0400 -#include <windows.h> -#include <wincrypt.h> -#include <tchar.h> -#include <string> -#include "../CryptoHelper.h" - - - -namespace license { -using namespace std; - -class CryptoHelperWindows: public CryptoHelper { -private : - void acquireContext(); - // Handle to the cryptography provider. - HCRYPTPROV m_hCryptProv; - // Handle to the cryptography key. - HCRYPTKEY m_hCryptKey; - void printHash(HCRYPTHASH* hHash) const; -public: - CryptoHelperWindows(); - - virtual void generateKeyPair(); - virtual const string exportPrivateKey() const; - virtual const string exportPublicKey() const; - - virtual const string signString(const void* privateKey, size_t pklen, - const string& license) const; - - virtual ~CryptoHelperWindows(); -}; - -} /* namespace license */ - -#endif /* CRYPTOHELPERWINDOWS_H_ */ +/* + * CryptoHelperWindows.h + * + * Created on: Sep 14, 2014 + * + */ + +#ifndef CRYPTOHELPERWINDOWS_H_ +#define CRYPTOHELPERWINDOWS_H_ + +//#define _WIN32_WINNT 0x0400 +#include <windows.h> +#include <wincrypt.h> +#include <tchar.h> +#include <string> +#include "../CryptoHelper.h" + + + +namespace license { +using namespace std; + +class CryptoHelperWindows: public CryptoHelper { +private : + void acquireContext(); + // Handle to the cryptography provider. + HCRYPTPROV m_hCryptProv; + // Handle to the cryptography key. + HCRYPTKEY m_hCryptKey; + void printHash(HCRYPTHASH* hHash) const; +public: + CryptoHelperWindows(); + + virtual void generateKeyPair(); + virtual const string exportPrivateKey() const; + virtual const string exportPublicKey() const; + + virtual const string signString(const void* privateKey, size_t pklen, + const string& license) const; + + virtual ~CryptoHelperWindows(); +}; + +} /* namespace license */ + +#endif /* CRYPTOHELPERWINDOWS_H_ */ diff --git a/src/tools/license-generator/CMakeLists.txt b/src/tools/license-generator/CMakeLists.txt index e707d5f..334b178 100644 --- a/src/tools/license-generator/CMakeLists.txt +++ b/src/tools/license-generator/CMakeLists.txt @@ -10,7 +10,8 @@ target_link_libraries( license_generator_lib tools_base - licensepp_static + base + licensecc_static $<$<CONFIG:Debug>:${Boost_PROGRAM_OPTIONS_LIBRARY_DEBUG}> $<$<NOT:$<CONFIG:Debug>>:${Boost_PROGRAM_OPTIONS_LIBRARY_RELEASE}> $<$<CONFIG:Debug>:${Boost_SYSTEM_LIBRARY_DEBUG}> diff --git a/src/tools/license-generator/license-generator.cpp b/src/tools/license-generator/license-generator.cpp index dcffd7e..d7335cf 100644 --- a/src/tools/license-generator/license-generator.cpp +++ b/src/tools/license-generator/license-generator.cpp @@ -1,32 +1,40 @@ -#include <build_properties.h> -#include <private-key.h> #include "license-generator.h" -#include "../base_lib/CryptoHelper.h" + +#include <stddef.h> #include <stdlib.h> -#include <stdio.h> +#include <cerrno> +#include <cstdio> +#include <cstring> +#include <ctime> +#include <fstream> +#include <iomanip> #include <iostream> -#include <string.h> -#include <iostream> -#include <string.h> -#include <boost/date_time.hpp> +#include <iterator> +#include <map> +#include <memory> +#include <regex> +#include <sstream> +#include <stdexcept> +#include <string> +#include <vector> #include <boost/program_options.hpp> #include <boost/algorithm/string.hpp> -#include <boost/unordered_map.hpp> -#include <boost/assign.hpp> -#include <fstream> -#include <regex> -#include <boost/filesystem.hpp> -namespace fs = boost::filesystem; -namespace bt = boost::posix_time; +#include <private-key.h> +#include <build_properties.h> +#include "../../library/base/base64.h" +#include "../base_lib/CryptoHelper.h" + +//namespace fs = boost::filesystem; +//namespace bt = boost::posix_time; namespace po = boost::program_options; using namespace std; namespace license { -void LicenseGenerator::printHelp(const char* prog_name, - const po::options_description& options) { +void LicenseGenerator::printHelp(const char *prog_name, + const po::options_description &options) { cout << endl; cout << prog_name << " Version " << PROJECT_VERSION << endl << ". Usage:" << endl; @@ -40,43 +48,41 @@ po::options_description LicenseGenerator::configureProgramOptions() { po::options_description common("General options"); - common.add_options() - ("help,h", "print help message and exit.") - ("verbose,v", "print more information.") - ("output,o", po::value<string>(), "Output file name. If not specified the " - "license will be printed in standard output") - ; + common.add_options()("help,h", "print help message and exit.") // + ("verbose,v", "print more information.")// + + ("output,o", po::value<string>(), "Output file name. If not specified the " + "license will be printed to standard output"); po::options_description licenseGeneration("License Generation"); - licenseGeneration.add_options() - ("private_key,p", po::value<string>(), + licenseGeneration.add_options()("private_key,p", po::value<string>(), "Specify an alternate file for the primary key to be used. " - "If not specified the internal primary key will be used.") - ("begin_date,b", po::value<string>(), + "If not specified the internal primary key will be used.")( + "begin_date,b", po::value<string>(), "Specify the start of the validity for this license. " - " Format YYYYMMDD. If not specified defaults to today") - ("expire_date,e", po::value<string>(), + " Format YYYYMMDD. If not specified defaults to today")( + "expire_date,e", po::value<string>(), "Specify the expire date for this license. " - " Format YYYYMMDD. If not specified the license won't expire") - ("client_signature,s", po::value<string>(), + " Format YYYYMMDD. If not specified the license won't expire")( + "client_signature,s", po::value<string>(), "The signature of the pc that requires the license. " "It should be in the format XXXX-XXXX-XXXX-XXXX." " If not specified the license " - "won't be linked to a specific pc.") - ("start_version,t", po::value<unsigned int>()->default_value(0 + "won't be linked to a specific pc.")("start_version,t", + po::value<unsigned int>()->default_value(0 /*FullLicenseInfo.UNUSED_SOFTWARE_VERSION*/, "All Versions"), - "Specify the first version of the software this license apply to.") - ("end_version,n", po::value<unsigned int>()->default_value(0 + "Specify the first version of the software this license apply to.")( + "end_version,n", po::value<unsigned int>()->default_value(0 /*FullLicenseInfo.UNUSED_SOFTWARE_VERSION*/, "All Versions"), - "Specify the last version of the software this license apply to.") - ("extra_data,x", po::value<string>(), "Specify extra data to be included into the license") - ; + "Specify the last version of the software this license apply to.")( + "extra_data,x", po::value<string>(), + "Specify extra data to be included into the license"); po::options_description visibleOptions; visibleOptions.add(common).add(licenseGeneration); return visibleOptions; } vector<FullLicenseInfo> LicenseGenerator::parseLicenseInfo( - const po::variables_map& vm) { + const po::variables_map &vm) { string begin_date = FullLicenseInfo::UNUSED_TIME; string end_date = FullLicenseInfo::UNUSED_TIME; if (vm.count("expire_date")) { @@ -108,13 +114,14 @@ if (vm.count("client_signature")) { client_signature = vm["client_signature"].as<string>(); cout << "cli sig:" << client_signature; - regex e("[A-Za-z0-9\\+/]{4}-[A-Za-z0-9\\+/]{4}-[A-Za-z0-9\\+/]{4}-[A-Za-z0-9\\+/]{4}"); + regex e( + "[A-Za-z0-9\\+/]{4}-[A-Za-z0-9\\+/]{4}-[A-Za-z0-9\\+/]{4}-[A-Za-z0-9\\+/]{4}"); cout << "\nregex:"; if (!regex_match(client_signature, e)) { cerr << endl << "Client signature not recognized: " - << client_signature - << " Please enter a valid signature in format XXXX-XXXX-XXXX-XXXX" - << endl; + << client_signature + << " Please enter a valid signature in format XXXX-XXXX-XXXX-XXXX" + << endl; exit(2); } } @@ -142,18 +149,32 @@ return licInfo; } -void LicenseGenerator::generateAndOutputLicenses(const po::variables_map& vm, - ostream& outputFile) { +void LicenseGenerator::generateAndOutputLicenses(const po::variables_map &vm, + ostream &outputFile) { vector<FullLicenseInfo> licenseInfo = parseLicenseInfo(vm); const unique_ptr<CryptoHelper> helper = CryptoHelper::getInstance(); const unsigned char pkey[] = PRIVATE_KEY; const size_t len = sizeof(pkey); for (auto it = licenseInfo.begin(); it != licenseInfo.end(); ++it) { const string license = it->printForSign(); - const string signature = helper->signString((const void *)pkey,len,license); + const string signature = helper->signString((const void*) pkey, len, + license); it->license_signature = signature; it->printAsIni(outputFile); } +} + +void LicenseGenerator::generateB64Licenses(const po::variables_map &vm, + ostream &outputFile) { + std::ostringstream tempStream; + generateAndOutputLicenses(vm, tempStream); + + std::string str = tempStream.str(); + const char *chr = str.c_str(); + int finalLenght; + char *encoded = base64(chr, str.length(), &finalLenght); + outputFile.write(encoded, finalLenght); + free(encoded); } int LicenseGenerator::generateLicense(int argc, const char **argv) { @@ -183,13 +204,21 @@ fstream ofstream(fname, std::ios::out | std::ios::app); if (!ofstream.is_open()) { cerr << "can't open file [" << fname << "] for output." << endl - << " error: " << strerror( errno); + << " error: " << strerror(errno) << endl; exit(3); } - generateAndOutputLicenses(vm, ofstream); + if (vm.count("base64")) { + generateB64Licenses(vm, ofstream); + } else { + generateAndOutputLicenses(vm, ofstream); + } ofstream.close(); } else { - generateAndOutputLicenses(vm, cout); + if (vm.count("base64")) { + generateB64Licenses(vm, cout); + } else { + generateAndOutputLicenses(vm, cout); + } } return 0; } @@ -197,22 +226,24 @@ const std::string formats[] = { "%4u-%2u-%2u", "%4u/%2u/%2u", "%4u%2u%2u" }; const size_t formats_n = 3; -string LicenseGenerator::normalize_date(const std::string& sDate) { - if(sDate.size()<8) +string LicenseGenerator::normalize_date(const std::string &sDate) { + if (sDate.size() < 8) throw invalid_argument("Date string too small for known formats"); unsigned int year, month, day; bool found = false; for (size_t i = 0; i < formats_n && !found; ++i) { - const int chread = sscanf(sDate.c_str(),formats[i].c_str(),&year,&month,&day); - if(chread==3) { + const int chread = sscanf(sDate.c_str(), formats[i].c_str(), &year, + &month, &day); + if (chread == 3) { found = true; break; } } - if(!found) + if (!found) throw invalid_argument("Date string did not match a known format"); ostringstream oss; - oss << year << "-" << setfill('0') << std::setw(2) << month << "-" << setfill('0') << std::setw(2) << day; + oss << year << "-" << setfill('0') << std::setw(2) << month << "-" + << setfill('0') << std::setw(2) << day; return oss.str(); } } diff --git a/src/tools/license-generator/license-generator.h b/src/tools/license-generator/license-generator.h index 361f263..04eaee6 100644 --- a/src/tools/license-generator/license-generator.h +++ b/src/tools/license-generator/license-generator.h @@ -2,14 +2,14 @@ * LicenseSigner.h * * Created on: Apr 6, 2014 - * + * */ #ifndef LICENSE_GENERATOR_H_ #define LICENSE_GENERATOR_H_ #include <boost/program_options.hpp> -#include "../../library/LicenseReader.h" +#include "../../library/LicenseReader.hpp" namespace license { @@ -21,12 +21,15 @@ class LicenseGenerator { private: LicenseGenerator(); + static void printHelp(const char* prog_name, const po::options_description& options); static po::options_description configureProgramOptions(); - static vector<FullLicenseInfo> parseLicenseInfo(const po::variables_map& vm); + static std::vector<FullLicenseInfo> parseLicenseInfo(const po::variables_map& vm); static void generateAndOutputLicenses(const po::variables_map& vm, - ostream& outputFile); - static string normalize_date(const std::string& s); + std::ostream& outputFile); + static void generateB64Licenses(const po::variables_map& vm, + std::ostream& outputFile); + static std::string normalize_date(const std::string& s); public: /** * Available options: diff --git a/test/functional/CMakeLists.txt b/test/functional/CMakeLists.txt index d2c718c..44b4a8d 100644 --- a/test/functional/CMakeLists.txt +++ b/test/functional/CMakeLists.txt @@ -8,37 +8,37 @@ ) add_executable( - standard_license_test + test_standard_license standard-license_test.cpp ) target_link_libraries( - standard_license_test - licensepp_static + test_standard_license + licensecc_static license_generator_snippet ${Boost_LIBRARIES} ) add_executable( - date_test + test_date date_test.cpp ) target_link_libraries( - date_test - licensepp_static + test_date + licensecc_static license_generator_snippet ${Boost_LIBRARIES} ) add_executable( - volid_test + test_volid volid_test.cpp ) target_link_libraries( - volid_test - licensepp_static + test_volid + licensecc_static license_generator_snippet ${Boost_LIBRARIES} ) @@ -46,13 +46,13 @@ IF( ( CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux") AND CMAKE_CROSSCOMPILING) #binfmt_misc doesn't work in my system :( - ADD_TEST(NAME standard_license_test COMMAND wine ${CMAKE_CURRENT_BINARY_DIR}/standard_license_test WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) - ADD_TEST(NAME date_test COMMAND wine ${CMAKE_CURRENT_BINARY_DIR}/date_test WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) - ADD_TEST(NAME volid_test COMMAND wine ${CMAKE_CURRENT_BINARY_DIR}/volid_test WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) + ADD_TEST(NAME test_standard_license COMMAND wine ${CMAKE_CURRENT_BINARY_DIR}/test_standard_license WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) + ADD_TEST(NAME test_date COMMAND wine ${CMAKE_CURRENT_BINARY_DIR}/test_date WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) + ADD_TEST(NAME test_volid COMMAND wine ${CMAKE_CURRENT_BINARY_DIR}/test_volid WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) ELSE() - ADD_TEST(NAME standard_license_test COMMAND standard_license_test WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) - ADD_TEST(NAME date_test COMMAND date_test WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) - ADD_TEST(NAME volid_test COMMAND volid_test WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) + ADD_TEST(NAME test_standard_license COMMAND test_standard_license WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) + ADD_TEST(NAME test_date COMMAND test_date WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) + ADD_TEST(NAME test_volid COMMAND test_volid WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) ENDIF() diff --git a/test/functional/date_test.cpp b/test/functional/date_test.cpp index b9d9ddc..44a9911 100644 --- a/test/functional/date_test.cpp +++ b/test/functional/date_test.cpp @@ -1,17 +1,19 @@ #define BOOST_TEST_MODULE date_test -//#define BOOST_TEST_MAIN -//#define BOOST_TEST_DYN_LINK + #include <boost/test/unit_test.hpp> +#include <boost/filesystem.hpp> + +#include <build_properties.h> #include "../../src/tools/license-generator/license-generator.h" #include "../../src/library/api/license++.h" -#include <build_properties.h> -#include <boost/filesystem.hpp> #include "../../src/library/ini/SimpleIni.h" #include "generate-license.h" namespace fs = boost::filesystem; using namespace license; using namespace std; + +namespace test { BOOST_AUTO_TEST_CASE( license_not_expired ) { const string licLocation(PROJECT_TEST_TEMP_DIR "/not_expired.lic"); @@ -22,10 +24,10 @@ /* */ LicenseInfo license; LicenseLocation licenseLocation; - licenseLocation.openFileNearModule = false; licenseLocation.licenseFileLocation = licLocation.c_str(); - licenseLocation.environmentVariableName = ""; - const EVENT_TYPE result = acquire_license("TEST", licenseLocation, &license); + licenseLocation.licenseData = ""; + const EVENT_TYPE result = acquire_license("TEST", &licenseLocation, + &license); BOOST_CHECK_EQUAL(result, LICENSE_OK); BOOST_CHECK_EQUAL(license.has_expiry, true); BOOST_CHECK_EQUAL(license.linked_to_pc, false); @@ -33,6 +35,7 @@ BOOST_AUTO_TEST_CASE( license_expired ) { const string licLocation(PROJECT_TEST_TEMP_DIR "/expired.lic"); + remove(licLocation.c_str()); vector<string> extraArgs; extraArgs.push_back("-e"); extraArgs.push_back("2013-10-10"); @@ -40,11 +43,14 @@ /* */ LicenseInfo license; LicenseLocation licenseLocation; - licenseLocation.openFileNearModule = false; licenseLocation.licenseFileLocation = licLocation.c_str(); - licenseLocation.environmentVariableName = ""; - const EVENT_TYPE result = acquire_license("TEST", licenseLocation, &license); + licenseLocation.licenseData = nullptr; + BOOST_TEST_MESSAGE("before acquire license"); + const EVENT_TYPE result = acquire_license("TEST", &licenseLocation, + &license); BOOST_CHECK_EQUAL(result, PRODUCT_EXPIRED); BOOST_CHECK_EQUAL(license.has_expiry, true); BOOST_CHECK_EQUAL(license.linked_to_pc, false); } + +} diff --git a/test/functional/generate-license.cpp b/test/functional/generate-license.cpp index 8ffac2b..c158c59 100644 --- a/test/functional/generate-license.cpp +++ b/test/functional/generate-license.cpp @@ -2,7 +2,7 @@ * generate-license.c * * Created on: Apr 13, 2014 - * + * */ #include <boost/test/unit_test.hpp> @@ -17,6 +17,7 @@ using namespace std; void generate_license(const string& fname, const vector<string>& other_args) { + remove(fname.c_str()); const int argc = 4+other_args.size(); const char** argv = new const char*[argc + 1]; unsigned int i=0; diff --git a/test/functional/generate-license.h b/test/functional/generate-license.h index c35dabd..4c1dcc0 100644 --- a/test/functional/generate-license.h +++ b/test/functional/generate-license.h @@ -1,7 +1,5 @@ - - #include<string> #include<vector> using namespace std; -void generate_license(const string& fname, const vector<string>& other_args) ; +void generate_license(const string& fname, const vector<string>& other_args); diff --git a/test/functional/hijiaking_test.cpp b/test/functional/hijiaking_test.cpp index b295796..009e47b 100644 --- a/test/functional/hijiaking_test.cpp +++ b/test/functional/hijiaking_test.cpp @@ -2,8 +2,8 @@ //#define BOOST_TEST_MAIN //#define BOOST_TEST_DYN_LINK #include <boost/test/unit_test.hpp> -#include "../../../src/license-generator/license-generator.h" -#include "../../../src/library/api/license++.h" +#include "../../src/tools/license-generator/license-generator.h" +#include "../../src/library/api/license++.h" #include <build_properties.h> #include <boost/filesystem.hpp> #include "../../src/library/ini/SimpleIni.h" @@ -23,7 +23,7 @@ LicenseLocation licenseLocation; licenseLocation.openFileNearModule=false; licenseLocation.licenseFileLocation = licLocation.c_str(); - licenseLocation.environmentVariableName = ""; + licenseLocation.licenseData = ""; EVENT_TYPE result = acquire_license("TEST", licenseLocation, & license); BOOST_CHECK_EQUAL(result, LICENSE_OK); diff --git a/test/functional/standard-license_test.cpp b/test/functional/standard-license_test.cpp index 18a6ae0..19b6000 100644 --- a/test/functional/standard-license_test.cpp +++ b/test/functional/standard-license_test.cpp @@ -1,6 +1,5 @@ -#define BOOST_TEST_MODULE standard_license_test -//#define BOOST_TEST_MAIN -//#define BOOST_TEST_DYN_LINK +#define BOOST_TEST_MODULE test_standard_license + #include <boost/test/unit_test.hpp> #include "../../src/tools/license-generator/license-generator.h" #include "../../src/library/api/license++.h" @@ -8,11 +7,12 @@ #include <boost/filesystem.hpp> #include "../../src/library/ini/SimpleIni.h" #include "generate-license.h" +#include "../../src/library/base/FileUtils.hpp" +namespace test { namespace fs = boost::filesystem; using namespace license; using namespace std; - BOOST_AUTO_TEST_CASE( standard_lic_file ) { const string licLocation(PROJECT_TEST_TEMP_DIR "/standard_license.lic"); @@ -21,14 +21,48 @@ /* */ LicenseInfo license; LicenseLocation licenseLocation; - licenseLocation.openFileNearModule=false; licenseLocation.licenseFileLocation = licLocation.c_str(); - licenseLocation.environmentVariableName = ""; - const EVENT_TYPE result = acquire_license("TEST", - licenseLocation, & license); + licenseLocation.licenseData = nullptr; + const EVENT_TYPE result = acquire_license("TEST", &licenseLocation, + &license); BOOST_CHECK_EQUAL(result, LICENSE_OK); BOOST_CHECK_EQUAL(license.has_expiry, false); BOOST_CHECK_EQUAL(license.linked_to_pc, false); } +/** + * Pass the license data to the application. + */ +BOOST_AUTO_TEST_CASE( b64_environment_variable ) { + const string licLocation(PROJECT_TEST_TEMP_DIR "/standard_env_license.lic"); + const vector<string> extraArgs; + generate_license(licLocation, extraArgs); + const string licensestr(license::get_file_contents(licLocation.c_str(), MAX_LICENSE_LENGTH)); + /* */ + LicenseInfo license; + LicenseLocation licenseLocation; + licenseLocation.licenseFileLocation = nullptr; + licenseLocation.licenseData = licensestr.c_str(); + const EVENT_TYPE result = acquire_license("TEST", &licenseLocation, + &license); + BOOST_CHECK_EQUAL(result, LICENSE_OK); + BOOST_CHECK_EQUAL(license.has_expiry, false); + BOOST_CHECK_EQUAL(license.linked_to_pc, false); +} +BOOST_AUTO_TEST_CASE( pc_identifier ) { + const string licLocation(PROJECT_TEST_TEMP_DIR "/pc_identifier.lic"); + const vector<string> extraArgs = { "-s", "Jaaa-aaaa-MG9F-ZhB1" }; + generate_license(licLocation, extraArgs); + + LicenseInfo license; + LicenseLocation licenseLocation; + licenseLocation.licenseFileLocation = licLocation.c_str(); + licenseLocation.licenseData = ""; + const EVENT_TYPE result = acquire_license("TEST", &licenseLocation, + &license); + BOOST_CHECK_EQUAL(result, IDENTIFIERS_MISMATCH); + BOOST_CHECK_EQUAL(license.has_expiry, false); + BOOST_CHECK_EQUAL(license.linked_to_pc, true); +} +} diff --git a/test/functional/volid_test.cpp b/test/functional/volid_test.cpp index a91d0bc..3ab5348 100644 --- a/test/functional/volid_test.cpp +++ b/test/functional/volid_test.cpp @@ -1,6 +1,5 @@ -#define BOOST_TEST_MODULE standard_license_test -//#define BOOST_TEST_MAIN -//#undef BOOST_TEST_DYN_LINK +#define BOOST_TEST_MODULE test_volid + #include <boost/test/unit_test.hpp> #include <fstream> #include <stdio.h> @@ -36,10 +35,9 @@ LicenseInfo license; LicenseLocation licenseLocation; - licenseLocation.openFileNearModule = false; licenseLocation.licenseFileLocation = licLocation.c_str(); - licenseLocation.environmentVariableName = ""; - const EVENT_TYPE result = acquire_license("TEST", licenseLocation, &license); + licenseLocation.licenseData = ""; + const EVENT_TYPE result = acquire_license("TEST", &licenseLocation, &license); BOOST_CHECK_EQUAL(result, LICENSE_OK); BOOST_CHECK_EQUAL(license.has_expiry, false); BOOST_CHECK_EQUAL(license.linked_to_pc, true); diff --git a/test/library/CMakeLists.txt b/test/library/CMakeLists.txt index 49edff0..b7f4d90 100644 --- a/test/library/CMakeLists.txt +++ b/test/library/CMakeLists.txt @@ -1,34 +1,72 @@ add_executable( - license_reader_test + test_license_reader LicenseReader_test.cpp ) target_link_libraries( - license_reader_test - licensepp_static + test_license_reader + licensecc_static ${Boost_LIBRARIES} ) IF( ( CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux") AND CMAKE_CROSSCOMPILING) #binfmt_misc doesn't work in my system :( - ADD_TEST(NAME license_reader_test COMMAND wine ${CMAKE_CURRENT_BINARY_DIR}/license_reader_test) + ADD_TEST(NAME test_license_reader COMMAND wine ${CMAKE_CURRENT_BINARY_DIR}/test_license_reader) ELSE() - ADD_TEST(NAME license_reader_test COMMAND license_reader_test) + ADD_TEST(NAME test_license_reader COMMAND test_license_reader) ENDIF() IF(WIN32) #test windows ELSE(WIN32) add_executable( - os_linux_test + test_os_linux Os_Linux_test.cpp ) target_link_libraries( - os_linux_test + test_os_linux os ${Boost_LIBRARIES} ) - ADD_TEST(NAME os_linux_test COMMAND os_linux_test) + ADD_TEST(NAME test_os_linux COMMAND test_os_linux) ENDIF(WIN32) + + +### LicenseLocator tests +add_executable( + test_license_locator + LicenseLocator_test.cpp +) + +target_link_libraries( + test_license_locator + locators + ${Boost_LIBRARIES} +) + +IF( ( CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux") AND CMAKE_CROSSCOMPILING) +#binfmt_misc doesn't work in my system :( + ADD_TEST(NAME test_license_locator COMMAND wine ${CMAKE_CURRENT_BINARY_DIR}/test_license_locator) +ELSE() + ADD_TEST(NAME test_license_locator COMMAND test_license_locator) +ENDIF() + +### LicenseLocator tests +add_executable( + test_event_registry + EventRegistry_test.cpp +) + +target_link_libraries( + test_event_registry + base + ${Boost_LIBRARIES} +) + +IF( ( CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux") AND CMAKE_CROSSCOMPILING) + ADD_TEST(NAME test_event_registry COMMAND wine ${CMAKE_CURRENT_BINARY_DIR}/test_event_registry) +ELSE() + ADD_TEST(NAME test_event_registry COMMAND test_event_registry) +ENDIF() \ No newline at end of file diff --git a/test/library/EventRegistry_test.cpp b/test/library/EventRegistry_test.cpp new file mode 100644 index 0000000..70abe9b --- /dev/null +++ b/test/library/EventRegistry_test.cpp @@ -0,0 +1,41 @@ +#define BOOST_TEST_MODULE "test_event_registry" + +#include <iostream> +#include <iterator> + +#include <fstream> +#include <string> +#include <vector> + +#include <boost/filesystem.hpp> +#include <boost/optional.hpp> +#include <boost/test/unit_test.hpp> +#include <stdlib.h> +#include <cstdio> + +#include <build_properties.h> + +#include "../../src/library/base/EventRegistry.h" + +namespace test { + +using namespace std; +using namespace license; + +/** + * The error reported is for the license that advanced most in the validation process + * + */ +BOOST_AUTO_TEST_CASE( test_most_advanced_license_error ) { + EventRegistry er; + er.addEvent(LICENSE_SPECIFIED, "lic2"); + er.addEvent(LICENSE_FOUND, "lic1"); + er.addEvent(LICENSE_CORRUPTED, "lic1"); + er.turnWarningsIntoErrors(); + const AuditEvent *event = er.getLastFailure(); + BOOST_CHECK_MESSAGE(event != nullptr, "An error is detected"); + BOOST_CHECK_MESSAGE(string("lic1") == event->license_reference, "Error is for lic1"); + BOOST_CHECK_MESSAGE(LICENSE_CORRUPTED == event->event_type, "Error is for LICENSE_CORRUPTED"); +} + +} //namespace test diff --git a/test/library/LicenseLocator_test.cpp b/test/library/LicenseLocator_test.cpp new file mode 100644 index 0000000..cf532b2 --- /dev/null +++ b/test/library/LicenseLocator_test.cpp @@ -0,0 +1,217 @@ +#define BOOST_TEST_MODULE "test_license_locator" + +#include <iostream> +#include <iterator> + +#include <fstream> +#include <string> +#include <vector> + +#include <boost/filesystem.hpp> +#include <boost/optional.hpp> +#include <boost/test/unit_test.hpp> +#include <stdlib.h> +#include <cstdio> + +#include <build_properties.h> + +#include "../../src/library/os/os.h" +#include "../../src/library/base/EventRegistry.h" +#include "../../src/library/locate/ApplicationFolder.hpp" +#include "../../src/library/locate/EnvironmentVarLocation.hpp" +#include "../../src/library/locate/ExternalDefinition.hpp" + +#define MOCK_LICENSE PROJECT_TEST_SRC_DIR "/library/test_reader.ini" + +namespace test { +using namespace license::locate; +using namespace std; +using namespace boost::filesystem; + +static boost::optional<path> find_file(const path& dir_path, const path& file_name) { + const recursive_directory_iterator end; + const auto it = find_if(recursive_directory_iterator(dir_path), end, + [&file_name](const directory_entry& e) { + return e.path().filename() == file_name; + }); + return it == end ? boost::optional<path>() : it->path(); +} + + +/***************************************************************************** + * Application Folder tests + *****************************************************************************/ +BOOST_AUTO_TEST_CASE( read_license_near_module ) { + const string testExeFolder = PROJECT_BINARY_DIR "/test/library"; + bool exeFileFound = false; + string referenceExeFileName; + string referenceLicenseFileName; + //Verify we're pointing the correct executable, in windows isn't clear where it's built +#ifdef _WIN32 + boost::optional<path> exeLocation(find_file(path(testExeFolder), path(BOOST_TEST_MODULE ".exe"))); + exeFileFound = exeLocation.has_value(); + if (exeFileFound) { + referenceExeFileName = exeLocation.get().string(); + referenceLicenseFileName = referenceExeFileName.replace(referenceExeFileName.find(BOOST_TEST_MODULE ".exe"), + string(BOOST_TEST_MODULE ".exe").size(), BOOST_TEST_MODULE ".lic"); + } +#else + referenceExeFileName = testExeFolder + "/" + BOOST_TEST_MODULE; + std::ifstream f(referenceExeFileName.c_str()); + exeFileFound = f.good(); + referenceLicenseFileName = testExeFolder + "/" + BOOST_TEST_MODULE ".lic"; +#endif + BOOST_WARN_MESSAGE(!exeFileFound, "File [" + referenceExeFileName + "] NOT found"); + if (exeFileFound) { + //copy test license near module + std::ifstream src(MOCK_LICENSE, std::ios::binary); + std::ofstream dst(referenceLicenseFileName, std::ios::binary); + dst << src.rdbuf(); + dst.close(); + + license::EventRegistry registry; + ApplicationFolder applicationFolder; + vector<string> licenseInfos = applicationFolder.license_locations(registry); + BOOST_CHECK(registry.isGood()); + BOOST_REQUIRE_EQUAL(1, licenseInfos.size()); + string currentLocation = licenseInfos[0]; + BOOST_CHECK_MESSAGE(equivalent(path(referenceLicenseFileName),path(currentLocation)), + "file " +currentLocation + "found at expected location"); + string licenseRealContent = applicationFolder.retrieve_license_content( + currentLocation); + src.seekg(0, ios::beg); + std::string referenceContent((std::istreambuf_iterator<char>(src)), + std::istreambuf_iterator<char>()); + BOOST_CHECK_MESSAGE(referenceContent.compare(licenseRealContent) == 0, + "File content is same"); + remove(referenceLicenseFileName.c_str()); + } +} + +/***************************************************************************** + * External_Definition tests + *****************************************************************************/ + +BOOST_AUTO_TEST_CASE( external_definition ) { + //an application can define multiple license locations separated by ';' + const char *applicationDefinedString = + MOCK_LICENSE ";/this/one/doesnt/exist"; + + //read test license + std::ifstream src(MOCK_LICENSE, std::ios::binary); + std::string referenceContent((std::istreambuf_iterator<char>(src)), + std::istreambuf_iterator<char>()); + license::EventRegistry registry; + const LicenseLocation licLocation({applicationDefinedString,nullptr}); + ExternalDefinition externalDefinition(&licLocation); + vector<string> licenseInfos = externalDefinition.license_locations(registry); + BOOST_CHECK(registry.isGood()); + BOOST_CHECK_EQUAL(1, licenseInfos.size()); + string currentLocation = licenseInfos[0]; + BOOST_CHECK_MESSAGE(string(MOCK_LICENSE).compare(currentLocation) == 0, + "file found at expected location"); + string licenseRealContent = externalDefinition.retrieve_license_content( + currentLocation); + BOOST_CHECK_MESSAGE(referenceContent.compare(licenseRealContent) == 0, + "File content is same"); +} + +/** + * The license file doesn't exist. Check that the locator reports the right error + */ +BOOST_AUTO_TEST_CASE( external_definition_not_found ) { + const char *applicationDefinedString = PROJECT_TEST_SRC_DIR "/this/file/doesnt/exist"; + license::EventRegistry registry; + const LicenseLocation licLocation({applicationDefinedString,nullptr}); + ExternalDefinition externalDefinition(&licLocation); + vector<string> licenseInfos = externalDefinition.license_locations(registry); + + BOOST_CHECK_MESSAGE(registry.isGood(), + "No fatal error for now, only warnings"); + registry.turnWarningsIntoErrors(); + BOOST_REQUIRE_MESSAGE(!registry.isGood(), "Error detected"); + BOOST_CHECK_EQUAL(0, licenseInfos.size()); + BOOST_CHECK_MESSAGE( + registry.getLastFailure()->event_type == LICENSE_FILE_NOT_FOUND, + "Error detected"); + +} + +/***************************************************************************** + * EnvironmentVarLocation tests + *****************************************************************************/ +BOOST_AUTO_TEST_CASE( environment_var_location ) { + //an application can define multiple license locations separated by ';' + const char *environment_variable_value = + MOCK_LICENSE ";/this/one/doesnt/exist"; +#ifdef _WIN32 + _putenv_s(LICENSE_LOCATION_ENV_VAR, environment_variable_value); +#else + setenv(LICENSE_LOCATION_ENV_VAR, environment_variable_value, 1); +#endif + //read test license + std::ifstream src(MOCK_LICENSE, std::ios::binary); + std::string referenceContent((std::istreambuf_iterator<char>(src)), + std::istreambuf_iterator<char>()); + license::EventRegistry registry; + + EnvironmentVarLocation envVarLocationStrategy; + vector<string> licenseInfos = envVarLocationStrategy.license_locations( + registry); + BOOST_CHECK(registry.isGood()); + BOOST_CHECK_EQUAL(1, licenseInfos.size()); + string currentLocation = licenseInfos[0]; + BOOST_CHECK_MESSAGE(string(MOCK_LICENSE).compare(currentLocation) == 0, + "file found at expected location"); + string licenseRealContent = envVarLocationStrategy.retrieve_license_content( + currentLocation); + BOOST_CHECK_MESSAGE(referenceContent.compare(licenseRealContent) == 0, + "File content is same"); + UNSETENV(LICENSE_LOCATION_ENV_VAR); +} + +/** + * The license file doesn't exist. Check that the locator reports the right error + */ +BOOST_AUTO_TEST_CASE( environment_var_location_not_found ) { + const char *environment_variable_value = + PROJECT_TEST_SRC_DIR "/this/file/doesnt/exist"; + SETENV(LICENSE_LOCATION_ENV_VAR, environment_variable_value); + + license::EventRegistry registry; + EnvironmentVarLocation envVarLocationStrategy; + vector<string> licenseInfos = envVarLocationStrategy.license_locations( + registry); + BOOST_CHECK_MESSAGE(registry.isGood(), + "No fatal error for now, only warnings"); + registry.turnWarningsIntoErrors(); + BOOST_REQUIRE_MESSAGE(!registry.isGood(), "Error detected"); + BOOST_CHECK_EQUAL(0, licenseInfos.size()); + BOOST_CHECK_MESSAGE( + registry.getLastFailure()->event_type == LICENSE_FILE_NOT_FOUND, + "Error detected"); + UNSETENV(LICENSE_LOCATION_ENV_VAR); +} + +/** + * The license file doesn't exist. Check that the locator reports the right error + */ +BOOST_AUTO_TEST_CASE( environment_var_location_not_defined ) { + UNSETENV(LICENSE_LOCATION_ENV_VAR); + license::EventRegistry registry; + EnvironmentVarLocation environmentVarLocation; + vector<string> licenseInfos = environmentVarLocation.license_locations( + registry); + + BOOST_CHECK_MESSAGE(registry.isGood(), + "No fatal error for now, only warnings"); + registry.turnWarningsIntoErrors(); + BOOST_REQUIRE_MESSAGE(!registry.isGood(), "Error detected"); + BOOST_CHECK_EQUAL(0, licenseInfos.size()); + BOOST_CHECK_MESSAGE( + registry.getLastFailure()->event_type + == ENVIRONMENT_VARIABLE_NOT_DEFINED, "Error detected"); + +} + +} //namespace test diff --git a/test/library/LicenseReader_test.cpp b/test/library/LicenseReader_test.cpp index 6fa4f59..2198ab3 100644 --- a/test/library/LicenseReader_test.cpp +++ b/test/library/LicenseReader_test.cpp @@ -1,18 +1,32 @@ -#define BOOST_TEST_MODULE license_reader_test -//#define BOOST_TEST_MAIN -//#define BOOST_TEST_DYN_LINK +#define BOOST_TEST_MODULE "test_license_reader" +#include <boost/assert.hpp> +#include <boost/test/tools/old/interface.hpp> +#include <boost/test/unit_test_suite.hpp> +#include <iostream> +#include <vector> + +#include "../../src/library/api/datatypes.h" +#include "../../src/library/base/EventRegistry.h" +#include "../../src/library/os/os.h" + + #include <boost/test/unit_test.hpp> -#include "../../src/library/LicenseReader.h" -#include <build_properties.h> #include <stdlib.h> -using namespace license; +#include <build_properties.h> +#include "../../src/library/LicenseReader.hpp" +namespace test { +using namespace license; +using namespace std; +/** + * Read license at fixed location + */ BOOST_AUTO_TEST_CASE( read_single_file ) { - const char * licLocation = - PROJECT_TEST_SRC_DIR "/library/test_reader.ini"; - const LicenseLocation location = { licLocation, nullptr, false }; - LicenseReader licenseReader(location); + const char *licLocation = PROJECT_TEST_SRC_DIR "/library/test_reader.ini"; + + const LicenseLocation location = { licLocation, nullptr }; + LicenseReader licenseReader(&location); vector<FullLicenseInfo> licenseInfos; const EventRegistry registry = licenseReader.readLicenses("PrODUCT", licenseInfos); @@ -20,11 +34,14 @@ BOOST_CHECK_EQUAL(1, licenseInfos.size()); } +/** + * Test the error return if the product code is not found in the license + */ BOOST_AUTO_TEST_CASE( product_not_licensed ) { - const char * licLocation = + const char *licLocation = PROJECT_TEST_SRC_DIR "/library/test_reader.ini"; - const LicenseLocation location = { licLocation, nullptr, false }; - LicenseReader licenseReader(location); + const LicenseLocation location = { licLocation, nullptr }; + LicenseReader licenseReader(&location); vector<FullLicenseInfo> licenseInfos; const EventRegistry registry = licenseReader.readLicenses("PRODUCT-NOT", licenseInfos); @@ -35,11 +52,14 @@ registry.getLastFailure()->event_type); } +/** + * Test the error code if the license file is specified but doesn't exists + */ BOOST_AUTO_TEST_CASE( file_not_found ) { - const char * licLocation = PROJECT_TEST_SRC_DIR "/library/not_found.ini"; + const char *licLocation = PROJECT_TEST_SRC_DIR "/library/not_found.ini"; //const char * envName = "MYVAR"; - const LicenseLocation location = { licLocation, nullptr, false }; - LicenseReader licenseReader(location); + const LicenseLocation location = { licLocation, nullptr }; + LicenseReader licenseReader(&location); vector<FullLicenseInfo> licenseInfos; const EventRegistry registry = licenseReader.readLicenses("PRODUCT", licenseInfos); @@ -50,10 +70,13 @@ registry.getLastFailure()->event_type); } +/** + * Test the error code if the license default environment variable isn't specified + */ BOOST_AUTO_TEST_CASE( env_var_not_defined ) { - const char * envName = "MYVAR"; - const LicenseLocation location = {nullptr, envName, false }; - LicenseReader licenseReader(location); + UNSETENV(LICENSE_LOCATION_ENV_VAR); + const LicenseLocation location = { nullptr, nullptr }; + LicenseReader licenseReader(&location); vector<FullLicenseInfo> licenseInfos; const EventRegistry registry = licenseReader.readLicenses("PRODUCT", licenseInfos); @@ -64,16 +87,26 @@ registry.getLastFailure()->event_type); } -BOOST_AUTO_TEST_CASE( read_env_var ) { - char str[MAX_PATH]; - strcpy(str,"LIC_VAR=" PROJECT_TEST_SRC_DIR "/library/test_reader.ini"); - putenv(str); - const LicenseLocation location = {nullptr, "LIC_VAR", false }; - LicenseReader licenseReader(location); - vector<FullLicenseInfo> licenseInfos; - const EventRegistry registry = licenseReader.readLicenses("PrODUCT", - licenseInfos); - BOOST_CHECK(registry.isGood()); - BOOST_CHECK_EQUAL(1, licenseInfos.size()); -} +/** + * Test the error code if the license default environment variable is + * specified but points to a non existent file. + */ +BOOST_AUTO_TEST_CASE( env_var_point_to_wrong_file ) { + const char *environment_variable_value = + PROJECT_TEST_SRC_DIR "/this/file/doesnt/exist"; + SETENV(LICENSE_LOCATION_ENV_VAR, environment_variable_value) + const LicenseLocation location = { nullptr, nullptr }; + LicenseReader licenseReader(&location); + vector<FullLicenseInfo> licenseInfos; + const EventRegistry registry = licenseReader.readLicenses("PRODUCT", + licenseInfos); + cout << registry << endl; + BOOST_CHECK(!registry.isGood()); + BOOST_CHECK_EQUAL(0, licenseInfos.size()); + BOOST_ASSERT(registry.getLastFailure()!=NULL); + BOOST_CHECK_EQUAL(LICENSE_FILE_NOT_FOUND, + registry.getLastFailure()->event_type); + UNSETENV(LICENSE_LOCATION_ENV_VAR); +} +} /* namespace test*/ diff --git a/test/license-generator/license-generator_test.cpp b/test/license-generator/license-generator_test.cpp index 335f787..4e8c6ec 100644 --- a/test/license-generator/license-generator_test.cpp +++ b/test/license-generator/license-generator_test.cpp @@ -2,9 +2,10 @@ //#define BOOST_TEST_MAIN //#define BOOST_TEST_DYN_LINK #include <boost/test/unit_test.hpp> -#include "../../src/tools/license-generator/license-generator.h" -#include <build_properties.h> #include <boost/filesystem.hpp> +#include <build_properties.h> + +#include "../../src/tools/license-generator/license-generator.h" #include "../../src/library/ini/SimpleIni.h" namespace fs = boost::filesystem; -- Gitblit v1.9.1