diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..4005d50
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,54 @@
+#cmake_minimum_required(VERSION 3.5)
+project(verify-policy)
+
+set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
+include(Version)
+include(Package)
+
+add_definitions(-D_GNU_SOURCE)
+set(CMAKE_CXX_STANDARD 11)
+set(CMAKE_C_STANDARD 11)
+
+if(NOT CMAKE_BUILD_TYPE)
+ set(CMAKE_BUILD_TYPE RelWithDebInfo)
+endif()
+
+if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
+ set (CMAKE_INSTALL_PREFIX "/home/mesasoft/tfe" CACHE PATH "default install path" FORCE )
+endif()
+
+# Global compile options
+option(ENABLE_PIC "Generate position independent code (necessary for shared libraries)" TRUE)
+option(ENABLE_WARNING_ALL "Enable all optional warnings which are desirable for normal code" TRUE)
+option(ENABLE_SANITIZE_ADDRESS "Enable AddressSanitizer" FALSE)
+option(ENABLE_SANITIZE_THREAD "Enable ThreadSanitizer" FALSE)
+
+if(ENABLE_WARNING_ALL)
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
+endif()
+
+if(ENABLE_SANITIZE_ADDRESS)
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fno-omit-frame-pointer")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer")
+ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lasan")
+elseif(ENABLE_SANITIZE_THREAD)
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=thread -fno-omit-frame-pointer")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=thread -fno-omit-frame-pointer")
+ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lasan")
+endif()
+
+if(ENABLE_SANITIZE_ADDRESS AND ENABLE_SANITIZE_THREAD)
+ message(WARNING "Both ENABLE_SANITIZE_ADDRESS and ENABLE_SANITIZE_THREAD set, only ENABLE_SANITIZE_ADDRESS effected.")
+endif()
+
+add_custom_target("install-program" COMMAND ${CMAKE_COMMAND} ARGS -DCOMPONENT=Program -P cmake_install.cmake)
+add_custom_target("install-profile" COMMAND ${CMAKE_COMMAND} ARGS -DCOMPONENT=Profile -P cmake_install.cmake)
+
+enable_testing()
+#add_subdirectory(conf)
+#add_subdirectory(resource)
+add_subdirectory(vendor)
+add_subdirectory(common)
+add_subdirectory(platform)
+add_subdirectory(scan)
diff --git a/autorevision.sh b/autorevision.sh
new file mode 100644
index 0000000..3baa179
--- /dev/null
+++ b/autorevision.sh
@@ -0,0 +1,1268 @@
+#!/bin/sh
+
+# Copyright (c) 2012 - 2016 dak180 and contributors. See
+# https://opensource.org/licenses/mit-license.php or the included
+# COPYING.md for licence terms.
+#
+# autorevision - extracts metadata about the head version from your
+# repository.
+
+# Usage message.
+arUsage() {
+ cat > "/dev/stderr" << EOF
+usage: autorevision {-t output-type | -s symbol} [-o cache-file [-f] ] [-V]
+ Options include:
+ -t output-type = specify output type
+ -s symbol = specify symbol output
+ -o cache-file = specify cache file location
+ -f = force the use of cache data
+ -U = check for untracked files in svn
+ -V = emit version and exit
+ -? = help message
+
+The following are valid output types:
+ clojure = clojure file
+ c = C/C++ file
+ h = Header for use with c/c++
+ hpp = Alternate C++ header strings with namespace
+ ini = INI file
+ java = Java file
+ javaprop = Java properties file
+ js = javascript file
+ json = JSON file
+ lua = Lua file
+ m4 = m4 file
+ matlab = matlab file
+ octave = octave file
+ php = PHP file
+ pl = Perl file
+ py = Python file
+ rpm = rpm file
+ scheme = scheme file
+ sh = Bash sytax
+ swift = Swift file
+ tex = (La)TeX file
+ xcode = Header useful for populating info.plist files
+ cmake = CMake file
+
+
+The following are valid symbols:
+ VCS_TYPE
+ VCS_BASENAME
+ VCS_UUID
+ VCS_NUM
+ VCS_DATE
+ VCS_BRANCH
+ VCS_TAG
+ VCS_TICK
+ VCS_EXTRA
+ VCS_FULL_HASH
+ VCS_SHORT_HASH
+ VCS_WC_MODIFIED
+ VCS_ACTION_STAMP
+EOF
+ exit 1
+}
+
+# Config
+ARVERSION="&&ARVERSION&&"
+TARGETFILE="/dev/stdout"
+while getopts ":t:o:s:VfU" OPTION; do
+ case "${OPTION}" in
+ t)
+ AFILETYPE="${OPTARG}"
+ ;;
+ o)
+ CACHEFILE="${OPTARG}"
+ ;;
+ f)
+ CACHEFORCE="1"
+ ;;
+ s)
+ VAROUT="${OPTARG}"
+ ;;
+ U)
+ UNTRACKEDFILES="1"
+ ;;
+ V)
+ echo "autorevision ${ARVERSION}"
+ exit 0
+ ;;
+ ?)
+ # If an unknown flag is used (or -?):
+ arUsage
+ ;;
+ esac
+done
+
+if [ ! -z "${VAROUT}" ] && [ ! -z "${AFILETYPE}" ]; then
+ # If both -s and -t are specified:
+ echo "error: Improper argument combination." 1>&2
+ exit 1
+elif [ -z "${VAROUT}" ] && [ -z "${AFILETYPE}" ]; then
+ # If neither -s or -t are specified:
+ arUsage
+elif [ -z "${CACHEFILE}" ] && [ "${CACHEFORCE}" = "1" ]; then
+ # If -f is specified without -o:
+ arUsage
+elif [ ! -f "${CACHEFILE}" ] && [ "${CACHEFORCE}" = "1" ]; then
+ # If we are forced to use the cache but it does not exist.
+ echo "error: Cache forced but no cache found." 1>&2
+ exit 1
+fi
+
+# Make sure that the path we are given is one we can source
+# (dash, we are looking at you).
+if [ ! -z "${CACHEFILE}" ] && ! echo "${CACHEFILE}" | grep -q '^\.*/'; then
+ CACHEFILE="./${CACHEFILE}"
+fi
+
+GENERATED_HEADER="Generated by autorevision - do not hand-hack!"
+
+# Functions to extract data from different repo types.
+# For git repos
+# shellcheck disable=SC2039,SC2164,SC2155
+gitRepo() {
+ local oldPath="${PWD}"
+
+ cd "$(git rev-parse --show-toplevel)"
+
+ VCS_TYPE="git"
+
+ VCS_BASENAME="$(basename "${PWD}")"
+
+ VCS_UUID="$(git rev-list --max-parents=0 --date-order --reverse HEAD 2>/dev/null | sed -n 1p)"
+ if [ -z "${VCS_UUID}" ]; then
+ VCS_UUID="$(git rev-list --topo-order HEAD | tail -n 1)"
+ fi
+
+ # Is the working copy clean?
+ test -z "$(git status --untracked-files=normal --porcelain)"
+ VCS_WC_MODIFIED="${?}"
+
+ # Enumeration of changesets
+ VCS_NUM="$(git rev-list --count HEAD 2>/dev/null)"
+ if [ -z "${VCS_NUM}" ]; then
+ echo "warning: Counting the number of revisions may be slower due to an outdated git version less than 1.7.2.3. If something breaks, please update it." 1>&2
+ VCS_NUM="$(git rev-list HEAD | wc -l)"
+ fi
+
+ # This may be a git-svn remote. If so, report the Subversion revision.
+ if [ -z "$(git config svn-remote.svn.url 2>/dev/null)" ]; then
+ # The full revision hash
+ VCS_FULL_HASH="$(git rev-parse HEAD)"
+
+ # The short hash
+ VCS_SHORT_HASH="$(echo "${VCS_FULL_HASH}" | cut -b 1-7)"
+ else
+ # The git-svn revision number
+ VCS_FULL_HASH="$(git svn find-rev HEAD)"
+ VCS_SHORT_HASH="${VCS_FULL_HASH}"
+ fi
+
+ # Current branch
+ VCS_BRANCH="$(git rev-parse --symbolic-full-name --verify "$(git name-rev --name-only --no-undefined HEAD 2>/dev/null)" 2>/dev/null | sed -e 's:refs/heads/::' | sed -e 's:refs/::')"
+
+ # Cache the description
+ local DESCRIPTION="$(git describe --long --tags 2>/dev/null)"
+
+ # Current or last tag ancestor (empty if no tags)
+ VCS_TAG="$(echo "${DESCRIPTION}" | sed -e "s:-g${VCS_SHORT_HASH}\$::" -e 's:-[0-9]*$::')"
+
+ # Distance to last tag or an alias of VCS_NUM if there is no tag
+ if [ ! -z "${DESCRIPTION}" ]; then
+ VCS_TICK="$(echo "${DESCRIPTION}" | sed -e "s:${VCS_TAG}-::" -e "s:-g${VCS_SHORT_HASH}::")"
+ else
+ VCS_TICK="${VCS_NUM}"
+ fi
+
+ # Date of the current commit
+ VCS_DATE="$(TZ=UTC git show -s --date=iso-strict-local --pretty=format:%ad | sed -e 's|+00:00|Z|')"
+ if [ -z "${VCS_DATE}" ]; then
+ echo "warning: Action stamps require git version 2.7+." 1>&2
+ VCS_DATE="$(git log -1 --pretty=format:%ci | sed -e 's: :T:' -e 's: ::' -e 's|+00:00|Z|')"
+ local ASdis="1"
+ fi
+
+ # Action Stamp
+ if [ -z "${ASdis}" ]; then
+ VCS_ACTION_STAMP="${VCS_DATE}!$(git show -s --pretty=format:%cE)"
+ else
+ VCS_ACTION_STAMP=""
+ fi
+
+ cd "${oldPath}"
+}
+
+# For hg repos
+# shellcheck disable=SC2039,SC2164
+hgRepo() {
+ local oldPath="${PWD}"
+
+ cd "$(hg root)"
+
+ VCS_TYPE="hg"
+
+ VCS_BASENAME="$(basename "${PWD}")"
+
+ VCS_UUID="$(hg log -r "0" -l 1 --template '{node}\n')"
+
+ # Is the working copy clean?
+ test -z "$(hg status -duram)"
+ VCS_WC_MODIFIED="${?}"
+
+ # Enumeration of changesets
+ VCS_NUM="$(hg id -n | tr -d '+')"
+
+ # The full revision hash
+ VCS_FULL_HASH="$(hg log -r "${VCS_NUM}" -l 1 --template '{node}\n')"
+
+ # The short hash
+ VCS_SHORT_HASH="$(hg id -i | tr -d '+')"
+
+ # Current bookmark (bookmarks are roughly equivalent to git's branches)
+ # or branch if no bookmark
+ VCS_BRANCH="$(hg id -B | cut -d ' ' -f 1)"
+ # Fall back to the branch if there are no bookmarks
+ if [ -z "${VCS_BRANCH}" ]; then
+ VCS_BRANCH="$(hg id -b)"
+ fi
+
+ # Current or last tag ancestor (excluding auto tags, empty if no tags)
+ VCS_TAG="$(hg log -r "${VCS_NUM}" -l 1 --template '{latesttag}\n' 2>/dev/null | sed -e 's:qtip::' -e 's:tip::' -e 's:qbase::' -e 's:qparent::' -e "s:$(hg --config 'extensions.color=' --config 'extensions.mq=' --color never qtop 2>/dev/null)::" | cut -d ' ' -f 1)"
+
+ # Distance to last tag or an alias of VCS_NUM if there is no tag
+ if [ ! -z "${VCS_TAG}" ]; then
+ VCS_TICK="$(hg log -r "${VCS_NUM}" -l 1 --template '{latesttagdistance}\n' 2>/dev/null)"
+ else
+ VCS_TICK="${VCS_NUM}"
+ fi
+
+ # Date of the current commit
+ VCS_DATE="$(hg log -r "${VCS_NUM}" -l 1 --template '{date|isodatesec}\n' 2>/dev/null | sed -e 's: :T:' -e 's: ::' -e 's|+00:00|Z|')"
+
+ # Action Stamp
+ VCS_ACTION_STAMP="$(TZ=UTC hg log -r "${VCS_NUM}" -l 1 --template '{date|localdate|rfc3339date}\n' 2>/dev/null | sed -e 's|+00:00|Z|')!$(hg log -r "${VCS_NUM}" -l 1 --template '{author|email}\n' 2>/dev/null)"
+
+ cd "${oldPath}"
+}
+
+# For bzr repos
+# shellcheck disable=SC2039,SC2164
+bzrRepo() {
+ local oldPath="${PWD}"
+
+ cd "$(bzr root)"
+
+ VCS_TYPE="bzr"
+
+ VCS_BASENAME="$(basename "${PWD}")"
+
+ # Currently unimplemented because more investigation is needed.
+ VCS_UUID=""
+
+ # Is the working copy clean?
+ bzr version-info --custom --template='{clean}\n' | grep -q '1'
+ VCS_WC_MODIFIED="${?}"
+
+ # Enumeration of changesets
+ VCS_NUM="$(bzr revno)"
+
+ # The full revision hash
+ VCS_FULL_HASH="$(bzr version-info --custom --template='{revision_id}\n')"
+
+ # The short hash
+ VCS_SHORT_HASH="${VCS_NUM}"
+
+ # Nick of the current branch
+ VCS_BRANCH="$(bzr nick)"
+
+ # Current or last tag ancestor (excluding auto tags, empty if no tags)
+ VCS_TAG="$(bzr tags --sort=time | sed '/?$/d' | tail -n1 | cut -d ' ' -f1)"
+
+ # Distance to last tag or an alias of VCS_NUM if there is no tag
+ if [ ! -z "${VCS_TAG}" ]; then
+ VCS_TICK="$(bzr log --line -r "tag:${VCS_TAG}.." | tail -n +2 | wc -l | sed -e 's:^ *::')"
+ else
+ VCS_TICK="${VCS_NUM}"
+ fi
+
+ # Date of the current commit
+ VCS_DATE="$(bzr version-info --custom --template='{date}\n' | sed -e 's: :T:' -e 's: ::')"
+
+ # Action Stamp
+ # Currently unimplemented because more investigation is needed.
+ VCS_ACTION_STAMP=""
+
+ cd "${oldPath}"
+}
+
+# For svn repos
+# shellcheck disable=SC2039,SC2164,SC2155
+svnRepo() {
+ local oldPath="${PWD}"
+
+ VCS_TYPE="svn"
+
+ case "${PWD}" in
+ /*trunk*|/*branches*|/*tags*)
+ local fn="${PWD}"
+ while [ "$(basename "${fn}")" != 'trunk' ] && [ "$(basename "${fn}")" != 'branches' ] && [ "$(basename "${fn}")" != 'tags' ] && [ "$(basename "${fn}")" != '/' ]; do
+ local fn="$(dirname "${fn}")"
+ done
+ local fn="$(dirname "${fn}")"
+ if [ "${fn}" = '/' ]; then
+ VCS_BASENAME="$(basename "${PWD}")"
+ else
+ VCS_BASENAME="$(basename "${fn}")"
+ fi
+ ;;
+ *) VCS_BASENAME="$(basename "${PWD}")" ;;
+ esac
+
+ VCS_UUID="$(svn info --xml | sed -n -e 's:::' -e 's:::p')"
+
+ # Cache svnversion output
+ local SVNVERSION="$(svnversion)"
+
+ # Is the working copy clean?
+ echo "${SVNVERSION}" | grep -q "M"
+ case "${?}" in
+ 0)
+ VCS_WC_MODIFIED="1"
+ ;;
+ 1)
+ if [ ! -z "${UNTRACKEDFILES}" ]; then
+ # `svnversion` does not detect untracked files and `svn status` is really slow, so only run it if we really have to.
+ if [ -z "$(svn status)" ]; then
+ VCS_WC_MODIFIED="0"
+ else
+ VCS_WC_MODIFIED="1"
+ fi
+ else
+ VCS_WC_MODIFIED="0"
+ fi
+ ;;
+ esac
+
+ # Enumeration of changesets
+ VCS_NUM="$(echo "${SVNVERSION}" | cut -d : -f 1 | sed -e 's:M::' -e 's:S::' -e 's:P::')"
+
+ # The full revision hash
+ VCS_FULL_HASH="${SVNVERSION}"
+
+ # The short hash
+ VCS_SHORT_HASH="${VCS_NUM}"
+
+ # Current branch
+ case "${PWD}" in
+ /*trunk*|/*branches*|/*tags*)
+ local lastbase=""
+ local fn="${PWD}"
+ while :
+ do
+ base="$(basename "${fn}")"
+ if [ "${base}" = 'trunk' ]; then
+ VCS_BRANCH='trunk'
+ break
+ elif [ "${base}" = 'branches' ] || [ "${base}" = 'tags' ]; then
+ VCS_BRANCH="${lastbase}"
+ break
+ elif [ "${base}" = '/' ]; then
+ VCS_BRANCH=""
+ break
+ fi
+ local lastbase="${base}"
+ local fn="$(dirname "${fn}")"
+ done
+ ;;
+ *) VCS_BRANCH="" ;;
+ esac
+
+ # Current or last tag ancestor (empty if no tags). But "current
+ # tag" can't be extracted reliably because Subversion doesn't
+ # have tags the way other VCSes do.
+ VCS_TAG=""
+ VCS_TICK=""
+
+ # Date of the current commit
+ VCS_DATE="$(svn info --xml | sed -n -e 's:::' -e 's:::p')"
+
+ # Action Stamp
+ VCS_ACTION_STAMP="${VCS_DATE}!$(svn log --xml -l 1 -r "${VCS_SHORT_HASH}" | sed -n -e 's:::' -e 's:::p')"
+
+ cd "${oldPath}"
+}
+
+
+# Functions to output data in different formats.
+# For bash output
+shOutput() {
+ cat > "${TARGETFILE}" << EOF
+# ${GENERATED_HEADER}
+
+VCS_TYPE="${VCS_TYPE}"
+VCS_BASENAME="${VCS_BASENAME}"
+VCS_UUID="${VCS_UUID}"
+VCS_NUM="${VCS_NUM}"
+VCS_DATE="${VCS_DATE}"
+VCS_BRANCH="${VCS_BRANCH}"
+VCS_TAG="${VCS_TAG}"
+VCS_TICK="${VCS_TICK}"
+VCS_EXTRA="${VCS_EXTRA}"
+
+VCS_ACTION_STAMP="${VCS_ACTION_STAMP}"
+VCS_FULL_HASH="${VCS_FULL_HASH}"
+VCS_SHORT_HASH="${VCS_SHORT_HASH}"
+
+VCS_WC_MODIFIED="${VCS_WC_MODIFIED}"
+
+# end
+EOF
+}
+
+# For source C output
+cOutput() {
+ cat > "${TARGETFILE}" << EOF
+/* ${GENERATED_HEADER} */
+
+const char *VCS_TYPE = "${VCS_TYPE}";
+const char *VCS_BASENAME = "${VCS_BASENAME}";
+const char *VCS_UUID = "${VCS_UUID}";
+const int VCS_NUM = ${VCS_NUM};
+const char *VCS_DATE = "${VCS_DATE}";
+const char *VCS_BRANCH = "${VCS_BRANCH}";
+const char *VCS_TAG = "${VCS_TAG}";
+const int VCS_TICK = ${VCS_TICK};
+const char *VCS_EXTRA = "${VCS_EXTRA}";
+
+const char *VCS_ACTION_STAMP = "${VCS_ACTION_STAMP}";
+const char *VCS_FULL_HASH = "${VCS_FULL_HASH}";
+const char *VCS_SHORT_HASH = "${VCS_SHORT_HASH}";
+
+const int VCS_WC_MODIFIED = ${VCS_WC_MODIFIED};
+
+/* end */
+EOF
+}
+
+# For header output
+hOutput() {
+ cat > "${TARGETFILE}" << EOF
+/* ${GENERATED_HEADER} */
+#ifndef AUTOREVISION_H
+#define AUTOREVISION_H
+
+#define VCS_TYPE "${VCS_TYPE}"
+#define VCS_BASENAME "${VCS_BASENAME}"
+#define VCS_UUID "${VCS_UUID}"
+#define VCS_NUM ${VCS_NUM}
+#define VCS_DATE "${VCS_DATE}"
+#define VCS_BRANCH "${VCS_BRANCH}"
+#define VCS_TAG "${VCS_TAG}"
+#define VCS_TICK ${VCS_TICK}
+#define VCS_EXTRA "${VCS_EXTRA}"
+
+#define VCS_ACTION_STAMP "${VCS_ACTION_STAMP}"
+#define VCS_FULL_HASH "${VCS_FULL_HASH}"
+#define VCS_SHORT_HASH "${VCS_SHORT_HASH}"
+
+#define VCS_WC_MODIFIED ${VCS_WC_MODIFIED}
+
+#endif
+
+/* end */
+EOF
+}
+
+# A header output for use with xcode to populate info.plist strings
+xcodeOutput() {
+ cat > "${TARGETFILE}" << EOF
+/* ${GENERATED_HEADER} */
+#ifndef AUTOREVISION_H
+#define AUTOREVISION_H
+
+#define VCS_TYPE ${VCS_TYPE}
+#define VCS_BASENAME ${VCS_BASENAME}
+#define VCS_UUID ${VCS_UUID}
+#define VCS_NUM ${VCS_NUM}
+#define VCS_DATE ${VCS_DATE}
+#define VCS_BRANCH ${VCS_BRANCH}
+#define VCS_TAG ${VCS_TAG}
+#define VCS_TICK ${VCS_TICK}
+#define VCS_EXTRA ${VCS_EXTRA}
+
+#define VCS_ACTION_STAMP ${VCS_ACTION_STAMP}
+#define VCS_FULL_HASH ${VCS_FULL_HASH}
+#define VCS_SHORT_HASH ${VCS_SHORT_HASH}
+
+#define VCS_WC_MODIFIED ${VCS_WC_MODIFIED}
+
+#endif
+
+/* end */
+EOF
+}
+
+# For Swift output
+swiftOutput() {
+ case "${VCS_WC_MODIFIED}" in
+ 0) VCS_WC_MODIFIED="false" ;;
+ 1) VCS_WC_MODIFIED="true" ;;
+ esac
+ # For values that may not exist depending on the type of repo we
+ # have read from, set them to `nil` when they are empty.
+ if [ -z "${VCS_UUID}" ]; then
+ VCS_UUID="nil"
+ else
+ VCS_UUID="\"${VCS_UUID}\""
+ fi
+ if [ -z "${VCS_TAG}" ]; then
+ VCS_TAG="nil"
+ else
+ VCS_TAG="\"${VCS_TAG}\""
+ fi
+ : "${VCS_TICK:="nil"}"
+ if [ -z "${VCS_EXTRA}" ]; then
+ VCS_EXTRA="nil"
+ else
+ VCS_EXTRA="\"${VCS_EXTRA}\""
+ fi
+ if [ -z "${VCS_ACTION_STAMP}" ]; then
+ VCS_ACTION_STAMP="nil"
+ else
+ VCS_ACTION_STAMP="\"${VCS_ACTION_STAMP}\""
+ fi
+ cat > "${TARGETFILE}" << EOF
+/* ${GENERATED_HEADER} */
+
+let VCS_TYPE = "${VCS_TYPE}"
+let VCS_BASENAME = "${VCS_BASENAME}"
+let VCS_UUID: String? = ${VCS_UUID}
+let VCS_NUM: Int = ${VCS_NUM}
+let VCS_DATE = "${VCS_DATE}"
+let VCS_BRANCH: String = "${VCS_BRANCH}"
+let VCS_TAG: String? = ${VCS_TAG}
+let VCS_TICK: Int? = ${VCS_TICK}
+let VCS_EXTRA: String? = ${VCS_EXTRA}
+
+let VCS_ACTION_STAMP: String? = ${VCS_ACTION_STAMP}
+let VCS_FULL_HASH: String = "${VCS_FULL_HASH}"
+let VCS_SHORT_HASH: String = "${VCS_SHORT_HASH}"
+
+let VCS_WC_MODIFIED: Bool = ${VCS_WC_MODIFIED}
+
+/* end */
+EOF
+}
+
+# For Python output
+pyOutput() {
+ case "${VCS_WC_MODIFIED}" in
+ 0) VCS_WC_MODIFIED="False" ;;
+ 1) VCS_WC_MODIFIED="True" ;;
+ esac
+ cat > "${TARGETFILE}" << EOF
+# ${GENERATED_HEADER}
+
+VCS_TYPE = "${VCS_TYPE}"
+VCS_BASENAME = "${VCS_BASENAME}"
+VCS_UUID = "${VCS_UUID}"
+VCS_NUM = ${VCS_NUM}
+VCS_DATE = "${VCS_DATE}"
+VCS_BRANCH = "${VCS_BRANCH}"
+VCS_TAG = "${VCS_TAG}"
+VCS_TICK = ${VCS_TICK}
+VCS_EXTRA = "${VCS_EXTRA}"
+
+VCS_ACTION_STAMP = "${VCS_ACTION_STAMP}"
+VCS_FULL_HASH = "${VCS_FULL_HASH}"
+VCS_SHORT_HASH = "${VCS_SHORT_HASH}"
+
+VCS_WC_MODIFIED = ${VCS_WC_MODIFIED}
+
+# end
+EOF
+}
+
+# For Perl output
+plOutput() {
+ cat << EOF
+# ${GENERATED_HEADER}
+
+\$VCS_TYPE = '${VCS_TYPE}';
+\$VCS_BASENAME = '${VCS_BASENAME}';
+\$VCS_UUID = '${VCS_UUID}';
+\$VCS_NUM = ${VCS_NUM};
+\$VCS_DATE = '${VCS_DATE}';
+\$VCS_BRANCH = '${VCS_BRANCH}';
+\$VCS_TAG = '${VCS_TAG}';
+\$VCS_TICK = ${VCS_TICK};
+\$VCS_EXTRA = '${VCS_EXTRA}';
+
+\$VCS_ACTION_STAMP = '${VCS_ACTION_STAMP}';
+\$VCS_FULL_HASH = '${VCS_FULL_HASH}';
+\$VCS_SHORT_HASH = '${VCS_SHORT_HASH}';
+
+\$VCS_WC_MODIFIED = ${VCS_WC_MODIFIED};
+
+# end
+1;
+EOF
+}
+
+# For lua output
+luaOutput() {
+ case "${VCS_WC_MODIFIED}" in
+ 0) VCS_WC_MODIFIED="false" ;;
+ 1) VCS_WC_MODIFIED="true" ;;
+ esac
+ cat > "${TARGETFILE}" << EOF
+-- ${GENERATED_HEADER}
+
+VCS_TYPE = "${VCS_TYPE}"
+VCS_BASENAME = "${VCS_BASENAME}"
+VCS_UUID = "${VCS_UUID}"
+VCS_NUM = ${VCS_NUM}
+VCS_DATE = "${VCS_DATE}"
+VCS_BRANCH = "${VCS_BRANCH}"
+VCS_TAG = "${VCS_TAG}"
+VCS_TICK = ${VCS_TICK}
+VCS_EXTRA = "${VCS_EXTRA}"
+
+VCS_ACTION_STAMP = "${VCS_ACTION_STAMP}"
+VCS_FULL_HASH = "${VCS_FULL_HASH}"
+VCS_SHORT_HASH = "${VCS_SHORT_HASH}"
+
+VCS_WC_MODIFIED = ${VCS_WC_MODIFIED}
+
+-- end
+EOF
+}
+
+# For php output
+phpOutput() {
+ case "${VCS_WC_MODIFIED}" in
+ 0) VCS_WC_MODIFIED="false" ;;
+ 1) VCS_WC_MODIFIED="true" ;;
+ esac
+ cat > "${TARGETFILE}" << EOF
+ "${VCS_TYPE}",
+ "VCS_BASENAME" => "${VCS_BASENAME}",
+ "VCS_UUID" => "${VCS_UUID}",
+ "VCS_NUM" => ${VCS_NUM},
+ "VCS_DATE" => "${VCS_DATE}",
+ "VCS_BRANCH" => "${VCS_BRANCH}",
+ "VCS_TAG" => "${VCS_TAG}",
+ "VCS_TICK" => ${VCS_TICK},
+ "VCS_EXTRA" => "${VCS_EXTRA}",
+ "VCS_ACTION_STAMP" => "${VCS_ACTION_STAMP}",
+ "VCS_FULL_HASH" => "${VCS_FULL_HASH}",
+ "VCS_SHORT_HASH" => "${VCS_SHORT_HASH}",
+ "VCS_WC_MODIFIED" => ${VCS_WC_MODIFIED}
+);
+
+# end
+?>
+EOF
+}
+
+# For ini output
+iniOutput() {
+ case "${VCS_WC_MODIFIED}" in
+ 0) VCS_WC_MODIFIED="false" ;;
+ 1) VCS_WC_MODIFIED="true" ;;
+ esac
+ cat > "${TARGETFILE}" << EOF
+; ${GENERATED_HEADER}
+[VCS]
+VCS_TYPE = "${VCS_TYPE}"
+VCS_BASENAME = "${VCS_BASENAME}"
+VCS_UUID = "${VCS_UUID}"
+VCS_NUM = ${VCS_NUM}
+VCS_DATE = "${VCS_DATE}"
+VCS_BRANCH = "${VCS_BRANCH}"
+VCS_TAG = "${VCS_TAG}"
+VCS_TICK = ${VCS_TICK}
+VCS_EXTRA = "${VCS_EXTRA}"
+VCS_ACTION_STAMP = "${VCS_ACTION_STAMP}"
+VCS_FULL_HASH = "${VCS_FULL_HASH}"
+VCS_SHORT_HASH = "${VCS_SHORT_HASH}"
+VCS_WC_MODIFIED = ${VCS_WC_MODIFIED}
+; end
+EOF
+}
+
+# For javascript output
+jsOutput() {
+ case "${VCS_WC_MODIFIED}" in
+ 1) VCS_WC_MODIFIED="true" ;;
+ 0) VCS_WC_MODIFIED="false" ;;
+ esac
+ cat > "${TARGETFILE}" << EOF
+/** ${GENERATED_HEADER} */
+
+var autorevision = {
+ VCS_TYPE: "${VCS_TYPE}",
+ VCS_BASENAME: "${VCS_BASENAME}",
+ VCS_UUID: "${VCS_UUID}",
+ VCS_NUM: ${VCS_NUM},
+ VCS_DATE: "${VCS_DATE}",
+ VCS_BRANCH: "${VCS_BRANCH}",
+ VCS_TAG: "${VCS_TAG}",
+ VCS_TICK: ${VCS_TICK},
+ VCS_EXTRA: "${VCS_EXTRA}",
+
+ VCS_ACTION_STAMP: "${VCS_ACTION_STAMP}",
+ VCS_FULL_HASH: "${VCS_FULL_HASH}",
+ VCS_SHORT_HASH: "${VCS_SHORT_HASH}",
+
+ VCS_WC_MODIFIED: ${VCS_WC_MODIFIED}
+};
+
+/** Node.js compatibility */
+if (typeof module !== 'undefined') {
+ module.exports = autorevision;
+}
+
+/** end */
+EOF
+}
+
+# For JSON output
+jsonOutput() {
+ case "${VCS_WC_MODIFIED}" in
+ 1) VCS_WC_MODIFIED="true" ;;
+ 0) VCS_WC_MODIFIED="false" ;;
+ esac
+ cat > "${TARGETFILE}" << EOF
+{
+ "_comment": "${GENERATED_HEADER}",
+ "VCS_TYPE": "${VCS_TYPE}",
+ "VCS_BASENAME": "${VCS_BASENAME}",
+ "VCS_UUID": "${VCS_UUID}",
+ "VCS_NUM": ${VCS_NUM},
+ "VCS_DATE": "${VCS_DATE}",
+ "VCS_BRANCH":"${VCS_BRANCH}",
+ "VCS_TAG": "${VCS_TAG}",
+ "VCS_TICK": ${VCS_TICK},
+ "VCS_EXTRA": "${VCS_EXTRA}",
+
+ "VCS_ACTION_STAMP": "${VCS_ACTION_STAMP}",
+ "VCS_FULL_HASH": "${VCS_FULL_HASH}",
+ "VCS_SHORT_HASH": "${VCS_SHORT_HASH}",
+
+ "VCS_WC_MODIFIED": ${VCS_WC_MODIFIED}
+}
+EOF
+}
+
+# For Java output
+javaOutput() {
+ case "${VCS_WC_MODIFIED}" in
+ 1) VCS_WC_MODIFIED="true" ;;
+ 0) VCS_WC_MODIFIED="false" ;;
+ esac
+ cat > "${TARGETFILE}" << EOF
+/* ${GENERATED_HEADER} */
+
+public class autorevision {
+ public static final String VCS_TYPE = "${VCS_TYPE}";
+ public static final String VCS_BASENAME = "${VCS_BASENAME}";
+ public static final String VCS_UUID = "${VCS_UUID}";
+ public static final long VCS_NUM = ${VCS_NUM};
+ public static final String VCS_DATE = "${VCS_DATE}";
+ public static final String VCS_BRANCH = "${VCS_BRANCH}";
+ public static final String VCS_TAG = "${VCS_TAG}";
+ public static final long VCS_TICK = ${VCS_TICK};
+ public static final String VCS_EXTRA = "${VCS_EXTRA}";
+
+ public static final String VCS_ACTION_STAMP = "${VCS_ACTION_STAMP}";
+ public static final String VCS_FULL_HASH = "${VCS_FULL_HASH}";
+ public static final String VCS_SHORT_HASH = "${VCS_SHORT_HASH}";
+
+ public static final boolean VCS_WC_MODIFIED = ${VCS_WC_MODIFIED};
+}
+EOF
+}
+
+# For Java properties output
+javapropOutput() {
+ case "${VCS_WC_MODIFIED}" in
+ 1) VCS_WC_MODIFIED="true" ;;
+ 0) VCS_WC_MODIFIED="false" ;;
+ esac
+ cat > "${TARGETFILE}" << EOF
+# ${GENERATED_HEADER}
+
+VCS_TYPE=${VCS_TYPE}
+VCS_BASENAME=${VCS_BASENAME}
+VCS_UUID=${VCS_UUID}
+VCS_NUM=${VCS_NUM}
+VCS_DATE=${VCS_DATE}
+VCS_BRANCH=${VCS_BRANCH}
+VCS_TAG=${VCS_TAG}
+VCS_TICK=${VCS_TICK}
+VCS_EXTRA=${VCS_EXTRA}
+
+VCS_ACTION_STAMP=${VCS_ACTION_STAMP}
+VCS_FULL_HASH=${VCS_FULL_HASH}
+VCS_SHORT_HASH=${VCS_SHORT_HASH}
+
+VCS_WC_MODIFIED=${VCS_WC_MODIFIED}
+EOF
+}
+
+# For m4 output
+m4Output() {
+ cat > "${TARGETFILE}" << EOF
+dnl ${GENERATED_HEADER}
+define(\`VCS_TYPE', \`${VCS_TYPE}')dnl
+define(\`VCS_BASENAME', \`${VCS_BASENAME}')dnl
+define(\`VCS_UUID', \`${VCS_UUID}')dnl
+define(\`VCS_NUM', \`${VCS_NUM}')dnl
+define(\`VCS_DATE', \`${VCS_DATE}')dnl
+define(\`VCS_BRANCH', \`${VCS_BRANCH}')dnl
+define(\`VCS_TAG', \`${VCS_TAG}')dnl
+define(\`VCS_TICK', \`${VCS_TICK}')dnl
+define(\`VCS_EXTRA', \`${VCS_EXTRA}')dnl
+define(\`VCS_ACTIONSTAMP', \`${VCS_ACTION_STAMP}')dnl
+define(\`VCS_FULLHASH', \`${VCS_FULL_HASH}')dnl
+define(\`VCS_SHORTHASH', \`${VCS_SHORT_HASH}')dnl
+define(\`VCS_WC_MODIFIED', \`${VCS_WC_MODIFIED}')dnl
+EOF
+}
+
+# For (La)TeX output
+texOutput() {
+ case "${VCS_WC_MODIFIED}" in
+ 0) VCS_WC_MODIFIED="false" ;;
+ 1) VCS_WC_MODIFIED="true" ;;
+ esac
+ cat > "${TARGETFILE}" << EOF
+% ${GENERATED_HEADER}
+\def \vcsType {${VCS_TYPE}}
+\def \vcsBasename {${VCS_BASENAME}}
+\def \vcsUUID {${VCS_UUID}}
+\def \vcsNum {${VCS_NUM}}
+\def \vcsDate {${VCS_DATE}}
+\def \vcsBranch {${VCS_BRANCH}}
+\def \vcsTag {${VCS_TAG}}
+\def \vcsTick {${VCS_TICK}}
+\def \vcsExtra {${VCS_EXTRA}}
+\def \vcsACTIONSTAMP {${VCS_ACTION_STAMP}}
+\def \vcsFullHash {${VCS_FULL_HASH}}
+\def \vcsShortHash {${VCS_SHORT_HASH}}
+\def \vcsWCModified {${VCS_WC_MODIFIED}}
+\endinput
+EOF
+}
+
+# For scheme output
+schemeOutput() {
+ case "${VCS_WC_MODIFIED}" in
+ 0) VCS_WC_MODIFIED="#f" ;;
+ 1) VCS_WC_MODIFIED="#t" ;;
+ esac
+ cat > "${TARGETFILE}" << EOF
+;; ${GENERATED_HEADER}
+(define VCS_TYPE "${VCS_TYPE}")
+(define VCS_BASENAME "${VCS_BASENAME}")
+(define VCS_UUID "${VCS_UUID}")
+(define VCS_NUM ${VCS_NUM})
+(define VCS_DATE "${VCS_DATE}")
+(define VCS_BRANCH "${VCS_BRANCH}")
+(define VCS_TAG "${VCS_TAG}")
+(define VCS_TICK ${VCS_TICK})
+(define VCS_EXTRA "${VCS_EXTRA}")
+
+(define VCS_ACTION_STAMP "${VCS_ACTION_STAMP}")
+(define VCS_FULL_HASH "${VCS_FULL_HASH}")
+(define VCS_SHORT_HASH "${VCS_SHORT_HASH}")
+
+(define VCS_WC_MODIFIED ${VCS_WC_MODIFIED})
+;; end
+EOF
+}
+
+# For clojure output
+clojureOutput() {
+ case "${VCS_WC_MODIFIED}" in
+ 0) VCS_WC_MODIFIED="false" ;;
+ 1) VCS_WC_MODIFIED="true" ;;
+ esac
+ cat > "${TARGETFILE}" << EOF
+;; ${GENERATED_HEADER}
+(def VCS_TYPE "${VCS_TYPE}")
+(def VCS_BASENAME "${VCS_BASENAME}")
+(def VCS_UUID "${VCS_UUID}")
+(def VCS_NUM ${VCS_NUM})
+(def VCS_DATE "${VCS_DATE}")
+(def VCS_BRANCH "${VCS_BRANCH}")
+(def VCS_TAG "${VCS_TAG}")
+(def VCS_TICK ${VCS_TICK})
+(def VCS_EXTRA "${VCS_EXTRA}")
+
+(def VCS_ACTION_STAMP "${VCS_ACTION_STAMP}")
+(def VCS_FULL_HASH "${VCS_FULL_HASH}")
+(def VCS_SHORT_HASH "${VCS_SHORT_HASH}")
+
+(def VCS_WC_MODIFIED ${VCS_WC_MODIFIED})
+;; end
+EOF
+}
+
+# For rpm spec file output
+rpmOutput() {
+ cat > "${TARGETFILE}" << EOF
+# ${GENERATED_HEADER}
+$([ "${VCS_TYPE}" ] && echo "%define vcs_type ${VCS_TYPE}")
+$([ "${VCS_BASENAME}" ] && echo "%define vcs_basename ${VCS_BASENAME}")
+$([ "${VCS_UUID}" ] && echo "%define vcs_uuid ${VCS_UUID}")
+$([ "${VCS_NUM}" ] && echo "%define vcs_num ${VCS_NUM}")
+$([ "${VCS_DATE}" ] && echo "%define vcs_date ${VCS_DATE}")
+$([ "${VCS_BRANCH}" ] && echo "%define vcs_branch ${VCS_BRANCH}")
+$([ "${VCS_TAG}" ] && echo "%define vcs_tag ${VCS_TAG}")
+$([ "${VCS_TICK}" ] && echo "%define vcs_tick ${VCS_TICK}")
+$([ "${VCS_EXTRA}" ] && echo "%define vcs_extra ${VCS_EXTRA}")
+
+$([ "${VCS_ACTION_STAMP}" ] && echo "%define vcs_action_stamp ${VCS_ACTION_STAMP}")
+$([ "${VCS_FULL_HASH}" ] && echo "%define vcs_full_hash ${VCS_FULL_HASH}")
+$([ "${VCS_SHORT_HASH}" ] && echo "%define vcs_short_hash ${VCS_SHORT_HASH}")
+
+$([ "${VCS_WC_MODIFIED}" ] && echo "%define vcs_wc_modified ${VCS_WC_MODIFIED}")
+# end
+EOF
+}
+
+# shellcheck disable=SC2155,SC2039
+hppOutput() {
+ local NAMESPACE="$(echo "${VCS_BASENAME}" | sed -e 's:_::g' | tr '[:lower:]' '[:upper:]')"
+ cat > "${TARGETFILE}" << EOF
+/* ${GENERATED_HEADER} */
+
+#ifndef ${NAMESPACE}_AUTOREVISION_H
+#define ${NAMESPACE}_AUTOREVISION_H
+
+#include
+
+namespace $(echo "${NAMESPACE}" | tr '[:upper:]' '[:lower:]')
+{
+ const std::string VCS_TYPE = "${VCS_TYPE}";
+ const std::string VCS_BASENAME = "${VCS_BASENAME}";
+ const std::string VCS_UUID = "${VCS_UUID}";
+ const int VCS_NUM = ${VCS_NUM};
+ const std::string VCS_DATE = "${VCS_DATE}";
+ const std::string VCS_BRANCH = "${VCS_BRANCH}";
+ const std::string VCS_TAG = "${VCS_TAG}";
+ const int VCS_TICK = ${VCS_TICK};
+ const std::string VCS_EXTRA = "${VCS_EXTRA}";
+
+ const std::string VCS_ACTION_STAMP = "${VCS_ACTION_STAMP}";
+ const std::string VCS_FULL_HASH = "${VCS_FULL_HASH}";
+ const std::string VCS_SHORT_HASH = "${VCS_SHORT_HASH}";
+
+ const int VCS_WC_MODIFIED = ${VCS_WC_MODIFIED};
+}
+
+#endif
+
+/* end */
+EOF
+}
+
+matlabOutput() {
+ case "${VCS_WC_MODIFIED}" in
+ 0) VCS_WC_MODIFIED="FALSE" ;;
+ 1) VCS_WC_MODIFIED="TRUE" ;;
+ esac
+ cat > "${TARGETFILE}" << EOF
+% ${GENERATED_HEADER}
+
+VCS_TYPE = '${VCS_TYPE}';
+VCS_BASENAME = '${VCS_BASENAME}';
+VCS_UUID = '${VCS_UUID}';
+VCS_NUM = ${VCS_NUM};
+VCS_DATE = '${VCS_DATE}';
+VCS_BRANCH = '${VCS_BRANCH}';
+VCS_TAG = '${VCS_TAG}';
+VCS_TICK = ${VCS_TICK};
+VCS_EXTRA = '${VCS_EXTRA}';
+
+VCS_ACTION_STAMP = '${VCS_ACTION_STAMP}';
+VCS_FULL_HASH = '${VCS_FULL_HASH}';
+VCS_SHORT_HASH = '${VCS_SHORT_HASH}';
+
+VCS_WC_MODIFIED = ${VCS_WC_MODIFIED};
+
+% end
+EOF
+}
+
+octaveOutput() {
+ cat > "${TARGETFILE}" << EOF
+% ${GENERATED_HEADER}
+
+VCS_TYPE = '${VCS_TYPE}';
+VCS_BASENAME = '${VCS_BASENAME}';
+VCS_UUID = '${VCS_UUID}';
+VCS_NUM = ${VCS_NUM};
+VCS_DATE = '${VCS_DATE}';
+VCS_BRANCH = '${VCS_BRANCH}';
+VCS_TAG = '${VCS_TAG}';
+VCS_TICK = ${VCS_TICK};
+VCS_EXTRA = '${VCS_EXTRA}';
+
+VCS_ACTION_STAMP = '${VCS_ACTION_STAMP}';
+VCS_FULL_HASH = '${VCS_FULL_HASH}';
+VCS_SHORT_HASH = '${VCS_SHORT_HASH}';
+
+VCS_WC_MODIFIED = ${VCS_WC_MODIFIED};
+
+% end
+EOF
+}
+
+cmakeOutput() {
+ cat > "${TARGETFILE}" << EOF
+# ${GENERATED_HEADER}
+
+set(VCS_TYPE ${VCS_TYPE})
+set(VCS_BASENAME ${VCS_BASENAME})
+set(VCS_UUID ${VCS_UUID})
+set(VCS_NUM ${VCS_NUM})
+set(VCS_DATE ${VCS_DATE})
+set(VCS_BRANCH ${VCS_BRANCH})
+set(VCS_TAG ${VCS_TAG})
+set(VCS_TICK ${VCS_TICK})
+set(VCS_EXTRA ${VCS_EXTRA})
+
+set(VCS_ACTION_STAMP ${VCS_ACTION_STAMP})
+set(VCS_FULL_HASH ${VCS_FULL_HASH})
+set(VCS_SHORT_HASH ${VCS_SHORT_HASH})
+
+set(VCS_WC_MODIFIED ${VCS_WC_MODIFIED})
+
+# end
+EOF
+}
+
+
+# Helper functions
+# Count path segments
+# shellcheck disable=SC2039
+pathSegment() {
+ local pathz="${1}"
+ local depth="0"
+
+ if [ ! -z "${pathz}" ]; then
+ # Continue until we are at / or there are no path separators left.
+ while [ ! "${pathz}" = "/" ] && [ ! "${pathz}" = "$(echo "${pathz}" | sed -e 's:/::')" ]; do
+ pathz="$(dirname "${pathz}")"
+ depth="$((depth+1))"
+ done
+ fi
+ echo "${depth}"
+}
+
+# Largest of four numbers
+# shellcheck disable=SC2039
+multiCompare() {
+ local larger="${1}"
+ local numA="${2}"
+ local numB="${3}"
+ local numC="${4}"
+
+ [ "${numA}" -gt "${larger}" ] && larger="${numA}"
+ [ "${numB}" -gt "${larger}" ] && larger="${numB}"
+ [ "${numC}" -gt "${larger}" ] && larger="${numC}"
+ echo "${larger}"
+}
+
+# Test for repositories
+# shellcheck disable=SC2155,SC2039
+repoTest() {
+ REPONUM="0"
+ if [ ! -z "$(git rev-parse HEAD 2>/dev/null)" ]; then
+ local gitPath="$(git rev-parse --show-toplevel)"
+ local gitDepth="$(pathSegment "${gitPath}")"
+ REPONUM="$((REPONUM+1))"
+ else
+ local gitDepth="0"
+ fi
+ if [ ! -z "$(hg root 2>/dev/null)" ]; then
+ local hgPath="$(hg root 2>/dev/null)"
+ local hgDepth="$(pathSegment "${hgPath}")"
+ REPONUM="$((REPONUM+1))"
+ else
+ local hgDepth="0"
+ fi
+ if [ ! -z "$(bzr root 2>/dev/null)" ]; then
+ local bzrPath="$(bzr root 2>/dev/null)"
+ local bzrDepth="$(pathSegment "${bzrPath}")"
+ REPONUM="$((REPONUM+1))"
+ else
+ local bzrDepth="0"
+ fi
+ if [ ! -z "$(svn info 2>/dev/null)" ]; then
+ local stringz=""
+ local stringx=""
+ local svnPath="$(svn info --xml | sed -n -e "s:${stringz}::" -e "s:${stringx}::p")"
+ # An old enough svn will not be able give us a path; default
+ # to 1 for that case.
+ if [ -z "${svnPath}" ]; then
+ local svnDepth="1"
+ else
+ local svnDepth="$(pathSegment "${svnPath}")"
+ fi
+ REPONUM="$((REPONUM+1))"
+ else
+ local svnDepth="0"
+ fi
+
+ # Do not do more work then we have to.
+ if [ "${REPONUM}" = "0" ]; then
+ return
+ fi
+
+ # Figure out which repo is the deepest and use it.
+ local wonRepo="$(multiCompare "${gitDepth}" "${hgDepth}" "${bzrDepth}" "${svnDepth}")"
+ if [ "${wonRepo}" = "${gitDepth}" ]; then
+ gitRepo
+ elif [ "${wonRepo}" = "${hgDepth}" ]; then
+ hgRepo
+ elif [ "${wonRepo}" = "${bzrDepth}" ]; then
+ bzrRepo
+ elif [ "${wonRepo}" = "${svnDepth}" ]; then
+ svnRepo
+ fi
+}
+
+
+
+# Detect which repos we are in and gather data.
+# shellcheck source=/dev/null
+if [ -f "${CACHEFILE}" ] && [ "${CACHEFORCE}" = "1" ]; then
+ # When requested only read from the cache to populate our symbols.
+ . "${CACHEFILE}"
+else
+ # If a value is not set through the environment set VCS_EXTRA to nothing.
+ : "${VCS_EXTRA:=""}"
+ repoTest
+
+ if [ -f "${CACHEFILE}" ] && [ "${REPONUM}" = "0" ]; then
+ # We are not in a repo; try to use a previously generated cache to populate our symbols.
+ . "${CACHEFILE}"
+ # Do not overwrite the cache if we know we are not going to write anything new.
+ CACHEFORCE="1"
+ elif [ "${REPONUM}" = "0" ]; then
+ echo "error: No repo or cache detected." 1>&2
+ exit 1
+ fi
+fi
+
+
+# -s output is handled here.
+if [ ! -z "${VAROUT}" ]; then
+ if [ "${VAROUT}" = "VCS_TYPE" ]; then
+ echo "${VCS_TYPE}"
+ elif [ "${VAROUT}" = "VCS_BASENAME" ]; then
+ echo "${VCS_BASENAME}"
+ elif [ "${VAROUT}" = "VCS_NUM" ]; then
+ echo "${VCS_NUM}"
+ elif [ "${VAROUT}" = "VCS_DATE" ]; then
+ echo "${VCS_DATE}"
+ elif [ "${VAROUT}" = "VCS_BRANCH" ]; then
+ echo "${VCS_BRANCH}"
+ elif [ "${VAROUT}" = "VCS_TAG" ]; then
+ echo "${VCS_TAG}"
+ elif [ "${VAROUT}" = "VCS_TICK" ]; then
+ echo "${VCS_TICK}"
+ elif [ "${VAROUT}" = "VCS_FULL_HASH" ]; then
+ echo "${VCS_FULL_HASH}"
+ elif [ "${VAROUT}" = "VCS_SHORT_HASH" ]; then
+ echo "${VCS_SHORT_HASH}"
+ elif [ "${VAROUT}" = "VCS_WC_MODIFIED" ]; then
+ echo "${VCS_WC_MODIFIED}"
+ elif [ "${VAROUT}" = "VCS_ACTION_STAMP" ]; then
+ echo "${VCS_ACTION_STAMP}"
+ else
+ echo "error: Not a valid output symbol." 1>&2
+ exit 1
+ fi
+fi
+
+
+# Detect requested output type and use it.
+if [ ! -z "${AFILETYPE}" ]; then
+ if [ "${AFILETYPE}" = "c" ]; then
+ cOutput
+ elif [ "${AFILETYPE}" = "h" ]; then
+ hOutput
+ elif [ "${AFILETYPE}" = "xcode" ]; then
+ xcodeOutput
+ elif [ "${AFILETYPE}" = "swift" ]; then
+ swiftOutput
+ elif [ "${AFILETYPE}" = "sh" ]; then
+ shOutput
+ elif [ "${AFILETYPE}" = "py" ] || [ "${AFILETYPE}" = "python" ]; then
+ pyOutput
+ elif [ "${AFILETYPE}" = "pl" ] || [ "${AFILETYPE}" = "perl" ]; then
+ plOutput
+ elif [ "${AFILETYPE}" = "lua" ]; then
+ luaOutput
+ elif [ "${AFILETYPE}" = "php" ]; then
+ phpOutput
+ elif [ "${AFILETYPE}" = "ini" ]; then
+ iniOutput
+ elif [ "${AFILETYPE}" = "js" ]; then
+ jsOutput
+ elif [ "${AFILETYPE}" = "json" ]; then
+ jsonOutput
+ elif [ "${AFILETYPE}" = "java" ]; then
+ javaOutput
+ elif [ "${AFILETYPE}" = "javaprop" ]; then
+ javapropOutput
+ elif [ "${AFILETYPE}" = "tex" ]; then
+ texOutput
+ elif [ "${AFILETYPE}" = "m4" ]; then
+ m4Output
+ elif [ "${AFILETYPE}" = "scheme" ]; then
+ schemeOutput
+ elif [ "${AFILETYPE}" = "clojure" ]; then
+ clojureOutput
+ elif [ "${AFILETYPE}" = "rpm" ]; then
+ rpmOutput
+ elif [ "${AFILETYPE}" = "hpp" ]; then
+ hppOutput
+ elif [ "${AFILETYPE}" = "matlab" ]; then
+ matlabOutput
+ elif [ "${AFILETYPE}" = "octave" ]; then
+ octaveOutput
+ elif [ "${AFILETYPE}" = "cmake" ]; then
+ cmakeOutput
+ else
+ echo "error: Not a valid output type." 1>&2
+ exit 1
+ fi
+fi
+
+
+# If requested, make a cache file.
+if [ ! -z "${CACHEFILE}" ] && [ ! "${CACHEFORCE}" = "1" ]; then
+ TARGETFILE="${CACHEFILE}.tmp"
+ shOutput
+
+ # Check to see if there have been any actual changes.
+ if [ ! -f "${CACHEFILE}" ]; then
+ mv -f "${CACHEFILE}.tmp" "${CACHEFILE}"
+ elif cmp -s "${CACHEFILE}.tmp" "${CACHEFILE}"; then
+ rm -f "${CACHEFILE}.tmp"
+ else
+ mv -f "${CACHEFILE}.tmp" "${CACHEFILE}"
+ fi
+fi
diff --git a/cmake/Package.cmake b/cmake/Package.cmake
new file mode 100644
index 0000000..d1e8880
--- /dev/null
+++ b/cmake/Package.cmake
@@ -0,0 +1,37 @@
+if(CMAKE_BUILD_TYPE STREQUAL "Debug")
+ set(CPACK_PACKAGE_NAME "verify-policy-debug")
+else()
+ set(CPACK_PACKAGE_NAME "verify-policy")
+endif()
+
+message(STATUS "Package: ${CPACK_PACKAGE_NAME}")
+
+set(CPACK_PACKAGE_VENDOR "MESASOFT")
+set(CPACK_PACKAGE_VERSION_MAJOR "${VERIFY_POLIC_VERSION_MAJOR}")
+set(CPACK_PACKAGE_VERSION_MINOR "${VERIFY_POLIC_VERSION_MINOR}")
+set(CPACK_PACKAGE_VERSION_PATCH "${VERIFY_POLIC_VERSION_PATCH}.${VERIFY_POLIC_DESCRIBE}")
+set(CPACK_PACKAGING_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX})
+
+# RPM Build
+set(CPACK_GENERATOR "RPM")
+set(CPACK_RPM_AUTO_GENERATED_FILE_NAME ON)
+set(CPACK_RPM_FILE_NAME "RPM-DEFAULT")
+set(CPACK_RPM_PACKAGE_AUTOREQPROV "no")
+set(CPACK_RPM_PACKAGE_RELEASE_DIST on)
+set(CPACK_RPM_DEBUGINFO_PACKAGE on)
+#set(CPACK_RPM_POST_INSTALL_SCRIPT_FILE ${CMAKE_SOURCE_DIR}/cmake/PostInstall.in)
+#set(CPACK_RPM_POST_UNINSTALL_SCRIPT_FILE ${CMAKE_SOURCE_DIR}/cmake/PostUninstall.in)
+#set(CPACK_RPM_PRE_UNINSTALL_SCRIPT_FILE ${CMAKE_SOURCE_DIR}/cmake/PreUninstall.in)
+
+# Must uninstall the debug package before install release package
+if(CMAKE_BUILD_TYPE STREQUAL "Debug")
+ set(CPACK_RPM_PACKAGE_CONFLICTS "verify-policy")
+else()
+ set(CPACK_RPM_PACKAGE_CONFLICTS "verify-policy-debug")
+endif()
+
+# setup %config(noreplace)
+set(CPACK_RPM_USER_FILELIST "%config(noreplace) ${CMAKE_INSTALL_PREFIX}/conf/pangu/pangu_pxy.conf"
+ "%config(noreplace) ${CMAKE_INSTALL_PREFIX}/conf/tfe/decrypt_mirror.conf"
+ "%config(noreplace) ${CMAKE_INSTALL_PREFIX}/conf/tfe/tfe.conf")
+include(CPack)
diff --git a/cmake/PostInstall.in b/cmake/PostInstall.in
new file mode 100644
index 0000000..d52334e
--- /dev/null
+++ b/cmake/PostInstall.in
@@ -0,0 +1,2 @@
+%systemd_post mrenv.service mrzcpd.service mrtunnat.service
+/sbin/ldconfig
\ No newline at end of file
diff --git a/cmake/PostUninstall.in b/cmake/PostUninstall.in
new file mode 100644
index 0000000..d24e6f5
--- /dev/null
+++ b/cmake/PostUninstall.in
@@ -0,0 +1,2 @@
+%systemd_postun_with_restart mrenv.service mrzcpd.service mrtunnat.service
+/sbin/ldconfig
\ No newline at end of file
diff --git a/cmake/PreUninstall.in b/cmake/PreUninstall.in
new file mode 100644
index 0000000..4dbf922
--- /dev/null
+++ b/cmake/PreUninstall.in
@@ -0,0 +1 @@
+%systemd_preun mrenv.service mrzcpd.service mrtunnat.service
\ No newline at end of file
diff --git a/cmake/Version.cmake b/cmake/Version.cmake
new file mode 100644
index 0000000..0456017
--- /dev/null
+++ b/cmake/Version.cmake
@@ -0,0 +1,38 @@
+
+# Using autorevision.sh to generate version information
+
+set(__SOURCE_AUTORESIVISION ${CMAKE_SOURCE_DIR}/autorevision.sh)
+set(__AUTORESIVISION ${CMAKE_BINARY_DIR}/autorevision.sh)
+set(__VERSION_CACHE ${CMAKE_SOURCE_DIR}/version.txt)
+set(__VERSION_CONFIG ${CMAKE_BINARY_DIR}/version.cmake)
+
+file(COPY ${__SOURCE_AUTORESIVISION} DESTINATION ${CMAKE_BINARY_DIR}
+ FILE_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE
+ WORLD_READ WORLD_EXECUTE)
+
+# execute autorevision.sh to generate version information
+execute_process(COMMAND ${__AUTORESIVISION} -t cmake -o ${__VERSION_CACHE} OUTPUT_FILE ${__VERSION_CONFIG})
+include(${__VERSION_CONFIG})
+
+# extract major, minor, patch version from git tag
+string(REGEX REPLACE "^v([0-9]+)\\..*" "\\1" VERIFY_POLICY_VERSION_MAJOR "${VCS_TAG}")
+string(REGEX REPLACE "^v[0-9]+\\.([0-9]+).*" "\\1" VERIFY_POLIC_VERSION_MINOR "${VCS_TAG}")
+string(REGEX REPLACE "^v[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" VERIFY_POLIC_VERSION_PATCH "${VCS_TAG}")
+
+if(NOT VERIFY_POLIC_VERSION_MAJOR)
+ set(VERIFY_POLIC_VERSION_MAJOR 1)
+endif()
+
+if(NOT VERIFY_POLIC_VERSION_MINOR)
+ set(VERIFY_POLIC_VERSION_MINOR 0)
+endif()
+
+if(NOT VERIFY_POLIC_VERSION_PATCH)
+ set(VERIFY_POLIC_VERSION_PATCH 0)
+endif()
+
+set(VERIFY_POLIC_VERSION "${VERIFY_POLIC_VERSION_MAJOR}.${VERIFY_POLIC_VERSION_MINOR}.${VERIFY_POLIC_VERSION_PATCH}")
+
+# print information
+message(STATUS "Welcome to Verify Policy Engine, Version: ${VERIFY_POLIC_VERSION}")
+add_definitions(-DVERIFY_POLIC_VERSION=${VERIFY_POLIC_VERSION})
diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt
new file mode 100644
index 0000000..eadaa1a
--- /dev/null
+++ b/common/CMakeLists.txt
@@ -0,0 +1,4 @@
+add_library(common src/verify_policy_logging.cpp)
+target_include_directories(common PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include)
+target_link_libraries(common PUBLIC MESA_handle_logger)
+
diff --git a/common/include/verify_policy.h b/common/include/verify_policy.h
new file mode 100644
index 0000000..5a96090
--- /dev/null
+++ b/common/include/verify_policy.h
@@ -0,0 +1,79 @@
+/*************************************************************************
+ > File Name: verify_policy.h
+ > Author:
+ > Mail:
+ > Created Time: 2019年08月23日 星期五 18时06分03秒
+ ************************************************************************/
+
+#ifndef _VERIFY_POLICY_H
+#define _VERIFY_POLICY_H
+
+#include
+#include "verify_policy_utils.h"
+
+enum scan_table
+{
+ PXY_CTRL_IP,
+ PXY_CTRL_HTTP_URL,
+ PXY_CTRL_HTTP_FQDN,
+ PXY_CTRL_HTTP_REQ_HDR,
+ PXY_CTRL_HTTP_REQ_BODY,
+ PXY_CTRL_HTTP_RES_HDR,
+ PXY_CTRL_HTTP_RES_BODY,
+ PXY_CTRL_SUBSCRIBE_ID,
+ __SCAN_TABLE_MAX
+};
+
+enum http_ev_bit_number
+{
+ IP_BITNUM = 0,
+ URL_BITNUM,
+ FQDN_BITNUM,
+ REQ_HDR_BITNUM,
+ RESP_HDR_BITNUM,
+ CONTENT_BITNUM,
+ SUBSCRIBE_ID
+};
+
+enum tfe_http_event
+{
+ EV_HTTP_IP = 1ULL << IP_BITNUM,
+ EV_HTTP_URL = 1ULL << URL_BITNUM,
+ EV_HTTP_FQDN = 1ULL << FQDN_BITNUM,
+ EV_HTTP_REQ_HDR = 1ULL << REQ_HDR_BITNUM,
+ EV_HTTP_RESP_HDR = 1ULL << RESP_HDR_BITNUM,
+ EV_HTTP_CONTENT = 1ULL << CONTENT_BITNUM,
+ EV_HTTP_SUBSCRIBE_ID = 1ULL << SUBSCRIBE_ID,
+};
+
+struct verify_proxy_thread
+{
+ int id;
+ pthread_t pid;
+ evutil_socket_t accept_fd;
+ pthread_attr_t *attr;
+ struct evhttp *http;
+ struct event_base *base;
+ void * (*routine)(void *);
+};
+
+struct verify_proxy
+{
+ char name[VERIFY_SYMBOL_MAX];
+ void * logger;
+ unsigned int log_level;
+ unsigned int nr_work_threads;
+ unsigned int listen_port;
+ struct verify_proxy_thread *work_threads[TFE_THREAD_MAX];
+};
+
+extern struct verify_proxy * g_verify_proxy;
+
+void * pangu_http_ctx_new(unsigned int thread_id);
+
+void http_scan(const char * value, enum tfe_http_event events,
+ const unsigned char * body_frag, size_t frag_size, void *pme);
+
+char *web_json_table_add(void *pme);
+
+#endif
diff --git a/common/include/verify_policy_logging.h b/common/include/verify_policy_logging.h
new file mode 100644
index 0000000..b2b7d2f
--- /dev/null
+++ b/common/include/verify_policy_logging.h
@@ -0,0 +1,51 @@
+/*************************************************************************
+ > File Name: logging.h
+ > Author:
+ > Mail:
+ > Created Time: 2018年06月18日 星期一 22时45分58秒
+ ************************************************************************/
+
+#ifndef _LOGGING_H
+#define _LOGGING_H
+
+#define MODULE_NAME "verify_policy"
+
+#define RLOG_LV_DEBUG 10
+#define RLOG_LV_INFO 20
+#define RLOG_LV_FATAL 30
+
+typedef struct RTLogInit2Data_ {
+ int debug_switch;
+
+ int run_log_level;
+
+ char run_log_path[256];
+
+ void *run_log_handle;
+} RTLogInit2Data;
+
+extern RTLogInit2Data logging_sc_lid;
+
+/* The maximum length of the log message */
+#define RT_LOG_MAX_LOG_MSG_LEN 2048
+
+extern void mesa_logging_print(int log_level, const char *module, const char *msg);
+
+#define mesa_log(x, y, z, ...) do { \
+ char _sc_log_msg[RT_LOG_MAX_LOG_MSG_LEN] = ""; \
+ char *_sc_log_temp = _sc_log_msg; \
+ if ( !x ) \
+ { } else { \
+ snprintf(_sc_log_temp, \
+ (RT_LOG_MAX_LOG_MSG_LEN - \
+ (_sc_log_temp - _sc_log_msg)), \
+ __VA_ARGS__); \
+ mesa_logging_print(y, z, _sc_log_msg); \
+ } \
+ } while(0)
+
+#define mesa_runtime_log(level, module, ...) mesa_log(logging_sc_lid.debug_switch, level, module, __VA_ARGS__)
+
+extern void * verify_syslog_init(const char *config);
+
+#endif
diff --git a/common/include/verify_policy_utils.h b/common/include/verify_policy_utils.h
new file mode 100644
index 0000000..d5fc219
--- /dev/null
+++ b/common/include/verify_policy_utils.h
@@ -0,0 +1,54 @@
+#ifndef __RT_COMMON_H__
+#define __RT_COMMON_H__
+
+#include
+#define EVAL_TM_STYLE "%Y-%m-%d"
+
+#define VERIFY_SYMBOL_MAX 64
+#define VERIFY_STRING_MAX 2048
+#define TFE_THREAD_MAX 128
+
+/** Alway treated the expr as true */
+#ifndef likely
+#define likely(expr) __builtin_expect(!!(expr), 1)
+#endif
+
+/** Alway treated the expr as false */
+#ifndef unlikely
+#define unlikely(expr) __builtin_expect(!!(expr), 0)
+#endif
+
+#ifndef FOREVER
+#define FOREVER for(;;)
+#endif
+
+#ifdef SOCK_NONBLOCK
+#define EVUTIL_SOCK_NONBLOCK SOCK_NONBLOCK
+#else
+#define EVUTIL_SOCK_NONBLOCK 0x4000000
+#endif
+#ifdef SOCK_CLOEXEC
+#define EVUTIL_SOCK_CLOEXEC SOCK_CLOEXEC
+#else
+#define EVUTIL_SOCK_CLOEXEC 0x80000000
+#endif
+#ifdef EFD_NONBLOCK
+#define EVUTIL_EFD_NONBLOCK EFD_NONBLOCK
+#else
+#define EVUTIL_EFD_NONBLOCK 0x4000
+#endif
+#ifdef EFD_CLOEXEC
+#define EVUTIL_EFD_CLOEXEC EFD_CLOEXEC
+#else
+#define EVUTIL_EFD_CLOEXEC 0x8000
+#endif
+
+#define __rt_always_inline__ __attribute__((always_inline)) inline
+
+#define ALLOC(type, number) ((type *)calloc(sizeof(type), number))
+#define FREE(p) {free(*p);*p=NULL;}
+
+#define CHECK_OR_EXIT(condition, fmt, ...) \
+do { if(!(condition)) { mesa_runtime_log(RLOG_LV_FATAL, MODULE_NAME, fmt, ##__VA_ARGS__); exit(EXIT_FAILURE); } } while(0) \
+
+#endif
diff --git a/common/src/verify_policy_logging.cpp b/common/src/verify_policy_logging.cpp
new file mode 100644
index 0000000..44fce95
--- /dev/null
+++ b/common/src/verify_policy_logging.cpp
@@ -0,0 +1,55 @@
+/*************************************************************************
+ > File Name: logging.c
+ > Author:
+ > Mail:
+ > Created Time: 2018年06月18日 星期一 22时45分43秒
+ ************************************************************************/
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "verify_policy_logging.h"
+#include "MESA_prof_load.h"
+#include "MESA_handle_logger.h"
+
+RTLogInit2Data logging_sc_lid;
+
+void mesa_logging_print(int log_level, const char *module, const char *msg)
+{
+ MESA_handle_runtime_log(logging_sc_lid.run_log_handle, log_level, (const char *)module, msg);
+ return;
+}
+
+void * verify_syslog_init(const char *config)
+{
+ char run_log_path[256] = {0};
+
+ MESA_load_profile_int_def(config, (const char *)"SYSTEM",(const char *)"DEBUG_SWITCH",
+ &logging_sc_lid.debug_switch, 1);
+ MESA_load_profile_int_def(config, (const char *)"SYSTEM",(const char *)"RUN_LOG_LEVEL",
+ &logging_sc_lid.run_log_level, 10);
+ MESA_load_profile_string_def(config, (const char *)"SYSTEM",(const char *)"RUN_LOG_PATH",
+ logging_sc_lid.run_log_path, 128, NULL);
+
+ snprintf(run_log_path, 255, "%s/%s", logging_sc_lid.run_log_path, "verify_policy.log");
+
+ logging_sc_lid.run_log_handle = MESA_create_runtime_log_handle(run_log_path, logging_sc_lid.run_log_level);
+ if(logging_sc_lid.run_log_handle == NULL){
+ mesa_runtime_log(RLOG_LV_FATAL, MODULE_NAME, "Create log runtime_log_handle error, init failed!");
+ goto finish;
+ }else{
+ mesa_runtime_log(RLOG_LV_INFO, MODULE_NAME, "Log module initialization");
+ }
+ return logging_sc_lid.run_log_handle;
+finish:
+ return NULL;
+}
+
+
diff --git a/conf/verify-policy.conf b/conf/verify-policy.conf
new file mode 100644
index 0000000..bec95e4
--- /dev/null
+++ b/conf/verify-policy.conf
@@ -0,0 +1,54 @@
+[SYSTEM]
+#1:print on screen, 0:don't
+DEBUG_SWITCH = 1
+#10:DEBUG, 20:INFO, 30:FATAL
+RUN_LOG_LEVEL = 10
+RUN_LOG_PATH = ./logs
+[CONFIG]
+#Number of running threads
+thread-nu = 4
+
+[maat]
+# 0:json 1: redis 2: iris
+maat_input_mode=0
+table_info=resource/pangu/table_info.conf
+json_cfg_file=resource/pangu/pangu_http.json
+stat_file=log/pangu_scan.status
+full_cfg_dir=pangu_policy/
+inc_cfg_dir=pangu_policy/
+
+maat_redis_server=192.168.10.31
+maat_redis_port=6379
+maat_redis_db_index=0
+effect_interval_s=1
+accept_tags={"tags":[{"tag":"location","value":"Astana"}]}
+
+[NTC_MAAT]
+#Configure the load mode,
+#0: using the configuration distribution network
+#1: using local json
+#2: using Redis reads
+maat_json_switch=2
+#When the loading mode is sent to the network, set the scanning configuration modification interval (s).
+effective_interval=1
+#Specify the location of the configuration library table file
+table_info=./conf/table_info.conf
+#Incremental profile path
+inc_cfg_dir=./rule/inc/index
+#Full profile path
+full_cfg_dir=./rule/full/index
+#Json file path when json schema is used
+pxy_obj_keyring=./conf/pxy_obj_keyring.json
+[LIBEVENT]
+#Local monitor port number, default is 9991
+port = 9991
+[CERTSTORE_REDIS]
+#The Redis server IP address and port number where the certificate is stored locally
+ip = 127.0.0.1
+port = 6379
+[MAAT_REDIS]
+#Maat monitors the Redsi server IP address and port number
+ip = 192.168.11.243
+port = 6379
+dbindex = 4
+
diff --git a/platform/CMakeLists.txt b/platform/CMakeLists.txt
new file mode 100644
index 0000000..e965f06
--- /dev/null
+++ b/platform/CMakeLists.txt
@@ -0,0 +1,13 @@
+add_executable(verify-policy src/verify_policy.cpp)
+
+#target_include_directories(verify-policy PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include)
+
+target_link_libraries(verify-policy common pangu-http)
+target_link_libraries(verify-policy pthread dl
+ libevent-static
+ MESA_handle_logger
+ MESA_prof_load
+ cjson
+ MESA_htable
+ MESA_field_stat)
+
diff --git a/platform/src/verify_policy.cpp b/platform/src/verify_policy.cpp
new file mode 100644
index 0000000..c18bef4
--- /dev/null
+++ b/platform/src/verify_policy.cpp
@@ -0,0 +1,492 @@
+/*************************************************************************
+ > File Name: verify-policy.cpp
+ > Author:
+ > Mail:
+ > Created Time: 2019年08月23日 星期五 14时41分17秒
+ ************************************************************************/
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#include "verify_policy.h"
+#include "MESA_prof_load.h"
+#include "MESA_handle_logger.h"
+#include "verify_policy_logging.h"
+
+struct verify_proxy * g_verify_proxy = NULL;
+
+struct keyword_obj
+{
+ enum scan_table condition_type;
+ char *condition_scope;
+ char *keyword;
+};
+
+struct verify_policy_query
+{
+ enum scan_table object_type;
+ int addr_type;
+
+ char *clientIp1;
+ unsigned int clientPort1;
+ char *serverIp1;
+ unsigned int serverPort1;
+
+ struct keyword_obj keywords[16];
+};
+
+#if 0
+#ifdef VERIFY_POLIC_VERSION
+char *git_version = VERIFY_POLIC_VERSION;
+#else
+char *default_version = "1.1.1";
+#endif
+#endif
+const char *default_version = "1.1.1";
+const char * version()
+{
+ return default_version;
+}
+
+extern int pangu_policy_init(struct verify_proxy * verify, const char* profile_path);
+
+static int verify_policy_init(struct verify_proxy * verify, const char *profile)
+{
+ int xret = -1;
+
+ xret = MESA_load_profile_uint_nodef(profile, "CONFIG", "thread-nu", &(verify->nr_work_threads));
+ if (xret < 0){
+ mesa_runtime_log(RLOG_LV_FATAL, MODULE_NAME, "Reading the number of running threads failed");
+ }
+ xret = MESA_load_profile_short_nodef(profile, "LISTEN", "port", (short *)&(verify->listen_port));
+ if (xret < 0){
+ mesa_runtime_log(RLOG_LV_FATAL, MODULE_NAME, "Listen Port invalid");
+ }
+ mesa_runtime_log(RLOG_LV_INFO, MODULE_NAME, "Listen Port %d", verify->listen_port);
+ return xret;
+}
+
+enum scan_table verify_type_str2idx(const char *action_str)
+{
+ const char * table_name[__SCAN_TABLE_MAX];
+ table_name[PXY_CTRL_IP] = "ip";
+ table_name[PXY_CTRL_HTTP_URL] = "url";
+ table_name[PXY_CTRL_HTTP_FQDN] = "fqdn";
+ table_name[PXY_CTRL_HTTP_REQ_HDR] = "req_hdr";
+ table_name[PXY_CTRL_HTTP_REQ_BODY] = "keywords";
+ table_name[PXY_CTRL_HTTP_RES_HDR] = "res_hdr";
+ table_name[PXY_CTRL_HTTP_RES_BODY] = "keywords";
+ table_name[PXY_CTRL_SUBSCRIBE_ID] = "subscribeid";
+
+ size_t i = 0;
+
+ for (i = 0; i < sizeof(table_name) / sizeof(const char *); i++)
+ {
+ if (0 == strcasecmp(action_str, table_name[i]))
+ break;
+ }
+ return (enum scan_table)i;
+}
+
+struct verify_policy_query *get_query_from_request(const char *data)
+{
+ int c_num = 0, i = 0;
+ char buff[VERIFY_STRING_MAX], *p = NULL;;
+
+ cJSON* data_json = cJSON_Parse(data);
+ if(data_json == NULL)
+ {
+ mesa_runtime_log(RLOG_LV_FATAL, MODULE_NAME, "invalid policy parameter");
+ return NULL;
+ }
+ struct verify_policy_query *query_ctx = ALLOC(struct verify_policy_query, 1);
+
+ cJSON* item = NULL, *subitem = NULL;
+ item = cJSON_GetObjectItem(data_json,"objectType");
+ if(item && item->type==cJSON_String)
+ {
+ query_ctx->object_type =verify_type_str2idx(item->valuestring);
+ }
+ item=cJSON_GetObjectItem(data_json,"addrType");
+ if(item && item->type==cJSON_Number)
+ {
+ query_ctx->addr_type = item->valueint;
+ }
+ item = cJSON_GetObjectItem(data_json,"clientIp1");
+ if(item && item->type==cJSON_String)
+ {
+ query_ctx->clientIp1 =strdup(item->valuestring);
+ }
+ item = cJSON_GetObjectItem(data_json,"serverIp1");
+ if(item && item->type==cJSON_String)
+ {
+ query_ctx->serverIp1 =strdup(item->valuestring);
+ }
+ item = cJSON_GetObjectItem(data_json,"clientPort1");
+ if(item && item->type==cJSON_String)
+ {
+ query_ctx->clientPort1 =atoi(item->valuestring);
+ }
+ item = cJSON_GetObjectItem(data_json,"serverPort1");
+ if(item && item->type==cJSON_String)
+ {
+ query_ctx->serverPort1 =atoi(item->valuestring);
+ }
+ p = buff;
+ p += snprintf(p, sizeof(buff) - (p - buff), "Query key objectType:%d, addrType:%d, clientIp1:%s, serverIp1:%s, clientPort1:%d, serverPort1:%d",
+ query_ctx->object_type, query_ctx->addr_type, query_ctx->clientIp1, query_ctx->serverIp1, query_ctx->clientPort1, query_ctx->serverPort1);
+ item = cJSON_GetObjectItem(data_json,"keywordObj");
+ if(item && item->type==cJSON_Array)
+ {
+ c_num=cJSON_GetArraySize(item);
+ for (subitem = item->child; subitem != NULL; subitem = subitem->next)
+ {
+ item = cJSON_GetObjectItem(subitem, "conditionScope");
+ if(item && item->type==cJSON_String)
+ {
+ query_ctx->keywords[i].condition_scope =strdup(item->valuestring);
+ query_ctx->keywords[i].condition_type = verify_type_str2idx(item->valuestring);
+ }
+ item = cJSON_GetObjectItem(subitem, "keywords");
+ if(item && item->type==cJSON_String)
+ {
+ query_ctx->keywords[i].keyword =strdup(item->valuestring);
+ }
+ i++;
+ }
+ }
+ for (i = 0; i < c_num; i++)
+ {
+ p += snprintf(p, sizeof(buff) - (p - buff), ", conditionScope:%s, keywords:%s", query_ctx->keywords[i].condition_scope, query_ctx->keywords[i].keyword);
+ }
+ *p = '\0';
+ mesa_runtime_log(RLOG_LV_DEBUG, MODULE_NAME, "%s", buff);
+ return query_ctx;
+}
+
+char *verify_policy_scan(struct verify_policy_query *policy_query, int thread_id)
+{
+ int c_num = 0; char *policy_payload= NULL;
+ void * ctx = pangu_http_ctx_new(thread_id);
+
+ for (c_num = 0; policy_query->keywords[c_num].keyword != NULL; c_num++)
+ {
+ struct keyword_obj *key_obj = &policy_query->keywords[c_num];
+
+ if (key_obj->condition_scope == NULL)
+ key_obj->condition_type = policy_query->object_type;
+
+ switch(key_obj->condition_type)
+ {
+ case PXY_CTRL_IP:
+ http_scan(key_obj->keyword, EV_HTTP_IP, NULL, 0, ctx);
+ break;
+ case PXY_CTRL_SUBSCRIBE_ID:
+ http_scan(key_obj->keyword, EV_HTTP_SUBSCRIBE_ID, NULL, 0, ctx);
+ case PXY_CTRL_HTTP_URL:
+ http_scan(key_obj->keyword, EV_HTTP_URL, NULL, 0, ctx);
+ break;
+ case PXY_CTRL_HTTP_FQDN:
+ http_scan(key_obj->keyword, EV_HTTP_FQDN, NULL, 0, ctx);
+ break;
+ case PXY_CTRL_HTTP_REQ_HDR:
+ http_scan(key_obj->keyword, EV_HTTP_REQ_HDR, NULL, 0, ctx);
+ break;
+ case PXY_CTRL_HTTP_RES_HDR:
+ http_scan(key_obj->keyword, EV_HTTP_RESP_HDR, NULL, 0, ctx);
+ break;
+ case PXY_CTRL_HTTP_REQ_BODY:
+ case PXY_CTRL_HTTP_RES_BODY:
+ http_scan(key_obj->keyword, EV_HTTP_CONTENT, NULL, 0, ctx);
+ break;
+ default:
+ break;
+ }
+ }
+ policy_payload = web_json_table_add(ctx);
+
+ return policy_payload;
+}
+
+static int
+evhttp_socket_send(struct evhttp_request *req, char *sendbuf)
+{
+ struct evbuffer *evb = NULL;
+
+ /* This holds the content we're sending. */
+ evb = evbuffer_new();
+
+ if (sendbuf[0] == '\0' && req == NULL){
+ goto err;
+ }
+ evhttp_add_header(evhttp_request_get_output_headers(req),
+ "Content-Type", "text/html");
+ evhttp_add_header(evhttp_request_get_output_headers(req), "Connection", "keep-alive");
+ evbuffer_add_printf(evb, "%s", sendbuf);
+ evhttp_send_reply(req, HTTP_OK, "OK", evb);
+ goto done;
+
+err:
+ evhttp_send_error(req, HTTP_NOTFOUND, "Document was not found");
+done:
+ evbuffer_free(evb);
+ return 0;
+}
+
+void evhttp_request_cb(struct evhttp_request *evh_req, void *arg)
+{
+ char *policy_payload= NULL;
+ struct evbuffer * evbuf_body = NULL;
+ char *input = NULL; ssize_t inputlen=0;
+ struct verify_policy_query *policy_query = NULL;
+
+ struct verify_proxy_thread *thread_ctx = (struct verify_proxy_thread *)arg;
+
+ if (evhttp_request_get_command(evh_req) != EVHTTP_REQ_POST)
+ {
+ mesa_runtime_log(RLOG_LV_DEBUG, MODULE_NAME, "FAILED (post type)");
+ goto error;
+ }
+ evbuf_body = evhttp_request_get_input_buffer(evh_req);
+ if (!evbuf_body || 0==(inputlen = evbuffer_get_length(evbuf_body)) ||!(input = (char *)evbuffer_pullup(evbuf_body,inputlen)))
+ {
+ mesa_runtime_log(RLOG_LV_FATAL, MODULE_NAME, "Failed to get post data information.");
+ goto error;
+ }
+ policy_query = get_query_from_request(input);
+ if (policy_query == NULL)
+ {
+ mesa_runtime_log(RLOG_LV_FATAL, MODULE_NAME, "Data parsing failed.");
+ goto error;
+ }
+
+ policy_payload = verify_policy_scan(policy_query, thread_ctx->id);
+ if (policy_payload)
+ {
+ mesa_runtime_log(RLOG_LV_DEBUG, MODULE_NAME, "%s", policy_payload);
+ evhttp_socket_send(evh_req, policy_payload);
+ free(policy_payload);
+ }
+ goto finish;
+
+error:
+ evhttp_send_error(evh_req, HTTP_BADREQUEST, 0);
+finish:
+ return;
+}
+
+void * verify_policy_thread(void * arg)
+{
+ struct evhttp_bound_socket *bound = NULL;
+ struct verify_proxy_thread *thread_ctx = (struct verify_proxy_thread *)arg;
+
+ thread_ctx->base = event_base_new();
+ if (! thread_ctx->base)
+ {
+ mesa_runtime_log(RLOG_LV_FATAL, MODULE_NAME, "Can'thread_ctx allocate event base");
+ goto finish;
+ }
+ thread_ctx->http = evhttp_new(thread_ctx->base);
+ if (!thread_ctx->http)
+ {
+ mesa_runtime_log(RLOG_LV_FATAL, MODULE_NAME, "couldn'thread_ctx create evhttp. Exiting.");
+ goto error;
+ }
+
+ evhttp_set_cb(thread_ctx->http, "/v1/policy/verification", evhttp_request_cb, thread_ctx);
+
+ bound = evhttp_accept_socket_with_handle(thread_ctx->http, thread_ctx->accept_fd);
+ if (bound != NULL)
+ {
+ mesa_runtime_log(RLOG_LV_INFO, MODULE_NAME, "Bound(%p) to port %d - Awaiting connections ... ", bound,
+ g_verify_proxy->listen_port);
+ }
+ mesa_runtime_log(RLOG_LV_INFO, MODULE_NAME, "Work thread %u is run...", thread_ctx->id);
+
+ event_base_dispatch(thread_ctx->base);
+error:
+ event_base_free(thread_ctx->base);
+finish:
+ return NULL;
+}
+
+static int
+evutil_fast_socket_nonblocking(evutil_socket_t fd)
+{
+#ifdef _WIN32
+ return evutil_make_socket_nonblocking(fd);
+#else
+ if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
+ return -1;
+ }
+ return 0;
+#endif
+}
+
+static int
+evutil_fast_socket_closeonexec(evutil_socket_t fd)
+{
+#if !defined(_WIN32) && defined(EVENT__HAVE_SETFD)
+ if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) {
+ return -1;
+ }
+#endif
+ return 0;
+}
+
+evutil_socket_t
+evutil_socket_(int domain, int type, int protocol)
+{
+ evutil_socket_t r;
+#if defined(SOCK_NONBLOCK) && defined(SOCK_CLOEXEC)
+ r = socket(domain, type, protocol);
+ if (r >= 0)
+ return r;
+ else if ((type & (SOCK_NONBLOCK|SOCK_CLOEXEC)) == 0)
+ return -1;
+#endif
+#define SOCKET_TYPE_MASK (~(EVUTIL_SOCK_NONBLOCK|EVUTIL_SOCK_CLOEXEC))
+ r = socket(domain, type & SOCKET_TYPE_MASK, protocol);
+ if (r < 0)
+ return -1;
+ if (type & EVUTIL_SOCK_NONBLOCK) {
+ if (evutil_fast_socket_nonblocking(r) < 0) {
+ evutil_closesocket(r);
+ return -1;
+ }
+ }
+ if (type & EVUTIL_SOCK_CLOEXEC) {
+ if (evutil_fast_socket_closeonexec(r) < 0) {
+ evutil_closesocket(r);
+ return -1;
+ }
+ }
+ return r;
+}
+
+static evutil_socket_t
+evhttp_listen_socket_byuser(const struct sockaddr *sa, int socklen,
+ unsigned flags, int backlog)
+{
+ evutil_socket_t fd;
+ int on = 1;
+ int family = sa ? sa->sa_family : AF_UNSPEC;
+ int socktype = SOCK_STREAM | EVUTIL_SOCK_NONBLOCK;
+
+ if (flags & LEV_OPT_CLOSE_ON_EXEC)
+ socktype |= EVUTIL_SOCK_CLOEXEC;
+
+ fd = evutil_socket_(family, socktype, 0);
+ if (fd == -1)
+ return fd;
+
+ if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void*)&on, sizeof(on))<0)
+ goto err;
+ if (flags & LEV_OPT_REUSEABLE) {
+ if (evutil_make_listen_socket_reuseable(fd) < 0)
+ goto err;
+ }
+ if (flags & LEV_OPT_REUSEABLE_PORT) {
+ if (evutil_make_listen_socket_reuseable_port(fd) < 0){
+ goto err;
+ }
+ }
+ if (sa) {
+ if (bind(fd, sa, socklen)<0)
+ goto err;
+ }
+ if (listen(fd, backlog) == -1) {
+ goto err;
+ }
+ return fd;
+err:
+ evutil_closesocket(fd);
+ return fd;
+}
+
+int pangu_policy_work_thread_run(struct verify_proxy * verify)
+{
+ int xret = 0;
+ unsigned int tid = 0;
+ struct verify_proxy_thread *thread_ctx = NULL;
+
+ struct sockaddr_in sin;
+ memset(&sin, 0, sizeof(struct sockaddr_in));
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(verify->listen_port);
+ evutil_socket_t accept_fd = evhttp_listen_socket_byuser((struct sockaddr*)&sin, sizeof(struct sockaddr_in),LEV_OPT_REUSEABLE_PORT|LEV_OPT_CLOSE_ON_FREE, -1);
+ if (accept_fd < 0)
+ {
+ mesa_runtime_log(RLOG_LV_FATAL, MODULE_NAME, "Could not create a listen!");
+ goto finish;
+ }
+
+ for (tid = 0; tid < verify->nr_work_threads; tid++)
+ {
+ verify->work_threads[tid] = ALLOC(struct verify_proxy_thread, 1);
+ thread_ctx = verify->work_threads[tid];
+ thread_ctx->id = tid;
+ thread_ctx->accept_fd =accept_fd;
+ thread_ctx->routine = verify_policy_thread;
+
+ if (pthread_create(&thread_ctx->pid, thread_ctx->attr, thread_ctx->routine, thread_ctx))
+ {
+ mesa_runtime_log(RLOG_LV_FATAL, MODULE_NAME, "%s", strerror(errno));
+ goto finish;
+ }
+ if (pthread_detach(thread_ctx->pid))
+ {
+ mesa_runtime_log(RLOG_LV_FATAL, MODULE_NAME, "%s", strerror(errno));
+ goto finish;
+ }
+ }
+ FOREVER{
+ sleep(1);
+ }
+finish:
+ return xret;
+}
+
+int main(int argc, char * argv[])
+{
+ const char * main_profile = "./conf/verify_policy.conf";
+
+ int ret = 0, opt = 0;
+ while ((opt = getopt(argc, argv, "v")) != -1)
+ {
+ switch (opt)
+ {
+ case 'v':
+ fprintf(stderr, "Tango Frontend Engine, Version: %s\n", version());
+ return 0;
+ default:
+ break;
+ }
+ }
+ g_verify_proxy = ALLOC(struct verify_proxy, 1);
+ assert(g_verify_proxy);
+ strcpy(g_verify_proxy->name, "verify_policy");
+
+ g_verify_proxy->logger = verify_syslog_init(main_profile);
+ CHECK_OR_EXIT(g_verify_proxy->logger != NULL, "Failed at init log module. Exit.");
+
+ ret = verify_policy_init(g_verify_proxy, main_profile);
+ CHECK_OR_EXIT(ret == 0, "Failed at loading profile %s, Exit.", main_profile);
+
+ ret = pangu_policy_init(g_verify_proxy, main_profile);
+ CHECK_OR_EXIT(ret == 0, "Failed at init panggu module, Exit.");
+
+ ret = pangu_policy_work_thread_run(g_verify_proxy);
+
+ return ret;
+}
+
diff --git a/scan/CMakeLists.txt b/scan/CMakeLists.txt
new file mode 100644
index 0000000..ddc69a5
--- /dev/null
+++ b/scan/CMakeLists.txt
@@ -0,0 +1,6 @@
+add_library(pangu-http src/pangu_http.cpp)
+target_include_directories(pangu-http PUBLIC ${CMAKE_CURRENT_LIST_DIR}/incluce)
+target_link_libraries(pangu-http PUBLIC common pthread cjson maatframe)
+
+
+
diff --git a/scan/include/pangu_http.h b/scan/include/pangu_http.h
new file mode 100644
index 0000000..537d958
--- /dev/null
+++ b/scan/include/pangu_http.h
@@ -0,0 +1,13 @@
+/*************************************************************************
+ > File Name: panggu_http.h
+ > Author:
+ > Mail:
+ > Created Time: 2019年08月26日 星期一 19时30分49秒
+ ************************************************************************/
+
+#ifndef _PANGGU_HTTP_H
+#define _PANGGU_HTTP_H
+
+extern int pangu_policy_init(struct verify_proxy * verify, const char* profile_path);
+
+#endif
diff --git a/scan/src/pangu_http.cpp b/scan/src/pangu_http.cpp
new file mode 100644
index 0000000..1fa5b02
--- /dev/null
+++ b/scan/src/pangu_http.cpp
@@ -0,0 +1,518 @@
+/*************************************************************************
+ > File Name: pangu_http.cpp
+ > Author:
+ > Mail:
+ > Created Time: 2019年08月23日 星期五 16时53分25秒
+ ************************************************************************/
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+
+#include "verify_policy.h"
+#include "verify_policy_utils.h"
+#include "verify_policy_logging.h"
+
+#define MAX_SCAN_RESULT 16
+
+enum pangu_action //Bigger action number is prior.
+{
+ PG_ACTION_NONE = 0x00,
+ PG_ACTION_MONIT = 0x01,
+ PG_ACTION_FORWARD = 0x02, /* N/A */
+ PG_ACTION_REJECT = 0x10,
+ PG_ACTION_DROP = 0x20, /* N/A */
+ PG_ACTION_MANIPULATE = 0x30,
+ PG_ACTION_RATELIMIT = 0x40, /* N/A */
+ PG_ACTION_LOOP = 0x60, /* N/A */
+ PG_ACTION_WHITELIST = 0x80,
+ __PG_ACTION_MAX
+};
+
+struct pangu_http_ctx
+{
+ enum pangu_action action;
+ char * action_para;
+ scan_status_t scan_mid;
+ stream_para_t sp;
+ size_t hit_cnt;
+ struct Maat_rule_t result[MAX_SCAN_RESULT];
+ size_t n_enforce;
+ struct Maat_rule_t * enforce_rules;
+ int thread_id;
+};
+
+struct pangu_rt
+{
+ Maat_feather_t maat;
+ Maat_feather_t dyn_maat;
+ int subscriber_id_table_id;
+ void * local_logger;
+ int log_level;
+ int thread_num;
+ int scan_table_id[__SCAN_TABLE_MAX];
+};
+struct pangu_rt * g_pangu_rt;
+
+#define MAAT_INPUT_JSON 0
+#define MAAT_INPUT_REDIS 1
+#define MAAT_INPUT_FILE 2
+
+void * pangu_http_ctx_new(unsigned int thread_id)
+{
+ struct pangu_http_ctx * ctx = ALLOC(struct pangu_http_ctx, 1);
+ ctx->scan_mid = NULL;
+ ctx->thread_id = (int) thread_id;
+ return (void *)ctx;
+}
+
+static int pangu_action_weight[__PG_ACTION_MAX] = {0};
+void __pangu_action_weight_init() __attribute__((constructor, used));
+void __pangu_action_weight_init()
+{
+ pangu_action_weight[PG_ACTION_NONE] = 0;
+ pangu_action_weight[PG_ACTION_MONIT] = 1;
+ pangu_action_weight[PG_ACTION_MANIPULATE] = 2;
+ pangu_action_weight[PG_ACTION_REJECT] = 3;
+ pangu_action_weight[PG_ACTION_WHITELIST] = 4;
+}
+
+static inline int action_cmp(enum pangu_action a1, enum pangu_action a2)
+{
+ return pangu_action_weight[a1] - pangu_action_weight[a2];
+}
+
+static enum pangu_action decide_ctrl_action(const struct Maat_rule_t * hit_rules, size_t n_hit,
+ struct Maat_rule_t ** enforce_rules, size_t * n_enforce)
+{
+ size_t n_monit = 0, exist_enforce_num = 0, i = 0;
+ const struct Maat_rule_t * prior_rule = hit_rules;
+ struct Maat_rule_t monit_rule[n_hit];
+ enum pangu_action prior_action = PG_ACTION_NONE;
+
+ for (i = 0; i < n_hit; i++)
+ {
+ unsigned char __expand_action = (unsigned char) hit_rules[i].action;
+ enum pangu_action __action = (enum pangu_action) __expand_action;
+
+ if (__action == PG_ACTION_MONIT)
+ {
+ memcpy(monit_rule + n_monit, hit_rules + i, sizeof(struct Maat_rule_t));
+ n_monit++;
+ }
+ if (action_cmp(__action, prior_action) > 0)
+ {
+ prior_rule = hit_rules + i;
+ prior_action = __action;
+ }
+ else if (action_cmp(__action, prior_action) == 0)
+ {
+ if (hit_rules[i].config_id > prior_rule->config_id)
+ {
+ prior_rule = hit_rules + i;
+ }
+ }
+ else
+ {
+ continue;
+ }
+ }
+
+ if (prior_action == PG_ACTION_WHITELIST)
+ {
+ if(*n_enforce==0)
+ {
+ *enforce_rules=ALLOC(struct Maat_rule_t, 1);
+ }
+ *enforce_rules[0]=*prior_rule;
+ *n_enforce=1;
+ return PG_ACTION_WHITELIST;
+ }
+
+ exist_enforce_num = *n_enforce;
+ if (prior_action == PG_ACTION_MONIT)
+ {
+ *n_enforce += n_monit;
+ }
+ else
+ {
+ *n_enforce += n_monit + 1;
+ }
+
+ *enforce_rules = (struct Maat_rule_t *) realloc(*enforce_rules, sizeof(struct Maat_rule_t) * (*n_enforce));
+ if (prior_action == PG_ACTION_MONIT)
+ {
+ memcpy(*enforce_rules + exist_enforce_num, monit_rule, n_monit * sizeof(struct Maat_rule_t));
+ }
+ else
+ {
+ memmove(*enforce_rules+1, *enforce_rules, exist_enforce_num*sizeof(struct Maat_rule_t));
+ memcpy(*enforce_rules, prior_rule, sizeof(struct Maat_rule_t));
+ memcpy(*enforce_rules + exist_enforce_num + 1, monit_rule, n_monit * sizeof(struct Maat_rule_t));
+ }
+
+ return prior_action;
+}
+
+char *web_json_table_add(void *pme)
+{
+ char *policy_payload = NULL; size_t i = 0;
+ cJSON *policy_obj=NULL, *data_obj=NULL, *hit_obj=NULL;
+ cJSON *execute_obj=NULL, *obj_list=NULL, *category_obj=NULL;
+
+ struct pangu_http_ctx * ctx = (struct pangu_http_ctx *) pme;
+
+ policy_obj=cJSON_CreateObject();
+ cJSON_AddNumberToObject(policy_obj, "code", 200);
+ cJSON_AddStringToObject(policy_obj, "msg", "");
+ cJSON_AddNumberToObject(policy_obj, "success", 1);
+
+ data_obj = cJSON_CreateObject();
+ cJSON_AddItemToObject(policy_obj, "data", data_obj);
+
+ /*hitPolicyList **/
+ hit_obj = cJSON_CreateObject();
+ cJSON_AddItemToObject(data_obj, "hitPolicyList", hit_obj);
+ if (ctx->hit_cnt >= 1)
+ {
+ for (i = 0; i < ctx->hit_cnt; i++)
+ {
+ cJSON_AddNumberToObject(hit_obj, "policyId", ctx->result[i].config_id);
+ cJSON_AddStringToObject(hit_obj, "policyName", "");
+ }
+ }
+ /*executePolicyList **/
+ execute_obj = cJSON_CreateObject();
+ cJSON_AddItemToObject(data_obj, "executePolicyList", execute_obj);
+ cJSON_AddNumberToObject(execute_obj, "policyId", ctx->enforce_rules[0].config_id);
+ cJSON_AddStringToObject(execute_obj, "policyName", "");
+
+ /*objectList**/
+ obj_list = cJSON_CreateObject();
+ cJSON_AddItemToObject(data_obj, "objectList", obj_list);
+ cJSON_AddNumberToObject(obj_list, "objectId", 12);
+ cJSON_AddStringToObject(obj_list, "objectName", "");
+ cJSON *itemList = cJSON_CreateObject();
+ cJSON_AddItemToObject(obj_list, "itemList", itemList);
+ cJSON_AddNumberToObject(itemList, "itemId", 12);
+ cJSON_AddStringToObject(itemList, "reqParam", "");
+
+ /*categoryList**/
+ category_obj = cJSON_CreateObject();
+ cJSON_AddItemToObject(data_obj, "categoryList", category_obj);
+ cJSON_AddNumberToObject(category_obj, "categoryId", 12);
+ cJSON_AddStringToObject(category_obj, "reqParam", "");
+
+ policy_payload = cJSON_PrintUnformatted(policy_obj);
+ printf("%s\n", policy_payload);
+ cJSON_Delete(policy_obj);
+
+ return policy_payload;
+}
+
+void http_scan(const char * value, enum tfe_http_event events,
+ const unsigned char * body_frag, size_t frag_size, void *pme)
+{
+ const char * field_val = NULL;
+ int scan_ret = 0, table_id = 0;
+ size_t hit_cnt = 0;
+
+ struct pangu_http_ctx * ctx = (struct pangu_http_ctx *) pme;
+
+ if (events & EV_HTTP_IP)
+ {
+ scan_ret = Maat_scan_proto_addr(g_pangu_rt->maat, g_pangu_rt->scan_table_id[PXY_CTRL_IP], NULL, 0,
+ ctx->result+hit_cnt, MAX_SCAN_RESULT-hit_cnt, &(ctx->scan_mid), ctx->thread_id);
+ if (scan_ret > 0)
+ {
+ hit_cnt += scan_ret;
+ }
+ }
+
+ if (events & EV_HTTP_SUBSCRIBE_ID)
+ {
+ scan_ret = Maat_full_scan_string(g_pangu_rt->maat, g_pangu_rt->scan_table_id[PXY_CTRL_SUBSCRIBE_ID],
+ CHARSET_UTF8, value, strlen(value),
+ ctx->result+hit_cnt, NULL, MAX_SCAN_RESULT-hit_cnt,
+ &(ctx->scan_mid), ctx->thread_id);
+ if(scan_ret>0)
+ {
+ hit_cnt+=scan_ret;
+ }
+ }
+
+ if (events & EV_HTTP_FQDN)
+ {
+ const char *str_host = value;
+ int str_host_length = (int) (strlen(value));
+
+ scan_ret = Maat_full_scan_string(g_pangu_rt->maat, g_pangu_rt->scan_table_id[PXY_CTRL_HTTP_FQDN],
+ CHARSET_UTF8, str_host, str_host_length, ctx->result, NULL, MAX_SCAN_RESULT, &(ctx->scan_mid), ctx->thread_id);
+ if (scan_ret > 0)
+ {
+ hit_cnt += scan_ret;
+ }
+ }
+ if (events & EV_HTTP_URL)
+ {
+ const char * str_url = value;
+ int str_url_length = (int) (strlen(value));
+
+ scan_ret = Maat_full_scan_string(g_pangu_rt->maat, g_pangu_rt->scan_table_id[PXY_CTRL_HTTP_URL],
+ CHARSET_UTF8, str_url, str_url_length, ctx->result + hit_cnt, NULL, MAX_SCAN_RESULT - hit_cnt, &(ctx->scan_mid), ctx->thread_id);
+
+ if (scan_ret > 0)
+ {
+ hit_cnt += scan_ret;
+ }
+ }
+
+ if ((events & EV_HTTP_REQ_HDR) || (events & EV_HTTP_RESP_HDR))
+ {
+ table_id = events & PXY_CTRL_HTTP_REQ_HDR ? g_pangu_rt->scan_table_id[PXY_CTRL_HTTP_REQ_HDR] : g_pangu_rt->scan_table_id[PXY_CTRL_HTTP_RES_HDR];
+
+ const char * str_field_name = NULL;
+ scan_ret = Maat_set_scan_status(g_pangu_rt->maat, &(ctx->scan_mid), MAAT_SET_SCAN_DISTRICT,
+ str_field_name, strlen(str_field_name));
+ assert(scan_ret == 0);
+ scan_ret = Maat_full_scan_string(g_pangu_rt->maat, table_id,
+ CHARSET_UTF8, field_val, strlen(field_val),
+ ctx->result + hit_cnt, NULL, MAX_SCAN_RESULT - hit_cnt, &(ctx->scan_mid), ctx->thread_id);
+ if (scan_ret > 0)
+ {
+ hit_cnt += scan_ret;
+ }
+ }
+
+ if ((events & EV_HTTP_CONTENT))
+ {
+ assert(ctx->sp == NULL);
+ table_id = events & EV_HTTP_CONTENT ? g_pangu_rt->scan_table_id[PXY_CTRL_HTTP_REQ_BODY] : g_pangu_rt->scan_table_id[PXY_CTRL_HTTP_RES_BODY];
+ ctx->sp = Maat_stream_scan_string_start(g_pangu_rt->maat, table_id, ctx->thread_id);
+ scan_ret = Maat_stream_scan_string(&(ctx->sp), CHARSET_UTF8, (const char *) body_frag, (int) frag_size,
+ ctx->result + hit_cnt, NULL, MAX_SCAN_RESULT - hit_cnt, &(ctx->scan_mid));
+ if (scan_ret > 0)
+ {
+ hit_cnt += scan_ret;
+ }
+ Maat_stream_scan_string_end(&(ctx->sp));
+ ctx->sp = NULL;
+ }
+
+ if (hit_cnt > 0)
+ {
+ ctx->action = decide_ctrl_action(ctx->result, hit_cnt, &ctx->enforce_rules, &ctx->n_enforce);
+ ctx->hit_cnt = hit_cnt;
+ }
+ return ;
+}
+
+char * verify_policy_str_to_addr()
+{
+ return NULL;
+}
+
+static Maat_feather_t create_maat_feather(const char * instance_name, const char * profile, const char * section, int max_thread, void * logger)
+{
+ Maat_feather_t target;
+ int input_mode = 0, maat_perf_on = 0;
+ int ret = 0, scan_detail = 0, effect_interval = 60;
+ char table_info[VERIFY_STRING_MAX] = {0}, inc_cfg_dir[VERIFY_STRING_MAX] = {0}, ful_cfg_dir[VERIFY_STRING_MAX] = {0};
+ char redis_server[VERIFY_STRING_MAX] = {0};
+ char redis_port_range[VERIFY_STRING_MAX] = {0};
+ char accept_tags[VERIFY_STRING_MAX] = {0};
+ int redis_port_begin=0, redis_port_end=0;
+ int redis_port_select=0;
+ int redis_db_idx = 0;
+ char json_cfg_file[VERIFY_STRING_MAX] = {0};
+ MESA_load_profile_int_def(profile, section, "maat_input_mode", &(input_mode), 0);
+ MESA_load_profile_int_def(profile, section, "perf_switch", &(maat_perf_on), 1);
+
+ MESA_load_profile_string_def(profile, section, "table_info", table_info, sizeof(table_info), "");
+ MESA_load_profile_string_def(profile, section, "accept_tags", accept_tags, sizeof(accept_tags), "");
+
+ MESA_load_profile_string_def(profile, section, "json_cfg_file", json_cfg_file, sizeof(json_cfg_file), "");
+
+ MESA_load_profile_string_def(profile, section, "maat_redis_server", redis_server, sizeof(redis_server), "");
+ MESA_load_profile_string_def(profile, section, "maat_redis_port_range", redis_port_range, sizeof(redis_server), "6379");
+ ret=sscanf(redis_port_range,"%d-%d", &redis_port_begin, &redis_port_end);
+ if(ret==1)
+ {
+ redis_port_select=redis_port_begin;
+ }
+ else if(ret==2)
+ {
+ srand(time(NULL));
+ redis_port_select=redis_port_begin+rand()%(redis_port_end-redis_port_begin);
+ }
+ else
+ {
+ mesa_runtime_log(RLOG_LV_FATAL, MODULE_NAME, "Invalid redis port range %s, MAAT init failed.", redis_port_range);
+ }
+ MESA_load_profile_int_def(profile, section, "maat_redis_db_index", &(redis_db_idx), 0);
+
+ MESA_load_profile_string_def(profile, section, "inc_cfg_dir", inc_cfg_dir, sizeof(inc_cfg_dir), "");
+ MESA_load_profile_string_def(profile, section, "full_cfg_dir", ful_cfg_dir, sizeof(ful_cfg_dir), "");
+ MESA_load_profile_int_def(profile, section, "effect_interval_s", &(effect_interval), 60);
+
+ effect_interval *= 1000;//convert s to ms
+ assert(strlen(inc_cfg_dir) != 0 || strlen(ful_cfg_dir) != 0 || strlen(redis_server)!=0 || strlen(json_cfg_file)!=0);
+
+ target = Maat_feather(max_thread, table_info, logger);
+ Maat_set_feather_opt(target, MAAT_OPT_INSTANCE_NAME, instance_name, strlen(instance_name) + 1);
+ switch (input_mode)
+ {
+ case MAAT_INPUT_JSON:
+ Maat_set_feather_opt(target, MAAT_OPT_JSON_FILE_PATH, json_cfg_file, strlen(json_cfg_file) + 1);
+ break;
+ case MAAT_INPUT_REDIS:
+ Maat_set_feather_opt(target, MAAT_OPT_REDIS_IP, redis_server, strlen(redis_server) + 1);
+ Maat_set_feather_opt(target, MAAT_OPT_REDIS_PORT, &redis_port_select, sizeof(redis_port_select));
+ Maat_set_feather_opt(target, MAAT_OPT_REDIS_INDEX, &redis_db_idx, sizeof(redis_db_idx));
+ break;
+ case MAAT_INPUT_FILE: Maat_set_feather_opt(target, MAAT_OPT_FULL_CFG_DIR, ful_cfg_dir, strlen(ful_cfg_dir) + 1);
+ Maat_set_feather_opt(target, MAAT_OPT_INC_CFG_DIR, inc_cfg_dir, strlen(inc_cfg_dir) + 1);
+ break;
+ default: mesa_runtime_log(RLOG_LV_FATAL, MODULE_NAME, "Invalid MAAT Input Mode: %d.", input_mode);
+ goto error_out;
+ break;
+ }
+
+ Maat_set_feather_opt(target, MAAT_OPT_FOREIGN_CONT_DIR, "./pangu_files", strlen("./pangu_files")+1);
+
+ Maat_set_feather_opt(target, MAAT_OPT_EFFECT_INVERVAL_MS, &effect_interval, sizeof(effect_interval));
+ Maat_set_feather_opt(target, MAAT_OPT_SCAN_DETAIL, &scan_detail, sizeof(scan_detail));
+
+ ret = Maat_initiate_feather(target);
+ if (ret < 0)
+ {
+ mesa_runtime_log(RLOG_LV_FATAL, MODULE_NAME, "%s MAAT init failed.", __FUNCTION__);
+ goto error_out;
+ }
+
+ return target;
+error_out:
+ Maat_burn_feather(target);
+ return NULL;
+}
+
+static int get_column_pos(const char* line, int column_seq, size_t *offset, size_t *len)
+{
+ const char* seps=" \t";
+ char* saveptr=NULL, *subtoken=NULL, *str=NULL;
+ char* dup_line=strdup(line);
+ int i=0, ret=-1;
+ for (str = dup_line; ; str = NULL)
+ {
+ subtoken = strtok_r(str, seps, &saveptr);
+ if (subtoken == NULL)
+ break;
+ if(i==column_seq-1)
+ {
+ *offset=subtoken-dup_line;
+ *len=strlen(subtoken);
+ ret=0;
+ break;
+ }
+ i++;
+ }
+ free(dup_line);
+ return ret;
+}
+
+void subscribe_id_new_cb(int table_id, const char* key, const char* table_line, MAAT_PLUGIN_EX_DATA* ad, long argl, void* argp)
+{
+ int ret=0;
+ size_t subscribe_id_offset, len;
+ ret=get_column_pos(table_line, 4, &subscribe_id_offset, &len);
+ if(ret<0)
+ {
+ mesa_runtime_log(RLOG_LV_FATAL, MODULE_NAME, "Add subscribe ID faild: %s", table_line);
+ return;
+ }
+ *ad=ALLOC(char, len+1);
+ memcpy(*ad, table_line+subscribe_id_offset, len);
+ mesa_runtime_log(RLOG_LV_INFO, MODULE_NAME, "Add subscribe ID: %s", (char*)*ad);
+ return;
+}
+
+void subscribe_id_free_cb(int table_id, MAAT_PLUGIN_EX_DATA* ad, long argl, void* argp)
+{
+ mesa_runtime_log(RLOG_LV_INFO, MODULE_NAME, "Delete subscribe ID: %s", (char*)*ad);
+ free(*ad);
+ *ad=NULL;
+}
+
+void subscribe_id_dup_cb(int table_id, MAAT_PLUGIN_EX_DATA* to, MAAT_PLUGIN_EX_DATA* from, long argl, void* argp)
+{
+ *to = strdup((char*)*from);
+ return;
+}
+
+int pangu_policy_init(struct verify_proxy * verify, const char* profile_path)
+{
+ int ret = -1;
+
+ g_pangu_rt = ALLOC(struct pangu_rt, 1);
+
+ g_pangu_rt->thread_num = verify->nr_work_threads;
+ g_pangu_rt->local_logger = verify->logger;
+
+ g_pangu_rt->maat = create_maat_feather("static", profile_path, "MAAT", g_pangu_rt->thread_num, g_pangu_rt->local_logger);
+ if (!g_pangu_rt->maat)
+ {
+ goto error_out;
+ }
+
+ const char * table_name[__SCAN_TABLE_MAX];
+ table_name[PXY_CTRL_IP] = "PXY_CTRL_IP";
+ table_name[PXY_CTRL_HTTP_URL] = "PXY_CTRL_HTTP_URL";
+ table_name[PXY_CTRL_HTTP_FQDN] = "TSG_OBJ_FQDN";
+ table_name[PXY_CTRL_HTTP_REQ_HDR] = "PXY_CTRL_HTTP_REQ_HDR";
+ table_name[PXY_CTRL_HTTP_REQ_BODY] = "TSG_OBJ_CONTENT";
+ table_name[PXY_CTRL_HTTP_RES_HDR] = "PXY_CTRL_HTTP_RES_HDR";
+ table_name[PXY_CTRL_HTTP_RES_BODY] = "TSG_OBJ_CONTENT";
+ table_name[PXY_CTRL_SUBSCRIBE_ID] = "PXY_CTRL_SUBSCRIBE_ID";
+ for (int i = 0; i < __SCAN_TABLE_MAX; i++)
+ {
+ g_pangu_rt->scan_table_id[i] = Maat_table_register(g_pangu_rt->maat, table_name[i]);
+ if (g_pangu_rt->scan_table_id[i] < 0)
+ {
+ mesa_runtime_log(RLOG_LV_FATAL, MODULE_NAME, "Pangu HTTP Maat table %s register failed.", table_name[i]);
+ goto error_out;
+ }
+ }
+
+ g_pangu_rt->dyn_maat = create_maat_feather("dyn", profile_path, "DYNAMIC_MAAT", g_pangu_rt->thread_num, g_pangu_rt->local_logger);
+ if (!g_pangu_rt->maat)
+ {
+ goto error_out;
+ }
+ g_pangu_rt->subscriber_id_table_id=Maat_table_register(g_pangu_rt->dyn_maat, "TSG_DYN_SUBSCRIBER_IP");
+ ret=Maat_plugin_EX_register(g_pangu_rt->dyn_maat,
+ g_pangu_rt->subscriber_id_table_id,
+ subscribe_id_new_cb,
+ subscribe_id_free_cb,
+ subscribe_id_dup_cb,
+ NULL,
+ 0,
+ NULL);
+ if(ret!=0)
+ {
+ mesa_runtime_log(RLOG_LV_FATAL, MODULE_NAME, "Pangu HTTP Dynamic Maat TSG_DYN_SUBSCRIBER_IP EX data register failed.");
+ goto error_out;
+ }
+
+ ret = 0;
+error_out:
+ return ret;
+}
+
diff --git a/vendor/CMakeLists.txt b/vendor/CMakeLists.txt
new file mode 100644
index 0000000..0ad3e30
--- /dev/null
+++ b/vendor/CMakeLists.txt
@@ -0,0 +1,118 @@
+# CMakeFiles for 3rd vendor library
+
+include(ExternalProject)
+
+### Libevent 2.1.8
+ExternalProject_Add(libevent PREFIX libevent
+ URL ${CMAKE_CURRENT_SOURCE_DIR}/libevent-2.1.8-stable.tar.gz
+ URL_MD5 f3eeaed018542963b7d2416ef1135ecc
+ CONFIGURE_COMMAND PKG_CONFIG_PATH=${OPENSSL_PKGCONFIG_PATH}
+ ./configure --prefix= --disable-shared --disable-samples
+ BUILD_IN_SOURCE 1)
+
+ExternalProject_Get_Property(libevent INSTALL_DIR)
+file(MAKE_DIRECTORY ${INSTALL_DIR}/include)
+
+add_library(libevent-static STATIC IMPORTED GLOBAL)
+add_dependencies(libevent-static libevent)
+set_property(TARGET libevent-static PROPERTY IMPORTED_LOCATION ${INSTALL_DIR}/lib/libevent.a)
+set_property(TARGET libevent-static PROPERTY IMPORTED_INTERFACE_LINK_LIBRARIES pthread crypto)
+set_property(TARGET libevent-static PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${INSTALL_DIR}/include)
+
+### cJSON
+ExternalProject_Add(cJSON PREFIX cJSON
+ URL ${CMAKE_CURRENT_SOURCE_DIR}/cJSON-1.7.7.tar.gz
+ URL_MD5 715009c99728bf81d6c97352718650ff
+ CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=
+ -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
+ -DBUILD_SHARED_AND_STATIC_LIBS=1)
+
+ExternalProject_Get_Property(cJSON INSTALL_DIR)
+file(MAKE_DIRECTORY ${INSTALL_DIR}/include)
+
+add_library(cjson SHARED IMPORTED GLOBAL)
+add_dependencies(cjson cJSON)
+set_property(TARGET cjson PROPERTY IMPORTED_LOCATION ${INSTALL_DIR}/lib64/libcjson.a)
+set_property(TARGET cjson PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${INSTALL_DIR}/include)
+
+#### GoogleTest
+ExternalProject_Add(googletest PREFIX googletest
+ URL ${CMAKE_CURRENT_SOURCE_DIR}/googletest-release-1.8.0.tar.gz
+ URL_MD5 16877098823401d1bf2ed7891d7dce36
+ CMAKE_ARGS -DCMAKE_INSTALL_PREFIX= -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE})
+
+ExternalProject_Get_Property(googletest INSTALL_DIR)
+file(MAKE_DIRECTORY ${INSTALL_DIR}/include)
+
+add_library(gtest STATIC IMPORTED GLOBAL)
+add_dependencies(gtest googletest)
+set_property(TARGET gtest PROPERTY IMPORTED_LOCATION ${INSTALL_DIR}/lib/libgtest.a)
+set_property(TARGET gtest PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${INSTALL_DIR}/include)
+set_property(TARGET gtest PROPERTY INTERFACE_LINK_LIBRARIES pthread)
+
+add_library(gmock STATIC IMPORTED GLOBAL)
+add_dependencies(gmock googletest)
+set_property(TARGET gmock PROPERTY IMPORTED_LOCATION ${INSTALL_DIR}/lib/libgmock.a)
+set_property(TARGET gmock PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${INSTALL_DIR}/include)
+
+
+### MESA Framework
+# Consider the MESA Framework is installed in the system. We declare a imported target instead of
+# ExternalProject target. we may retrive the MESAFramework source code from git.mesalab.cn and
+# compile staticly to TFE binarys in the future.
+
+set(MESA_FRAMEWORK_LIB_DIR /opt/MESA/lib)
+set(MESA_FRAMEWORK_INCLUDE_DIR /opt/MESA/include)
+set(MRZCPD_LIB_DIR /opt/mrzcpd/lib)
+set(MRZCPD_INCLUDE_DIR /opt/mrzcpd/include)
+
+add_library(MESA_handle_logger SHARED IMPORTED GLOBAL)
+set_property(TARGET MESA_handle_logger PROPERTY IMPORTED_LOCATION ${MESA_FRAMEWORK_LIB_DIR}/libMESA_handle_logger.so)
+set_property(TARGET MESA_handle_logger PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${MESA_FRAMEWORK_INCLUDE_DIR})
+
+add_library(MESA_prof_load SHARED IMPORTED GLOBAL)
+set_property(TARGET MESA_prof_load PROPERTY IMPORTED_LOCATION ${MESA_FRAMEWORK_LIB_DIR}/libMESA_prof_load.so)
+set_property(TARGET MESA_prof_load PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${MESA_FRAMEWORK_INCLUDE_DIR})
+
+add_library(wiredcfg SHARED IMPORTED GLOBAL)
+set_property(TARGET wiredcfg PROPERTY IMPORTED_LOCATION ${MESA_FRAMEWORK_LIB_DIR}/libwiredcfg.so)
+set_property(TARGET wiredcfg PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${MESA_FRAMEWORK_INCLUDE_DIR})
+
+add_library(MESA_htable SHARED IMPORTED GLOBAL)
+set_property(TARGET MESA_htable PROPERTY IMPORTED_LOCATION ${MESA_FRAMEWORK_LIB_DIR}/libMESA_htable.so)
+set_property(TARGET MESA_htable PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${MESA_FRAMEWORK_INCLUDE_DIR})
+
+add_library(wiredLB SHARED IMPORTED GLOBAL)
+set_property(TARGET wiredLB PROPERTY IMPORTED_LOCATION ${MESA_FRAMEWORK_LIB_DIR}/libWiredLB.so)
+set_property(TARGET wiredLB PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${MESA_FRAMEWORK_INCLUDE_DIR})
+
+add_library(maatframe SHARED IMPORTED GLOBAL)
+set_property(TARGET maatframe PROPERTY IMPORTED_LOCATION ${MESA_FRAMEWORK_LIB_DIR}/libmaatframe.so)
+set_property(TARGET maatframe PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${MESA_FRAMEWORK_INCLUDE_DIR})
+
+add_library(MESA_field_stat SHARED IMPORTED GLOBAL)
+set_property(TARGET MESA_field_stat PROPERTY IMPORTED_LOCATION ${MESA_FRAMEWORK_LIB_DIR}/libMESA_field_stat2.so)
+set_property(TARGET MESA_field_stat PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${MESA_FRAMEWORK_INCLUDE_DIR})
+
+add_library(librdkafka SHARED IMPORTED GLOBAL)
+set_property(TARGET librdkafka PROPERTY IMPORTED_LOCATION ${MESA_FRAMEWORK_LIB_DIR}/librdkafka.so)
+set_property(TARGET librdkafka PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${MESA_FRAMEWORK_INCLUDE_DIR})
+
+add_library(mrzcpd SHARED IMPORTED GLOBAL)
+set_property(TARGET mrzcpd PROPERTY IMPORTED_LOCATION ${MRZCPD_LIB_DIR}/libmarsio.so)
+set_property(TARGET mrzcpd PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${MRZCPD_INCLUDE_DIR})
+
+### pcre2
+ExternalProject_Add(pcre2 PREFIX pcre2
+ URL ${CMAKE_CURRENT_SOURCE_DIR}/pcre2-10.32.tar.gz
+ URL_MD5 a660db882ff171e6a0de5fb1decd5ff5
+ CMAKE_ARGS -DCMAKE_INSTALL_PREFIX= -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE})
+
+ExternalProject_Get_Property(pcre2 INSTALL_DIR)
+file(MAKE_DIRECTORY ${INSTALL_DIR}/include)
+
+add_library(pcre2-static STATIC IMPORTED GLOBAL)
+add_dependencies(pcre2-static pcre2)
+set_property(TARGET pcre2-static PROPERTY IMPORTED_LOCATION ${INSTALL_DIR}/lib/libpcre2-8.a)
+set_property(TARGET pcre2-static PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${INSTALL_DIR}/include)
+
diff --git a/vendor/MESA_prof_load-3b2bfd.tar.gz b/vendor/MESA_prof_load-3b2bfd.tar.gz
new file mode 100644
index 0000000..8004fa3
Binary files /dev/null and b/vendor/MESA_prof_load-3b2bfd.tar.gz differ
diff --git a/vendor/cJSON-1.7.7.tar.gz b/vendor/cJSON-1.7.7.tar.gz
new file mode 100644
index 0000000..c2350cf
Binary files /dev/null and b/vendor/cJSON-1.7.7.tar.gz differ
diff --git a/vendor/googletest-release-1.8.0.tar.gz b/vendor/googletest-release-1.8.0.tar.gz
new file mode 100644
index 0000000..a40df33
Binary files /dev/null and b/vendor/googletest-release-1.8.0.tar.gz differ
diff --git a/vendor/libevent-2.1.8-stable.tar.gz b/vendor/libevent-2.1.8-stable.tar.gz
new file mode 100644
index 0000000..2004f84
Binary files /dev/null and b/vendor/libevent-2.1.8-stable.tar.gz differ
diff --git a/vendor/pcre2-10.32.tar.gz b/vendor/pcre2-10.32.tar.gz
new file mode 100644
index 0000000..7dca599
Binary files /dev/null and b/vendor/pcre2-10.32.tar.gz differ