Gabriele Contini
2020-03-15 36ce07093b68b07513149577c209ae7a57ab356b
Merge branch 'feature/pc_identifiers' into develop
issues #2 #3 #14 #49
42个文件已修改
54个文件已添加
21 文件已重命名
9个文件已删除
6129 ■■■■ 已修改文件
.gitignore 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.travis.yml 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
CMakeLists.txt 102 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
CONTRIBUTING.md 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
README.md 23 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cmake/FindSphinx.cmake 53 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cmake/toolchain-ubuntu-mingw64.cmake 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
doc/Home.md 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
doc/_static/googleae93b5a7f3766641.html 补丁 | 查看 | 原始文档 | blame | 历史
doc/_static/pc-id-selection.png 补丁 | 查看 | 原始文档 | blame | 历史
doc/analysis/Backoffice.md 补丁 | 查看 | 原始文档 | blame | 历史
doc/analysis/Development-And-Usage-Workflow.md 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
doc/analysis/features.md 37 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
doc/api/public_api.rst 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
doc/conf.py 175 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
doc/development/Build-the-library-windows.md 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
doc/development/Build-the-library.md 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
doc/development/Dependencies.md 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
doc/development/Development-Environment-Setup.md 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
doc/index.rst 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
doc/open-license-manager.vsdx 补丁 | 查看 | 原始文档 | blame | 历史
doc/other/CREDITS.md 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
doc/other/QA.md 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
doc/other/glossary.md 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
doc/snippets.txt 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
doc/snippets/hardware.cpp 266 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
doc/usage/Hardware-identifiers.md 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
doc/usage/License-retrieval.md 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
doc/usage/integration.md 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
doc/usage/issue-licenses.md 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
include/licensecc/datatypes.h 93 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
include/licensecc/licensecc.h 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/CMakeLists.txt 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/inspector/CMakeLists.txt 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/inspector/inspector.cpp 91 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/CMakeLists.txt 28 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/LicenseReader.cpp 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/LicenseReader.hpp 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/base/CMakeLists.txt 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/base/EventRegistry.cpp 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/base/EventRegistry.h 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/base/StringUtils.cpp 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/base/base64.c 134 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/base/base64.cpp 153 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/base/base64.h 48 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/base/file_utils.cpp 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/base/file_utils.hpp 补丁 | 查看 | 原始文档 | blame | 历史
src/library/base/logger.cpp 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/base/logger.h 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/hw_identifier/CMakeLists.txt 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/hw_identifier/default_strategy.cpp 77 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/hw_identifier/default_strategy.hpp 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/hw_identifier/disk_strategy.cpp 97 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/hw_identifier/disk_strategy.hpp 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/hw_identifier/ethernet.cpp 78 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/hw_identifier/ethernet.hpp 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/hw_identifier/hw_identifier.cpp 99 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/hw_identifier/hw_identifier.hpp 72 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/hw_identifier/hw_identifier_facade.cpp 77 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/hw_identifier/hw_identifier_facade.hpp 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/hw_identifier/identification_strategy.cpp 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/hw_identifier/identification_strategy.hpp 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/ini/ConvertUTF.cpp 补丁 | 查看 | 原始文档 | blame | 历史
src/library/licensecc.cpp 59 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/limits/license_verifier.cpp 53 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/locate/ApplicationFolder.cpp 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/locate/CMakeLists.txt 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/locate/EnvironmentVarData.cpp 19 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/locate/EnvironmentVarLocation.cpp 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/locate/ExternalDefinition.cpp 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/locate/ExternalDefinition.hpp 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/locate/LocatorStrategy.cpp 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/os/CMakeLists.txt 44 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/os/cpu_info.hpp 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/os/cpu_info_common.cpp 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/os/execution_environment.hpp 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/os/execution_environment_common.cpp 59 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/os/linux/cpu_info.cpp 76 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/os/linux/execution_environment.cpp 115 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/os/linux/network.cpp 125 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/os/linux/os_linux.cpp 100 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/os/network.hpp 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/os/network_id.c 176 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/os/openssl/signature_verifier.cpp 13 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/os/os-win.c 214 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/os/os.h 39 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/os/signature_verifier.hpp 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/os/windows/cpu_info.cpp 78 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/os/windows/execution_environment.cpp 86 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/os/windows/isvm/BIOSReader.cpp 121 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/os/windows/isvm/BIOSReader.h 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/os/windows/isvm/Native.cpp 438 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/os/windows/isvm/Native.h 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/os/windows/isvm/main.cpp 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/os/windows/network.cpp 113 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/os/windows/os_win.cpp 104 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/os/windows/signature_verifier.cpp 23 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/pc-identifiers.c 399 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/library/pc-identifiers.h 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/licensecc_properties.h.in 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
test/CMakeLists.txt 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
test/IdentificationStrategy_test.cpp 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
test/default_strategy_test.cpp 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
test/functional/CMakeLists.txt 40 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
test/functional/crack_test.cpp 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
test/functional/date_test.cpp 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
test/functional/generate-license.cpp 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
test/functional/hijiaking_test.cpp 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
test/functional/hw_identifier_it_test.cpp 95 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
test/functional/signature_verifier_test.cpp 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
test/functional/standard-license_test.cpp 41 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
test/functional/volid_test.cpp 145 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
test/library/CMakeLists.txt 28 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
test/library/LicenseLocator_test.cpp 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
test/library/LicenseReader_test.cpp 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
test/library/Os_Linux_test.cpp 85 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
test/library/hw_identifier/CMakeLists.txt 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
test/library/hw_identifier/disk_strategy_test.cpp 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
test/library/hw_identifier/ethernet_test.cpp 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
test/library/hw_identifier/hw_identifier_facade_test.cpp 100 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
test/library/hw_identifier/hw_identifier_test.cpp 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
test/library/os/CMakeLists.txt 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
test/library/os/cpu_info_test.cpp 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
test/library/os/execution_environment_test.cpp 48 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
test/library/os/network_test.cpp 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
test/library/os_linux_test.cpp 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.gitignore
@@ -9,6 +9,7 @@
#Visual studio files
.vs
/out
# Compiled Static libraries
*.lai
@@ -31,3 +32,6 @@
projects/*
!projects/.gitkeep
**/CMakeCache.txt
**/CMakeFiles
/CMakeSettings.json
.travis.yml
@@ -11,6 +11,8 @@
   - os: linux
     dist: bionic
     name: "Ubuntu 18.04 - Travis CI VM"
     env:
     - VIRTUAL_ENV=VM
     addons:
        apt:
          packages:
@@ -51,6 +53,8 @@
   - os: linux
     dist: bionic
     name: "Ubuntu 18.04 - Travis CI VM - Debug build"
     env:
     - VIRTUAL_ENV=VM
     addons:
        apt:
          packages:
@@ -72,7 +76,6 @@
     script: 
         - cmake --build . --target install
         - ctest
         - ctest -T memcheck
     after_success:
         # Create lcov report
         - lcov --capture --directory . --output-file coverage.info
@@ -80,7 +83,6 @@
         - lcov --list coverage.info # debug info
         # Uploading report to CodeCov
         - bash <(curl -s https://codecov.io/bash) -f coverage.info || echo "Codecov did not collect coverage reports"
   - os: linux
     dist: bionic
     name: "CentOS-7 Docker"
@@ -110,7 +112,7 @@
        - docker commit centos8_toconfigure centos8_configured
     script: 
        - docker run --name centos8_make -v `pwd`:/root/open-license-manager centos8_configured /bin/bash -c \
            "cd /root/open-license-manager/build && make && make install && VIRT_ENV=CONTAINER make test"
            "cd /root/open-license-manager/build && make && make install && VIRTUAL_ENV=DOCKER make test"
   - os: linux
     dist: bionic
     name: "Ubuntu 18.04 - MinGW cross-compile for Windows x64"
@@ -203,10 +205,12 @@
             - libboost-system-dev
             - libboost-thread-dev
             - libboost-date-time-dev
             - python3-pip
             - doxygen
             - graphviz
     script: 
        - make docs
        - pip3 install sphinx sphinx_rtd_theme breathe sphinx-markdown-tables recommonmark sphinx-rtd-theme
        - make documentation
     deploy:
        provider: pages
        skip_cleanup: true
@@ -214,11 +218,11 @@
        keep_history: false
        verbose: true
        target_branch: "gh-pages"
        local_dir: "build/html"
        local_dir: "build/docs/sphinx"
        on:
            branch: develop
env:
    - CTEST_OUTPUT_ON_FAILURE=1
    - CTEST_OUTPUT_ON_FAILURE=1
before_script:
    - cd build && cmake -DCMAKE_INSTALL_PREFIX=../../install ..
CMakeLists.txt
@@ -17,10 +17,11 @@
ENDIF(NOT LCC_PROJECTS_BASE_DIR)
cmake_policy(SET CMP0048 NEW)
#cmake_policy(SET CMP0091 NEW)
project (licensecc 
            VERSION 2.0.0
            DESCRIPTION "Copy protection and licensing library" 
            LANGUAGES C CXX)
            LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
@@ -34,22 +35,22 @@
    SET(CMAKE_CROSSCOMPILING_EMULATOR "wine")    
ENDIF()
SET (OPENSSL_USE_STATIC_LIBS ON)
SET (OPENSSL_USE_STATIC_LIBS TRUE)
IF(${STATIC_RUNTIME})
    SET(OPENSSL_MSVC_STATIC_RT TRUE)
ENDIF(${STATIC_RUNTIME})
find_package(OpenSSL COMPONENTS Crypto QUIET)
IF(OPENSSL_FOUND)
    MESSAGE(STATUS "Found openssl version ${OPENSSL_VERSION}")
    MESSAGE(STATUS "Found openssl version ${OPENSSL_VERSION} -licensecc")
ENDIF(OPENSSL_FOUND)
if(UNIX) #this is true for all the linux systems but not for cross compiling "linux->windows"
    IF(${STATIC_RUNTIME})
        set(CMAKE_EXE_LINKER_FLAGS "-static-libgcc -static-libstdc++ -static")
    ENDIF(${STATIC_RUNTIME})
    IF(NOT OPENSSL_FOUND)
        MESSAGE(SEND_ERROR "Openssl required in Linux, please install it or specify -DOPENSSL_ROOT")
    ENDIF(NOT OPENSSL_FOUND)
    #Zlib required when openssl version < 1.0.1f (centos 7)
    SET ( ZLIB_USE_STATIC_LIBS ON )
    find_package(ZLIB REQUIRED)
    list(APPEND EXTERNAL_LIBS ${ZLIB_LIBRARIES})
    MESSAGE(STATUS "Found zlib version ${ZLIB_VERSION} ")
    
    find_package(Threads)
    if(THREADS_HAVE_PTHREAD_ARG)
@@ -59,17 +60,19 @@
               list(APPEND EXTERNAL_LIBS "${CMAKE_THREAD_LIBS_INIT}")
        endif()
    endif(THREADS_HAVE_PTHREAD_ARG)
    #Zlib required with old openssl version < 1.0.1f in centos 7
    IF(OPENSSL_VERSION VERSION_LESS_EQUAL 1.0.2)
        SET ( ZLIB_USE_STATIC_LIBS ON )
        find_package(ZLIB REQUIRED)
        list(APPEND EXTERNAL_LIBS ${ZLIB_LIBRARIES})
        MESSAGE(STATUS "Found zlib version ${ZLIB_VERSION_STRING} - licensecc")
    ELSE(OPENSSL_VERSION VERSION_LESS_EQUAL 1.0.2)
        MESSAGE(STATUS "openssl ${OPENSSL_VERSION} zlib not required - licensecc")
    ENDIF(OPENSSL_VERSION VERSION_LESS_EQUAL 1.0.2)
    
    find_program( MEMORYCHECK_COMMAND valgrind )
    set( MEMORYCHECK_COMMAND_OPTIONS "--trace-children=yes --leak-check=full" )
    if(USE_DBUS_IDENTIFIER)
        FIND_PACKAGE(Dbus REQUIRED)
        add_definitions(-DUSE_DBUS)
        include_directories(${DBUS_INCLUDE_DIR})
        include_directories(${DBUS_ARCH_INCLUDE_DIR})
        list(APPEND EXTERNAL_LIBS ${DBUS_LIBRARIES})
    endif(USE_DBUS_IDENTIFIER)
    set(main_lib_dest "lib/${PROJECT_NAME}")  
else(UNIX)
    IF(NOT OPENSSL_FOUND)
@@ -79,21 +82,20 @@
        include(target_arch)
        target_architecture( TARGET_ARCHITECTURE )
        message(STATUS "architecture detected: ${TARGET_ARCHITECTURE}")
        #cmake > 3.15 handle the /MD flag more nicely than this
        if(${STATIC_RUNTIME})
            string(REPLACE "/MD" "/MT" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}")
        if(STATIC_RUNTIME)
            message(STATUS "Static runtime ${STATIC_RUNTIME}")
            string(REPLACE "/MD" "/MT" CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}")
            string(REPLACE "/MDd" "/MTd" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}")
            string(REPLACE "/MDd" "/MTd" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
            #list(APPEND CMAKE_CXX_FLAGS_DEBUG "/MTd")
            SET(Boost_USE_STATIC_RUNTIME ON)
        endif(${STATIC_RUNTIME})
        endif(STATIC_RUNTIME)
        add_definitions("/D _CRT_SECURE_NO_WARNINGS")
        list(APPEND EXTERNAL_LIBS "bcrypt" "crypt32" "ws2_32" "iphlpapi")
    else(MSVC)
        if(MINGW)
            list(APPEND EXTERNAL_LIBS "-lcrypt32 -lbcrypt -lws2_32 -liphlpapi")
            SET(CMAKE_EXE_LINKER_FLAGS "-static")
        if(MINGW)
            list(APPEND EXTERNAL_LIBS "-lbcrypt" "-lcrypt32" "-lws2_32" "-liphlpapi")
            SET(CMAKE_EXE_LINKER_FLAGS "-static -static-libstdc++")
        endif(MINGW)
    endif(MSVC)
    set(main_lib_dest "${PROJECT_NAME}")  
@@ -111,21 +113,19 @@
  COMMENT "generating ${LCC_PROJECT_PUBLIC_KEY}"
  USES_TERMINAL
)
include_directories( ${LCC_INCLUDE_DIR} "${CMAKE_CURRENT_SOURCE_DIR}/include" )
add_custom_target(project_initialize DEPENDS "${LCC_PROJECT_PUBLIC_KEY}" "${LCC_PROJECT_PRIVATE_KEY}")
include_directories( ${LCC_INCLUDE_DIR} ${CMAKE_BINARY_DIR} "${CMAKE_CURRENT_SOURCE_DIR}/include")
message( STATUS "C compiler        : " ${CMAKE_C_COMPILER})
message( STATUS "C compiler flags  : " ${CMAKE_C_FLAGS})
message( STATUS "CXX compiler      : " ${CMAKE_CXX_COMPILER})
message( STATUS "CXX compiler flags: " ${CMAKE_CXX_FLAGS})
message( STATUS "CXX compiler        : " ${CMAKE_CXX_COMPILER})
message( STATUS "CXX compiler flags  : " ${CMAKE_CXX_FLAGS})
message( STATUS "CXX compiler flags debug : " ${CMAKE_CXX_FLAGS_DEBUG})
message( STATUS "CXX compiler flags release: " ${CMAKE_CXX_FLAGS_RELEASE})
if(CMAKE_BUILD_TYPE)
  message( STATUS "Build type        : " ${CMAKE_BUILD_TYPE})
  message( STATUS "Build type          : " ${CMAKE_BUILD_TYPE})
endif(CMAKE_BUILD_TYPE)
message( STATUS "Install prefix    : " ${CMAKE_INSTALL_PREFIX})
message( STATUS "Project name      : " ${LCC_PROJECT_NAME} )
message( STATUS "Project base dir  : " ${LCC_PROJECTS_BASE_DIR}/${LCC_PROJECT_NAME} )
message( STATUS "Install prefix      : " ${CMAKE_INSTALL_PREFIX})
message( STATUS "Project name        : " ${LCC_PROJECT_NAME} )
message( STATUS "Project base dir    : " ${LCC_PROJECTS_BASE_DIR}/${LCC_PROJECT_NAME} )
add_subdirectory(src)
@@ -150,22 +150,44 @@
        MARK_AS_ADVANCED(BUILDNAME)
        add_subdirectory(test)
    ENDIF(BUILD_TESTING)
    add_subdirectory("src/inspector")
ELSE(Boost_FOUND)
    message(WARNING "Boost not found, disabling tests")
ENDIF(Boost_FOUND)
#################################
# Documentation
#################################
find_package(Doxygen COMPONENTS dot)
IF(Doxygen_FOUND)
find_package(Sphinx)
IF(Doxygen_FOUND AND Sphinx_FOUND)
    message(STATUS "Doxygen found, generating docs.")
    SET(DOXYGEN_EXCLUDE_PATTERNS "*/library/ini/*;*/doc/resources/*")
    SET(DOXYGEN_DISABLE_INDEX YES)
    SET(DOXYGEN_GENERATE_TREEVIEW YES)
    SET(DOXYGEN_GENERATE_XML YES)
    SET(DOXYGEN_LAYOUT_FILE "${CMAKE_CURRENT_SOURCE_DIR}/doc/DoxygenLayout.xml")
    doxygen_add_docs(docs doc src include/licensecc COMMENT "doxygen docs")
    file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/doc/resources/" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/html")
ELSE(Doxygen_FOUND)
    message(STATUS "Doxygen not found, not generating docs.")
ENDIF(Doxygen_FOUND)
    #file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/doc/resources/" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/html")
    #file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/doc/sphinx/" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}")
    set(SPHINX_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/doc)
    set(SPHINX_BUILD ${CMAKE_CURRENT_BINARY_DIR}/docs/sphinx)
    add_custom_target(documentation
                  COMMAND
                  ${SPHINX_EXECUTABLE} -b html
                  ${SPHINX_SOURCE} ${SPHINX_BUILD}
                  -Dbreathe_projects.licensecc=${CMAKE_CURRENT_BINARY_DIR}/xml
                  WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
                  COMMENT "Generating documentation with Sphinx")
    add_dependencies(documentation docs)
ELSE(Doxygen_FOUND AND Sphinx_FOUND)
    message(STATUS "Doxygen or Sphynx not found, not generating docs.")
ENDIF(Doxygen_FOUND AND Sphinx_FOUND)
install(DIRECTORY ${LCC_INCLUDE_DIR} DESTINATION include/${PROJECT_NAME})
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/ DESTINATION include)
CONTRIBUTING.md
@@ -4,7 +4,7 @@
The following is a set of guidelines for contributing to Open License Manager and its packages, which are hosted in the [Open License Manager organization](https://github.com/open-license-manager) on GitHub. These are mostly guidelines, not rules. 
## How to Contribute
## How to contribute
### Interacting with the team 
@@ -90,3 +90,4 @@
-   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 beta stage, however we would like to discuss it with you before we take project changing decision. You can reach us on the [project forum](https://groups.google.com/forum/#!forum/licensecc). 
    -  Even it it's in beta stage it's used ( _by some really courageous people!_ ) in production. We can't break current functionality, user established habits without documenting the change.
README.md
@@ -10,26 +10,25 @@
[![codecov](https://codecov.io/gh/open-license-manager/open-license-manager/branch/develop/graph/badge.svg)](https://codecov.io/gh/open-license-manager/open-license-manager)
[![Github Issues](https://img.shields.io/github/issues/open-license-manager/open-license-manager)](http://github.com/open-license-manager/open-license-manager/issues)
Protect the software you develop from unauthorized copies,
limit the usage in time, to a specific set of machines, or prevent the usage in
virtualized environments. It is an Open License Manager that helps to keep your
software closed :smirk: . A comprehensive [list of features](https://github.com/open-license-manager/open-license-manager/wiki/features), and their status is available in the project wiki.
Protect the software you develop from unauthorized copies, limit the usage in time, to a specific set of
machines, or prevent the usage in  virtualized environments. It is an Open License Manager that helps to keep your
software closed :smirk: . Among other features if it runs on a "real hardware" it can generate a signature of that hardware and report if the signature doesn't match.
A comprehensive [list of features](https://github.com/open-license-manager/open-license-manager/wiki/features), and their status is available in the project wiki.
If you plan to use this library or part of it remember to show us your appreciation giving it a
<a class="github-button" href="https://github.com/open-license-manager/open-license-manager" data-icon="octicon-star" aria-label="Star open-license-manager/open-license-manager on GitHub">star</a> here on GitHub.
## License
The project is donated to the community. It comes with a very large freedom of use for everyone, and it will always be. 
It uses a [BSD 3 clauses](https://opensource.org/licenses/BSD-3-Clause) licensing schema, that allows free modification and inclusion in commercial software. 
If you plan to use the project or part of it consider showing us your appreciation placing a star here on github.
## Project Structure
The software is made by 2 main sub-components:
The software is made by 3 main sub-components:
-   a C++ library with a nice C api, `licensecc` with minimal (or no) external dependencies (the part you have to integrate in your software) that is the project you're currently in.
-   a license generator lcc-license-generator `lcc` for customizing the library and generate the licenses.
-   a license debugger `lcc-inspector` to be sent to the final customer when there are licensing problems or for calculating the pc hash before issuing the license.
-   a license generator (github project [lcc-license-generator](https://github.com/open-license-manager/lcc-license-generator)) `lcc` for customizing the library and generate the licenses.
 
The following modules are planned...
-   a license [backoffice](../../issues/7) in php (in order to handle multiple licenses).
-   a license debugger to be sent to the final customer when there are licensing problems.
-   a [log descriptor](../../issues/8) in order to decrypt logs generated by the license system.
## How to build
Below an overview of the basic build procedure, you can find detailed instructions for [linux](https://github.com/open-license-manager/open-license-manager/wiki/Build-the-library) or [windows](https://github.com/open-license-manager/open-license-manager/wiki/Build-the-library-windows) in the wiki. 
cmake/FindSphinx.cmake
New file
@@ -0,0 +1,53 @@
# - This module looks for Sphinx
# Find the Sphinx documentation generator
#
# This modules defines
# SPHINX_EXECUTABLE
# SPHINX_FOUND
find_program(SPHINX_EXECUTABLE
  NAMES sphinx-build
  PATHS
    /usr/bin
    /usr/local/bin
    /opt/local/bin
    ~/.local/bin
  DOC "Sphinx documentation generator"
)
if( NOT SPHINX_EXECUTABLE )
  set(_Python_VERSIONS
    2.7 2.6 2.5 2.4 2.3 2.2 2.1 2.0 1.6 1.5
  )
  foreach( _version ${_Python_VERSIONS} )
    set( _sphinx_NAMES sphinx-build-${_version} )
    find_program( SPHINX_EXECUTABLE
      NAMES ${_sphinx_NAMES}
      PATHS
        /usr/bin
        /usr/local/bin
        /opt/local/bin
        ~/.local/bin
      DOC "Sphinx documentation generator"
    )
  endforeach()
endif()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Sphinx DEFAULT_MSG SPHINX_EXECUTABLE)
mark_as_advanced(SPHINX_EXECUTABLE)
function(Sphinx_add_target target_name builder conf source destination)
  add_custom_target(${target_name} ALL
    COMMAND ${SPHINX_EXECUTABLE} -b ${builder}
    -c ${conf}
    ${source}
    ${destination}
    COMMENT "Generating sphinx documentation: ${builder}"
  )
  set_property(DIRECTORY
    APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${destination}
  )
endfunction()
cmake/toolchain-ubuntu-mingw64.cmake
@@ -13,11 +13,15 @@
set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}-gcc)
set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}-g++)
set(CMAKE_RC_COMPILER ${TOOLCHAIN_PREFIX}-windres)
set(CMAKE_CXX_LINK_EXECUTABLE ${TOOLCHAIN_PREFIX}-g++)
# target environment on the build host system
#   set 1st to dir with the cross compiler's C/C++ headers/libs
set(CMAKE_FIND_ROOT_PATH /usr/${TOOLCHAIN_PREFIX})
#if(CMAKE_CROSSCOMPILING) #cross compiling for linux... a crazy bug on my system
#    link_directories(BEFORE /usr/lib/gcc/x86_64-w64-mingw32/7.3-win32)
#endif(CMAKE_CROSSCOMPILING)
# modify default behavior of FIND_XXX() commands to
# search for headers/libs in the target environment and
# search for programs in the build host environment
doc/Home.md
File was deleted
doc/_static/googleae93b5a7f3766641.html
doc/_static/pc-id-selection.png

doc/analysis/Backoffice.md
doc/analysis/Development-And-Usage-Workflow.md
File was renamed from doc/Development-And-Usage-Workflow.md
@@ -1,3 +1,5 @@
# Development and usage workflow
Below a description of the planned development and usage process. Comments and progress are reported on [issue #42](https://github.com/open-license-manager/open-license-manager/issues/42)
![dev-build-process](https://user-images.githubusercontent.com/1121667/64474031-e5afff80-d1a0-11e9-9819-f3b7e4e2126d.png)
@@ -8,7 +10,7 @@
### Binary release contents
Binary release contains: 
 * open-license-manager executable (merge of the actual `license_generator` executable and `bootstrap`).
 * open-license-manager executable (`lcc`).
 * source code of the unconfigured library.
 * source code of (part of) the tests.
 
@@ -18,7 +20,7 @@
In this phase the library is configured, compiled (only for the tests sake), linked with a mock executable and tested together with the license generator.
## Initialize library
In this phase the signing keys are generated by open-license-manager executable (`olm`), and optionally the source code of the library may be modified or obfuscated.
In this phase the signing keys are generated by open-license-manager executable (`lcc`), and optionally the source code of the library may be modified or obfuscated.
### Test (2)
@@ -30,6 +32,6 @@
 * If we want to link the execution to a specific hardware we need to send the product to the client without a license (or a demo executable, with the sole intent to generate the machine identifier). 
 * If we just want to send a demo product with an expiry date we prepare a license without the machine identifier.
 
# Build process
From the process described above, (strange to say) the license generator (`olm`) configures itself as a build
## Build process
From the process described above, (strange to say) the license generator (`lcc`) configures itself as a build
dependency of the licensing library, thus it needs to be built first.
doc/analysis/features.md
File was renamed from doc/features.md
@@ -1,5 +1,6 @@
# General features:
# Features:
## features and their status
| Feature                              | Implementation status | 
|--------------------------------------|:---------------------:|
| Trial license with expiry date       | :heavy_check_mark:    |
@@ -11,38 +12,38 @@
| Java/C# bindings                     | Planned               |
| Floating/network licenses            | Planned               |
## Issue a "demo" license with only expiry date.
### Issue a "demo" license with only expiry date.
Software editors often want to release a trial license that is not linked to a specified machine, but just limit the usage in time or to some other feature (number of cpu, process memory).
See [execution limits](Implemented/Planned execution limits) section.
## Licenses linked to "physical" hardware id
### Licenses linked to "physical" hardware id
Link the software to a physical hardware (a pc). In this scenario the software editor wants his software to be executed on a specific piece of hardware. We suppose the operating system is installed "bare to metal" and we're able to calculate an identifier of that hardware. This isn't always true for virtualized environments for which alternative strategies must be planned [eg. floating licenses (not yet implemented)]. See the section on [hardware identifiers](hardware-identifiers) for a detailed discussion of the use cases.
Depending on the situation there are are different kinds of hardware id that can be used. See [execution limits](Implemented/Planned execution limits) section.
## Virtual machine detection
### Virtual machine detection
Detect if the software is running in a virtualized environment and (optionally) forbid the execution. This is useful if software editors want to prevent the execution in virtual machines (lxc/dockers...) and be able to compute a meaningful hardware id. 
Another use case is the software is to be used only in a specific class of virtualized environments. For instance it was initially packaged as a docker image, the software editor don't want it to be "extracted" and placed elsewhere.
## License retrieval
### License retrieval
Open License Manager, when integrated into a licensed software will find its license file based on many different strategies.
It can handle multiple licenses at the same time. See the wiki page about [license retrieval](license-retrieval) for details.
 
## Licensed software features (partially implemented)
### Licensed software features (partially implemented)
A licensed software may be composed by many features (functions) each one activable independently. Licensing system tells the licensed software which features are enabled, and which features are disabled.
 
## License Management (planned)
It is necessary to keep track of the licenses that have been issued, of the clients, and their pc identifier.
### License Management (planned)
It is necessary to keep track of the licenses that have been issued, of the clients, and their hardware identifier.
A web application is planned that will provide integration with payment systems to allow licensed software customers to buy licenses.
## Customizable execution limits (planned)
### Customizable execution limits (planned)
It should be easy to add and implement your own "execution limit": that is require/forbid some feature in the application execution environment.
## Java/C# bindings (planned)
### Java/C# bindings (planned)
The application should support bindings to java language. The library has to be compiled as a .dll for use with JNI or C# integration layer. This is especially challenging on the api side.
Since the api is public, and the library is packaged as a separate .dll/.so everybody can compile a version of it always returning LICENSE_OK easily defeating the license schema. 
## Floating licenses (planned)
### Floating licenses (planned)
Limit the execution of the licensed software to a certain number of instances per license. 
This can be done in multiple ways:
    * without a central server, using broadcast or scanning the local network to find peers.
@@ -51,7 +52,7 @@
Status of this implementation is tracked in [issue #4](https://github.com/open-license-manager/open-license-manager/issues/4)
# Implemented/Planned execution limits
## Implemented/Planned execution limits
Open License Manager can limit execution of licensed software based on some criteria, called "execution limits".
Depending on the execution environment some criteria may not be applicable:
@@ -69,22 +70,20 @@
| concurrent execution | Planned | Planned | Planned | Planned |
| licensed sw version | Planned       | Planned            | Planned            | Planned            |
## Date
### Date
This is the most common limit set on a license, allow the software to expire after the defined date.
## Disk label/Disk id
### Disk label/Disk id
It is possible to limit the execution to a computer that has a certain disk connected.
This kind of limitation doesn't make sense in linux containerized environments.
## Cpu Number/Machine memory
### Cpu Number/Machine memory
Allow to restrict the execution only to a machine with the specified amount of cpu or memory or less. This is useful in virtualized environments, to create a licensed software demo version with limited performaces or with limited scalability.
Status of this implementation is tracked in [issue #4](https://github.com/open-license-manager/open-license-manager/issues/4)
## Virtualization type
### Virtualization type
Allow the execution of the licensed software only on some type of hardware or virtualized environment eg. only bare to metal, only in virtual machine, only in docker.
## Licensed software version
### Licensed software version
A licensed software may declare a version (eg 1.0.0). A license may span multiple releases of the software e.g. allow version 1.1.1 but not 2.0.0.
#
doc/api/public_api.rst
New file
@@ -0,0 +1,8 @@
Documentation
==================
.. doxygennamespace:: license
   :project: licensecc
   :members:
doc/conf.py
New file
@@ -0,0 +1,175 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# licensecc documentation build configuration file, created by
# sphinx-quickstart on Sat Mar 14 13:43:01 2020.
#
# This file is execfile()d with the current directory set to its
# containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
# import os
# import sys
# sys.path.insert(0, os.path.abspath('.'))
# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#
# needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = ['sphinx.ext.todo',
    'sphinx.ext.githubpages', 'breathe', 'recommonmark', 'sphinx_markdown_tables', 'sphinx_rtd_theme' ]
# Breathe Configuration
breathe_default_project = "licensecc"
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
#
# source_suffix = ['.rst', '.md']
source_suffix = ['.rst', '.md']
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = 'licensecc'
copyright = '2020, Open License Manager'
author = 'Open License Manager'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '2.0.0'
# The full version, including alpha/beta/rc tags.
release = '2.0.0'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = None
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This patterns also effect to html_static_path and html_extra_path
exclude_patterns = []
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = True
# -- Options for HTML output ----------------------------------------------
# The theme to use for HTML and HTML Help pages.  See the documentation for
# a list of builtin themes.
#
html_theme = 'sphinx_rtd_theme'
# Theme options are theme-specific and customize the look and feel of a theme
# further.  For a list of options available for each theme, see the
# documentation.
#
html_theme_options = {
  'titles_only': False
}
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# Custom sidebar templates, must be a dictionary that maps document names
# to template names.
#
# This is required for the alabaster theme
# refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars
#html_sidebars = {
#    '**': [
#        'relations.html',  # needs 'show_related': True theme option to display
#        'searchbox.html',
#    ]
#}
# -- Options for HTMLHelp output ------------------------------------------
# Output file base name for HTML help builder.
htmlhelp_basename = 'licenseccdoc'
# -- Options for LaTeX output ---------------------------------------------
latex_elements = {
    # The paper size ('letterpaper' or 'a4paper').
    #
    # 'papersize': 'letterpaper',
    # The font size ('10pt', '11pt' or '12pt').
    #
    # 'pointsize': '10pt',
    # Additional stuff for the LaTeX preamble.
    #
    # 'preamble': '',
    # Latex figure (float) alignment
    #
    # 'figure_align': 'htbp',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
#  author, documentclass [howto, manual, or own class]).
latex_documents = [
    (master_doc, 'licensecc.tex', 'licensecc Documentation',
     'Open License Manager', 'manual'),
]
# -- Options for manual page output ---------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
    (master_doc, 'licensecc', 'licensecc Documentation',
     [author], 1)
]
# -- Options for Texinfo output -------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
#  dir menu entry, description, category)
texinfo_documents = [
    (master_doc, 'licensecc', 'licensecc Documentation',
     author, 'licensecc', 'One line description of project.',
     'Miscellaneous'),
]
doc/development/Build-the-library-windows.md
File was renamed from doc/Build-the-library-windows.md
@@ -1,4 +1,4 @@
@ingroup  group_02
# Windows
This page describes how to build the library. It's a good starting point if you just downloaded it and you want to start explore.
doc/development/Build-the-library.md
File was renamed from doc/Build-the-library.md
@@ -1,5 +1,3 @@
@ingroup  group_01
# Linux
## Install prerequisites
doc/development/Dependencies.md
File was renamed from doc/Dependencies.md
@@ -1,3 +1,5 @@
# Dependencies
This page describes the dependencies of open-license-manager and the supported build environments.
Dependencies varies with the environment, if you're building the library for the first time we suggest you download or set up one of the supported environments to be sure not to incur in dependency/compiler errors (you can use virtual machines , docker or lxc/lxd technologies).
doc/development/Development-Environment-Setup.md
File was renamed from doc/Development-Environment-Setup.md
@@ -1,4 +1,4 @@
# Developer's environment setup
This guide is just an help in case you haven't decided your development environment or your development environment match ours. 
We don't have any specific dependency on development tools, you can choose the one you prefer. Though if you want to contribute
you're required to  format the code using `clang-format` before you submit the pull request.
doc/index.rst
New file
@@ -0,0 +1,50 @@
Welcome to licensecc's documentation.
=====================================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
.. toctree::
   :glob:
   :maxdepth: 2
   :hidden:
   :caption: Build the library:
   development/*
.. toctree::
   :glob:
   :maxdepth: 2
   :hidden:
   :caption: Integrate and use:
   usage/*
.. toctree::
   :glob:
   :maxdepth: 2
   :hidden:
   :caption: API:
   api/*
.. toctree::
   :glob:
   :maxdepth: 2
   :hidden:
   :caption: Analysis:
   analysis/*
.. toctree::
   :glob:
   :maxdepth: 2
   :hidden:
   :caption: Miscellaneous:
   other/*
doc/open-license-manager.vsdx
Binary files differ
doc/other/CREDITS.md
New file
@@ -0,0 +1,33 @@
# Credits
The following open source code has been used in OpenLicenseManager.
Thanks to every one of the authors of such projects. Without you open license manager would never have been completed.
## isVM
Thanks for the great smbios parsing code. It saved me days.
isvm : https://github.com/0of/isvm
The MIT License (MIT)
Copyright (c) 2015 Magnus
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
doc/other/QA.md
File was renamed from doc/QA.md
@@ -1,3 +1,5 @@
# Q&A
## Development
Development related questions.
doc/other/glossary.md
File was renamed from doc/Basic-concepts.md
@@ -1,12 +1,13 @@
#Basic concepts and terminology
# Glossary
##Project
Some `common` word that recur into the documentation have a specific meaning. Below an explanation of the terms and concepts used.
## Project
A project corresponds to one application where the licensing system need to be integrated.
Each project has its own private key and its own folder where `licensecc` is compiled. 
Currently we support only one project per (build) machine. This is especially true in Windows, where the private key has the same name for all the projects.
##Features
## Features
Features let licensed application to selectively enable or disable functions in the application, features are part of the original license, they do not have hardware identifications, they only have validity date. 
#Customizing the build
doc/snippets.txt
@@ -18,4 +18,9 @@
        echo "Boost installed"
        cd C:/local/boost
        dir
) else echo "Boost already installed"
) else echo "Boost already installed"
linux cross compile for windows openssl
 ./Configure no-zlib no-shared --prefix=$PWD/dist-win-64 --cross-compile-prefix=x86_64-w64-mingw32- mingw64
 /usr/local/bin/cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/toolchain-ubuntu-mingw64.cmake -DCMAKE_INSTALL_PREFIX=../../install -DBOOST_ROOT=$PWD/../../boost_1_69_0/dist-win-x64/ -DOPENSSL_ROOT_DIR=$PWD/../../openssl-OpenSSL_1_1_1d/dist-win-64/ -DBoost_ARCHITECTURE="-x64" -DCMAKE_CXX_COMPILER_ARCHITECTURE_ID="x64" -DCMAKE_SH="CMAKE_SH-NOTFOUND" -DCMAKE_VERBOSE_MAKEFILE=ON  -DLOGS_DISABLED=ON ..
doc/snippets/hardware.cpp
New file
@@ -0,0 +1,266 @@
/*********************  physical_processors.cpp   *****************************
* Author:        Agner Fog
* Date created:  2019-10-29
* Last modified: 2019-11-25
* Version:       1.02 beta
* Project:       vector class library
* Description:   Detect number of physical and logical processors on CPU chip.
*                Compile for C++11 or later
*
* (c) Copyright 2019 Agner Fog.
* Apache License version 2.0 or later.
*******************************************************************************
Some modern CPUs can run two threads in each CPU core when simultaneous
multithreading (SMT, called hyperthreading by Intel) is enabled.
The number of physical processors is the number of CPU cores.
The number of logical processors is the same number multiplied by the number of
threads that can run simultaneously in each CPU core.
Simultaneous multithreading will slow down performance when two CPU-intensive
threads running in the same physical processor (CPU core) are competing for the
same resources. Therefore, the optimal number of threads for CPU-intensive
tasks is most likely to be the number of physical processors.
Tasks that are less CPU-intensive but limited by RAM access, disk access,
network, etc. may get an advantage by running as many threads as the number of
logical processors. This will be double the number of physical processors when
simultaneous multithreading is enabled.
The physicalProcessors function detects the number of physical processors and
logical processors on an x86 computer. This is useful for determining the
optimal number of threads.
Note: There are several problems in detecting the number of physical processors:
1. The CPUID instruction on Intel CPUs will return a wrong number of logical
   processors when SMT (hyperthreading) is disabled. It may be necessary to
   compare the number of processors returned by the CPUID instruction with the
   number of processors reported by the operating system to detect if SMT is
   enabled (AMD processors do not have this problem).
2. It is necessary to rely on system functions to detect if there is more than
   one CPU chip installed. It is assumed that the status of SMT is the same on
   all CPU chips in a system.
3. The behavior of VIA processors is undocumented.
4. This function is not guaranteed to work on future CPUs. It may need updating
   when new CPUs with different configurations or different CPUID functionality
   appear.
******************************************************************************/
#include <thread>     // std::thread functions
#ifdef _MSC_VER
#include <intrin.h>   // __cpuidex intrinsic function available on microsoft compilers
#endif
// Define interface to CPUID instruction.
// input:  leaf = eax, subleaf = ecx
// output: output[0] = eax, output[1] = ebx, output[2] = ecx, output[3] = edx
static inline void cpuid(int output[4], int leaf, int subleaf = 0) {
#if defined(__GNUC__) || defined(__clang__)      // use inline assembly, Gnu/AT&T syntax
    int a, b, c, d;
    __asm("cpuid" : "=a"(a), "=b"(b), "=c"(c), "=d"(d) : "a"(leaf), "c"(subleaf) : );
    output[0] = a;
    output[1] = b;
    output[2] = c;
    output[3] = d;
#elif defined (_MSC_VER)                         // Microsoft compiler, intrin.h included
    __cpuidex(output, leaf, subleaf);            // intrinsic function for CPUID
#else                                            // unknown platform. try inline assembly with masm/intel syntax
    __asm {
        mov eax, leaf
        mov ecx, subleaf
        cpuid;
        mov esi, output
        mov[esi], eax
        mov[esi + 4], ebx
        mov[esi + 8], ecx
        mov[esi + 12], edx
    }
#endif
}
// Function prototype:
int physicalProcessors(int * logical_processors = 0);
// Find the number of physical and logical processors supported by CPU
// Parameter:
// logical_processors: an optional pointer to an integer that will receive the number of logical processors.
// Return value: number of physical processors
int physicalProcessors(int * logical_processors) {
    int vendor = 0;                              // CPU vendor: 1 = Intel, 2 = AMD, 3 = VIA, 0 = other
    int logicalProc = 1;                         // number of logical processor cores
    int physicalProc = 1;                        // number of physical processor cores
    int procPerCore = 1;                         // logical cores per physical core
    bool hyperthreadingSupported = false;        // CPU supports hyperthreading / simultaneous multithreading
    int systemProcessors = std::thread::hardware_concurrency(); // number of processors reported by operating system
    int abcd[4] = { 0,0,0,0 };                   // CPUID output
    cpuid(abcd, 0);                              // CPUID function 0
    int maxLeaf = abcd[0];                       // maximum eax input for CPUID
    if (abcd[2] == 0x6C65746E) {                 // last 4 chars of "GenuineIntel"
        vendor = 1;
    }
    else if (abcd[2] == 0x444D4163) {            // last 4 chars of "AuthenticAMD"
        vendor = 2;
    }
    else if (abcd[2] == 0x736C7561) {            // last 4 chars of "CentaurHauls"
        vendor = 3;
    }
    if (maxLeaf >= 1) {
        cpuid(abcd, 1);
        if (abcd[3] & (1 << 28)) {               // hyperthreading supported
            hyperthreadingSupported = true;
        }
    }
    if (vendor == 1) {
        //////////////////
        //    Intel     //
        //////////////////
        int hyper = 0;                           // hyperthreading status: 0 = unknown, 1 = disabled, 2 = enabled
        if (maxLeaf >= 0xB) {                    // leaf 0xB or 0x1F: Extended Topology Enumeration
            int num = 0xB;
            // if (maxLeaf >= 0x1F) num = 0x1F;
            for (int c = 0; c < 5; c++) {
                cpuid(abcd, num, c);             // enumeration level c
                int type = (abcd[2] >> 8) & 0xFF;// enumeration type at level c
                if (type == 1) {                 // SMT level
                    procPerCore = abcd[1] & 0xFFFF;
                }
                else if (type >= 2) {            // core level
                    logicalProc = abcd[1] & 0xFFFF;
                }
                else if (type == 0) break;
                // There are more types/levels to consider if we use num = 0x1F. We may need
                // to fix this in the future if CPUs with more complex configurations appear
            }
            physicalProc = logicalProc / procPerCore;
            // The number of performance monitor registers depends on hyperthreading status
            // on Intel CPUs with performance monitoring version 3 or 4
            cpuid(abcd, 0xA, 0);                 // performance monitor counters information
            int perfVersion = abcd[0] & 0xFF;    // performance monitoring version
            int perfNum = (abcd[0] >> 8) & 0xFF; // number of performance monitoring registers
            if (perfVersion == 3 || perfVersion == 4) {
                if (perfNum == 4) {
                    hyper = 2;                   // 4 performance registers when hyperthreading enabled
                }
                else if (perfNum == 8) {         // 8 performance registers when hyperthreading disabled
                    hyper = 1;
                    procPerCore = 1;
                    logicalProc = physicalProc;  // reduce the number of logical processors when hyperthreading is disabled
                }
                // hyper remains 0 in all other cases, indicating unknown status
            }
        }
        else if (maxLeaf >= 4) {                 // CPUID function 4: cache parameters and cores
            cpuid(abcd, 4);
            logicalProc = (abcd[0] >> 26) + 1;
            if (hyperthreadingSupported) {
                // number of logical processors per core is not known. Assume 2 if hyperthreading supported
                procPerCore = 2;
            }
            physicalProc = logicalProc / procPerCore;
        }
        else {
            // no information. Assume 1 processor
        }
        if (systemProcessors > logicalProc) {
            // Multiple CPU chips. Assume that chips are identical with respect to hypethreading
            physicalProc = systemProcessors * physicalProc / logicalProc;
            logicalProc = systemProcessors;
        }
        else if (logicalProc > systemProcessors && systemProcessors > 0 && hyper == 0) {
            // Hyperthreading is disabled
            logicalProc = systemProcessors;
            physicalProc = systemProcessors;
        }
    }
    else if (vendor == 2) {
        //////////////////
        //    AMD       //
        //////////////////
        cpuid(abcd, 0x80000000);                 // AMD specific CPUID functions
        int maxLeaf8 = abcd[0] & 0xFFFF;         // maximum eax 0x8000.... input for CPUID
        if (maxLeaf8 >= 8) {
            cpuid(abcd, 0x80000008);
            logicalProc = (abcd[2] & 0xFF) + 1;
            if (maxLeaf8 >= 0x1E) {
                cpuid(abcd, 0x8000001E);
                procPerCore = ((abcd[1] >> 8) & 0x03) + 1;
                // procPerCore = 2 if simultaneous multithreading is enabled, 1 if disabled
            }
            else {
                if (hyperthreadingSupported) {
                    procPerCore = 2;
                }
                else {
                    procPerCore = 1;
                }
            }
            physicalProc = logicalProc / procPerCore;
        }
        else if (hyperthreadingSupported) {
            // number of logical processors per core is not known. Assume 2 if SMT supported
            logicalProc = 2;
            physicalProc = 1;
        }
        if (systemProcessors > logicalProc) {
            // Multiple CPU chips. Assume that chips are identical with respect to SMT
            physicalProc = systemProcessors * physicalProc / logicalProc;
            logicalProc = systemProcessors;
        }
    }
    else {
        //////////////////////////////
        //    VIA or unknown CPU    //
        //////////////////////////////
        // The behavior of VIA processors is undocumented! It is not known how to detect threads on a VIA processor
        physicalProc = logicalProc = systemProcessors;
        if (hyperthreadingSupported && physicalProc > 1) {
            physicalProc /= 2;
        }
    }
    if (logical_processors) {
        // return logical_processors if pointer is not null
        *logical_processors = logicalProc;
    }
    return physicalProc;
}
/* Uncomment this for testing:
#include <stdio.h>
int main() {
    int logicalProc = 0;
    int physicalProc = physicalProcessors(&logicalProc);
    printf("\nlogical processors: %i",  logicalProc);
    printf("\nphysical processors: %i", physicalProc);
    printf("\nlogical processors per core: %i", logicalProc / physicalProc);
    int sysproc = std::thread::hardware_concurrency();
    printf("\nsystem processors: %i", sysproc);
    return 0;
}
*/
doc/usage/Hardware-identifiers.md
File was renamed from doc/Hardware-identifiers.md
@@ -1,5 +1,8 @@
# Hardware Identifiers
## Use cases
Linking the execution of a software to a. With the recent coming of virtualized environments the installation of software directly on the machine has been less and less.
Linking the execution of a software to a physical hardware (a pc). With the recent coming of virtualized environments
the installation of software directly on the machine has been less and less.
OpenLicenseManager guess the environment where the user is trying to launch the software, and reports it to the software publisher when he is generating a license in a way that he can decide how to limit the usage on per license basis.
@@ -7,7 +10,7 @@
This is straightforward case. If the software is executing on a physical hardware it is possible to identify the hardware by various parameters (cpu type/memory/disk label/mac address)
### Execution in a virtual machine
Generating a pc identifier on a virtual machine doesn't make much sense, since the vm can be copied as a whole elsewhere
Generating a hardware identifier on a virtual machine doesn't make much sense, since the vm can be copied as a whole elsewhere
and there are few ways to detect this without using an external license server.
*   Usually when the machine is copied the MAC address is changed. But sometimes it changes on its own. Software publishers may want to use this as a last resort to prevent the vm for being cloned. It has to be verified case by case.
@@ -22,4 +25,5 @@
If the licensed software specify the parameter
If the licensed software uses `STRATEGY_DEFAULT` and the strategy generates an unstable identifier it is possible to ask the user to set t
If the licensed software uses `STRATEGY_DEFAULT` and the strategy generates an unstable identifier it is possible to ask the user to
set the environemnt variable.
doc/usage/License-retrieval.md
File was renamed from doc/License-retrieval.md
@@ -1,4 +1,5 @@
# License retrieval
# Place the license file
Open License Manager, when integrated into a licensed software can automatically find its license file (or multiple license files) based on:
 
 * An environment variable: 
doc/usage/integration.md
File was renamed from doc/Integration.md
@@ -1,3 +1,5 @@
# Integrate license in your application
This short guide explain how to integrate `open-license-manager` in your application.
Working examples are provided in the [examples](https://github.com/open-license-manager/examples) project. 
@@ -6,7 +8,7 @@
The file containing the public api is `include/licensecc/licensecc.h`. Functions in there are considered stable.
### Print a pc identifier
### Print a hardware identifier
```CPP
bool identify_pc(IDENTIFICATION_STRATEGY pc_id_method, char* identifier_out, size_t bufSize);
doc/usage/issue-licenses.md
File was renamed from doc/Issue-licenses.md
@@ -1,3 +1,4 @@
# Issue licenses
The easiest way to issue licenses is to enter the project library and create the following project structure:
The projects folder can be anyware. We created one in `open-license-manager/projects` for your convenience (and for testing purposes). A default project<sup>1</sup> named `DEFAULT` has been created for you when you configured the project with cmake.
include/licensecc/datatypes.h
@@ -25,16 +25,7 @@
#define DllExport __declspec(dllexport)
#endif
// define api structure sizes
#define PC_IDENTIFIER_SIZE 19
#define PROPRIETARY_DATA_SIZE 16
#define AUDIT_EVENT_NUM 5
#define AUDIT_EVENT_PARAM2 255
#define VERSION_SIZE 15
#define PROJECT_NAME_SIZE 15
#define EXPIRY_DATE_SIZE 10
#define ERROR_BUFFER_SIZE 256
#include <licensecc_properties.h>
typedef enum {
    LICENSE_OK = 0,  // OK
@@ -44,32 +35,48 @@
    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,
    PRODUCT_EXPIRED = 7,    //!< PRODUCT_EXPIRED
    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_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;
    SIGNATURE_VERIFIED = 103//!< SIGNATURE_VERIFIED
} LCC_EVENT_TYPE;
typedef enum {
    LOCAL,
    REMOTE  // remote licenses are not supported now.
} LICENSE_TYPE;
    LCC_LOCAL,
    LCC_REMOTE  // remote licenses are not supported now.
} LCC_LICENSE_TYPE;
typedef enum { SVRT_INFO, SVRT_WARN, SVRT_ERROR } SEVERITY;
typedef enum { SVRT_INFO, SVRT_WARN, SVRT_ERROR } LCC_SEVERITY;
typedef struct {
    SEVERITY severity;
    EVENT_TYPE event_type;
    LCC_SEVERITY severity;
    LCC_EVENT_TYPE event_type;
    /**
     * License file name or location where the license is stored.
     */
    char license_reference[MAX_PATH];
    char param2[AUDIT_EVENT_PARAM2 + 1];
    char param2[LCC_API_AUDIT_EVENT_PARAM2 + 1];
} AuditEvent;
typedef enum {
    /**
     * A list of absolute path separated by ';' containing the eventual location
     * of the license files. Can be NULL.
     */
    LICENSE_PATH,
    /**
     * The license is provided as plain data
     */
    LICENSE_PLAIN_DATA,
    /**
     * The license is encoded
     */
    LICENSE_ENCODED
} LCC_LICENSE_DATA_TYPE;
/**
 * This structure contains informations on the raw license data. Software authors
@@ -79,61 +86,45 @@
 * 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;
    /**
     * 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;
    LCC_LICENSE_DATA_TYPE license_data_type;
    char licenseData[LCC_API_MAX_LICENSE_DATA_LENGTH];
} LicenseLocation;
/**
 * Informations on the software requiring the license
 */
typedef struct {
    char version[VERSION_SIZE + 1];  // software version in format xxxx.xxxx.xxxx
    char project_name[PROJECT_NAME_SIZE + 1];  // name of the project (must correspond to the name in the license)
    uint32_t magic;  // reserved
    char version[LCC_API_VERSION_LENGTH + 1];  // software version in format xxxx[.xxxx.xxxx] //TODO
    char project_name[LCC_API_PROJECT_NAME_SIZE + 1];  // name of the project (must correspond to the name in the license)
    /**
     * this number passed in by the application must correspond to the magic number used when compiling the library.
     * See cmake parameter -DLCC_PROJECT_MAGIC_NUM and licensecc_properties.h macro VERIFY_MAGIC
     */
    unsigned int magic;
} CallerInformations;
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 AUDIT_EVENT_NUM are reported.
     */
    AuditEvent status[AUDIT_EVENT_NUM];
    AuditEvent status[LCC_API_AUDIT_EVENT_NUM];
    /**
     * Eventual expiration date of the software,
     * can be '\0' if the software don't expire
     * */
    char expiry_date[EXPIRY_DATE_SIZE + 1];
    char expiry_date[LCC_API_EXPIRY_DATE_SIZE + 1];
    unsigned int days_left;
    bool has_expiry;
    bool linked_to_pc;
    LICENSE_TYPE license_type;  // Local or Remote
    LCC_LICENSE_TYPE license_type;  // Local or Remote
    /* A string of character inserted into the license understood
     * by the calling application.
     * '\0' if the application didn't specify one */
    char proprietary_data[PROPRIETARY_DATA_SIZE + 1];
    char proprietary_data[LCC_API_PROPRIETARY_DATA_SIZE + 1];
    int license_version;  // license file version
} LicenseInfo;
/**
 * Enum to select a specific pc identification_strategy. DEFAULT Should be used
 * in most cases.
 */
typedef enum {
    STRATEGY_DEFAULT,
    STRATEGY_ETHERNET,
    STRATEGY_IP_ADDRESS,
    STRATEGY_DISK_NUM,
    STRATEGY_DISK_LABEL,
    STRATEGY_PLATFORM_SPECIFIC,
    STRATEGY_UNKNOWN
} IDENTIFICATION_STRATEGY;
#ifdef __cplusplus
}
include/licensecc/licensecc.h
@@ -11,20 +11,22 @@
extern "C" {
#endif
#include <licensecc_properties.h>
#include "datatypes.h"
/*
/**
 * Method used to convert the LicenseInfo into a human readable
 * representation. //not yet implemented
 * representation.
 */
void print_error(char out_buffer[ERROR_BUFFER_SIZE], LicenseInfo* licenseInfo);
void print_error(char out_buffer[LCC_API_ERROR_BUFFER_SIZE], LicenseInfo* licenseInfo);
/**
 * This method calculates the pc identifier. The string need to be shown to the user and given back to the software
 * This method calculates the hardware identifier. The string need to be shown to the user and given back to the software
 * editor when issuing a license.
 *  pc_id_method = STRATEGY_DEFAULT usually works.
 */
bool identify_pc(IDENTIFICATION_STRATEGY pc_id_method, char* identifier_out, size_t* bufSize);
bool identify_pc(LCC_API_IDENTIFICATION_STRATEGY pc_id_method, char* identifier_out, size_t* bufSize);
/**
 * This method is used to request the use of one license for a product.
@@ -39,7 +41,7 @@
 * @param license[out] optional, can be NULL, if set it will return extra informations about the license.
 */
EVENT_TYPE acquire_license(const CallerInformations* callerInformation, const LicenseLocation* licenseLocation,
LCC_EVENT_TYPE acquire_license(const CallerInformations* callerInformation, const LicenseLocation* licenseLocation,
                           LicenseInfo* license_out);
/**
@@ -47,11 +49,11 @@
 * Should be called from time to time to confirm we're still using the
 * license.
 */
EVENT_TYPE confirm_license(char* featureName, LicenseLocation* licenseLocation);
LCC_EVENT_TYPE confirm_license(char* featureName, LicenseLocation* licenseLocation);
/**
 * Do nothing for now, useful for network licenses.
 */
EVENT_TYPE release_license(char* featureName, LicenseLocation licenseLocation);
LCC_EVENT_TYPE release_license(char* featureName, LicenseLocation licenseLocation);
#ifdef __cplusplus
}
src/CMakeLists.txt
@@ -1,7 +1,10 @@
add_subdirectory("library")
IF (NOT LCC_PROJECT_MAGIC_NUM)
    set(LCC_PROJECT_MAGIC_NUM 0)
ENDIF (NOT LCC_PROJECT_MAGIC_NUM)
#for no reason overwrite it (maybe it's manually customized)
IF(NOT EXISTS "${LCC_INCLUDE_DIR}/licensecc_properties.h")
    configure_file ("templates/licensecc_properties.h.in" 
        "${LCC_INCLUDE_DIR}/licensecc_properties.h")
ENDIF(NOT EXISTS "${LCC_INCLUDE_DIR}/licensecc_properties.h")
ENDIF(NOT EXISTS "${LCC_INCLUDE_DIR}/licensecc_properties.h")
add_subdirectory("library")
src/inspector/CMakeLists.txt
New file
@@ -0,0 +1,8 @@
ADD_EXECUTABLE(inspector inspector.cpp )
target_link_libraries(inspector
     licensecc_static
      Boost::unit_test_framework
     Boost::filesystem
     Boost::system)
src/inspector/inspector.cpp
New file
@@ -0,0 +1,91 @@
#include <iostream>
#include <map>
#include <unordered_map>
#include <licensecc/licensecc.h>
#include <fstream>
#include "../library/os/cpu_info.hpp"
#include "../library/os/execution_environment.hpp"
using namespace std;
using namespace license::os;
const map<int, string> stringByStrategyId = {{STRATEGY_DEFAULT, "DEFAULT"},
                                             {STRATEGY_ETHERNET, "MAC"},
                                             {STRATEGY_IP_ADDRESS, "IP"},
                                             {STRATEGY_DISK_NUM, "Disk1"},
                                             {STRATEGY_DISK_LABEL, "Disk2"}};
const unordered_map<int, string> descByVirtDetail = {{BARE_TO_METAL, "No virtualization"},
                                                     {VMWARE, "Vmware"},
                                                     {VIRTUALBOX, "Virtualbox"},
                                                     {V_XEN, "XEN"},
                                                     {KVM, "KVM"},
                                                     {HV, "Microsoft Hypervisor"},
                                                     {V_OTHER, "Other type of vm"}};
const unordered_map<int, string> descByVirt = {
    {VIRTUALIZATION::NONE, "No virtualization"}, {VIRTUALIZATION::VM, "VM"}, {VIRTUALIZATION::CONTAINER, "Container"}};
const unordered_map<int, string> stringByEventType = {
    {LICENSE_OK, "OK "},
    {LICENSE_FILE_NOT_FOUND, "license file not found "},
    {LICENSE_SERVER_NOT_FOUND, "license server can't be contacted "},
    {ENVIRONMENT_VARIABLE_NOT_DEFINED, "environment variable not defined "},
    {FILE_FORMAT_NOT_RECOGNIZED, "license file has invalid format (not .ini file) "},
    {LICENSE_MALFORMED, "some mandatory field are missing, or data can't be fully read. "},
    {PRODUCT_NOT_LICENSED, "this product was not licensed "},
    {PRODUCT_EXPIRED, "license expired "},
    {LICENSE_CORRUPTED, "license signature didn't match with current license "},
    {IDENTIFIERS_MISMATCH, "Calculated identifier and the one provided in license didn't match"}};
static LCC_EVENT_TYPE verifyLicense(const string& fname) {
    LicenseInfo licenseInfo;
    LicenseLocation licLocation = {LICENSE_PATH};
    std::copy(fname.begin(), fname.end(), licLocation.licenseData);
    LCC_EVENT_TYPE result = acquire_license(nullptr, &licLocation, &licenseInfo);
    if (result == LICENSE_OK) {
        cout << "license OK" << endl;
    } else {
        cerr << stringByEventType.find(result)->second << endl;
    }
    return result;
}
int main(int argc, char* argv[]) {
    license::os::CpuInfo cpu;
    cout << "Cpu Vendor      :" << cpu.vendor() << endl;
    cout << "Cpu Brand       :" << cpu.brand() << endl;
    cout << "Cpu is hypervis.:" << cpu.cpu_virtual() << endl;
    cout << "Cpu model       :0x" << std::hex << ((long)cpu.model()) << std::dec << endl;
    cout << "Virt. detail cpu:" << descByVirtDetail.find(cpu.virtualization_details())->second << endl <<endl;
    ExecutionEnvironment execEnv;
    cout << "Running in cloud:" << execEnv.is_cloud() << endl;
    cout << "Docker          :" << execEnv.is_docker() << endl;
    cout << "other container :" << execEnv.is_container() << endl;
    cout << "Virtualiz. class:" << descByVirt.find(execEnv.getVirtualization())->second << endl;
    cout << "Bios vendor     :" << execEnv.bios_vendor() << endl;
    cout << "Bios description:" << execEnv.bios_description() << endl;
    cout << "System vendor   :" << execEnv.sys_vendor() << endl <<endl;
    char hw_identifier[LCC_API_PC_IDENTIFIER_SIZE + 1];
    size_t bufSize = LCC_API_PC_IDENTIFIER_SIZE + 1;
    for (const auto& x : stringByStrategyId) {
        if (identify_pc(static_cast<LCC_API_IDENTIFICATION_STRATEGY>(x.first), hw_identifier, &bufSize)) {
            std::cout << x.second << ':' << hw_identifier << std::endl;
        } else {
            std::cout << x.second << ": NA" << endl;
        }
    }
    if (argc == 2) {
        const string fname(argv[1]);
        ifstream license_file(fname);
        if (license_file.good()) {
            verifyLicense(fname);
        } else {
            cerr << "license file :" << fname << " not found." << endl;
        }
    }
}
src/library/CMakeLists.txt
@@ -1,30 +1,44 @@
add_subdirectory("base")
add_subdirectory("os")
add_subdirectory("locate")
add_subdirectory("hw_identifier")
ADD_LIBRARY(licensecc_static STATIC
    licensecc.cpp
    LicenseReader.cpp
    pc-identifiers.c
    limits/license_verifier.cpp
    ini/ConvertUTF.c
    ini/ConvertUTF.cpp
    $<TARGET_OBJECTS:hw_identifier>
    $<TARGET_OBJECTS:locate>
    $<TARGET_OBJECTS:os>
    $<TARGET_OBJECTS:base>
)
add_subdirectory("locate")
add_subdirectory("os")
if(CODE_COVERAGE AND UNIX)
      if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.13)
        target_link_options(licensecc_static PUBLIC --coverage)
      endif()
      list(APPEND EXTERNAL_LIBS gcov)
endif(CODE_COVERAGE AND UNIX)
define_property(TARGET PROPERTY WITH_OPENSSL BRIEF_DOCS "need openssl to compile" FULL_DOCS "ff")
IF(UNIX OR OPENSSL_FOUND)
    target_compile_definitions(licensecc_static PUBLIC HAS_OPENSSL)
    set_target_properties(licensecc_static PROPERTIES WITH_OPENSSL 1)
    target_link_libraries(licensecc_static PUBLIC base OpenSSL::Crypto ${EXTERNAL_LIBS} ${CMAKE_DL_LIBS})
    target_link_libraries(licensecc_static PUBLIC OpenSSL::Crypto ${EXTERNAL_LIBS} ${CMAKE_DL_LIBS})
ELSE(UNIX OR OPENSSL_FOUND)
    set_target_properties(licensecc_static PROPERTIES WITH_OPENSSL 0)
    target_link_libraries(licensecc_static PUBLIC base ${EXTERNAL_LIBS})
    target_link_libraries(licensecc_static PUBLIC ${EXTERNAL_LIBS})
ENDIF(UNIX OR OPENSSL_FOUND)
#set_property(TARGET licensecc_static PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
target_include_directories(licensecc_static
    INTERFACE
    PUBLIC
        $<INSTALL_INTERFACE:include>
        $<INSTALL_INTERFACE:include/${PROJECT_NAME}/${LCC_PROJECT_NAME}>
        $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../../include>
        $<BUILD_INTERFACE:${LCC_INCLUDE_DIR}>
)
add_library(licensecc::licensecc_static ALIAS licensecc_static)
src/library/LicenseReader.cpp
@@ -22,12 +22,9 @@
#include <stdlib.h>
#include <math.h>
#include <public_key.h>
#include <licensecc_properties.h>
#include <licensecc/licensecc.h>
#include "base/base.h"
#include "pc-identifiers.h"
#include "LicenseReader.hpp"
#include "base/StringUtils.h"
#include "base/logger.h"
@@ -39,7 +36,8 @@
FullLicenseInfo::FullLicenseInfo(const string &source, const string &product, const string &license_signature)
    : source(source),
      m_project(product),  //
      license_signature(license_signature) {}
      license_signature(license_signature),
      m_magic(0) {}
LicenseReader::LicenseReader(const LicenseLocation *licenseLocation) : licenseLocation(licenseLocation) {}
src/library/LicenseReader.hpp
@@ -24,6 +24,7 @@
    const std::string license_signature;
    const std::string source;
    const std::string m_project;
    unsigned int m_magic;
    std::map<std::string, std::string> m_limits;
    FullLicenseInfo(const std::string& source, const std::string& product, const std::string& license_signature);
src/library/base/CMakeLists.txt
@@ -1,9 +1,9 @@
ADD_LIBRARY(base STATIC
ADD_LIBRARY(base OBJECT
    EventRegistry.cpp
    StringUtils.cpp
    FileUtils.cpp
    logger.c
    base64.c
    file_utils.cpp
    base64.cpp
    logger.cpp
)
if(CODE_COVERAGE AND UNIX)
@@ -13,10 +13,6 @@
        -g         # generate debug info
        --coverage # sets all required flags
      )
      target_link_libraries(base PUBLIC gcov)
endif(CODE_COVERAGE AND UNIX)
add_dependencies( base project_initialize )
install(TARGETS base EXPORT licensecc ARCHIVE DESTINATION lib/${PROJECT_NAME}/${LCC_PROJECT_NAME})
src/library/base/EventRegistry.cpp
@@ -17,7 +17,7 @@
namespace license {
using namespace std;
const map<EVENT_TYPE, int> PROGRESS_BY_EVENT_TYPE = {
const map<LCC_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; }
@@ -73,11 +73,11 @@
    return result;
}
void EventRegistry::addEvent(EVENT_TYPE event, const std::string &licenseLocationId) {
void EventRegistry::addEvent(LCC_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) {
void EventRegistry::addEvent(LCC_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());
src/library/base/EventRegistry.h
@@ -52,8 +52,8 @@
     * @return NULL if no failures are found.
     */
    const AuditEvent *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 addEvent(LCC_EVENT_TYPE event, const std::string &licenseLocationId);
    void addEvent(LCC_EVENT_TYPE event, const char *licenseLocationId = nullptr, const char *info = nullptr);
    void exportLastEvents(AuditEvent *auditEvents, int nlogs);
};
}  // namespace license
src/library/base/StringUtils.cpp
@@ -28,7 +28,7 @@
        ++it;
    }
    std::string::const_reverse_iterator rit = string_to_trim.rbegin();
    while (rit.base() != it && isspace(*rit)) {
    while (rit.base() != it && (isspace(*rit) || *rit == 0)) {
        ++rit;
    }
    return std::string(it, rit.base());
src/library/base/base64.c
File was deleted
src/library/base/base64.cpp
New file
@@ -0,0 +1,153 @@
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include "base64.h"
namespace license {
using namespace std;
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
void add_CR_if_needed(string& encodeBuffer, int lineLenght) {
    if (lineLenght > 0 && ((encodeBuffer.size() + 1) % lineLenght) == 0) {
        encodeBuffer += '\n';
    }
}
string base64(const void* binaryData, size_t len, int lineLenght) {
    const unsigned char* bin = (const unsigned char*)binaryData;
    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.
    const size_t flen = 4 * (len + pad) / 3;
    size_t totalLength = flen;
    if (lineLenght > 0) {
        totalLength += ((int)flen / lineLenght) + 3;
    }
    string encodeBuffer;
    encodeBuffer.reserve(totalLength);
    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];
        add_CR_if_needed(encodeBuffer, lineLenght);
        encodeBuffer += b64[BYTE0 >> 2];
        add_CR_if_needed(encodeBuffer, lineLenght);
        encodeBuffer += b64[((0x3 & BYTE0) << 4) + (BYTE1 >> 4)];
        add_CR_if_needed(encodeBuffer, lineLenght);
        encodeBuffer += b64[((0x0f & BYTE1) << 2) + (BYTE2 >> 6)];
        add_CR_if_needed(encodeBuffer, lineLenght);
        encodeBuffer += b64[0x3f & BYTE2];
    }
    if (pad == 2) {
        add_CR_if_needed(encodeBuffer, lineLenght);
        encodeBuffer += b64[bin[byteNo] >> 2];
        add_CR_if_needed(encodeBuffer, lineLenght);
        encodeBuffer += b64[(0x3 & bin[byteNo]) << 4];
        add_CR_if_needed(encodeBuffer, lineLenght);
        encodeBuffer += '=';
        add_CR_if_needed(encodeBuffer, lineLenght);
        encodeBuffer += '=';
    } else if (pad == 1) {
        add_CR_if_needed(encodeBuffer, lineLenght);
        encodeBuffer += b64[bin[byteNo] >> 2];
        add_CR_if_needed(encodeBuffer, lineLenght);
        encodeBuffer += b64[((0x3 & bin[byteNo]) << 4) + (bin[byteNo + 1] >> 4)];
        add_CR_if_needed(encodeBuffer, lineLenght);
        encodeBuffer += b64[(0x0f & bin[byteNo + 1]) << 2];
        add_CR_if_needed(encodeBuffer, lineLenght);
        encodeBuffer += '=';
    }
    if (lineLenght && encodeBuffer[encodeBuffer.length() - 1] != '\n') {
        encodeBuffer += '\n';
    }
    return encodeBuffer;
}
std::vector<uint8_t> unbase64(const std::string& base64_data) {
    string tmp_str(base64_data);
    tmp_str.erase(std::remove(tmp_str.begin(), tmp_str.end(), '\n'), tmp_str.end());
    const unsigned char* safeAsciiPtr = (const unsigned char*)tmp_str.c_str();
    std::vector<uint8_t> bin;
    int cb = 0;
    int charNo;
    int pad = 0;
    size_t len = tmp_str.size();
    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.");
        return bin;
    }
    if (safeAsciiPtr[len - 1] == '=') ++pad;
    if (safeAsciiPtr[len - 2] == '=') ++pad;
    size_t flen = 3 * len / 4 - pad;
    bin.reserve(flen);
    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.push_back((A << 2) | (B >> 4));
        bin.push_back((B << 4) | (C >> 2));
        bin.push_back((C << 6) | (D));
    }
    if (pad == 1) {
        int A = unb64[safeAsciiPtr[charNo]];
        int B = unb64[safeAsciiPtr[charNo + 1]];
        int C = unb64[safeAsciiPtr[charNo + 2]];
        bin.push_back((A << 2) | (B >> 4));
        bin.push_back((B << 4) | (C >> 2));
    } else if (pad == 2) {
        int A = unb64[safeAsciiPtr[charNo]];
        int B = unb64[safeAsciiPtr[charNo + 1]];
        bin.push_back((A << 2) | (B >> 4));
    }
    return bin;
}
}  // namespace license
src/library/base/base64.h
@@ -1,44 +1,18 @@
/*
 https://github.com/superwills/NibbleAndAHalf
 base64.h -- Fast base64 encoding and decoding.
 version 1.0.0, April 17, 2013 143a
 Copyright (C) 2013 William Sherif
 This software is provided 'as-is', without any express or implied
 warranty.  In no event will the authors be held liable for any damages
 arising from the use of this software.
 Permission is granted to anyone to use this software for any purpose,
 including commercial applications, and to alter it and redistribute it
 freely, subject to the following restrictions:
 1. The origin of this software must not be misrepresented; you must not
 claim that you wrote the original software. If you use this software
 in a product, an acknowledgment in the product documentation would be
 appreciated but is not required.
 2. Altered source versions must be plainly marked as such, and must not be
 misrepresented as being the original software.
 3. This notice may not be removed or altered from any source distribution.
 William Sherif
 will.sherif@gmail.com
 YWxsIHlvdXIgYmFzZSBhcmUgYmVsb25nIHRvIHVz
 */
#ifndef BASE64_H
#define BASE64_H
#ifdef __cplusplus
extern "C" {
#include <string>
#include <vector>
#if _WIN32
#include <wtypes.h>
#endif
unsigned char* unbase64(const char* ascii, int len, int *flen);
char* base64(const void* binaryData, int len, int *flen);
namespace license {
#ifdef __cplusplus
}
#endif
std::vector<uint8_t> unbase64(const std::string& base64_data);
std::string base64(const void* binaryData, size_t len, int lineLenght = -1);
}  // namespace license
#endif
src/library/base/file_utils.cpp
File was renamed from src/library/base/FileUtils.cpp
@@ -11,7 +11,7 @@
#include <iostream>
#include <algorithm>
#include "FileUtils.hpp"
#include "file_utils.hpp"
namespace license {
using namespace std;
src/library/base/file_utils.hpp
src/library/base/logger.cpp
File was renamed from src/library/base/logger.c
@@ -5,6 +5,8 @@
#include <stdarg.h>
#include <time.h>
#ifndef LOG_DISABLED
#ifdef __unix__
#include <unistd.h>
#define MAX_PATH 255
@@ -69,3 +71,4 @@
        logFile = NULL;
    }
}
#endif
src/library/base/logger.h
@@ -1,12 +1,13 @@
#ifndef logger_INCLUDED
#define logger_INCLUDED
#ifdef __cplusplus
extern "C" {
#endif
#define LOG_DISABLED 1
#ifndef LOG_DISABLED
#include <errno.h>
#include <string.h>
#ifdef __cplusplus
extern "C" {
#endif
#define clean_errno() (errno == 0 ? "None" : strerror(errno))
src/library/hw_identifier/CMakeLists.txt
New file
@@ -0,0 +1,12 @@
add_library(hw_identifier OBJECT
    hw_identifier_facade.cpp
    default_strategy.cpp
    ethernet.cpp
    disk_strategy.cpp
    identification_strategy.cpp
    hw_identifier.cpp
)
if(CODE_COVERAGE AND UNIX)
      target_compile_options(hw_identifier PUBLIC -O0 -g --coverage)
endif(CODE_COVERAGE AND UNIX)
src/library/hw_identifier/default_strategy.cpp
New file
@@ -0,0 +1,77 @@
/*
 * default_strategy.cpp
 *
 *  Created on: Jan 1, 2020
 *      Author: devel
 */
#include <vector>
#include "../os/execution_environment.hpp"
#include "default_strategy.hpp"
using namespace std;
namespace license {
namespace hw_identifier {
static vector<LCC_API_IDENTIFICATION_STRATEGY> available_strategies() {
    os::ExecutionEnvironment exec;
    os::VIRTUALIZATION virtualization = exec.getVirtualization();
    vector<LCC_API_IDENTIFICATION_STRATEGY> strategy_to_try;
    if (virtualization == os::CONTAINER) {
        if (exec.is_docker()) {
            strategy_to_try = LCC_DOCKER_STRATEGIES;
        } else {
            strategy_to_try = LCC_LXC_STRATEGIES;
        }
    } else if (virtualization == os::VM) {
        if (exec.is_cloud()) {
            strategy_to_try = LCC_CLOUD_STRATEGIES;
        } else {
            strategy_to_try = LCC_VM_STRATEGIES;
        }
    } else {
        strategy_to_try = LCC_BARE_TO_METAL_STRATEGIES;
    }
    return strategy_to_try;
}
DefaultStrategy::DefaultStrategy() {}
DefaultStrategy::~DefaultStrategy() {}
LCC_API_IDENTIFICATION_STRATEGY DefaultStrategy::identification_strategy() const { return STRATEGY_DEFAULT; }
FUNCTION_RETURN DefaultStrategy::identify_pc(HwIdentifier& pc_id) const {
    vector<LCC_API_IDENTIFICATION_STRATEGY> strategy_to_try = available_strategies();
    FUNCTION_RETURN ret = FUNC_RET_NOT_AVAIL;
    for (auto it : strategy_to_try) {
        LCC_API_IDENTIFICATION_STRATEGY strat_to_try = it;
        unique_ptr<IdentificationStrategy> strategy_ptr = IdentificationStrategy::get_strategy(strat_to_try);
        ret = strategy_ptr->identify_pc(pc_id);
        if (ret == FUNC_RET_OK) {
            break;
        }
    }
    return ret;
}
std::vector<HwIdentifier> DefaultStrategy::alternative_ids() const {
    vector<LCC_API_IDENTIFICATION_STRATEGY> strategy_to_try = available_strategies();
    vector<HwIdentifier> identifiers;
    FUNCTION_RETURN ret = FUNC_RET_NOT_AVAIL;
    for (auto it : strategy_to_try) {
        LCC_API_IDENTIFICATION_STRATEGY strat_to_try = it;
        unique_ptr<IdentificationStrategy> strategy_ptr = IdentificationStrategy::get_strategy(strat_to_try);
        vector<HwIdentifier> alt_ids = strategy_ptr->alternative_ids();
        identifiers.insert(alt_ids.begin(), alt_ids.end(), identifiers.end());
    }
    return identifiers;
}
LCC_EVENT_TYPE DefaultStrategy::validate_identifier(const HwIdentifier& identifier) const {
    // default strategy should always realize itself as a concrete strategy
    return IDENTIFIERS_MISMATCH;
}
}  // namespace hw_identifier
} /* namespace license */
src/library/hw_identifier/default_strategy.hpp
New file
@@ -0,0 +1,27 @@
/*
 * default_strategy.hpp
 *
 *  Created on: Jan 2, 2020
 *      Author: devel
 */
#ifndef SRC_LIBRARY_PC_IDENTIFIER_DEFAULT_STRATEGY_HPP_
#define SRC_LIBRARY_PC_IDENTIFIER_DEFAULT_STRATEGY_HPP_
#include "identification_strategy.hpp"
namespace license {
namespace hw_identifier {
class DefaultStrategy : public IdentificationStrategy {
public:
    DefaultStrategy();
    virtual ~DefaultStrategy();
    virtual LCC_API_IDENTIFICATION_STRATEGY identification_strategy() const;
    virtual FUNCTION_RETURN identify_pc(HwIdentifier &pc_id) const;
    virtual std::vector<HwIdentifier> alternative_ids() const;
    virtual LCC_EVENT_TYPE validate_identifier(const HwIdentifier &identifier) const;
};
}  // namespace hw_identifier
} /* namespace license */
#endif /* SRC_LIBRARY_PC_IDENTIFIER_DEFAULT_STRATEGY_HPP_ */
src/library/hw_identifier/disk_strategy.cpp
New file
@@ -0,0 +1,97 @@
/*
 * disk_strategy.cpp
 *
 *  Created on: Jan 14, 2020
 *      Author: devel
 */
#include <string.h>
#include "../os/os.h"
#include "disk_strategy.hpp"
using namespace std;
namespace license {
namespace hw_identifier {
static FUNCTION_RETURN generate_disk_pc_id(vector<array<uint8_t, HW_IDENTIFIER_PROPRIETARY_DATA>> &v_disk_id,
                                           bool use_id) {
    size_t disk_num = 0;
    size_t available_disk_info = 0;
    FUNCTION_RETURN result_diskinfos;
    result_diskinfos = getDiskInfos(nullptr, &disk_num);
    if (result_diskinfos != FUNC_RET_OK && result_diskinfos != FUNC_RET_BUFFER_TOO_SMALL) {
        return result_diskinfos;
    }
    if (disk_num == 0) {
        return FUNC_RET_NOT_AVAIL;
    }
    size_t mem = disk_num * sizeof(DiskInfo);
    DiskInfo *diskInfos = (DiskInfo *)malloc(mem);
    if (diskInfos == nullptr) {
        return FUNC_RET_NOT_AVAIL;
    }
    memset(diskInfos, 0, mem);
    result_diskinfos = getDiskInfos(diskInfos, &disk_num);
    if (result_diskinfos != FUNC_RET_OK) {
        free(diskInfos);
        return result_diskinfos;
    }
    for (unsigned int i = 0; i < disk_num; i++) {
        char firstChar = use_id ? diskInfos[i].label[0] : diskInfos[i].disk_sn[0];
        available_disk_info += firstChar == 0 ? 0 : 1;
    }
    if (available_disk_info == 0) {
        free(diskInfos);
        return FUNC_RET_NOT_AVAIL;
    }
    v_disk_id.reserve(available_disk_info);
    for (int j = 0; j < 2; j++) {
        int preferred = (j == 0 ? 1 : 0);
        for (unsigned int i = 0; i < disk_num; i++) {
            array<uint8_t, HW_IDENTIFIER_PROPRIETARY_DATA> a_disk_id;
            a_disk_id.fill(0);
            if (use_id) {
                if (diskInfos[i].disk_sn[0] != 0 && diskInfos[i].preferred == preferred) {
                    size_t size = min(a_disk_id.size(), sizeof(&diskInfos[i].disk_sn));
                    memcpy(&a_disk_id[0], diskInfos[i].disk_sn, size);
                    v_disk_id.push_back(a_disk_id);
                }
            } else {
                if (diskInfos[i].label[0] != 0 && diskInfos[i].preferred == preferred) {
                    strncpy((char *)&a_disk_id[0], diskInfos[i].label, a_disk_id.size() - 1);
                    v_disk_id.push_back(a_disk_id);
                }
            }
        }
    }
    free(diskInfos);
    return FUNC_RET_OK;
}
DiskStrategy::DiskStrategy(bool use_id) : m_use_id(use_id) {}
DiskStrategy::~DiskStrategy() {}
LCC_API_IDENTIFICATION_STRATEGY DiskStrategy::identification_strategy() const {
    return m_use_id ? STRATEGY_DISK_NUM : STRATEGY_DISK_LABEL;
}
std::vector<HwIdentifier> DiskStrategy::alternative_ids() const {
    vector<array<uint8_t, HW_IDENTIFIER_PROPRIETARY_DATA>> data;
    FUNCTION_RETURN result = generate_disk_pc_id(data, m_use_id);
    vector<HwIdentifier> identifiers;
    if (result == FUNC_RET_OK) {
        identifiers.reserve(data.size());
        for (auto &it : data) {
            HwIdentifier pc_id;
            pc_id.set_identification_strategy(identification_strategy());
            pc_id.set_data(it);
            identifiers.push_back(pc_id);
        }
    }
    return identifiers;
}
}  // namespace hw_identifier
} /* namespace license */
src/library/hw_identifier/disk_strategy.hpp
New file
@@ -0,0 +1,29 @@
/*
 * disk_strategy.hpp
 *
 *  Created on: Jan 14, 2020
 *      Author: devel
 */
#ifndef SRC_LIBRARY_PC_IDENTIFIER_DISK_STRATEGY_HPP_
#define SRC_LIBRARY_PC_IDENTIFIER_DISK_STRATEGY_HPP_
#include "identification_strategy.hpp"
namespace license {
namespace hw_identifier {
class DiskStrategy : public IdentificationStrategy {
private:
    bool m_use_id;
public:
    DiskStrategy(bool use_id);
    virtual ~DiskStrategy();
    virtual LCC_API_IDENTIFICATION_STRATEGY identification_strategy() const;
    virtual std::vector<HwIdentifier> alternative_ids() const;
};
}  // namespace hw_identifier
} /* namespace license */
#endif /* SRC_LIBRARY_PC_IDENTIFIER_DISK_STRATEGY_HPP_ */
src/library/hw_identifier/ethernet.cpp
New file
@@ -0,0 +1,78 @@
/*
 * ethernet.cpp
 *
 *  Created on: Jan 11, 2020
 *      Author: GC
 */
#include <array>
#include <vector>
#include <licensecc/datatypes.h>
#include <licensecc_properties.h>
#include "../base/base.h"
#include "../os/network.hpp"
#include "hw_identifier.hpp"
#include "ethernet.hpp"
namespace license {
namespace hw_identifier {
using namespace std;
static FUNCTION_RETURN generate_ethernet_pc_id(vector<array<uint8_t, HW_IDENTIFIER_PROPRIETARY_DATA>> &data,
                                               const bool use_ip) {
    vector<os::OsAdapterInfo> adapters;
    FUNCTION_RETURN result_adapterInfos = getAdapterInfos(adapters);
    if (result_adapterInfos != FUNC_RET_OK) {
        return result_adapterInfos;
    }
    if (adapters.size() == 0) {
        return FUNC_RET_NOT_AVAIL;
    }
    for (auto &it : adapters) {
        unsigned int k, data_len;
        array<uint8_t, HW_IDENTIFIER_PROPRIETARY_DATA> identifier;
        data_len = use_ip ? sizeof(os::OsAdapterInfo::ipv4_address) : sizeof(os::OsAdapterInfo::mac_address);
        for (k = 0; k < HW_IDENTIFIER_PROPRIETARY_DATA; k++) {
            if (k < data_len) {
                identifier[k] = use_ip ? it.ipv4_address[k] : it.mac_address[k];
            } else {
                identifier[k] = 42;
            }
        }
        identifier[0] = identifier[0] & 0x1F;
        data.push_back(identifier);
    }
    return result_adapterInfos;
}
Ethernet::Ethernet(bool useIp) : use_ip(useIp) {}
Ethernet::~Ethernet() {}
LCC_API_IDENTIFICATION_STRATEGY Ethernet::identification_strategy() const {
    return use_ip ? STRATEGY_IP_ADDRESS : STRATEGY_ETHERNET;
}
std::vector<HwIdentifier> Ethernet::alternative_ids() const {
    vector<array<uint8_t, HW_IDENTIFIER_PROPRIETARY_DATA>> data;
    FUNCTION_RETURN result = generate_ethernet_pc_id(data, use_ip);
    vector<HwIdentifier> identifiers;
    if (result == FUNC_RET_OK) {
        identifiers.reserve(data.size());
        for (auto &it : data) {
            HwIdentifier pc_id;
            pc_id.set_identification_strategy(identification_strategy());
            pc_id.set_data(it);
            identifiers.push_back(pc_id);
        }
    }
    return identifiers;
}
}  // namespace hw_identifier
} /* namespace license */
src/library/hw_identifier/ethernet.hpp
New file
@@ -0,0 +1,29 @@
/*
 * ethernet.hpp
 *
 *  Created on: Jan 11, 2020
 *      Author: devel
 */
#ifndef SRC_LIBRARY_PC_IDENTIFIER_ETHERNET_HPP_
#define SRC_LIBRARY_PC_IDENTIFIER_ETHERNET_HPP_
#include "identification_strategy.hpp"
namespace license {
namespace hw_identifier {
class Ethernet : public IdentificationStrategy {
private:
    const bool use_ip;
public:
    Ethernet(bool use_ip);
    virtual ~Ethernet();
    virtual LCC_API_IDENTIFICATION_STRATEGY identification_strategy() const;
    virtual std::vector<HwIdentifier> alternative_ids() const;
};
}  // namespace hw_identifier
} /* namespace license */
#endif /* SRC_LIBRARY_PC_IDENTIFIER_ETHERNET_HPP_ */
src/library/hw_identifier/hw_identifier.cpp
New file
@@ -0,0 +1,99 @@
/*
 * hw_identifier.cpp
 *
 *  Created on: Dec 22, 2019
 *      Author: GC
 */
#include <algorithm>
#include "hw_identifier.hpp"
#include "../base/base64.h"
namespace license {
namespace hw_identifier {
using namespace std;
HwIdentifier::HwIdentifier() {}
HwIdentifier::HwIdentifier(const std::string& param) {
    string tmp_str(param);  // throw away const
    std::replace(tmp_str.begin(), tmp_str.end(), '-', '\n');
    vector<uint8_t> decoded = unbase64(tmp_str);
    if (decoded.size() != HW_IDENTIFIER_PROPRIETARY_DATA + 1) {
        cerr << decoded.size();
        throw logic_error("wrong identifier size " + param);
    }
    std::copy_n(decoded.begin(), HW_IDENTIFIER_PROPRIETARY_DATA + 1, m_data.begin());
}
HwIdentifier::~HwIdentifier() {}
HwIdentifier::HwIdentifier(const HwIdentifier& other) : m_data(other.m_data) {}
void HwIdentifier::set_identification_strategy(LCC_API_IDENTIFICATION_STRATEGY strategy) {
    if (strategy == STRATEGY_NONE || strategy == STRATEGY_DEFAULT) {
        throw logic_error("Only known strategies are permitted");
    }
    uint8_t stratMov = (strategy << 5);
    m_data[1] = (m_data[1] & 0x1F) | stratMov;
}
void HwIdentifier::set_use_environment_var(bool use_env_var) {
    if (use_env_var) {
        m_data[0] = m_data[0] | 0x40;
    } else {
        m_data[0] = m_data[0] & ~0x40;
    }
}
void HwIdentifier::set_virtual_environment(os::VIRTUALIZATION virt) {
    // 110000 0x30
    m_data[0] = (m_data[0] & ~0x30) | virt << 4;
}
void HwIdentifier::set_virtualization(os::VIRTUALIZATION_DETAIL virtualization_detail) {
    m_data[0] = (m_data[0] & ~0x0F) | virtualization_detail;
}
void HwIdentifier::set_cloud_provider(os::CLOUD_PROVIDER cloud_provider) {
    m_data[0] = (m_data[0] & ~0x0F) | cloud_provider | 0x08;
}
void HwIdentifier::set_data(const std::array<uint8_t, HW_IDENTIFIER_PROPRIETARY_DATA>& data) {
    m_data[1] = (m_data[1] & (~0x1f)) | (data[0] & 0x1f);
    for (int i = 1; i < HW_IDENTIFIER_PROPRIETARY_DATA; i++) {
        m_data[i + 1] = data[i];
    }
}
std::string HwIdentifier::print() const {
    string result = base64(m_data.data(), m_data.size(), 5);
    std::replace(result.begin(), result.end(), '\n', '-');
    return result.substr(0, result.size() - 1);
}
LCC_API_IDENTIFICATION_STRATEGY HwIdentifier::get_identification_strategy() const {
    uint8_t stratMov = m_data[1] >> 5;
    return static_cast<LCC_API_IDENTIFICATION_STRATEGY>(stratMov);
}
bool HwIdentifier::data_match(const std::array<uint8_t, HW_IDENTIFIER_PROPRIETARY_DATA>& data) const {
    bool equals = true;
    for (int i = 0; i < HW_IDENTIFIER_PROPRIETARY_DATA && equals; i++) {
        equals = (i == 0) ? ((data[i] & 0x1f) == (m_data[i + 1] & 0x1f)) : (data[i] == m_data[i + 1]);
    }
    return equals;
}
bool operator==(const HwIdentifier& lhs, const HwIdentifier& rhs) {
    bool equals = lhs.get_identification_strategy() == rhs.get_identification_strategy();
    for (int i = 0; i < HW_IDENTIFIER_PROPRIETARY_DATA && equals; i++) {
        equals = (i == 0) ? ((rhs.m_data[i + 1] & 0x1f) == (lhs.m_data[i + 1] & 0x1f))
                          : (lhs.m_data[i + 1] == rhs.m_data[i + 1]);
    }
    return equals;
}
}  // namespace hw_identifier
} /* namespace license */
src/library/hw_identifier/hw_identifier.hpp
New file
@@ -0,0 +1,72 @@
/*
 * hw_identifier.h
 *
 *  Created on: Dec 22, 2019
 *      Author: GC
 */
#ifndef SRC_LIBRARY_PC_IDENTIFIER_PC_IDENTIFIER_HPP_
#define SRC_LIBRARY_PC_IDENTIFIER_PC_IDENTIFIER_HPP_
#include <array>
#include <iostream>
#include <string>
#include <licensecc_properties.h>
#include "../../../include/licensecc/datatypes.h"
#include "../os/execution_environment.hpp"
#include "../os/cpu_info.hpp"
namespace license {
namespace hw_identifier {
#define HW_IDENTIFIER_PROPRIETARY_DATA 8
/**
 * data[0]
 * bit 7 = 0 if pc id is being generated 1 if it is coming from an issued license.
 *
 * if bit 7 = 0
 * bit 6 = environment variable was used to generate pc_id
 * bit 5-4 = execution environment information (0=BARE_TO_METAL,1=VM,2=CONTAINER)
 * bit 3 = 0 on premise vm 1 = cloud
 * if on premise vm bits 2-1-0 are virtualization technology
 * if cloud vm bits 2-1-0 identify cloud provider
 *
 * if bit 7 = 1 hardware identifier is used to enable some flag that we don't want to show openly in the license
 * bit 6 = 1 enable magic file/registry key
 * ----
 * data[1] bit 7-6-5 define identification strategy.
 * data[1] bits 4-0, data[2-8] are hardware identifier proprietary strategy data.
 */
class HwIdentifier {
private:
    std::array<uint8_t, HW_IDENTIFIER_PROPRIETARY_DATA + 1> m_data = {};
    friend bool operator==(const HwIdentifier &lhs, const HwIdentifier &rhs);
public:
    HwIdentifier();
    HwIdentifier(const std::string &param);
    virtual ~HwIdentifier();
    HwIdentifier(const HwIdentifier &other);
    void set_identification_strategy(LCC_API_IDENTIFICATION_STRATEGY strategy);
    LCC_API_IDENTIFICATION_STRATEGY get_identification_strategy() const;
    void set_use_environment_var(bool use_env_var);
    void set_virtual_environment(os::VIRTUALIZATION virtualization);
    void set_virtualization(os::VIRTUALIZATION_DETAIL virtualization_detail);
    void set_cloud_provider(os::CLOUD_PROVIDER cloud_provider);
    void set_data(const std::array<uint8_t, HW_IDENTIFIER_PROPRIETARY_DATA> &data);
    bool data_match(const std::array<uint8_t, HW_IDENTIFIER_PROPRIETARY_DATA> &data) const;
    std::string print() const;
    friend std::ostream &operator<<(std::ostream &output, const HwIdentifier &d) {
        output << d.print();
        return output;
    };
};
}  // namespace hw_identifier
} /* namespace license */
#endif /* SRC_LIBRARY_PC_IDENTIFIER_PC_IDENTIFIER_HPP_ */
src/library/hw_identifier/hw_identifier_facade.cpp
New file
@@ -0,0 +1,77 @@
/*
 * hw_identifier_facade.cpp
 *
 *  Created on: Dec 26, 2019
 *      Author: devel
 */
#include "hw_identifier_facade.hpp"
#include <cstdlib>
#include <stdexcept>
#include "../base/base.h"
#include "../base/logger.h"
#include "../os/cpu_info.hpp"
#include "../os/execution_environment.hpp"
#include "identification_strategy.hpp"
#include "hw_identifier.hpp"
namespace license {
namespace hw_identifier {
using namespace std;
LCC_EVENT_TYPE HwIdentifierFacade::validate_pc_signature(const std::string& str_code) {
    HwIdentifier pc_id(str_code);
    LCC_API_IDENTIFICATION_STRATEGY id_strategy = pc_id.get_identification_strategy();
    LCC_EVENT_TYPE result = IDENTIFIERS_MISMATCH;
    try {
        unique_ptr<IdentificationStrategy> strategy = IdentificationStrategy::get_strategy(id_strategy);
        result = strategy->validate_identifier(pc_id);
    } catch (logic_error& e) {
        LOG_ERROR("Error validating identifier %s: %s", str_code.c_str(), e.what());
    }
    return result;
}
std::string HwIdentifierFacade::generate_user_pc_signature(LCC_API_IDENTIFICATION_STRATEGY strategy) {
    bool use_env_var = false;
    vector<LCC_API_IDENTIFICATION_STRATEGY> strategies_to_try;
    if (strategy == STRATEGY_DEFAULT) {
        char* env_var_value = getenv(LCC_IDENTIFICATION_STRATEGY_ENV_VAR);
        if (env_var_value != nullptr && env_var_value[0] != '\0') {
            int strategy_int = atoi(env_var_value);
            if (strategy_int < 0 || strategy_int > 3) {
                LOG_WARN("unknown " LCC_IDENTIFICATION_STRATEGY_ENV_VAR " %s", env_var_value);
            } else {
                strategy = (LCC_API_IDENTIFICATION_STRATEGY)strategy_int;
                use_env_var = true;
            }
        }
    }
    unique_ptr<IdentificationStrategy> strategy_ptr = IdentificationStrategy::get_strategy(strategy);
    HwIdentifier pc_id;
    FUNCTION_RETURN result = strategy_ptr->identify_pc(pc_id);
    if (result != FUNC_RET_OK) {
        throw logic_error("strategy " + to_string(strategy_ptr->identification_strategy()) + " failed");
    }
    os::ExecutionEnvironment exec;
    os::VIRTUALIZATION virtualization = exec.getVirtualization();
    pc_id.set_virtual_environment(virtualization);
    pc_id.set_use_environment_var(use_env_var);
    if (virtualization != os::NONE) {
        bool isCloud = exec.is_cloud();
        if (isCloud) {
            pc_id.set_cloud_provider(exec.getCloudProvider());
        } else {
            os::CpuInfo cpu;
            pc_id.set_virtualization(cpu.virtualization_details());
        }
    }
    return pc_id.print();
}
}  // namespace hw_identifier
} /* namespace license */
src/library/hw_identifier/hw_identifier_facade.hpp
New file
@@ -0,0 +1,38 @@
/*
 * hw_identifier_facade.hpp
 *
 *  Created on: Dec 26, 2019
 *      Author: devel
 */
#ifndef SRC_LIBRARY_PC_IDENTIFIER_HW_IDENTIFIER_FACADE_HPP_
#define SRC_LIBRARY_PC_IDENTIFIER_HW_IDENTIFIER_FACADE_HPP_
#include "hw_identifier_facade.hpp"
#include <string>
#include <unordered_map>
#include <licensecc/datatypes.h>
#include "identification_strategy.hpp"
namespace license {
namespace hw_identifier {
class HwIdentifierFacade {
private:
    HwIdentifierFacade(){};
    virtual ~HwIdentifierFacade(){};
public:
    static LCC_EVENT_TYPE validate_pc_signature(const std::string& str_code);
    /**
     *
     * @throws logic_error if pc_identifier can't be generated.
     * @param strategy
     * @return
     */
    static std::string generate_user_pc_signature(LCC_API_IDENTIFICATION_STRATEGY strategy);
};
}  // namespace hw_identifier
} /* namespace license */
#endif /* SRC_LIBRARY_PC_IDENTIFIER_HW_IDENTIFIER_FACADE_HPP_ */
src/library/hw_identifier/identification_strategy.cpp
New file
@@ -0,0 +1,60 @@
#include <array>
#include "identification_strategy.hpp"
#include "default_strategy.hpp"
#include "ethernet.hpp"
#include "disk_strategy.hpp"
namespace license {
namespace hw_identifier {
using namespace std;
LCC_EVENT_TYPE IdentificationStrategy::validate_identifier(const HwIdentifier& identifier) const {
    LCC_EVENT_TYPE result = IDENTIFIERS_MISMATCH;
    if (identifier.get_identification_strategy() == identification_strategy()) {
        const vector<HwIdentifier> available_ids = alternative_ids();
        for (const auto& it : available_ids) {
            if (it == identifier) {
                result = LICENSE_OK;
                break;
            }
        }
    }
    return result;
}
FUNCTION_RETURN IdentificationStrategy::identify_pc(HwIdentifier& pc_id) const {
    vector<array<uint8_t, HW_IDENTIFIER_PROPRIETARY_DATA>> data;
    const vector<HwIdentifier> available_ids = alternative_ids();
    FUNCTION_RETURN result = FUNC_RET_NOT_AVAIL;
    if (available_ids.size() > 0) {
        pc_id = available_ids[0];
        result = FUNC_RET_OK;
    }
    return result;
}
std::unique_ptr<IdentificationStrategy> IdentificationStrategy::get_strategy(LCC_API_IDENTIFICATION_STRATEGY strategy) {
    unique_ptr<IdentificationStrategy> result;
    switch (strategy) {
        case STRATEGY_DEFAULT:
            result = unique_ptr<IdentificationStrategy>(dynamic_cast<IdentificationStrategy*>(new DefaultStrategy()));
            break;
        case STRATEGY_ETHERNET:
            result = unique_ptr<IdentificationStrategy>(dynamic_cast<IdentificationStrategy*>(new Ethernet(false)));
            break;
        case STRATEGY_IP_ADDRESS:
            result = unique_ptr<IdentificationStrategy>(dynamic_cast<IdentificationStrategy*>(new Ethernet(true)));
            break;
        case STRATEGY_DISK_NUM:
            result = unique_ptr<IdentificationStrategy>(dynamic_cast<IdentificationStrategy*>(new DiskStrategy(true)));
            break;
        case STRATEGY_DISK_LABEL:
            result = unique_ptr<IdentificationStrategy>(dynamic_cast<IdentificationStrategy*>(new DiskStrategy(false)));
            break;
        default:
            throw logic_error("strategy not supported");
    }
    return result;
}
}  // namespace hw_identifier
}  // namespace license
src/library/hw_identifier/identification_strategy.hpp
New file
@@ -0,0 +1,43 @@
/*
 * identification_strategy.hpp
 *
 *  Created on: Jan 1, 2020
 *      Author: devel
 */
#ifndef SRC_LIBRARY_PC_IDENTIFIER_IDENTIFICATION_STRATEGY_HPP_
#define SRC_LIBRARY_PC_IDENTIFIER_IDENTIFICATION_STRATEGY_HPP_
#include <licensecc/datatypes.h>
#include <licensecc_properties.h>
#include <vector>
#include <memory>
#include "../base/base.h"
#include "hw_identifier.hpp"
namespace license {
namespace hw_identifier {
class IdentificationStrategy {
protected:
    IdentificationStrategy(){};
public:
    virtual ~IdentificationStrategy(){};
    virtual LCC_API_IDENTIFICATION_STRATEGY identification_strategy() const = 0;
    virtual FUNCTION_RETURN identify_pc(HwIdentifier& identifier_out) const;
    virtual std::vector<HwIdentifier> alternative_ids() const = 0;
    virtual LCC_EVENT_TYPE validate_identifier(const HwIdentifier& identifier_in) const;
    /**
     * Factory method to create an instance of IdentificationStrategy
     * @param strategy
     * @return
     */
    static std::unique_ptr<IdentificationStrategy> get_strategy(LCC_API_IDENTIFICATION_STRATEGY strategy);
};
}  // namespace hw_identifier
} /* namespace license */
#endif /* SRC_LIBRARY_PC_IDENTIFIER_IDENTIFICATION_STRATEGY_HPP_ */
src/library/ini/ConvertUTF.cpp
src/library/licensecc.cpp
@@ -17,25 +17,35 @@
#include <licensecc/licensecc.h>
#include <licensecc_properties.h>
#include "base/logger.h"
#include "hw_identifier/hw_identifier_facade.hpp"
#include "limits/license_verifier.hpp"
#include "base/StringUtils.h"
#include "LicenseReader.hpp"
#include "pc-identifiers.h"
using namespace std;
void print_error(char out_buffer[ERROR_BUFFER_SIZE], LicenseInfo* licenseInfo) {}
bool identify_pc(IDENTIFICATION_STRATEGY pc_id_method, char* chbuffer, size_t* bufSize) {
    FUNCTION_RETURN result = FUNC_RET_BUFFER_TOO_SMALL;
    if (*bufSize > sizeof(PcSignature)) {
        PcSignature identifier_out;
        result = generate_user_pc_signature(identifier_out, pc_id_method);
        strncpy(chbuffer, identifier_out, *bufSize);
void print_error(char out_buffer[LCC_API_ERROR_BUFFER_SIZE], LicenseInfo* licenseInfo) {}
bool identify_pc(LCC_API_IDENTIFICATION_STRATEGY pc_id_method, char* chbuffer, size_t* bufSize) {
    bool result = false;
    if (*bufSize > LCC_API_PC_IDENTIFIER_SIZE && chbuffer != nullptr) {
        try {
            string pc_id = license::hw_identifier::HwIdentifierFacade::generate_user_pc_signature(pc_id_method);
            strncpy(chbuffer, pc_id.c_str(), *bufSize);
            result = true;
        } catch (const std::exception& ex) {
            LOG_ERROR("Error calculating hw_identifier: %s", ex.what());
#ifdef _DEBUG
                cout
                << "Error occurred: " << ex.what() << std::endl;
#endif
        }
    } else {
        *bufSize = sizeof(PcSignature) + 1;
        *bufSize = LCC_API_PC_IDENTIFIER_SIZE + 1;
    }
    return result == FUNC_RET_OK;
    return result;
}
static void mergeLicenses(const vector<LicenseInfo>& licenses, LicenseInfo* license_out) {
@@ -54,8 +64,8 @@
    }
}
EVENT_TYPE acquire_license(const CallerInformations* callerInformation, const LicenseLocation* licenseLocation,
                           LicenseInfo* license_out) {
LCC_EVENT_TYPE acquire_license(const CallerInformations* callerInformation,
                                     const LicenseLocation* licenseLocation, LicenseInfo* license_out) {
    const license::LicenseReader lr = license::LicenseReader(licenseLocation);
    vector<license::FullLicenseInfo> licenses;
    string project;
@@ -67,21 +77,25 @@
        project = string(LCC_PROJECT_NAME);
    }
    license::EventRegistry er = lr.readLicenses(string(project), licenses);
    EVENT_TYPE result;
    LCC_EVENT_TYPE result;
    if (licenses.size() > 0) {
        vector<LicenseInfo> licenses_with_errors;
        vector<LicenseInfo> licenses_ok;
        license::LicenseVerifier verifier(er);
        for (auto it = licenses.begin(); it != licenses.end(); it++) {
            FUNCTION_RETURN signatureValid = verifier.verify_signature(*it);
        for (auto full_lic_info_it = licenses.begin(); full_lic_info_it != licenses.end(); full_lic_info_it++) {
            if (callerInformation != nullptr) {
                full_lic_info_it->m_magic = callerInformation->magic;
            }
            const FUNCTION_RETURN signatureValid = verifier.verify_signature(*full_lic_info_it);
            LicenseInfo licInfo = verifier.toLicenseInfo(*full_lic_info_it);
            if (signatureValid == FUNC_RET_OK) {
                if (verifier.verify_limits(*it) == FUNC_RET_OK) {
                    licenses_ok.push_back(verifier.toLicenseInfo(*it));
                if (verifier.verify_limits(*full_lic_info_it) == FUNC_RET_OK) {
                    licenses_ok.push_back(licInfo);
                } else {
                    licenses_with_errors.push_back(verifier.toLicenseInfo(*it));
                    licenses_with_errors.push_back(licInfo);
                }
            } else {
                licenses_with_errors.push_back(verifier.toLicenseInfo(*it));
                licenses_with_errors.push_back(licInfo);
            }
        }
        if (licenses_ok.size() > 0) {
@@ -107,11 +121,12 @@
#endif
    if (license_out != nullptr) {
        er.exportLastEvents(license_out->status, AUDIT_EVENT_NUM);
        er.exportLastEvents(license_out->status, LCC_API_AUDIT_EVENT_NUM);
    }
    return result;
}
EVENT_TYPE confirm_license(char* product, LicenseLocation licenseLocation) { return LICENSE_OK; }
LCC_EVENT_TYPE confirm_license(char* product, LicenseLocation licenseLocation) { return LICENSE_OK; }
EVENT_TYPE release_license(char* product, LicenseLocation licenseLocation) { return LICENSE_OK; }
LCC_EVENT_TYPE release_license(char* product, LicenseLocation licenseLocation) { return LICENSE_OK; }
src/library/limits/license_verifier.cpp
@@ -6,11 +6,12 @@
 */
#include <cmath>
#include <algorithm>
#include <licensecc_properties.h>
#include "license_verifier.hpp"
#include "../os/signature_verifier.h"
#include "../base/StringUtils.h"
#include "../pc-identifiers.h"
#include "../os/signature_verifier.hpp"
#include "../hw_identifier/hw_identifier_facade.hpp"
namespace license {
using namespace std;
@@ -22,7 +23,7 @@
FUNCTION_RETURN LicenseVerifier::verify_signature(const FullLicenseInfo& licInfo) {
    const string licInfoData(licInfo.printForSign());
    FUNCTION_RETURN ret = license::verify_signature(licInfoData, licInfo.license_signature);
    FUNCTION_RETURN ret = license::os::verify_signature(licInfoData, licInfo.license_signature);
    if (ret == FUNC_RET_OK) {
        m_event_registry.addEvent(SIGNATURE_VERIFIED, licInfo.source);
@@ -33,35 +34,31 @@
}
// TODO: split in different classes
FUNCTION_RETURN LicenseVerifier::verify_limits(const FullLicenseInfo& licInfo) {
    bool is_valid = true;
FUNCTION_RETURN LicenseVerifier::verify_limits(const FullLicenseInfo& lic_info) {
    bool is_valid = LCC_VERIFY_MAGIC;
    if (!is_valid) {
        m_event_registry.addEvent(LICENSE_CORRUPTED, lic_info.source.c_str());
    }
    const time_t now = time(nullptr);
    auto expiry = licInfo.m_limits.find(PARAM_EXPIRY_DATE);
    if (expiry != licInfo.m_limits.end()) {
    auto expiry = lic_info.m_limits.find(PARAM_EXPIRY_DATE);
    if (is_valid && expiry != lic_info.m_limits.end()) {
        if (seconds_from_epoch(expiry->second) < now) {
            /*
                        eventRegistryOut.addEvent(PRODUCT_EXPIRED, source.c_str(),
                                string("Expired on: " + this->to_date).c_str());*/
            m_event_registry.addEvent(PRODUCT_EXPIRED, licInfo.source.c_str(), ("Expired " + expiry->second).c_str());
            m_event_registry.addEvent(PRODUCT_EXPIRED, lic_info.source.c_str(), ("Expired " + expiry->second).c_str());
            is_valid = false;
        }
    }
    auto start_date = licInfo.m_limits.find(PARAM_BEGIN_DATE);
    if (is_valid && start_date != licInfo.m_limits.end()) {
    const auto start_date = lic_info.m_limits.find(PARAM_BEGIN_DATE);
    if (is_valid && start_date != lic_info.m_limits.end()) {
        if (seconds_from_epoch(start_date->second) > now) {
            /*eventRegistryOut.addEvent(PRODUCT_EXPIRED, source.c_str(),
                    string("Valid from " + this->from_date).c_str());*/
            m_event_registry.addEvent(PRODUCT_EXPIRED, licInfo.source.c_str(),
            m_event_registry.addEvent(PRODUCT_EXPIRED, lic_info.source.c_str(),
                                      ("Valid from " + start_date->second).c_str());
            is_valid = false;
        }
    }
    auto client_sig = licInfo.m_limits.find(PARAM_CLIENT_SIGNATURE);
    if (is_valid && client_sig != licInfo.m_limits.end()) {
        PcSignature str_code;
        strncpy(str_code, client_sig->second.c_str(), sizeof(str_code) - 1);
        const EVENT_TYPE event = validate_pc_signature(str_code);
        m_event_registry.addEvent(event, licInfo.source);
    const auto client_sig = lic_info.m_limits.find(PARAM_CLIENT_SIGNATURE);
    if (is_valid && client_sig != lic_info.m_limits.end()) {
        const LCC_EVENT_TYPE event = hw_identifier::HwIdentifierFacade::validate_pc_signature(client_sig->second);
        m_event_registry.addEvent(event, lic_info.source);
        is_valid = is_valid && (event == LICENSE_OK);
    }
    return is_valid ? FUNC_RET_OK : FUNC_RET_ERROR;
@@ -69,9 +66,9 @@
LicenseInfo LicenseVerifier::toLicenseInfo(const FullLicenseInfo& fullLicInfo) const {
    LicenseInfo info;
    info.license_type = LOCAL;
    info.license_type = LCC_LOCAL;
    auto expiry = fullLicInfo.m_limits.find(PARAM_EXPIRY_DATE);
    const auto expiry = fullLicInfo.m_limits.find(PARAM_EXPIRY_DATE);
    if (expiry != fullLicInfo.m_limits.end()) {
        strncpy(info.expiry_date, expiry->second.c_str(), sizeof(info.expiry_date));
        info.has_expiry = true;
@@ -83,16 +80,16 @@
        info.expiry_date[0] = '\0';
    }
    auto start_date = fullLicInfo.m_limits.find(PARAM_BEGIN_DATE);
    const auto start_date = fullLicInfo.m_limits.find(PARAM_BEGIN_DATE);
    if (start_date != fullLicInfo.m_limits.end()) {
    }
    auto client_sig = fullLicInfo.m_limits.find(PARAM_CLIENT_SIGNATURE);
    const auto client_sig = fullLicInfo.m_limits.find(PARAM_CLIENT_SIGNATURE);
    info.linked_to_pc = (client_sig != fullLicInfo.m_limits.end());
    auto proprietary_data = fullLicInfo.m_limits.find(PARAM_EXTRA_DATA);
    const auto proprietary_data = fullLicInfo.m_limits.find(PARAM_EXTRA_DATA);
    if (proprietary_data != fullLicInfo.m_limits.end()) {
        strncpy(info.proprietary_data, proprietary_data->second.c_str(), PROPRIETARY_DATA_SIZE);
        strncpy(info.proprietary_data, proprietary_data->second.c_str(), LCC_API_PROPRIETARY_DATA_SIZE);
    }
    return info;
}
src/library/locate/ApplicationFolder.cpp
@@ -15,9 +15,9 @@
#include "../base/logger.h"
#include "../base/base.h"
#include "../base/EventRegistry.h"
#include "../base/FileUtils.hpp"
#include "../os/os.h"
#include "ApplicationFolder.hpp"
#include "../base/file_utils.hpp"
namespace license {
namespace locate {
@@ -33,7 +33,7 @@
    const FUNCTION_RETURN fret = getModuleName(fname);
    if (fret == FUNC_RET_OK) {
        const string module_name = remove_extension(fname);
        const string temptativeLicense = string(module_name) + LICENSE_FILE_EXTENSION;
        const string temptativeLicense = string(module_name) + LCC_LICENSE_FILE_EXTENSION;
        ifstream f(temptativeLicense.c_str());
        if (f.good()) {
            diskFiles.push_back(temptativeLicense);
src/library/locate/CMakeLists.txt
@@ -1,9 +1,17 @@
target_sources(licensecc_static PRIVATE
    ${CMAKE_CURRENT_SOURCE_DIR}/ApplicationFolder.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/EnvironmentVarLocation.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/EnvironmentVarData.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/ExternalDefinition.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/LocatorStrategy.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/LocatorFactory.cpp
add_library(locate OBJECT
    ApplicationFolder.cpp
    EnvironmentVarLocation.cpp
    EnvironmentVarData.cpp
    ExternalDefinition.cpp
    LocatorStrategy.cpp
    LocatorFactory.cpp
)
target_include_directories(locate PRIVATE
        $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../../include>
        $<BUILD_INTERFACE:${LCC_INCLUDE_DIR}>
)
if(CODE_COVERAGE AND UNIX)
      target_compile_options(locate PUBLIC -O0 -g --coverage)
endif(CODE_COVERAGE AND UNIX)
src/library/locate/EnvironmentVarData.cpp
@@ -29,32 +29,31 @@
const vector<string> EnvironmentVarData::license_locations(EventRegistry &eventRegistry) {
    vector<string> diskFiles;
    char *env_var_value = getenv(LICENSE_DATA_ENV_VAR);
    char *env_var_value = getenv(LCC_LICENSE_DATA_ENV_VAR);
    if (env_var_value != nullptr && env_var_value[0] != '\0') {
        eventRegistry.addEvent(LICENSE_SPECIFIED, LICENSE_LOCATION_ENV_VAR);
        eventRegistry.addEvent(LICENSE_SPECIFIED, LCC_LICENSE_LOCATION_ENV_VAR);
        FILE_FORMAT licenseFormat = identify_format(env_var_value);
        if (licenseFormat == UNKNOWN) {
            eventRegistry.addEvent(LICENSE_MALFORMED, LICENSE_LOCATION_ENV_VAR);
            eventRegistry.addEvent(LICENSE_MALFORMED, LCC_LICENSE_LOCATION_ENV_VAR);
        } else {
            diskFiles.push_back(LICENSE_LOCATION_ENV_VAR);
            diskFiles.push_back(LCC_LICENSE_LOCATION_ENV_VAR);
            isBase64 = (licenseFormat == BASE64);
        }
    } else {
        eventRegistry.addEvent(ENVIRONMENT_VARIABLE_NOT_DEFINED, LICENSE_LOCATION_ENV_VAR);
        eventRegistry.addEvent(ENVIRONMENT_VARIABLE_NOT_DEFINED, LCC_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);
    string env_val = getenv(LCC_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);
        vector<uint8_t> data = unbase64(env_val);
        string str = string(reinterpret_cast<char *>(data.data()));
        return str;
    }
    return tmpVal;
    return env_val;
}
}  // namespace locate
src/library/locate/EnvironmentVarLocation.cpp
@@ -7,9 +7,9 @@
#include <licensecc_properties.h>
#include "../base/FileUtils.hpp"
#include "../base/StringUtils.h"
#include "EnvironmentVarLocation.hpp"
#include "../base/file_utils.hpp"
namespace license {
namespace locate {
@@ -22,14 +22,14 @@
const vector<string> EnvironmentVarLocation::license_locations(EventRegistry &eventRegistry) {
    vector<string> licenseFileFoundWithEnvVariable;
    const string varName(LICENSE_LOCATION_ENV_VAR);
    const string varName(LCC_LICENSE_LOCATION_ENV_VAR);
    if (varName.length() > 0) {
        // var name is defined in header files.
        char *env_var_value = getenv(LICENSE_LOCATION_ENV_VAR);
        char *env_var_value = getenv(LCC_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);
                license::filter_existing_files(declared_positions, eventRegistry, LCC_LICENSE_LOCATION_ENV_VAR);
        } else {
            eventRegistry.addEvent(ENVIRONMENT_VARIABLE_NOT_DEFINED);
        }
src/library/locate/ExternalDefinition.cpp
@@ -9,64 +9,57 @@
#include <cstring>
#include <string>
#include <vector>
#include <stdexcept>
#include <licensecc/datatypes.h>
#include "../base/base64.h"
#include "../base/EventRegistry.h"
#include "../base/FileUtils.hpp"
#include "../base/StringUtils.h"
#include "ExternalDefinition.hpp"
#include "../base/file_utils.hpp"
namespace license {
namespace locate {
using namespace std;
    using namespace std;
ExternalDefinition::ExternalDefinition(const LicenseLocation *location) :
        LocatorStrategy("ExternalDefinition"), m_location(location) {
}
ExternalDefinition::ExternalDefinition(const LicenseLocation *location)
    : LocatorStrategy("ExternalDefinition"), m_location(location) {}
ExternalDefinition::~ExternalDefinition() {
}
ExternalDefinition::~ExternalDefinition() {}
const std::vector<std::string> ExternalDefinition::license_locations(
        EventRegistry &eventRegistry) {
const std::vector<std::string> ExternalDefinition::license_locations(EventRegistry &eventRegistry) {
    vector<string> existing_pos;
    if (m_location->licenseData != nullptr
            && m_location->licenseData[0] != '\0') {
    if (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);
        switch (m_location->license_data_type) {
            case LICENSE_PATH: {
                string licData(m_location->licenseData, mstrnlen_s(m_location->licenseData, LCC_API_MAX_LICENSE_DATA_LENGTH));
                const vector<string> declared_positions = license::split_string(licData, ';');
                existing_pos =
                    license::filter_existing_files(declared_positions, eventRegistry, get_strategy_name().c_str());
            } break;
            case LICENSE_ENCODED:
            case LICENSE_PLAIN_DATA:
                existing_pos.push_back(get_strategy_name());
                break;
            default:
                throw logic_error("license type not supported ");
        }
    }
    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 {
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);
        string licData(m_location->licenseData, mstrnlen_s(m_location->licenseData, LCC_API_MAX_LICENSE_DATA_LENGTH));
        if (m_location->license_data_type == LICENSE_ENCODED) {
            // FIXME what if license is wrong
            vector<uint8_t> raw = unbase64(licData);
            string str = string(reinterpret_cast<char *>(raw.data()));
            return str;
        } else {
            return m_location->licenseData;
            return licData;
        }
    } else {
        return LocatorStrategy::retrieve_license_content(licenseLocation);
src/library/locate/ExternalDefinition.hpp
@@ -16,11 +16,10 @@
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;
    const virtual std::vector<std::string> license_locations(EventRegistry& eventRegistry);
    const virtual std::string retrieve_license_content(const std::string& licenseLocation) const;
    virtual ~ExternalDefinition();
};
src/library/locate/LocatorStrategy.cpp
@@ -7,15 +7,15 @@
#include <licensecc_properties.h>
#include "../base/FileUtils.hpp"
#include "LocatorStrategy.hpp"
#include "../base/file_utils.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);
    return get_file_contents(licenseLocation.c_str(), LCC_API_MAX_LICENSE_DATA_LENGTH);
}
}  // namespace locate
src/library/os/CMakeLists.txt
@@ -1,17 +1,41 @@
IF(UNIX OR OPENSSL_FOUND)
    IF(UNIX)
        target_sources(licensecc_static PRIVATE
            ${CMAKE_CURRENT_SOURCE_DIR}/openssl/signature_verifier.cpp
            ${CMAKE_CURRENT_SOURCE_DIR}/os-linux.c
            ${CMAKE_CURRENT_SOURCE_DIR}/network_id.c)
        add_library(os OBJECT
            openssl/signature_verifier.cpp
            execution_environment_common.cpp
            linux/execution_environment.cpp
            cpu_info_common.cpp
            linux/cpu_info.cpp
            linux/network.cpp
            linux/os_linux.cpp)
    ELSE(UNIX)
          target_sources(licensecc_static PRIVATE
            ${CMAKE_CURRENT_SOURCE_DIR}/openssl/signature_verifier.cpp
              ${CMAKE_CURRENT_SOURCE_DIR}/os-win.c)
        #windows and openssl
          add_library(os OBJECT
          cpu_info_common.cpp windows/cpu_info.cpp
          openssl/signature_verifier.cpp
        execution_environment_common.cpp windows/execution_environment.cpp
          windows/isvm/Native.cpp
        windows/isvm/BIOSReader.cpp
          windows/os_win.cpp
          windows/network.cpp)
    ENDIF(UNIX)
    target_include_directories(os PUBLIC ${OPENSSL_INCLUDE_DIR})
ELSE(UNIX OR OPENSSL_FOUND)
    target_sources(licensecc_static PRIVATE
        ${CMAKE_CURRENT_SOURCE_DIR}/windows/signature_verifier.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/os-win.c)
#windows no openssl
    add_library(os OBJECT
        cpu_info_common.cpp
        windows/cpu_info.cpp
        windows/signature_verifier.cpp
        execution_environment_common.cpp windows/execution_environment.cpp
        windows/isvm/Native.cpp
        windows/isvm/BIOSReader.cpp
        windows/os_win.cpp
        windows/network.cpp)
ENDIF(UNIX OR OPENSSL_FOUND)
#dependency of signature_verifier.cpp
add_dependencies( os project_initialize )
if(CODE_COVERAGE AND UNIX)
      target_compile_options(os PUBLIC -O0 -g --coverage)
endif(CODE_COVERAGE AND UNIX)
src/library/os/cpu_info.hpp
New file
@@ -0,0 +1,39 @@
/*
 * cpu_info.h
 *
 *  Created on: Dec 14, 2019
 *      Author: devel
 */
#ifndef SRC_LIBRARY_OS_CPU_INFO_H_
#define SRC_LIBRARY_OS_CPU_INFO_H_
#include <string>
namespace license {
namespace os {
typedef enum { BARE_TO_METAL, VMWARE, VIRTUALBOX, V_XEN, KVM, HV, V_OTHER } VIRTUALIZATION_DETAIL;
/**
 * Cpu informations
 */
class CpuInfo {
private:
    bool is_hypervisor_set() const;
    const std::string m_vendor;
    const std::string m_brand;
public:
    CpuInfo();
    virtual ~CpuInfo();
    /**
     * Detect Virtual machine using hypervisor bit or the cpu vendor name.
     * @return true if the cpu is detected to be a virtual cpu
     */
    bool cpu_virtual() const;
    uint32_t model() const;
    const std::string& vendor() const { return m_vendor; }
    const std::string& brand() const { return m_brand; }
    VIRTUALIZATION_DETAIL virtualization_details() const;
};
}  // namespace os
}  // namespace license
#endif /* SRC_LIBRARY_OS_CPU_INFO_H_ */
src/library/os/cpu_info_common.cpp
New file
@@ -0,0 +1,45 @@
/*
 * cpu_info_common.cpp
 *
 *  Created on: Jan 19, 2020
 *      Author: GC
 */
#include <unordered_map>
#include "cpu_info.hpp"
namespace license {
namespace os {
using namespace std;
const unordered_map<string, VIRTUALIZATION_DETAIL> virtual_cpu_names{
    {"bhyve bhyve ", V_OTHER}, {"KVMKVMKVM", KVM},          {"Microsoft Hv", HV},
    {" lrpepyh vr", HV},       {"prl hyperv  ", V_OTHER}, {"VMwareVMware", VMWARE},
    {"XenVMMXenVMM", V_XEN},   {"ACRNACRNACRN", V_OTHER}, {"VBoxVBoxVBox", VIRTUALBOX}};
/**
 * Detect Virtual machine using hypervisor bit.
 * @return true if the cpu hypervisor bit is set to 1
 */
bool CpuInfo::cpu_virtual() const {
    bool is_virtual = is_hypervisor_set();
    if (!is_virtual) {
        string cpu_vendor = vendor();
        auto it = virtual_cpu_names.find(cpu_vendor);
        is_virtual = (it != virtual_cpu_names.end());
    }
    return is_virtual;
}
VIRTUALIZATION_DETAIL CpuInfo::virtualization_details() const {
    string cpu_vendor = vendor();
    auto it = virtual_cpu_names.find(cpu_vendor);
    VIRTUALIZATION_DETAIL result = BARE_TO_METAL;
    if (it != virtual_cpu_names.end()) {
        result = it->second;
    } else if (is_hypervisor_set()) {
        result = (VIRTUALIZATION_DETAIL)V_OTHER;
    }
    return result;
}
}  // namespace os
}  // namespace license
src/library/os/execution_environment.hpp
New file
@@ -0,0 +1,63 @@
/*
 * virtualization.hpp
 *
 *  Created on: Dec 15, 2019
 *      Author: GC
 */
#ifndef SRC_LIBRARY_OS_VIRTUALIZATION_HPP_
#define SRC_LIBRARY_OS_VIRTUALIZATION_HPP_
#include <string>
namespace license {
namespace os {
/*
 * windows bios sometimes reports vm names add execution environment detection from bios
const char *vmVendors[] = {
    "VMware", "Microsoft Corporation", "Virtual Machine", "innotek GmbH", "PowerVM", "Bochs", "KVM"};
*/
typedef enum { NONE, CONTAINER, VM } VIRTUALIZATION;
typedef enum {
    PROV_UNKNOWN,
    ON_PREMISE,
    GOOGLE_CLOUD,
    AZURE_CLOUD,
    AWS,
    /**
     * "/sys/class/dmi/id/bios_vendor" SeaBIOS
     * "/sys/class/dmi/id/sys_vendor" Alibaba Cloud
     * modalias
     * "dmi:bvnSeaBIOS:bvrrel-1.7.5-0-ge51488c-20140602_164612-nilsson.home.kraxel.org:bd04/01/2014:svnAlibabaCloud:pnAlibabaCloudECS:pvrpc-i440fx-2.1:cvnAlibabaCloud:ct1:cvrpc-i440fx-2.1:"
     */
    ALI_CLOUD
} CLOUD_PROVIDER;
class ExecutionEnvironment {
private:
    std::string m_sys_vendor;
    std::string m_bios_vendor;
    std::string m_bios_description;
public:
    ExecutionEnvironment();
    ~ExecutionEnvironment(){};
    VIRTUALIZATION getVirtualization() const;
    bool is_cloud() const;
    bool is_docker() const;
    // detect if it's a kind of container technology (docker or lxc)
    bool is_container() const;
    CLOUD_PROVIDER getCloudProvider() const;
    const std::string& bios_vendor() const { return m_bios_vendor; };
    const std::string& sys_vendor() const { return m_sys_vendor; };
    const std::string& bios_description() const { return m_bios_description; };
    // VIRTUALIZATION_DETAIL getVirtualizationDetail() const; //as reported by the bios
};
}  // namespace os
}  // namespace license
#endif /* SRC_LIBRARY_OS_VIRTUALIZATION_HPP_ */
src/library/os/execution_environment_common.cpp
New file
@@ -0,0 +1,59 @@
/*
 *
 *  Created on: Feb 23, 2020
 *      Author: GC
 */
#include <stdio.h>
#include <string.h>
#include <unordered_map>
#include <array>
#include "../base/base.h"
#include "cpu_info.hpp"
#include "execution_environment.hpp"
namespace license {
namespace os {
using namespace std;
VIRTUALIZATION ExecutionEnvironment::getVirtualization() const {
    VIRTUALIZATION result;
    CpuInfo cpuInfo;
    bool isContainer = is_container();
    if (isContainer) {
        result = CONTAINER;
    } else if (cpuInfo.cpu_virtual() || is_cloud()) {
        result = VM;
    } else {
        result = NONE;
    }
    return result;
}
bool ExecutionEnvironment::is_cloud() const {
    CLOUD_PROVIDER prov = getCloudProvider();
    return prov != ON_PREMISE && prov != PROV_UNKNOWN;
}
// TODO test and azure
CLOUD_PROVIDER ExecutionEnvironment::getCloudProvider() const {
    CLOUD_PROVIDER result = PROV_UNKNOWN;
    if (m_bios_description.size() > 0 || m_bios_vendor.size() > 0 || m_sys_vendor.size() > 0) {
        if (m_bios_vendor.find("SEABIOS") != string::npos || m_bios_description.find("ALIBABA") != string::npos ||
            m_sys_vendor.find("ALIBABA") != string::npos) {
            result = ALI_CLOUD;
        } else if (m_sys_vendor.find("GOOGLE") != string::npos || m_bios_description.find("GOOGLE") != string::npos) {
            result = GOOGLE_CLOUD;
        } else if (m_bios_vendor.find("AWS") != string::npos || m_bios_description.find("AMAZON") != string::npos ||
                   m_sys_vendor.find("AWS") != string::npos) {
            result = AWS;
        } else if (m_bios_description.find("HP-COMPAQ") != string::npos || m_bios_description.find("ASUS") ||
                   m_bios_description.find("DELL")) {
            result = ON_PREMISE;
        }
    }
    return result;
}
}  // namespace os
}  // namespace license
src/library/os/linux/cpu_info.cpp
New file
@@ -0,0 +1,76 @@
/*
 * cpu_info.cpp
 *
 *  Created on: Dec 14, 2019
 *      Author: devel
 */
#include <cpuid.h>
#include <string>
#include <unordered_set>
#include <memory.h>
#include "../cpu_info.hpp"
namespace license {
namespace os {
using namespace std;
struct CPUVendorID {
    unsigned int ebx;
    unsigned int edx;
    unsigned int ecx;
    string toString() const { return string(reinterpret_cast<const char *>(this), 12); }
};
static string get_cpu_vendor() {
    unsigned int level = 0, eax = 0, ebx = 0, ecx = 0, edx = 0;
    // hypervisor flag false, try to get the vendor name, see if it's a virtual cpu
    __get_cpuid(level, &eax, &ebx, &ecx, &edx);
    CPUVendorID vendorID{.ebx = ebx, .edx = edx, .ecx = ecx};
    return vendorID.toString();
}
// https://en.wikipedia.org/wiki/CPUID
static string get_cpu_brand() {
    string result;
    uint32_t brand[0x10];
    if (!__get_cpuid_max(0x80000004, NULL)) {
        result = "NA";
    } else {
        memset(brand, 0, sizeof(brand));
        __get_cpuid(0x80000002, brand + 0x0, brand + 0x1, brand + 0x2, brand + 0x3);
        __get_cpuid(0x80000003, brand + 0x4, brand + 0x5, brand + 0x6, brand + 0x7);
        __get_cpuid(0x80000004, brand + 0x8, brand + 0x9, brand + 0xa, brand + 0xb);
        result = string(reinterpret_cast<char *>(brand));
    }
    return result;
}
CpuInfo::CpuInfo() : m_vendor(get_cpu_vendor()), m_brand(get_cpu_brand()) {}
CpuInfo::~CpuInfo() {}
/**
 * Detect Virtual machine using hypervisor bit.
 * @return true if the cpu hypervisor bit is set to 1
 */
bool CpuInfo::is_hypervisor_set() const {
    unsigned int level = 1, eax = 0, ebx = 0, ecx = 0, edx = 0;
    __get_cpuid(level, &eax, &ebx, &ecx, &edx);
    bool is_virtual = (((ecx >> 31) & 1) == 1);  // hypervisor flag
    return is_virtual;
}
uint32_t CpuInfo::model() const {
    unsigned int level = 1, eax = 0, ebx = 0, ecx = 0, edx = 0;
    __get_cpuid(level, &eax, &ebx, &ecx, &edx);
    // ax bits 0-3 stepping,4-7 model,8-11 family id,12-13 processor type
    //        14-15 reserved, 16-19 extended model, 20-27 extended family, 27-31 reserved
    // bx bits 0-7 brand index
    return (eax & 0x3FFF) | (eax & 0x3FF8000) >> 2 | (ebx & 0xff) << 24;
}
}  // namespace os
} /* namespace license */
src/library/os/linux/execution_environment.cpp
New file
@@ -0,0 +1,115 @@
/*
 * virtualization.cpp
 *
 *  Created on: Dec 15, 2019
 *      Author: GC
 */
#include <paths.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fstream>
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <dirent.h>
#include <sys/utsname.h>
#include "../../base/base.h"
#include "../cpu_info.hpp"
#include "../execution_environment.hpp"
#include "../../base/file_utils.hpp"
#include "../../base/StringUtils.h"
namespace license {
namespace os {
using namespace std;
// 0=NO 1=Docker/2=Lxc
static int checkContainerProc() {
    // in docer /proc/self/cgroups contains the "docker" or "lxc" string
    // https://stackoverflow.com/questions/23513045/how-to-check-if-a-process-is-running-inside-docker-container
    char path[MAX_PATH] = {0};
    char proc_path[MAX_PATH], pidStr[64];
    pid_t pid = getpid();
    sprintf(pidStr, "%d", pid);
    strcpy(proc_path, "/proc/");
    strcat(proc_path, pidStr);
    strcat(proc_path, "/cgroup");
    FILE *fp;
    char *line = NULL;
    size_t len = 0;
    ssize_t read;
    int result = 0;
    fp = fopen(proc_path, "r");
    if (fp == NULL) {
        return 0;
    }
    while ((read = getline(&line, &len, fp)) != -1 && result == 0) {
        // line[len]=0;
        // printf("Retrieved line of length %zu:\n", read);
        // printf("%s", line);
        if (strstr(line, "docker") != NULL) {
            result = 1;
        }
        if (strstr(line, "lxc") != NULL) {
            result = 2;
        }
    }
    fclose(fp);
    if (line) free(line);
    return result;
}
// 0=NO 1=Docker/2=Lxc
static int checkSystemdContainer() {
    ifstream systemd_container("/var/run/systemd/container");
    int result = 0;
    if (systemd_container.good()) {
        result = 1;
        for (string line; getline(systemd_container, line);) {
            if (line.find("docker") != string::npos) {
                result = 1;
                break;
            } else if (line.find("lxc") != string::npos) {
                result = 2;
                break;
            }
        }
    }
    return result;
}
ExecutionEnvironment::ExecutionEnvironment() {
    try {
        m_bios_vendor = toupper_copy(trim_copy(get_file_contents("/sys/class/dmi/id/sys_vendor", 256)));
    } catch (...) {
    }
    try {
        m_bios_description = toupper_copy(trim_copy(get_file_contents("/sys/class/dmi/id/modalias", 256)));
        char last_char = m_bios_description[m_bios_description.length() - 1];
        if (last_char == '\r' || last_char == '\n') {
            m_bios_description = m_bios_description.erase(m_bios_description.length() - 1);
        }
    } catch (...) {
    }
    try {
        m_sys_vendor = get_file_contents("/sys/class/dmi/id/sys_vendor", 256);
        char last_char = m_sys_vendor[m_sys_vendor.length() - 2];
        if (last_char == '\r' || last_char == '\n') {
            m_sys_vendor = m_sys_vendor.erase(m_sys_vendor.length() - 1);
        }
    } catch (...) {
    }
}
bool ExecutionEnvironment::is_container() const { return (checkContainerProc() != 0 || checkSystemdContainer() != 0); }
bool ExecutionEnvironment::is_docker() const { return (checkContainerProc() == 1 || checkSystemdContainer() == 1); }
}  // namespace os
}  // namespace license
src/library/os/linux/network.cpp
New file
@@ -0,0 +1,125 @@
/**
 * @file network_id.c
 * @date 16 Sep 2014
 * @brief File containing network interface detection functions for Linux.
 *
 * The only public function of this module is #getAdapterInfos(OsAdapterInfo *,
 *        size_t *), other functions are either static or inline.
 *
 * Responsibility of this module is to fill OsAdapterInfo structures, in a
 * predictable way (skip "lo" interfaces,
 * @TODO: place physical interfaces in front in a repeatable order: "eth", "wlan","ib"
 * and other interfaces later, first the one with a a specified mac address, then
 * the ones with only an ip.)
 */
#ifndef _GNU_SOURCE
#define _GNU_SOURCE /* To get defns of NI_MAXSERV and NI_MAXHOST */
#endif
#include <arpa/inet.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netdb.h>
#include <ifaddrs.h>
#include <linux/if_link.h>
#include <netpacket/packet.h>
#include <stdio.h>
#include <unordered_map>
#include <string.h>
#include <memory.h>
#include "../../base/StringUtils.h"
#include "../../base/logger.h"
#include "../network.hpp"
namespace license {
namespace os {
using namespace std;
/**
 *
 * @param adapterInfos
 * @param adapter_info_size
 * @return
 */
FUNCTION_RETURN getAdapterInfos(vector<OsAdapterInfo> &adapterInfos) {
    unordered_map<string, OsAdapterInfo> adapterByName;
    FUNCTION_RETURN f_return = FUNC_RET_OK;
    struct ifaddrs *ifaddr, *ifa;
    int family, n = 0;
    unsigned int if_num, if_max;
    if (getifaddrs(&ifaddr) == -1) {
        LOG_WARN("getifaddrs failed == -1");
        return FUNC_RET_ERROR;
    }
    for (ifa = ifaddr, n = 0, if_num = 0; ifa != NULL; ifa = ifa->ifa_next, n++) {
        if (ifa->ifa_addr == NULL || (ifa->ifa_flags & IFF_LOOPBACK) != 0) {
            continue;
        }
        string if_name(ifa->ifa_name, mstrnlen_s(ifa->ifa_name, NI_MAXHOST));
        // if_name_position = ifname_position(ifnames, ifa->ifa_name, if_num);
        // interface name not seen en advance
        OsAdapterInfo *currentAdapter;
        // FIXME not working
        if (adapterByName.find(if_name) == adapterByName.end()) {
            OsAdapterInfo newAdapter;
            memset(&newAdapter, 0, sizeof(OsAdapterInfo));
            strncpy(&newAdapter.description[0], ifa->ifa_name, NI_MAXHOST);
            adapterByName[if_name] = newAdapter;
        }
        auto it = adapterByName.find(if_name);
        currentAdapter = &it->second;
        family = ifa->ifa_addr->sa_family;
        /* Display interface name and family (including symbolic
         form of the latter for the common families) */
#ifdef _DEBUG
        printf("%-8s %s (%d)\n", ifa->ifa_name,
               (family == AF_PACKET) ? "AF_PACKET"
                                     : (family == AF_INET) ? "AF_INET" : (family == AF_INET6) ? "AF_INET6" : "???",
               family);
#endif
        /* For an AF_INET* interface address, display the address
         * || family == AF_INET6*/
        if (family == AF_INET) {
            struct sockaddr_in *s1 = (struct sockaddr_in *)ifa->ifa_addr;
            in_addr_t iaddr = s1->sin_addr.s_addr;
            currentAdapter->ipv4_address[0] = (iaddr & 0x000000ff);
            currentAdapter->ipv4_address[1] = (iaddr & 0x0000ff00) >> 8;
            currentAdapter->ipv4_address[2] = (iaddr & 0x00ff0000) >> 16;
            currentAdapter->ipv4_address[3] = (iaddr & 0xff000000) >> 24;
        } else if (family == AF_PACKET && ifa->ifa_data != NULL) {
            struct sockaddr_ll *s1 = (struct sockaddr_ll *)ifa->ifa_addr;
            int i;
            for (i = 0; i < 6; i++) {
                currentAdapter->mac_address[i] = s1->sll_addr[i];
#ifdef _DEBUG
                printf("%02x:", s1->sll_addr[i]);
#endif
            }
#ifdef _DEBUG
            printf("\t %s\n", ifa->ifa_name);
#endif
        }
    }
    freeifaddrs(ifaddr);
    // FIXME sort by eth , enps, wlan
    if (adapterByName.size() == 0) {
        f_return = FUNC_RET_NOT_AVAIL;
    } else {
        f_return = FUNC_RET_OK;
        adapterInfos.reserve(adapterByName.size());
        for (auto &it : adapterByName) {
            adapterInfos.push_back(it.second);
        }
    }
    return f_return;
}
}  // namespace os
}  // namespace license
src/library/os/linux/os_linux.cpp
File was renamed from src/library/os/os-linux.c
@@ -1,9 +1,8 @@
#include <paths.h>
#include <sys/stat.h>
#include "os.h"
#include "../base/logger.h"
#include <openssl/pem.h>
#include <openssl/err.h>
#include <stdio.h>
#include "../os.h"
#include "../../base/logger.h"
#include <mntent.h>
#include <dirent.h>
@@ -112,7 +111,9 @@
                if (strcmp(ent->mnt_dir, "/") == 0) {
                    strcpy(tmpDrives[drive_found].label, "root");
                    LOG_DEBUG("drive %s set to preferred\n", ent->mnt_fsname);
                    tmpDrives[drive_found].preferred = true;
                    tmpDrives[drive_found].preferred = 1;
                } else {
                    tmpDrives[drive_found].preferred = 0;
                }
            }
        }
@@ -170,27 +171,9 @@
    } else {
        result = FUNC_RET_BUFFER_TOO_SMALL;
    }
    /*
     FILE *mounts = fopen(_PATH_MOUNTED, "r");
     if (mounts == NULL) {
     return ERROR;
     }
     while (fscanf(mounts, "%64s %64s %64s %1024[^\n]", device, name, type,
     discard) != EOF) {
     if (stat(device, &mount_stat) != 0)
     continue;
     if (filename_stat.st_dev == mount_stat.st_rdev) {
     fprintf(stderr, "device: %s; name: %s; type: %s\n", device, name,
     type);
     }
     }
     */
    free(statDrives);
    return result;
}
void os_initialize() {}
static void _getCpuid(unsigned int *p, unsigned int ax) {
    __asm __volatile(
@@ -212,78 +195,7 @@
    return FUNC_RET_OK;
}
// 0=NO 1=Docker/Lxc
static int checkContainerProc() {
    // in docer /proc/self/cgroups contains the "docker" or "lxc" string
    // https://stackoverflow.com/questions/23513045/how-to-check-if-a-process-is-running-inside-docker-container
    char path[MAX_PATH] = {0};
    char proc_path[MAX_PATH], pidStr[64];
    pid_t pid = getpid();
    sprintf(pidStr, "%d", pid);
    strcpy(proc_path, "/proc/");
    strcat(proc_path, pidStr);
    strcat(proc_path, "/cgroup");
    FILE *fp;
    char *line = NULL;
    size_t len = 0;
    ssize_t read;
    int result = 0;
    fp = fopen(proc_path, "r");
    if (fp == NULL) {
        return 0;
    }
    while ((read = getline(&line, &len, fp)) != -1 && result == 0) {
        // line[len]=0;
        // printf("Retrieved line of length %zu:\n", read);
        // printf("%s", line);
        if (strstr(line, "docker") != NULL || strstr(line, "lxc") != NULL) {
            result = 1;
        }
    }
    fclose(fp);
    if (line) free(line);
    return result;
}
// 0=NO 1=Docker/Lxc
static int checkLXC() { return (access("/var/run/systemd/container", F_OK) == 0) ? 1 : 0; }
VIRTUALIZATION getVirtualization() {
    VIRTUALIZATION result = NONE;
    int isContainer = checkContainerProc();
    if (isContainer == 1) {
        result = CONTAINER;
    } else if (checkLXC()) {
        result = CONTAINER;
    }
    return result;
    // http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html
    //
    // bool rc = true;
    /*__asm__ (
     "push   %edx\n"
     "push   %ecx\n"
     "push   %ebx\n"
     "mov    %eax, 'VMXh'\n"
     "mov    %ebx, 0\n" // any value but not the MAGIC VALUE
     "mov    %ecx, 10\n"// get VMWare version
     "mov    %edx, 'VX'\n"// port number
     "in     %eax, dx\n"// read port on return EAX returns the VERSION
     "cmp    %ebx, 'VMXh'\n"// is it a reply from VMWare?
     "setz   [rc] \n"// set return value
     "pop    %ebx \n"
     "pop    %ecx \n"
     "pop    %edx \n"
     );*/
    // systemd-detect-virt
    return NONE;
}
FUNCTION_RETURN getMachineName(unsigned char identifier[6]) {
    static struct utsname u;
src/library/os/network.hpp
New file
@@ -0,0 +1,32 @@
/*
 * network.hpp
 *
 *  Created on: Feb 8, 2020
 *      Author: devel
 */
#ifndef SRC_LIBRARY_OS_NETWORK_HPP_
#define SRC_LIBRARY_OS_NETWORK_HPP_
#include <stdlib.h>
#include <vector>
#include "../base/base.h"
namespace license {
namespace os {
typedef enum { IFACE_TYPE_ETHERNET, IFACE_TYPE_WIRELESS } IFACE_TYPE;
typedef struct {
    int id;
    char description[1024];
    unsigned char mac_address[8];
    unsigned char ipv4_address[4];
    IFACE_TYPE type;
} OsAdapterInfo;
FUNCTION_RETURN getAdapterInfos(std::vector<OsAdapterInfo>& adapterInfos);
}  // namespace os
}  // namespace license
#endif /* SRC_LIBRARY_OS_NETWORK_HPP_ */
src/library/os/network_id.c
File was deleted
src/library/os/openssl/signature_verifier.cpp
@@ -10,16 +10,17 @@
#include <stdlib.h>
#include <errno.h>
#ifdef _WIN32
#include <windows.h>
#endif
//#ifdef _WIN32
//#include <windows.h>
//#endif
#include <public_key.h>
#include "../signature_verifier.h"
#include "../signature_verifier.hpp"
#include "../../base/logger.h"
namespace license {
#include "../../base/logger.h"
namespace os {
static void free_resources(EVP_PKEY* pkey, EVP_MD_CTX* mdctx) {
    if (pkey) {
@@ -103,5 +104,5 @@
    free_resources(pkey, mdctx);
    return result;
}
}  // namespace os
} /* namespace license */
src/library/os/os-win.c
File was deleted
src/library/os/os.h
@@ -12,48 +12,29 @@
extern "C" {
#endif
#include "../base/base.h"
#include <stddef.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
//definition of size_t
// definition of size_t
#include <stdlib.h>
#ifdef __unix__
#include <unistd.h>
#include <stdbool.h>
#endif
typedef enum {
    NONE, CONTAINER, VM
} VIRTUALIZATION;
typedef enum {
    IFACE_TYPE_ETHERNET, IFACE_TYPE_WIRELESS
} IFACE_TYPE;
#include "../base/base.h"
typedef struct {
    int id;
    char description[1024];
    unsigned char mac_address[8];
    unsigned char ipv4_address[4];
    IFACE_TYPE type;
} OsAdapterInfo;
typedef struct {
    int id;
    char device[255];
    char device[MAX_PATH];
    unsigned char disk_sn[8];
    char label[255];
    bool preferred;
    int preferred;
} DiskInfo;
FUNCTION_RETURN getAdapterInfos(OsAdapterInfo * adapterInfos,
        size_t * adapter_info_size);
FUNCTION_RETURN getDiskInfos(DiskInfo * diskInfos, size_t * disk_info_size);
FUNCTION_RETURN getDiskInfos(DiskInfo* diskInfos, size_t* disk_info_size);
FUNCTION_RETURN getUserHomePath(char[MAX_PATH]);
FUNCTION_RETURN getModuleName(char buffer[MAX_PATH]);
FUNCTION_RETURN getCpuId(unsigned char identifier[6]);
FUNCTION_RETURN getMachineName(unsigned char identifier[6]);
/**
 * Get an identifier of the machine in an os specific way.
@@ -74,17 +55,15 @@
 * @return
 */
FUNCTION_RETURN getOsSpecificIdentifier(unsigned char identifier[6]);
VIRTUALIZATION getVirtualization();
void os_initialize();
// 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, "");
#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);
#define SETENV(VAR, VAL) setenv(VAR, VAL, 1);
#define UNSETENV(P) unsetenv(P);
#endif
#ifdef __cplusplus
src/library/os/signature_verifier.hpp
File was renamed from src/library/os/signature_verifier.h
@@ -12,9 +12,9 @@
#include "../base/base.h"
namespace license {
namespace os {
FUNCTION_RETURN verify_signature(const std::string& stringToVerify, const std::string& signatureB64);
}
} /* namespace license */
#endif /* SRC_LIBRARY_OS_VERIFIER_HPP_ */
src/library/os/windows/cpu_info.cpp
New file
@@ -0,0 +1,78 @@
/*
 * cpu_info.cpp
 *
 *  Created on: Dec 14, 2019
 *      Author: devel
 */
#include <intrin.h>
#include <string>
#include <unordered_set>
#include "../cpu_info.hpp"
namespace license {
namespace os {
using namespace std;
static string get_cpu_vendor() {
    // hypervisor flag false, try to get the vendor name, see if it's a virtual cpu
    int cpui[4] = {0};
    __cpuidex(cpui, 0x0, 0x0);
    char vendor[13];
    memset(vendor, 0, sizeof(vendor));
    *reinterpret_cast<int *>(vendor) = cpui[1];
    *reinterpret_cast<int *>(vendor + 4) = cpui[3];
    *reinterpret_cast<int *>(vendor + 8) = cpui[2];
    return string(vendor, 12);
}
static string get_cpu_brand() {
    int cpui[4] = {0};
    __cpuid(cpui, 0x80000000);
    int maxSupported = cpui[0];
    char brand[0x41];
    memset(brand, 0, sizeof(brand));
    string result;
    if (maxSupported >= 0x80000004) {
        int instruction = 0x80000002;
        for (int i = 0; i <= 2; ++i) {
            __cpuidex(cpui, instruction + i, 0);
            memcpy(&brand[i * sizeof(cpui)], cpui, sizeof(cpui));
        }
        result = string(brand);
    } else {
        result = "NA";
    }
    return result;
}
CpuInfo::CpuInfo() : m_vendor(get_cpu_vendor()), m_brand(get_cpu_brand()) {}
CpuInfo::~CpuInfo() {}
/**
 * Detect Virtual machine using hypervisor bit.
 * @return true if the cpu hypervisor bit is set to 1
 */
bool CpuInfo::is_hypervisor_set() const {
    int cpui[4] = {0};
    __cpuid(cpui, 0x1);
    return ((cpui[2] >> 31) & 1);
}
uint32_t CpuInfo::model() const {
    int cpui[4] = {0};
    __cpuid(cpui, 0x1);
    // ax bits 0-3 stepping,4-7 model,8-11 family id,12-13 processor type
    //        14-15 reserved, 16-19 extended model, 20-27 extended family, 27-31 reserved
    // bx bits 0-7 brand index
    return (cpui[0] & 0x3FFF) | (cpui[0] & 0x3FF8000) >> 2 | (cpui[1] & 0xff) << 24;
}
}  // namespace os
} /* namespace license */
src/library/os/windows/execution_environment.cpp
New file
@@ -0,0 +1,86 @@
/*
 * virtualization.cpp
 *
 *  Created on: Dec 15, 2019
 *      Author: GC
 */
#include <windows.h>
#include <sys/stat.h>
#include <fstream>
#include <iostream>
#include <stdio.h>
#include <string>
#include "isvm/BIOSReader.h"
#include "isvm/Native.h"
#include "../../base/base.h"
#include "../../base/StringUtils.h"
#include "../cpu_info.hpp"
#include "../execution_environment.hpp"
namespace license {
namespace os {
using namespace std;
ExecutionEnvironment::ExecutionEnvironment() {
    if (InitEntryPoints()) {
        BIOSReader reader;
        SystemInformation info = reader.readSystemInfo();
        m_sys_vendor = toupper_copy(info.Manufacturer);
        m_bios_vendor = toupper_copy(info.ProductName);
        m_bios_description = toupper_copy(info.SysVersion) + toupper_copy(info.family);
    }
}
#define MAX_UNITS 20
int wine_container() {
DWORD fileMaxLen;
size_t ndrives = 0;
DWORD fileFlags;
char volName[MAX_PATH], fileSysName[MAX_PATH];
DWORD volSerial = 0;
const DWORD dwSize = MAX_PATH;
char szLogicalDrives[MAX_PATH] = {0};
int result = 0;
const DWORD dwResult = GetLogicalDriveStrings(dwSize, szLogicalDrives);
if (dwResult > 0 && dwResult <= MAX_PATH) {
    char* szSingleDrive = szLogicalDrives;
    while (*szSingleDrive && ndrives < MAX_UNITS) {
        // get the next drive
        UINT driveType = GetDriveType(szSingleDrive);
        if (driveType == DRIVE_FIXED) {
            string name = szSingleDrive + string("/var/run/systemd/container");
            try {
                ifstream systemd_container(name);
                if (systemd_container.good()) {
                    result = 1;
                    for (string line; getline(systemd_container, line);) {
                        if (line.find("docker") != string::npos) {
                            result = 1;
                            break;
                        } else if (line.find("lxc") != string::npos) {
                            result = 2;
                            break;
                        }
                    }
                }
            } catch (...) {
                //no problem,we're just guessing
            }
        }
    }
}
    return result;
}
bool ExecutionEnvironment::is_docker() const {
    // let's check we're not in linux under wine ;) ...
//int cont = wine_container();
    return false;
}
//TODO
bool ExecutionEnvironment::is_container() const { return is_docker(); }
}  // namespace os
}  // namespace license
src/library/os/windows/isvm/BIOSReader.cpp
New file
@@ -0,0 +1,121 @@
#include "BIOSReader.h"
#include <cstdint>
#include "Native.h"
struct smbios_structure_header {
    uint8_t type;
    uint8_t length;
    uint16_t handle;
};
//
//    System information
//
struct smbios_type_1 {
    struct smbios_structure_header header;
    uint8_t manufacturer_str;
    uint8_t product_name_str;
    uint8_t version_str;
    uint8_t serial_number_str;
    uint8_t uuid[16];
    uint8_t wake_up_type;
    uint8_t sku_number_str;
    uint8_t family_str;
};
#define _TYPE_COUNT1 6
#define _CONCATE(x, y) x##y
#define CONCATE(x, y) _CONCATE(x, y)
#define TYPE_COUNT(t) CONCATE(_TYPE_COUNT, t)
//
//    Windows
//
#include <windows.h>
#include <tchar.h>
int8_t *parse_smbiod_content(int8_t *addr, int8_t **indexes, int32_t *count) {
    //!    ignore 0
    int8_t parsed_count = 0;
    int8_t *raw_addr = addr;
    //!    first one
    if (indexes) *indexes = raw_addr;
    bool reach_terminal = false;
    while (true) {
        if (0 == *raw_addr++) {
            if (reach_terminal)
                break;
            else {
                ++parsed_count;
                if (count && parsed_count < *count) {
                    if (indexes) *(indexes + parsed_count) = raw_addr;
                }
                reach_terminal = true;
            }
        } else {
            reach_terminal = false;
            continue;
        }
    }
    if (count) *count = parsed_count;
    return raw_addr;
}
void read_smbios_type_1(int8_t *addr, SystemInformation *info) {
    smbios_type_1 *t1 = (smbios_type_1 *)addr;
    int32_t offset = ((0x0F) & (t1->header.length >> 4)) * 16 + (t1->header.length & 0x0F);
    int8_t *string_addr[TYPE_COUNT(1)] = {0};
    int32_t count = TYPE_COUNT(1);
    parse_smbiod_content((int8_t *)t1 + offset, string_addr, &count);
    if (0 != t1->manufacturer_str)
        info->Manufacturer = (std::string::traits_type::char_type *)string_addr[t1->manufacturer_str - 1];
    if (0 != t1->product_name_str)
        info->ProductName = (std::string::traits_type::char_type *)string_addr[t1->product_name_str - 1];
    if (0 != t1->serial_number_str)
        info->SerialNum = (std::string::traits_type::char_type *)string_addr[t1->serial_number_str - 1];
    if (0 != t1->version_str)
        info->SysVersion = (std::string::traits_type::char_type *)string_addr[t1->version_str - 1];
    if (0 != t1->family_str) info->family = (std::string::traits_type::char_type *)string_addr[t1->family_str - 1];
}
SystemInformation BIOSReader::readSystemInfo() {
    SystemInformation info;
    uint32_t size = 0;
    RawSMBIOSData *data = (RawSMBIOSData *)(LocateSMBIOS(&size));
    if (NULL == data || 0 == size) return info;
    smbios_structure_header *header = (smbios_structure_header *)(data->SMBIOSTableData);
    while (NULL != header) {
        if (1 == header->type) {
            read_smbios_type_1((int8_t *)header, &info);
            header = NULL;    //!    stop
        } else {
            int32_t offset = ((0x0F) & (header->length >> 4)) * 16 + (header->length & 0x0F);
            header = (smbios_structure_header *)parse_smbiod_content((int8_t *)header + offset, NULL, NULL);
        }
    }
    free(data);
    return info;
}
src/library/os/windows/isvm/BIOSReader.h
New file
@@ -0,0 +1,22 @@
#ifndef BIOSREADER_H
#define BIOSREADER_H
#include <string>
class SystemInformation
{
public:
    std::string Manufacturer;
    std::string ProductName;
    std::string SysVersion;
    std::string SerialNum;
    std::string family;
};
class BIOSReader
{
public:
    SystemInformation readSystemInfo();
};
#endif
src/library/os/windows/isvm/Native.cpp
New file
@@ -0,0 +1,438 @@
#include "Native.h"
#include <tchar.h>
typedef LARGE_INTEGER PHYSICAL_ADDRESS, *PPHYSICAL_ADDRESS; // windbgkd
typedef LONG NTSTATUS;
#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)
typedef struct _UNICODE_STRING
{
    USHORT Length;
    USHORT MaximumLength;
#ifdef MIDL_PASS
    [size_is(MaximumLength / 2), length_is((Length) / 2)] USHORT * Buffer;
#else // MIDL_PASS
    PWSTR  Buffer;
#endif // MIDL_PASS
} UNICODE_STRING;
typedef UNICODE_STRING *PUNICODE_STRING;
typedef enum _SECTION_INHERIT
{
    ViewShare = 1,
    ViewUnmap = 2
} SECTION_INHERIT;
#define OBJ_INHERIT             0x00000002L
#define OBJ_PERMANENT           0x00000010L
#define OBJ_EXCLUSIVE           0x00000020L
#define OBJ_CASE_INSENSITIVE    0x00000040L
#define OBJ_OPENIF              0x00000080L
#define OBJ_OPENLINK            0x00000100L
#define OBJ_VALID_ATTRIBUTES    0x000001F2L
static bool bIsWindowsXPLater = false;
static DWORD dwPageSize = 0;
#ifdef _UNICODE
#define GetVersionExProc "GetVersionExW"
#else
#define GetVersionExProc "GetVersionExA"
#endif
typedef struct _OBJECT_ATTRIBUTES
{
    ULONG Length;
    HANDLE RootDirectory;
    PUNICODE_STRING ObjectName;
    ULONG Attributes;
    PVOID SecurityDescriptor;        // Points to type SECURITY_DESCRIPTOR
    PVOID SecurityQualityOfService;  // Points to type SECURITY_QUALITY_OF_SERVICE
} OBJECT_ATTRIBUTES;
typedef OBJECT_ATTRIBUTES *POBJECT_ATTRIBUTES;
typedef struct SMBIOSEntryPoint
{
    char EntryPointString[4];
    uint8_t Checksum;
    uint8_t Length;
    uint8_t MajorVersion;
    uint8_t MinorVersion;
    uint16_t MaxStructureSize;
    uint8_t EntryPointRevision;
    char FormattedArea[5];
    char EntryPointString2[5];
    uint8_t Checksum2;
    uint16_t TableLength;
    uint32_t TableAddress;
    uint16_t NumberOfStructures;
    uint8_t BCDRevision;
} SMBIOSEntryPoint, *PSMBIOSEntryPoint;
#define InitializeObjectAttributes( p, n, a, r, s ) { \
    (p)->Length = sizeof(OBJECT_ATTRIBUTES);          \
    (p)->RootDirectory = r;                             \
    (p)->Attributes = a;                                \
    (p)->ObjectName = n;                                \
    (p)->SecurityDescriptor = s;                        \
    (p)->SecurityQualityOfService = NULL;               \
}
NTSTATUS(WINAPI *NtUnmapViewOfSection)(
    IN HANDLE  ProcessHandle,
    IN PVOID  BaseAddress
    );
NTSTATUS(WINAPI *NtOpenSection)(
    OUT PHANDLE  SectionHandle,
    IN ACCESS_MASK  DesiredAccess,
    IN POBJECT_ATTRIBUTES  ObjectAttributes
    );
NTSTATUS(WINAPI *NtMapViewOfSection)(
    IN HANDLE  SectionHandle,
    IN HANDLE  ProcessHandle,
    IN OUT PVOID *BaseAddress,
    IN ULONG  ZeroBits,
    IN ULONG  CommitSize,
    IN OUT PLARGE_INTEGER  SectionOffset,    /* optional */
    IN OUT PULONG  ViewSize,
    IN SECTION_INHERIT  InheritDisposition,
    IN ULONG  AllocationType,
    IN ULONG  Protect
    );
VOID(WINAPI *RtlInitUnicodeString)(
    IN OUT PUNICODE_STRING  DestinationString,
    IN PCWSTR  SourceString
    );
ULONG(WINAPI *RtlNtStatusToDosError) (
    IN NTSTATUS Status
    );
UINT(WINAPI *Win32GetSystemFirmwareTable)(
    _In_ DWORD FirmwareTableProviderSignature,
    _In_ DWORD FirmwareTableID,
    _Out_writes_bytes_to_opt_(BufferSize, return) PVOID pFirmwareTableBuffer,
    _In_ DWORD BufferSize);
BOOL(WINAPI *Win32GetVersionEx)(
    _Inout_  LPOSVERSIONINFO lpVersionInfo
    );
VOID(WINAPI *Win32GetSystemInfo)(
    _Out_  LPSYSTEM_INFO lpSystemInfo
    );
BOOL(WINAPI *Win32VirtualProtect)(
    _In_   LPVOID lpAddress,
    _In_   SIZE_T dwSize,
    _In_   DWORD flNewProtect,
    _Out_  PDWORD lpflOldProtect
    );
//----------------------------------------------------------------------
//
// PrintError
//
// Formats an error message for the last error
//
// Mark Russinovich
// Systems Internals
// http://www.sysinternals.com
//----------------------------------------------------------------------
void PrintError(char *message, NTSTATUS status)
{
    char *errMsg;
    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
        NULL, RtlNtStatusToDosError(status),
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        (LPTSTR)&errMsg, 0, NULL);
    LocalFree(errMsg);
}
//--------------------------------------------------------
//
// UnmapPhysicalMemory
//
// Maps a view of a section.
//
// Mark Russinovich
// Systems Internals
// http://www.sysinternals.com
//--------------------------------------------------------
static VOID UnmapPhysicalMemory(PVOID Address)
{
    NTSTATUS        status;
    status = NtUnmapViewOfSection((HANDLE)-1, Address);
    if (!NT_SUCCESS(status))
    {
        PrintError("Unable to unmap view", status);
    }
}
//--------------------------------------------------------
//
// MapPhysicalMemory
//
// Maps a view of a section.
//
// Mark Russinovich
// Systems Internals
// http://www.sysinternals.com
//--------------------------------------------------------
static BOOLEAN MapPhysicalMemory(HANDLE PhysicalMemory,
    PVOID Address, PDWORD Length,
    PVOID *VirtualAddress)
{
    NTSTATUS            ntStatus;
    PHYSICAL_ADDRESS    viewBase;
    char                error[256];
    viewBase.QuadPart = (ULONGLONG)(Address);
    ntStatus = NtMapViewOfSection(PhysicalMemory,
        (HANDLE)-1,
        VirtualAddress,
        0L, *Length,
        &viewBase,
        Length,
        ViewShare,
        0,
        PAGE_READONLY);
    if (!NT_SUCCESS(ntStatus)) {
        PrintError(error, ntStatus);
        return FALSE;
    }
    return TRUE;
}
//--------------------------------------------------------
//
// OpensPhysicalMemory
//
// This function opens the physical memory device. It
// uses the native API since
//
// Mark Russinovich
// Systems Internals
// http://www.sysinternals.com
//--------------------------------------------------------
static HANDLE OpenPhysicalMemory()
{
    NTSTATUS        status;
    HANDLE            physmem;
    UNICODE_STRING    physmemString;
    OBJECT_ATTRIBUTES attributes;
    WCHAR            physmemName[] = L"\\device\\physicalmemory";
    RtlInitUnicodeString(&physmemString, physmemName);
    InitializeObjectAttributes(&attributes, &physmemString,
        OBJ_CASE_INSENSITIVE, NULL, NULL);
    status = NtOpenSection(&physmem, SECTION_MAP_READ, &attributes);
    if (!NT_SUCCESS(status))
    {
        PrintError("Could not open \\device\\physicalmemory", status);
        return NULL;
    }
    return physmem;
}
static PVOID MapPhysicalMemoryWithBase(HANDLE hPhyHandle, PVOID pBase, PDWORD pLen, PVOID *pVirtualBase)
{
    DWORD dwOffset = (ULONGLONG)pBase % dwPageSize;
    DWORD dwLen = *pLen + dwOffset;
    PVOID pVAddr = NULL;
    if (MapPhysicalMemory(hPhyHandle, pBase, &dwLen, &pVAddr))
    {
        *pVirtualBase = pVAddr;
        *pLen = dwLen;
        return (PBYTE)pVAddr + dwOffset;
    }
    else
    {
        return NULL;
    }
}
bool InitEntryPoints()
{
    Win32GetVersionEx = decltype(Win32GetVersionEx)(GetProcAddress(::GetModuleHandle(_T("kernel32.dll")), GetVersionExProc));
    if (!Win32GetVersionEx)
        return false;
    Win32GetSystemInfo = decltype(Win32GetSystemInfo)(GetProcAddress(::GetModuleHandle(_T("kernel32.dll")), "GetSystemInfo"));
    if (!Win32GetSystemInfo)
        return false;
    OSVERSIONINFO osvi;
    ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
    osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
    if (!Win32GetVersionEx(&osvi))
        return false;
    bIsWindowsXPLater = ((osvi.dwMajorVersion > 5) || ((osvi.dwMajorVersion == 5) && (osvi.dwMinorVersion > 1)));
    SYSTEM_INFO sysinfo;
    ::ZeroMemory(&sysinfo, sizeof (SYSTEM_INFO));
    Win32GetSystemInfo(&sysinfo);
    dwPageSize = sysinfo.dwPageSize;
    if (bIsWindowsXPLater)
    {
        Win32GetSystemFirmwareTable = decltype(Win32GetSystemFirmwareTable)(GetProcAddress(GetModuleHandle(_T("kernel32.dll")), "GetSystemFirmwareTable"));
        if (!Win32GetSystemFirmwareTable)
            return false;
    }
    else
    {
        Win32VirtualProtect = decltype(Win32VirtualProtect)(GetProcAddress(GetModuleHandle(_T("kernel32.dll")), "VirtualProtect"));
        if (!Win32VirtualProtect)
            return false;
        RtlInitUnicodeString = (decltype(RtlInitUnicodeString))(GetProcAddress(GetModuleHandle(_T("ntdll.dll")), "RtlInitUnicodeString"));
        if (!RtlInitUnicodeString)
            return false;
        NtUnmapViewOfSection = (decltype(NtUnmapViewOfSection))(GetProcAddress(GetModuleHandle(_T("ntdll.dll")), "NtUnmapViewOfSection"));
        if (!NtUnmapViewOfSection)
            return false;
        NtOpenSection = (decltype(NtOpenSection))(GetProcAddress(GetModuleHandle(_T("ntdll.dll")), "NtOpenSection"));
        if (!NtOpenSection)
            return false;
        NtMapViewOfSection = (decltype(NtMapViewOfSection))(GetProcAddress(GetModuleHandle(_T("ntdll.dll")), "NtMapViewOfSection"));
        if (!NtMapViewOfSection)
            return false;
        RtlNtStatusToDosError = (decltype(RtlNtStatusToDosError))(GetProcAddress(GetModuleHandle(_T("ntdll.dll")), "RtlNtStatusToDosError"));
        if (!NtMapViewOfSection)
            return false;
    }
    return true;
}
void *LocateSMBIOS(uint32_t *smbios_size) {
    void *buf = NULL;
    const DWORD tableSignature = ('R' << 24) | ('S' << 16) | ('M' << 8) | 'B';
    if (bIsWindowsXPLater)
    {
        uint32_t size = 0;
        size = Win32GetSystemFirmwareTable(tableSignature, 0, buf, size);
        if (0 == size)
        {
            return NULL;
        }
        buf = malloc(size);
        if (buf)
        {
            if (0 == Win32GetSystemFirmwareTable(tableSignature, 0, buf, size))
            {
                free(buf);
                buf = NULL;
            }
            else
            {
                *smbios_size = size;
            }
        }
    }
    else
    {
        HANDLE hPhysMem = OpenPhysicalMemory();
        if (NULL == hPhysMem)
            return NULL;
        DWORD dwReadLen = 0x10000;
        DWORD dwActualLen = dwReadLen;
        PVOID pBaseVAddr = NULL;
        PVOID pVAddr = MapPhysicalMemoryWithBase(hPhysMem, (PVOID)0xF0000, &dwActualLen, &pBaseVAddr);
        if (!pVAddr)
        {
            ::CloseHandle(hPhysMem);
            return NULL;
        }
        DWORD dwReadOffset = 0;
        PBYTE pbVAddr = (PBYTE)pVAddr;
        PBYTE pbGuardVAddr = pbVAddr + dwReadLen;
        while (pbVAddr < pbGuardVAddr)
        {
            if (pbVAddr[0] == '_' && pbVAddr[1] == 'S' && pbVAddr[2] == 'M' && pbVAddr[3] == '_')
            {
                break;
            }
            pbVAddr += 16;
        }
        //!    no SMBIOS found
        if (pbVAddr >= pbGuardVAddr)
        {
            UnmapPhysicalMemory(pVAddr);
            ::CloseHandle(hPhysMem);
            return NULL;
        }
        PSMBIOSEntryPoint pEntryPoint = (PSMBIOSEntryPoint)pbVAddr;
        RawSMBIOSData *pData = (RawSMBIOSData *)::malloc(pEntryPoint->TableLength + sizeof(RawSMBIOSData));
        PVOID pTableBaseVAddr = NULL;
        if (NULL != pData)
        {
            DWORD dwTableLen = pEntryPoint->TableLength;
            PVOID pTableVAddr = MapPhysicalMemoryWithBase(hPhysMem, (PVOID)pEntryPoint->TableAddress, &dwTableLen, &pTableBaseVAddr);
            if (!pTableVAddr)
            {
                UnmapPhysicalMemory(pBaseVAddr);
                ::CloseHandle(hPhysMem);
                return NULL;
            }
            pData->Used20CallingMethod = 0;
            pData->DmiRevision = 0;
            pData->SMBIOSMajorVersion = pEntryPoint->MajorVersion;
            pData->SMBIOSMinorVersion = pEntryPoint->MinorVersion;
            pData->Length = pEntryPoint->TableLength;
            ::memcpy(pData->SMBIOSTableData, (PVOID)pTableVAddr, pEntryPoint->TableLength);
            *smbios_size = pEntryPoint->TableLength;
        }
        if (NULL != pTableBaseVAddr)
            UnmapPhysicalMemory(pTableBaseVAddr);
        if (NULL != pBaseVAddr)
            UnmapPhysicalMemory(pBaseVAddr);
        ::CloseHandle(hPhysMem);
        buf = pData;
    }
    return buf;
}
src/library/os/windows/isvm/Native.h
New file
@@ -0,0 +1,18 @@
#pragma once
#include <stdint.h>
#include <windows.h>
struct RawSMBIOSData
{
    BYTE    Used20CallingMethod;
    BYTE    SMBIOSMajorVersion;
    BYTE    SMBIOSMinorVersion;
    BYTE    DmiRevision;
    DWORD   Length;
    BYTE    SMBIOSTableData[];
};
bool InitEntryPoints();
void *LocateSMBIOS(uint32_t *smbios_size);
src/library/os/windows/isvm/main.cpp
New file
@@ -0,0 +1,51 @@
#include "intrin.h"
#include <iostream>
#include "BIOSReader.h"
#include "Native.h"
int _tmain(int argc, _TCHAR* argv[])
{
    int cpui[4] = { 0 };
    __cpuid(cpui, 0x1);
    if ((cpui[2] >> 31) & 1)
    {
        std::cout << "Inside virual machine!";
        return 1;
    }
    if (InitEntryPoints())
    {
        BIOSReader reader;
        SystemInformation info = reader.readSystemInfo();
        const char *vmVendors[] =
        {
            "VMware", "Microsoft Corporation", "Virtual Machine", "innotek GmbH", "PowerVM", "Bochs", "KVM"
        };
        const int count = _countof(vmVendors);
        for (int i = 0; i != count; ++i)
        {
            const char *vendor = vmVendors[i];
            if (std::string::npos != info.Manufacturer.find(vendor) ||
                std::string::npos != info.ProductName.find(vendor) ||
                std::string::npos != info.SerialNum.find(vendor))
            {
                std::cout << "Inside virual machine!";
                return 1;
            }
        }
    }
    else
    {
        return -1;
    }
    std::cout << "Inside host machine!";
    return 0;
}
src/library/os/windows/network.cpp
New file
@@ -0,0 +1,113 @@
/**
 * @file network_id.c
 * @date 16 Sep 2014
 * @brief File containing network interface detection functions for Windows.
 *
 * The only public function of this module is #getAdapterInfos(OsAdapterInfo *,
 *        size_t *), other functions are either static or inline.
 *
 * Responsibility of this module is to fill OsAdapterInfo structures, in a predictable way (skip loopback/vpn interfaces)
 */
#ifdef _MSC_VER
#include <Windows.h>
#endif
#include <iphlpapi.h>
#include <unordered_map>
#include <stdio.h>
//#pragma comment(lib, "IPHLPAPI.lib")
#include "../../base/StringUtils.h"
#include "../../base/logger.h"
#include "../network.hpp"
namespace license {
namespace os {
using namespace std;
static int translate(char ipStringIn[16], unsigned char ipv4[4]) {
    size_t index = 0;
    char *str2 = ipStringIn; /* save the pointer */
    while (*str2) {
        if (isdigit((unsigned char)*str2)) {
            ipv4[index] *= 10;
            ipv4[index] += *str2 - '0';
        } else {
            index++;
        }
        str2++;
    }
    return 0;
}
/**
 *
 * @param adapterInfos
 * @param adapter_info_size
 * @return
 */
FUNCTION_RETURN getAdapterInfos(vector<OsAdapterInfo> &adapterInfos) {
    unordered_map<string, OsAdapterInfo> adapterByName;
    FUNCTION_RETURN f_return = FUNC_RET_OK;
    DWORD dwStatus;
    int adapter_info_size;
    PIP_ADAPTER_INFO pAdapterInfo;
    DWORD dwBufLen = sizeof(IP_ADAPTER_INFO);
    unsigned int i = 3;
    do {
        pAdapterInfo = (PIP_ADAPTER_INFO)malloc(dwBufLen);
        dwStatus = GetAdaptersInfo(     // Call GetAdapterInfo
            pAdapterInfo,  // [out] buffer to receive data
            &dwBufLen  // [in] size of receive data buffer
        );
        if (dwStatus != NO_ERROR && pAdapterInfo != nullptr) {
            free(pAdapterInfo);
            pAdapterInfo = nullptr;
        }
    } while (dwStatus == ERROR_BUFFER_OVERFLOW && i-- > 0);
    if (dwStatus == ERROR_BUFFER_OVERFLOW) {
        return FUNC_RET_ERROR;
    }
    adapter_info_size = dwBufLen / sizeof(IP_ADAPTER_INFO);
    if (adapter_info_size == 0) {
        return FUNC_RET_NOT_AVAIL;
    }
    PIP_ADAPTER_INFO pAdapter = pAdapterInfo;
    i = 0;
    FUNCTION_RETURN result = FUNC_RET_OK;
    while (pAdapter) {
        OsAdapterInfo ai = {};
        strncpy(ai.description, pAdapter->Description,
                min((int)sizeof(ai.description), MAX_ADAPTER_DESCRIPTION_LENGTH));
        memcpy(ai.mac_address, pAdapter->Address, 8);
        translate(pAdapter->IpAddressList.IpAddress.String, ai.ipv4_address);
        ai.type = IFACE_TYPE_ETHERNET;
        i++;
        pAdapter = pAdapter->Next;
        if (i == adapter_info_size) {
            result = FUNC_RET_BUFFER_TOO_SMALL;
            break;
        }
        adapterByName[string(ai.description)] = ai;
    }
    free(pAdapterInfo);
    // FIXME sort by eth , enps, wlan
    if (adapterByName.size() == 0) {
        f_return = FUNC_RET_NOT_AVAIL;
    } else {
        f_return = FUNC_RET_OK;
        adapterInfos.reserve(adapterByName.size());
        for (auto &it : adapterByName) {
            adapterInfos.push_back(it.second);
        }
    }
    return f_return;
}
}  // namespace os
}  // namespace license
src/library/os/windows/os_win.cpp
New file
@@ -0,0 +1,104 @@
#define NOMINMAX
#include <windows.h>
#include <algorithm>
#include <licensecc/datatypes.h>
#include <iphlpapi.h>
#include <stdio.h>
#include "../../base/logger.h"
#include "../os.h"
using namespace std;
FUNCTION_RETURN getMachineName(unsigned char identifier[6]) {
    FUNCTION_RETURN result = FUNC_RET_ERROR;
    char buffer[MAX_COMPUTERNAME_LENGTH + 1];
    int bufsize = MAX_COMPUTERNAME_LENGTH + 1;
    const BOOL cmpName = GetComputerName(buffer, (unsigned long*)&bufsize);
    if (cmpName) {
        strncpy((char*)identifier, buffer, 6);
        result = FUNC_RET_OK;
    }
    return result;
}
//http://www.ok-soft-gmbh.com/ForStackOverflow/EnumMassStorage.c
//http://stackoverflow.com/questions/3098696/same-code-returns-diffrent-result-on-windows7-32-bit-system
#define MAX_UNITS 30
//bug check return with diskinfos == null func_ret_ok
FUNCTION_RETURN getDiskInfos(DiskInfo * diskInfos, size_t * disk_info_size) {
    DWORD fileMaxLen;
    size_t ndrives = 0;
    DWORD fileFlags;
    char volName[MAX_PATH], fileSysName[MAX_PATH];
    DWORD volSerial = 0;
    const DWORD dwSize = MAX_PATH;
    char szLogicalDrives[MAX_PATH] = { 0 };
    FUNCTION_RETURN return_value = FUNC_RET_NOT_AVAIL;
    const DWORD dwResult = GetLogicalDriveStrings(dwSize, szLogicalDrives);
    if (dwResult > 0 && dwResult <= MAX_PATH) {
        return_value = FUNC_RET_OK;
        char* szSingleDrive = szLogicalDrives;
        while (*szSingleDrive && ndrives < MAX_UNITS) {
            // get the next drive
            UINT driveType = GetDriveType(szSingleDrive);
            if (driveType == DRIVE_FIXED) {
                BOOL success = GetVolumeInformation(szSingleDrive, volName, MAX_PATH,
                                                    &volSerial, &fileMaxLen, &fileFlags, fileSysName,
                                                    MAX_PATH);
                if (success) {
                    LOG_INFO("drive         : %s", szSingleDrive);
                    LOG_INFO("Volume Name   : %s", volName);
                    LOG_INFO("Volume Serial : 0x%x", volSerial);
                    LOG_DEBUG("Max file length : %d", fileMaxLen);
                    LOG_DEBUG("Filesystem      : %s", fileSysName);
                    if (diskInfos != NULL) {
                        if (ndrives < (int)*disk_info_size) {
                            diskInfos[ndrives].id = (int)ndrives;
                            strncpy(diskInfos[ndrives].device, volName,
                                    min(std::size_t{MAX_PATH}, sizeof(volName)) - 1);
                            strncpy(diskInfos[ndrives].label, fileSysName,
                                    min(sizeof(diskInfos[ndrives].label), sizeof(fileSysName)) - 1);
                            memcpy(diskInfos[ndrives].disk_sn, &volSerial, sizeof(DWORD));
                            diskInfos[ndrives].preferred = (szSingleDrive[0] == 'C');
                        } else {
                            return_value = FUNC_RET_BUFFER_TOO_SMALL;
                        }
                    }
                    ndrives++;
                } else {
                    LOG_WARN("Unable to retrieve information of '%s'", szSingleDrive);
                }
            } else {
                LOG_INFO("This volume is not fixed : %s, type: %d",    szSingleDrive);
            }
            szSingleDrive += strlen(szSingleDrive) + 1;
        }
    }
    if (diskInfos == NULL || *disk_info_size == 0) {
        if (ndrives > 0) {
            return_value = FUNC_RET_OK;
        } else {
            return_value = FUNC_RET_NOT_AVAIL;
            LOG_INFO("No fixed drive was detected");
        }
        *disk_info_size = ndrives;
    } else {
        *disk_info_size = min(ndrives, *disk_info_size);
    }
    return return_value;
}
FUNCTION_RETURN getModuleName(char buffer[MAX_PATH]) {
    FUNCTION_RETURN result = FUNC_RET_OK;
    const DWORD wres = GetModuleFileName(NULL, buffer, MAX_PATH);
    if (wres == 0) {
        result = FUNC_RET_ERROR;
    }
    return result;
}
src/library/os/windows/signature_verifier.cpp
@@ -15,16 +15,17 @@
#include <wincrypt.h>
#include <iphlpapi.h>
#include <windows.h>
#pragma comment(lib, "bcrypt.lib")
//#pragma comment(lib, "bcrypt.lib")
#include <public_key.h>
#include "../../base/logger.h"
#include "../../base/base64.h"
#include "../signature_verifier.h"
#include "../signature_verifier.hpp"
#define RSA_KEY_BITLEN 1024
namespace license {
namespace os {
using namespace std;
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
@@ -135,12 +136,11 @@
    DWORD status;
    FUNCTION_RETURN result = FUNC_RET_ERROR;
    PBYTE pbSignature = nullptr;
    DWORD dwSigLen;
    BYTE* sigBlob = nullptr;
    BCRYPT_ALG_HANDLE hSignAlg = nullptr;
    // FIXME!!
    sigBlob = unbase64(signatureBuffer.c_str(), (int)signatureBuffer.size(), (int*)&dwSigLen);
    vector<uint8_t> signatureBlob = unbase64(signatureBuffer);
    DWORD dwSigLen = (DWORD) signatureBlob.size();
    BYTE* sigBlob = &signatureBlob[0];
    if (NT_SUCCESS(status = BCryptOpenAlgorithmProvider(&hSignAlg, BCRYPT_RSA_ALGORITHM, NULL, 0))) {
        if ((result = readPublicKey(hSignAlg, &phKey)) == FUNC_RET_OK) {
@@ -159,7 +159,8 @@
        } else {
            LOG_DEBUG("Error reading public key");
        }
    } else {
    }
    else {
        result = FUNC_RET_NOT_AVAIL;
#ifdef _DEBUG
        formatError(status, "error opening RSA provider");
@@ -172,9 +173,9 @@
    if (hSignAlg != nullptr) {
        BCryptCloseAlgorithmProvider(hSignAlg, 0);
    }
    if (sigBlob) {
        free(sigBlob);
    }
    //if (sigBlob) {
    //    free(sigBlob);
    //}
    return result;
}
@@ -241,5 +242,5 @@
    }
    return result;
}
}  // namespace os
} /* namespace license */
src/library/pc-identifiers.c
File was deleted
src/library/pc-identifiers.h
File was deleted
src/templates/licensecc_properties.h.in
@@ -1,17 +1,74 @@
#ifndef BUILD_PROPERTIES_H_
#define BUILD_PROPERTIES_H_
/**
 * This file contains all the properties that are customizable on on a per-project basis eg:
 * 1) api parameter sizes
 * 2)
 *
 * It is safe to place the values that your project need to customize here, since each project get its own copy of this
 * file.
 */
#define LCC_PROJECT_NAME "@LCC_PROJECT_NAME@"
//License retrieval configuration
#define FIND_LICENSE_NEAR_MODULE true
#define FIND_LICENSE_WITH_ENV_VAR false
#define LICENSE_FILE_EXTENSION ".lic"
#define LICENSE_LOCATION_ENV_VAR "LICENSE_LOCATION"
#define LICENSE_DATA_ENV_VAR "LICENSE_DATA"
/**
 * License file name extension
 */
#define LCC_LICENSE_FILE_EXTENSION ".lic"
#define LCC_LICENSE_LOCATION_ENV_VAR "LICENSE_LOCATION"
#define LCC_LICENSE_DATA_ENV_VAR "LICENSE_DATA"
/**
 * Environment variable that if defined will change the identification strategy used to generate the hardware identifier.
 * If a client has an unstable pc-identifier use this variable to generate one.
 * Valid values are integers defined in `LCC_IDENTIFICATION_STRATEGY` enum.
 */
#define LCC_IDENTIFICATION_STRATEGY_ENV_VAR "IDENTIFICATION_STRATEGY"
//Internal data structures limits
#define MAX_LICENSE_LENGTH 256*1024
/**
 * Enum to select a specific pc identification_strategy. DEFAULT Should be used in most cases.
 */
typedef enum {
    STRATEGY_DEFAULT = -1,
    STRATEGY_ETHERNET = 0,
    STRATEGY_IP_ADDRESS = 1,
    STRATEGY_DISK_NUM = 2,
    STRATEGY_DISK_LABEL = 3,
    STRATEGY_MEMORY_CPU_SIZE = 4,
    STRATEGY_HOST_NAME = 5,
    STRATEGY_NONE = -2
} LCC_API_IDENTIFICATION_STRATEGY;
//strategies used for each virtual environment.
#define LCC_BARE_TO_METAL_STRATEGIES { STRATEGY_ETHERNET, STRATEGY_DISK_LABEL, STRATEGY_NONE }
#define LCC_VM_STRATEGIES { STRATEGY_ETHERNET, STRATEGY_NONE }
#define LCC_LXC_STRATEGIES { STRATEGY_ETHERNET, STRATEGY_NONE }
#define LCC_DOCKER_STRATEGIES { STRATEGY_NONE }
#define LCC_CLOUD_STRATEGIES { STRATEGY_NONE }
//Api structure limits
/**
 * Maximum size of a license file or base64 data
 */
#define LCC_API_MAX_LICENSE_DATA_LENGTH 1024 * 4
// define api structure sizes
#define LCC_API_PC_IDENTIFIER_SIZE 19
#define LCC_API_PROPRIETARY_DATA_SIZE 16
#define LCC_API_AUDIT_EVENT_NUM 5
#define LCC_API_AUDIT_EVENT_PARAM2 255
#define LCC_API_VERSION_LENGTH 15
#define LCC_API_PROJECT_NAME_SIZE 15
#define LCC_API_EXPIRY_DATE_SIZE 10
#define LCC_API_ERROR_BUFFER_SIZE 256
/**
This definition allows to specify a custom expression to verify the magic number passed in by the api.
*/
#define LCC_VERIFY_MAGIC (lic_info.m_magic == @LCC_PROJECT_MAGIC_NUM@)
#endif
test/CMakeLists.txt
@@ -1,8 +1,5 @@
#if we're here boost has been found
add_definitions(-DBOOST_ALL_NO_LIB) #Disable Boost Microsoft magic, all dependencies are handled by cmake
add_definitions(-DBOOST_LIB_DIAGNOSTIC) #Check it is really disabled
include_directories(${Boost_INCLUDE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
link_directories ( ${Boost_LIBRARY_DIR} )
configure_file (
    "${CMAKE_CURRENT_SOURCE_DIR}/../src/templates/licensecc_properties_test.h.in" 
@@ -11,7 +8,6 @@
file(GENERATE OUTPUT "${CMAKE_BINARY_DIR}/include/$<CONFIG>/licensecc_properties_test.h" 
        INPUT "${CMAKE_BINARY_DIR}/licensecc_properties_test.h.tmp")
include_directories ( ${CMAKE_BINARY_DIR}/include/$<CONFIG> )
add_subdirectory(library)
add_subdirectory(functional)
test/IdentificationStrategy_test.cpp
New file
@@ -0,0 +1,10 @@
/*
 * IdentificationStrategy_test.cpp
 *
 *  Created on: Jan 1, 2020
 *      Author: devel
 */
#include "identification_strategy.hpp"
namespace license {} /* namespace license */
test/default_strategy_test.cpp
New file
@@ -0,0 +1,10 @@
/*
 * default_strategy_test.cpp
 *
 *  Created on: Jan 2, 2020
 *      Author: devel
 */
#include "default_strategy.hpp"
namespace license {} /* namespace license */
test/functional/CMakeLists.txt
@@ -2,20 +2,17 @@
     generate-license.cpp
)
target_link_libraries(
    license_generator_snippet
target_link_libraries( license_generator_snippet
      Boost::unit_test_framework 
     Boost::filesystem
     Boost::system
)
add_executable(
 test_standard_license
add_executable( test_standard_license
 standard-license_test.cpp
)
target_link_libraries(
 test_standard_license
target_link_libraries( test_standard_license
 licensecc_static
 license_generator_snippet
 Boost::unit_test_framework 
@@ -23,13 +20,11 @@
 Boost::system
)
add_executable(
 test_date
add_executable( test_date
 date_test.cpp
)
target_link_libraries(
 test_date
target_link_libraries( test_date
 licensecc_static
 license_generator_snippet
 Boost::unit_test_framework 
@@ -37,8 +32,7 @@
 Boost::system
)
add_executable(
 test_signature_verifier
add_executable( test_signature_verifier
 signature_verifier_test.cpp
)
@@ -52,24 +46,30 @@
)
add_executable(
 test_volid
 volid_test.cpp
)
add_executable(test_it_hw_identifier hw_identifier_it_test.cpp)
target_link_libraries(
 test_volid
 licensecc_static
target_link_libraries(test_it_hw_identifier
 license_generator_snippet
 licensecc_static
 Boost::unit_test_framework 
 Boost::filesystem
 Boost::system
)
add_executable(test_crack crack_test.cpp)
target_link_libraries( test_crack
 license_generator_snippet
 licensecc_static
 Boost::unit_test_framework
 Boost::filesystem
 Boost::system
)
ADD_TEST(NAME test_crack COMMAND test_crack WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
ADD_TEST(NAME test_date COMMAND test_date WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
ADD_TEST(NAME test_it_hw_identifier COMMAND test_it_hw_identifier WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
ADD_TEST(NAME test_standard_license COMMAND test_standard_license WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
ADD_TEST(NAME test_signature_verifier COMMAND test_signature_verifier WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
ADD_TEST(NAME test_volid COMMAND test_volid WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
test/functional/crack_test.cpp
New file
@@ -0,0 +1,39 @@
#define BOOST_TEST_MODULE standard_license_test
#include <boost/test/unit_test.hpp>
#include <boost/filesystem.hpp>
#include <licensecc/licensecc.h>
#include <licensecc_properties_test.h>
#include <licensecc_properties.h>
#include <iostream>
#include "../../src/library/ini/SimpleIni.h"
#include "generate-license.h"
#include "../../src/library/base/file_utils.hpp"
namespace license {
namespace test {
namespace fs = boost::filesystem;
using namespace license;
using namespace std;
/**
 * Test a generic license, passing a bad license number trough the api.
 * see projects/DEFAULT/include/licensecc/DEFAULT/licensecc_properties.h (magic should be 0)
 */
BOOST_AUTO_TEST_CASE(test_bad_magic_number) {
    const vector<string> extraArgs;
    const string licLocation = generate_license("standard_license", extraArgs);
    /* */
    LicenseInfo license;
    LicenseLocation location = {LICENSE_PATH};
    std::copy(licLocation.begin(), licLocation.end(), location.licenseData);
    // magic should be 0 for this build...
    CallerInformations callInfo{{0}, {0}, 42};
    const LCC_EVENT_TYPE result = acquire_license(&callInfo, &location, &license);
    BOOST_CHECK_EQUAL(result, LICENSE_CORRUPTED);
}
}  // namespace test
}  // namespace license
test/functional/date_test.cpp
@@ -24,14 +24,14 @@
    const string licLocation = generate_license("not_expired.lic", extraArgs);
    /* */
    LicenseInfo license;
    LicenseLocation licenseLocation;
    licenseLocation.licenseFileLocation = licLocation.c_str();
    licenseLocation.licenseData = "";
    const EVENT_TYPE result = acquire_license(nullptr, &licenseLocation, &license);
    LicenseLocation location = {LICENSE_PATH};
    std::copy(licLocation.begin(), licLocation.end(), location.licenseData);
    const LCC_EVENT_TYPE result = acquire_license(nullptr, &location, &license);
    BOOST_CHECK_EQUAL(result, LICENSE_OK);
    BOOST_CHECK_EQUAL(license.has_expiry, true);
    BOOST_CHECK_EQUAL(license.linked_to_pc, false);
    BOOST_CHECK_GT(license.days_left, 0);
    BOOST_CHECK_GT(license.days_left, (unsigned int)0);
}
BOOST_AUTO_TEST_CASE(license_expired) {
@@ -41,11 +41,10 @@
    const string licLocation = generate_license("expired", extraArgs);
    /* */
    LicenseInfo license;
    LicenseLocation licenseLocation;
    licenseLocation.licenseFileLocation = licLocation.c_str();
    licenseLocation.licenseData = nullptr;
    LicenseLocation location = {LICENSE_PATH};
    std::copy(licLocation.begin(), licLocation.end(), location.licenseData);
    BOOST_TEST_MESSAGE("before acquire license");
    const EVENT_TYPE result = acquire_license(nullptr, &licenseLocation, &license);
    const LCC_EVENT_TYPE result = acquire_license(nullptr, &location, &license);
    BOOST_CHECK_EQUAL(result, PRODUCT_EXPIRED);
    BOOST_CHECK_EQUAL(license.has_expiry, true);
    BOOST_CHECK_EQUAL(license.linked_to_pc, false);
test/functional/generate-license.cpp
@@ -20,8 +20,10 @@
namespace fs = boost::filesystem;
using namespace std;
namespace license {
namespace test {
string generate_license(const string& license_name, const vector<string>& other_args) {
    fs::path lcc_exe(LCC_EXE);
    BOOST_REQUIRE_MESSAGE(fs::is_regular_file(lcc_exe), "License generator not found: " LCC_EXE);
test/functional/hijiaking_test.cpp
File was deleted
test/functional/hw_identifier_it_test.cpp
New file
@@ -0,0 +1,95 @@
#define BOOST_TEST_MODULE integration_test_hw_identifier
#include <boost/test/unit_test.hpp>
#include <fstream>
#include <iostream>
#include <stdio.h>
#include <cstring>
#include <boost/filesystem.hpp>
#include <licensecc_properties.h>
#include <licensecc_properties_test.h>
#include <licensecc/licensecc.h>
#include "../../src/library/ini/SimpleIni.h"
#include "../../src/library/hw_identifier/hw_identifier_facade.hpp"
#include "../../src/library/os/os.h"
#include "../../src/library/os/network.hpp"
#include "generate-license.h"
namespace license {
namespace test {
namespace fs = boost::filesystem;
using namespace std;
using namespace hw_identifier;
/**
 * If the current pc has at least one disk generate a hardware identifier using disk, generate a license, verify the license
 * is OK
 */
static void generate_and_verify_license(LCC_API_IDENTIFICATION_STRATEGY strategy, const string& lic_fname) {
    BOOST_TEST_CHECKPOINT("Before generate");
    const string identifier_out = HwIdentifierFacade::generate_user_pc_signature(strategy);
    BOOST_TEST_CHECKPOINT("After generate signature");
    cout << "Identifier:" << identifier_out << endl;
    vector<string> extraArgs;
    extraArgs.push_back("-s");
    extraArgs.push_back(identifier_out);
    BOOST_TEST_CHECKPOINT("Before generate license");
    const string licLocation = generate_license(lic_fname, extraArgs);
    LicenseInfo license;
    LicenseLocation location = {LICENSE_PATH};
    std::copy(licLocation.begin(), licLocation.end(), location.licenseData);
    const LCC_EVENT_TYPE result = acquire_license(nullptr, &location, &license);
    BOOST_CHECK_EQUAL(result, LICENSE_OK);
    BOOST_CHECK_EQUAL(license.has_expiry, false);
    BOOST_CHECK_EQUAL(license.linked_to_pc, true);
}
BOOST_AUTO_TEST_CASE(volid_lic_file) {
    HwIdentifier identifier_out;
    size_t disk_num;
    FUNCTION_RETURN result_diskinfos = getDiskInfos(nullptr, &disk_num);
    if ((result_diskinfos == FUNC_RET_BUFFER_TOO_SMALL || result_diskinfos == FUNC_RET_OK) && disk_num > 0) {
        generate_and_verify_license(LCC_API_IDENTIFICATION_STRATEGY::STRATEGY_DISK_NUM, "volid_lic_file");
    } else {
        BOOST_TEST_MESSAGE("No disk found skipping testing disk hardware identifier");
    }
}
BOOST_AUTO_TEST_CASE(volume_name_lic_file) {
    HwIdentifier identifier_out;
    size_t disk_num;
    FUNCTION_RETURN result_diskinfos = getDiskInfos(nullptr, &disk_num);
    if ((result_diskinfos == FUNC_RET_BUFFER_TOO_SMALL || result_diskinfos == FUNC_RET_OK) && disk_num > 0) {
        generate_and_verify_license(LCC_API_IDENTIFICATION_STRATEGY::STRATEGY_DISK_LABEL, "volume_name_lic_file");
    } else {
        BOOST_TEST_MESSAGE("No disk found skipping testing volume name disk hardware identifier");
    }
}
BOOST_AUTO_TEST_CASE(strategy_mac_address) {
    vector<os::OsAdapterInfo> adapters;
    FUNCTION_RETURN result_adapterInfos = os::getAdapterInfos(adapters);
    if ((result_adapterInfos == FUNC_RET_BUFFER_TOO_SMALL || result_adapterInfos == FUNC_RET_OK) &&
        adapters.size() > 0) {
        generate_and_verify_license(LCC_API_IDENTIFICATION_STRATEGY::STRATEGY_ETHERNET, "strategy_mac_address");
    } else {
        BOOST_TEST_MESSAGE("No ethernet adapter found skipping testing mac address hardware identifier");
    }
}
BOOST_AUTO_TEST_CASE(strategy_ip_address) {
    vector<os::OsAdapterInfo> adapters;
    FUNCTION_RETURN result_adapterInfos = os::getAdapterInfos(adapters);
    if ((result_adapterInfos == FUNC_RET_BUFFER_TOO_SMALL || result_adapterInfos == FUNC_RET_OK) &&
        adapters.size() > 0) {
        generate_and_verify_license(LCC_API_IDENTIFICATION_STRATEGY::STRATEGY_IP_ADDRESS, "strategy_ip_address");
    } else {
        BOOST_TEST_MESSAGE("No ethernet adapter found skipping testing ip hardware identifier");
    }
}
}  // namespace test
}  // namespace license
test/functional/signature_verifier_test.cpp
@@ -1,3 +1,4 @@
/*
 * LicenseVerifier_test.cpp
 *
@@ -10,7 +11,7 @@
#include <licensecc_properties_test.h>
#include <licensecc_properties.h>
#include "../../src/library/os/signature_verifier.h"
#include "../../src/library/os/signature_verifier.hpp"
#include "generate-license.h"
namespace license {
@@ -21,7 +22,7 @@
    const string test_data("test_data");
    const string signature = sign_data(test_data, string("verify_signature"));
    FUNCTION_RETURN result = license::verify_signature(test_data, signature);
    FUNCTION_RETURN result = license::os::verify_signature(test_data, signature);
    BOOST_CHECK_MESSAGE(result == FUNC_RET_OK, "signature verified");
}
@@ -29,7 +30,7 @@
    const string test_data("test_data");
    const string signature = sign_data(test_data, string("verify_signature"));
    FUNCTION_RETURN result = license::verify_signature(string("other data"), signature);
    FUNCTION_RETURN result = license::os::verify_signature(string("other data"), signature);
    BOOST_CHECK_MESSAGE(result == FUNC_RET_ERROR, "signature NOT verified");
}
@@ -37,7 +38,7 @@
    const string test_data("test_data");
    string signature = sign_data(test_data, string("verify_signature"));
    signature[2] = signature[2] + 1;
    FUNCTION_RETURN result = license::verify_signature(test_data, signature);
    FUNCTION_RETURN result = license::os::verify_signature(test_data, signature);
    BOOST_CHECK_MESSAGE(result == FUNC_RET_ERROR, "signature NOT verified");
}
test/functional/standard-license_test.cpp
@@ -1,3 +1,4 @@
#define BOOST_TEST_MODULE test_standard_license
#include <boost/test/unit_test.hpp>
@@ -9,26 +10,42 @@
#include "../../src/library/ini/SimpleIni.h"
#include "generate-license.h"
#include "../../src/library/base/FileUtils.hpp"
#include "../../src/library/base/file_utils.hpp"
using namespace std;
namespace fs = boost::filesystem;
namespace license {
namespace test {
namespace fs = boost::filesystem;
using namespace license;
using namespace std;
/**
 * Test a generic license with no expiry neither client id.
 * Test a generic license with no expiry neither client id. The license is read from file
 */
BOOST_AUTO_TEST_CASE(test_generic_license) {
BOOST_AUTO_TEST_CASE(test_generic_license_read_file) {
    const vector<string> extraArgs;
    const string licLocation = generate_license("standard_license", extraArgs);
    /* */
    LicenseInfo license;
    LicenseLocation licenseLocation;
    licenseLocation.licenseFileLocation = licLocation.c_str();
    licenseLocation.licenseData = nullptr;
    const EVENT_TYPE result = acquire_license(nullptr, &licenseLocation, &license);
    LicenseLocation location = {LICENSE_PATH};
    std::copy(licLocation.begin(), licLocation.end(), location.licenseData);
    const LCC_EVENT_TYPE result = acquire_license(nullptr, &location, &license);
    BOOST_CHECK_EQUAL(result, LICENSE_OK);
    BOOST_CHECK_EQUAL(license.has_expiry, false);
    BOOST_CHECK_EQUAL(license.linked_to_pc, false);
}
/**
 * Test a generic license with no expiry neither client id. The license is passed in trhough the licenseData structure.
 */
BOOST_AUTO_TEST_CASE(test_read_license_data) {
    const vector<string> extraArgs;
    const fs::path licLocation = fs::path(generate_license("standard_license1", extraArgs));
    const string licLocationStr = licLocation.string();
    string license_data = get_file_contents(licLocationStr.c_str(), 65536);
    LicenseInfo license;
    LicenseLocation location = {LICENSE_PLAIN_DATA};
    std::copy(license_data.begin(), license_data.end(), location.licenseData);
    const LCC_EVENT_TYPE result = acquire_license(nullptr, &location, &license);
    BOOST_CHECK_EQUAL(result, LICENSE_OK);
    BOOST_CHECK_EQUAL(license.has_expiry, false);
    BOOST_CHECK_EQUAL(license.linked_to_pc, false);
@@ -55,8 +72,8 @@
//    BOOST_CHECK_EQUAL(license.linked_to_pc, false);
//}
//
// BOOST_AUTO_TEST_CASE( pc_identifier ) {
//    const string licLocation(PROJECT_TEST_TEMP_DIR "/pc_identifier.lic");
// BOOST_AUTO_TEST_CASE( hw_identifier ) {
//    const string licLocation(PROJECT_TEST_TEMP_DIR "/hw_identifier.lic");
//    const vector<string> extraArgs = { "-s", "Jaaa-aaaa-MG9F-ZhB1" };
//    generate_license(licLocation, extraArgs);
//
test/functional/volid_test.cpp
File was deleted
test/library/CMakeLists.txt
@@ -1,24 +1,20 @@
add_executable(
 test_license_reader
add_executable( test_license_reader
 LicenseReader_test.cpp
)
target_link_libraries(
 test_license_reader
target_link_libraries( test_license_reader
 licensecc_static
 Boost::unit_test_framework 
 Boost::filesystem
 Boost::system
)
ADD_TEST(NAME test_license_reader COMMAND test_license_reader)
IF(WIN32)
#test windows
ELSE(WIN32)
    add_executable(
         test_os_linux
         Os_Linux_test.cpp
         os_linux_test.cpp
    )
    target_link_libraries(
@@ -34,8 +30,8 @@
### LicenseLocator tests
add_executable(
 test_license_locator
 LicenseLocator_test.cpp
    test_license_locator
     LicenseLocator_test.cpp
)
target_link_libraries(
@@ -46,20 +42,26 @@
 Boost::system
)
ADD_TEST(NAME test_license_locator COMMAND test_license_locator)
### LicenseLocator tests
add_executable(
 test_event_registry
 EventRegistry_test.cpp
 $<TARGET_OBJECTS:base>
)
target_link_libraries(
 test_event_registry
 base
 Boost::unit_test_framework 
 Boost::filesystem
 Boost::system
)
if(CODE_COVERAGE AND UNIX)
  target_link_libraries(test_event_registry gcov)
endif(CODE_COVERAGE AND UNIX)
ADD_TEST(NAME test_license_reader COMMAND test_license_reader)
ADD_TEST(NAME test_license_locator COMMAND test_license_locator)
ADD_TEST(NAME test_event_registry COMMAND test_event_registry)
ADD_SUBDIRECTORY(os)
ADD_SUBDIRECTORY(hw_identifier)
test/library/LicenseLocator_test.cpp
@@ -1,10 +1,11 @@
#define BOOST_TEST_MODULE "test_license_locator"
#define __STDC_WANT_LIB_EXT1__ 1
#include <string.h>
#include <iostream>
#include <iterator>
#include <cstdio>
#include <fstream>
#include <string>
#include <vector>
#include <boost/filesystem.hpp>
#include <boost/optional.hpp>
@@ -88,13 +89,14 @@
BOOST_AUTO_TEST_CASE(external_definition) {
    // an application can define multiple license locations separated by ';'
    const char *applicationDefinedString = MOCK_LICENSE ";/this/one/doesnt/exist";
    string 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};
    LicenseLocation licLocation = {LICENSE_PATH};
    std::copy(applicationDefinedString.begin(), applicationDefinedString.end(), licLocation.licenseData);
    ExternalDefinition externalDefinition(&licLocation);
    vector<string> licenseInfos = externalDefinition.license_locations(registry);
    BOOST_CHECK(registry.isGood());
@@ -109,9 +111,10 @@
 * 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";
    string applicationDefinedString = PROJECT_TEST_SRC_DIR "/this/file/doesnt/exist";
    license::EventRegistry registry;
    const LicenseLocation licLocation = {applicationDefinedString, nullptr};
    LicenseLocation licLocation = {LICENSE_PATH};
    std::copy(applicationDefinedString.begin(), applicationDefinedString.end(), licLocation.licenseData);
    ExternalDefinition externalDefinition(&licLocation);
    vector<string> licenseInfos = externalDefinition.license_locations(registry);
@@ -129,9 +132,9 @@
    // 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);
    _putenv_s(LCC_LICENSE_LOCATION_ENV_VAR, environment_variable_value);
#else
    setenv(LICENSE_LOCATION_ENV_VAR, environment_variable_value, 1);
    setenv(LCC_LICENSE_LOCATION_ENV_VAR, environment_variable_value, 1);
#endif
    // read test license
    std::ifstream src(MOCK_LICENSE, std::ios::binary);
@@ -146,7 +149,7 @@
    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);
    UNSETENV(LCC_LICENSE_LOCATION_ENV_VAR);
}
/**
@@ -154,7 +157,7 @@
 */
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);
    SETENV(LCC_LICENSE_LOCATION_ENV_VAR, environment_variable_value);
    license::EventRegistry registry;
    EnvironmentVarLocation envVarLocationStrategy;
@@ -164,14 +167,14 @@
    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);
    UNSETENV(LCC_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);
    UNSETENV(LCC_LICENSE_LOCATION_ENV_VAR);
    license::EventRegistry registry;
    EnvironmentVarLocation environmentVarLocation;
    vector<string> licenseInfos = environmentVarLocation.license_locations(registry);
test/library/LicenseReader_test.cpp
@@ -1,4 +1,7 @@
#define BOOST_TEST_MODULE "test_license_reader"
#define __STDC_WANT_LIB_EXT1__ 1
#include <string>
#include <boost/test/unit_test.hpp>
#include <iostream>
@@ -22,10 +25,11 @@
 * Read license at application provided location
 */
BOOST_AUTO_TEST_CASE(read_single_file) {
    const char *licLocation = PROJECT_TEST_SRC_DIR "/library/test_reader.ini";
    string location = PROJECT_TEST_SRC_DIR "/library/test_reader.ini";
    const LicenseLocation location = {licLocation, nullptr};
    LicenseReader licenseReader(&location);
    LicenseLocation licLocation = {LICENSE_PATH};
    std::copy(location.begin(), location.end(), licLocation.licenseData);
    LicenseReader licenseReader(&licLocation);
    vector<FullLicenseInfo> licenseInfos;
    const EventRegistry registry = licenseReader.readLicenses("PrODUCT", licenseInfos);
    BOOST_CHECK(registry.isGood());
@@ -36,9 +40,10 @@
 * Test the error return if the product code is not found in the license
 */
BOOST_AUTO_TEST_CASE(product_not_licensed) {
    const char *licLocation = PROJECT_TEST_SRC_DIR "/library/test_reader.ini";
    const LicenseLocation location = {licLocation, nullptr};
    LicenseReader licenseReader(&location);
    string location = PROJECT_TEST_SRC_DIR "/library/test_reader.ini";
    LicenseLocation licLocation = {LICENSE_PATH};
    std::copy(location.begin(), location.end(), licLocation.licenseData);
    LicenseReader licenseReader(&licLocation);
    vector<FullLicenseInfo> licenseInfos;
    const EventRegistry registry = licenseReader.readLicenses("PRODUCT-NOT", licenseInfos);
    BOOST_CHECK(!registry.isGood());
@@ -51,11 +56,12 @@
 * 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";
    string licLocation = PROJECT_TEST_SRC_DIR "/library/not_found.ini";
    locate::LocatorFactory::find_license_near_module(false);
    locate::LocatorFactory::find_license_with_env_var(false);
    const LicenseLocation location = {licLocation, nullptr};
    LicenseLocation location = {LICENSE_PATH};
    std::copy(licLocation.begin(), licLocation.end(), location.licenseData);
    LicenseReader licenseReader(&location);
    vector<FullLicenseInfo> licenseInfos;
    const EventRegistry registry = licenseReader.readLicenses("PRODUCT", licenseInfos);
@@ -69,11 +75,10 @@
 * Test the error code if the license default environment variable isn't specified
 */
BOOST_AUTO_TEST_CASE(env_var_not_defined) {
    UNSETENV(LICENSE_LOCATION_ENV_VAR);
    const LicenseLocation location = {nullptr, nullptr};
    UNSETENV(LCC_LICENSE_LOCATION_ENV_VAR);
    locate::LocatorFactory::find_license_near_module(false);
    locate::LocatorFactory::find_license_with_env_var(true);
    LicenseReader licenseReader(&location);
    LicenseReader licenseReader(nullptr);
    vector<FullLicenseInfo> licenseInfos;
    const EventRegistry registry = licenseReader.readLicenses("PRODUCT", licenseInfos);
    BOOST_CHECK(!registry.isGood());
@@ -89,12 +94,11 @@
 */
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)
    SETENV(LCC_LICENSE_LOCATION_ENV_VAR, environment_variable_value)
    locate::LocatorFactory::find_license_near_module(false);
    locate::LocatorFactory::find_license_with_env_var(true);
    const LicenseLocation location = {nullptr, nullptr};
    LicenseReader licenseReader(&location);
    LicenseReader licenseReader(nullptr);
    vector<FullLicenseInfo> licenseInfos;
    const EventRegistry registry = licenseReader.readLicenses("PRODUCT", licenseInfos);
    cout << registry << endl;
@@ -102,7 +106,7 @@
    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);
    UNSETENV(LCC_LICENSE_LOCATION_ENV_VAR);
}
}  // namespace test
}  // namespace license
test/library/Os_Linux_test.cpp
File was deleted
test/library/hw_identifier/CMakeLists.txt
New file
@@ -0,0 +1,16 @@
add_executable( test_hw_identifier
 hw_identifier_test.cpp
)
target_link_libraries( test_hw_identifier
 licensecc_static
 Boost::unit_test_framework
 Boost::filesystem
 Boost::system
)
if(CODE_COVERAGE AND UNIX)
      target_compile_options(test_hw_identifier PUBLIC -O0 -g --coverage)
endif(CODE_COVERAGE AND UNIX)
ADD_TEST(NAME test_hw_identifier COMMAND test_hw_identifier)
test/library/hw_identifier/disk_strategy_test.cpp
New file
@@ -0,0 +1,10 @@
/*
 * default_strategy_test.cpp
 *
 *  Created on: Jan 2, 2020
 *      Author: devel
 */
#include "default_strategy.hpp"
namespace license {} /* namespace license */
test/library/hw_identifier/ethernet_test.cpp
New file
@@ -0,0 +1,10 @@
/*
 * ethernet_test.cpp
 *
 *  Created on: Jan 11, 2020
 *      Author: devel
 */
#include "ethernet.hpp"
namespace license {} /* namespace license */
test/library/hw_identifier/hw_identifier_facade_test.cpp
New file
@@ -0,0 +1,100 @@
/*
 * hw_identifier_facade_test.cpp
 *
 *  Created on: Dec 26, 2019
 *      Author: devel
 */
#include "../../../src/library/hw_identifier/hw_identifier_facade.hpp"
namespace license {
/*
 * Test identifier stability:
 * 1) generate the pc-identifier
 * 2) save it to disk
 * 3) every time check that the identifier can still be verified.
 */
static void generate_reference_file(const string &idfileLocation, LCC_API_IDENTIFICATION_STRATEGY strategies[],
                                    int num_strategies) {
    ofstream idfile(idfileLocation);
    PcSignature identifier_out;
    for (int i = 0; i < num_strategies; i++) {
        FUNCTION_RETURN generate_ok = generate_user_pc_signature(identifier_out, strategies[i]);
        if (generate_ok != FUNC_RET_OK) {
            BOOST_ERROR("Generating identifier for strategy " << strategies[i] << " failed with: " << generate_ok);
            idfile << "0000-0000-0000-0000" << endl;
            BOOST_ASSERT(generate_ok == FUNC_RET_OK);
        } else
            idfile << identifier_out << endl;
    }
    idfile.close();
}
BOOST_AUTO_TEST_CASE(generated_identifiers_stability) {
    const string idfileLocation(PROJECT_TEST_TEMP_DIR "/identifiers_file");
    std::vector<LCC_API_IDENTIFICATION_STRATEGY> strategies;
    size_t disk_num;
    getDiskInfos(NULL, &disk_num);
    if (disk_num > 0) {
        strategies = {STRATEGY_DEFAULT, STRATEGY_DISK_NUM, STRATEGY_DISK_LABEL};
    } else {
        BOOST_TEST_CHECKPOINT("if no disk default strategy fails see #49");
        // strategies = { DEFAULT };
        strategies = {};
    }
    size_t adapters;
    getAdapterInfos(nullptr, &adapters);
    if (adapters > 0) {
        strategies.push_back(STRATEGY_ETHERNET);
    }
    size_t num_strategies = strategies.size();
    if (num_strategies == 0) {
        // see issue #49 can't use default
        return;
    }
    std::ifstream test_idfile_exist(idfileLocation);
    if (!test_idfile_exist.good()) {
        generate_reference_file(idfileLocation, strategies.data(), strategies.size());
    } else {
        std::istream_iterator<string> start(test_idfile_exist), end;
        std::vector<string> reference_signatures(start, end);
        test_idfile_exist.close();
        if (reference_signatures.size() != num_strategies ||
            std::find(reference_signatures.begin(), reference_signatures.end(), "0000-0000-0000-0000") !=
                reference_signatures.end())
            generate_reference_file(idfileLocation, strategies.data(), num_strategies);
    }
    std::ifstream is(idfileLocation);
    std::istream_iterator<string> start(is), end;
    std::vector<string> reference_signatures(start, end);
    BOOST_TEST_CHECKPOINT("Generating current signatures and comparing with past");
    for (int i = 0; i < num_strategies; i++) {
        PcSignature generated_identifier;
        FUNCTION_RETURN generate_ok = generate_user_pc_signature(generated_identifier, strategies[i]);
        BOOST_ASSERT(generate_ok == FUNCTION_RETURN::FUNC_RET_OK);
        if (generate_ok != FUNC_RET_OK) {
            BOOST_ERROR("Generating identifier for strategy " << strategies[i] << " failed with: " << generate_ok);
            continue;
        }
        if (reference_signatures[i] != generated_identifier) {
            string message = string("pc signature compare fail: strategy: ") +
                             to_string(static_cast<long long>(strategies[i])) + " generated: [" + generated_identifier +
                             "] reference: [" + reference_signatures[i] + "]";
            BOOST_ERROR(message);
        }
    }
    BOOST_TEST_CHECKPOINT("Verifying signatures");
    for (int j = 0; j < 100; j++) {
        for (unsigned int i = 0; i < reference_signatures.size(); i++) {
            if (reference_signatures[i] == "0000-0000-0000-0000") continue;
            PcSignature pcsig;
            strncpy(pcsig, reference_signatures[i].c_str(), sizeof(PcSignature) - 1);
            LCC_EVENT_TYPE val_result = validate_pc_signature(pcsig);
            BOOST_TEST_CHECKPOINT("Verifying signature: ");
            BOOST_CHECK_EQUAL(val_result, LICENSE_OK);
        }
    }
}
} /* namespace license */
test/library/hw_identifier/hw_identifier_test.cpp
New file
@@ -0,0 +1,65 @@
/*
 * Test on class HwIdentifier
 *
 *  Created on: Dec 26, 2019
 *      Author: devel
 */
#define BOOST_TEST_MODULE test_hw_identifier
#include <boost/test/unit_test.hpp>
#include <fstream>
#include <iostream>
#include <stdio.h>
#include <cstring>
#include <boost/filesystem.hpp>
#include <licensecc_properties.h>
#include <licensecc_properties_test.h>
#include <licensecc/licensecc.h>
#include "../../../src/library/hw_identifier/hw_identifier.hpp"
namespace license {
namespace test {
using namespace std;
using namespace license::hw_identifier;
/**
 * Test get and set and compare hardware identifier data
 */
BOOST_AUTO_TEST_CASE(set_and_compare_data) {
    array<uint8_t, HW_IDENTIFIER_PROPRIETARY_DATA> data = {0xFF, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42};
    HwIdentifier pc_id;
    pc_id.set_data(data);
    data[0] = data[0] & 0x1f;
    BOOST_CHECK_MESSAGE(pc_id.data_match(data), "Data match");
}
/**
 * Test get and set and compare hardware identifier data
 */
BOOST_AUTO_TEST_CASE(compare_wrong_data) {
    array<uint8_t, HW_IDENTIFIER_PROPRIETARY_DATA> data = {0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42};
    HwIdentifier pc_id;
    pc_id.set_data(data);
    data[4] = 0;
    BOOST_CHECK_MESSAGE(!pc_id.data_match(data), "Data shouldn't match");
}
/**
 * Print a hardware identifier and read it from the same string, check the data matches
 */
BOOST_AUTO_TEST_CASE(print_and_read) {
    array<uint8_t, HW_IDENTIFIER_PROPRIETARY_DATA> data = {0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42};
    HwIdentifier pc_id;
    pc_id.set_data(data);
    pc_id.set_identification_strategy(LCC_API_IDENTIFICATION_STRATEGY::STRATEGY_ETHERNET);
    string pc_id_str = pc_id.print();
    cout << pc_id_str << endl;
    const HwIdentifier id2(pc_id_str);
    BOOST_CHECK_MESSAGE(id2.get_identification_strategy() == LCC_API_IDENTIFICATION_STRATEGY::STRATEGY_ETHERNET,
                        "Strategy decoded correctly");
    BOOST_CHECK_MESSAGE(id2.data_match(data), "Data deserialized correctly");
}
}  // namespace test
}  // namespace license
test/library/os/CMakeLists.txt
New file
@@ -0,0 +1,29 @@
add_executable( test_network
 network_test.cpp
)
target_link_libraries( test_network
 licensecc_static
 Boost::unit_test_framework
 Boost::filesystem
 Boost::system
)
ADD_TEST(NAME test_network COMMAND test_network)
add_executable( test_execution_environment
 execution_environment_test.cpp
)
target_link_libraries( test_execution_environment
 licensecc_static
 Boost::unit_test_framework
 Boost::filesystem
 Boost::system
)
ADD_TEST(NAME test_execution_environment COMMAND test_execution_environment)
if(CODE_COVERAGE AND UNIX)
    target_compile_options(test_network PUBLIC -O0 -g --coverage)
    target_compile_options(test_execution_environment PUBLIC -O0 -g --coverage)
endif(CODE_COVERAGE AND UNIX)
test/library/os/cpu_info_test.cpp
New file
@@ -0,0 +1,10 @@
/*
 * cpu_info_test.cpp
 *
 *  Created on: Dec 19, 2019
 *      Author: devel
 */
#include "cpu_info.hpp"
namespace license {} /* namespace license */
test/library/os/execution_environment_test.cpp
New file
@@ -0,0 +1,48 @@
#define BOOST_TEST_MODULE network_test
#include <string>
#include <iostream>
#include <boost/test/unit_test.hpp>
#include <licensecc_properties.h>
#include <licensecc_properties_test.h>
#include "../../../src/library/base/StringUtils.h"
#include "../../../src/library/os/network.hpp"
#include "../../../src/library/os/execution_environment.hpp"
namespace license {
namespace os {
namespace test {
using namespace license::os;
using namespace std;
// To test if virtualization is detected correctly define an env variable VIRT_ENV
// otherwise the test is skipped
BOOST_AUTO_TEST_CASE(test_virtualization) {
    const char *env = getenv("VIRTUAL_ENV");
    os::ExecutionEnvironment exec_env;
    bool docker = false;
    if (env != nullptr) {
        os::VIRTUALIZATION virt = exec_env.getVirtualization();
        if (strcmp(env, "CONTAINER") == 0 || (docker = (strcmp(env, "DOCKER") == 0))) {
            BOOST_CHECK_MESSAGE(virt == VIRTUALIZATION::CONTAINER, "container detected");
            BOOST_CHECK_MESSAGE(exec_env.is_container(), "container detected");
            if (docker) {
                BOOST_CHECK_MESSAGE(exec_env.is_docker(), "docker detected");
            }
        } else if (strcmp(env, "VM") == 0) {
            BOOST_CHECK_MESSAGE(virt == VIRTUALIZATION::VM, "VM detected");
            BOOST_CHECK_MESSAGE(!exec_env.is_container(), "VM is not a container");
            BOOST_CHECK_MESSAGE(!exec_env.is_docker(), "VM is not a docker");
        } else if (strcmp(env, "NONE") == 0) {
            BOOST_CHECK_EQUAL(virt, VIRTUALIZATION::NONE);
            BOOST_CHECK_MESSAGE(!exec_env.is_container(), "not a container");
            BOOST_CHECK_MESSAGE(!exec_env.is_docker(), "not a docker");
        } else {
            BOOST_FAIL(string("value ") + env + " not supported: VM,DOCKER,CONTAINER,NONE");
        }
    }
}
}  // namespace test
}  // namespace os
}  // namespace license
test/library/os/network_test.cpp
New file
@@ -0,0 +1,50 @@
#define BOOST_TEST_MODULE network_test
#include <string>
#include <iostream>
#include <boost/test/unit_test.hpp>
#include <licensecc_properties.h>
#include <licensecc_properties_test.h>
#include "../../../src/library/base/StringUtils.h"
#include "../../../src/library/os/network.hpp"
#include "../../../src/library/os/execution_environment.hpp"
namespace license {
namespace os {
namespace test {
using namespace license::os;
using namespace std;
BOOST_AUTO_TEST_CASE(read_network_adapters) {
    std::vector<license::os::OsAdapterInfo> adapters;
    // we can suppose every test environment  other than docker has at least one network interface (it's hard to
    // download this source code)
    FUNCTION_RETURN result = getAdapterInfos(adapters);
    ExecutionEnvironment exec_env;
    if (result != FUNC_RET_OK && exec_env.is_docker()) {
        BOOST_TEST_MESSAGE("detected docker environment, not having network interfaces is normal here");
        return;
    }
    BOOST_CHECK_EQUAL(result, FUNC_RET_OK);
    for (auto& it : adapters) {
        cout << "Interface found: " << string(it.description) << endl;
        BOOST_CHECK_GT(strlen(it.description), 0);
        // lo mac address is always 0 but it has ip
        // other interfaces may not be connected
        if (string(it.description) == "lo") {
            BOOST_FAIL("loopback adapters shouldn't appear");
        } else {
            // check mac address are not all zero
            bool mac_is_0 = true;
            for (int j = 0; j < 6; j++) {
                mac_is_0 = mac_is_0 || (it.mac_address[j] != 0);
            }
            BOOST_CHECK_MESSAGE(mac_is_0, "Mac address for interface " << it.description << " is 0");
        }
    }
}
}  // namespace test
}  // namespace os
}  // namespace license
test/library/os_linux_test.cpp
New file
@@ -0,0 +1,43 @@
#define BOOST_TEST_MODULE os_linux_test
#include <string>
#include <iostream>
#include <boost/test/unit_test.hpp>
#include <licensecc_properties.h>
#include <licensecc_properties_test.h>
#include "../../src/library/base/StringUtils.h"
#include "../../src/library/os/os.h"
#include "../../src/library/os/execution_environment.hpp"
namespace license {
namespace test {
using namespace std;
using namespace os;
BOOST_AUTO_TEST_CASE(read_disk_id) {
    os::ExecutionEnvironment exec_env;
    os::VIRTUALIZATION virt = exec_env.getVirtualization();
    if (virt == VIRTUALIZATION::NONE || virt == VIRTUALIZATION::VM) {
        DiskInfo *diskInfos = NULL;
        size_t disk_info_size = 0;
        FUNCTION_RETURN result = getDiskInfos(NULL, &disk_info_size);
        BOOST_CHECK_EQUAL(result, FUNC_RET_OK);
        BOOST_CHECK_GT(disk_info_size, 0);
        diskInfos = (DiskInfo *)malloc(sizeof(DiskInfo) * disk_info_size);
        result = getDiskInfos(diskInfos, &disk_info_size);
        BOOST_CHECK_EQUAL(result, FUNC_RET_OK);
        BOOST_CHECK_GT(mstrnlen_s(diskInfos[0].device, sizeof(diskInfos[0].device)), 0);
        BOOST_CHECK_GT(mstrnlen_s(diskInfos[0].label, sizeof diskInfos[0].label), 0);
        BOOST_CHECK_GT(diskInfos[0].disk_sn[0], 0);
        free(diskInfos);
    } else if (virt == VIRTUALIZATION::CONTAINER) {
        // docker or lxc diskInfo is not meaningful
        DiskInfo *diskInfos = NULL;
        size_t disk_info_size = 0;
        FUNCTION_RETURN result = getDiskInfos(NULL, &disk_info_size);
        BOOST_CHECK_EQUAL(result, FUNC_RET_NOT_AVAIL);
    }
}
}  // namespace test
}  // namespace license