commit 0475eb7e59baa947cba2ec1cd58da57934ef70d9 Author: zhao Date: Thu May 29 15:07:58 2025 +0800 Initial commit diff --git a/bash-completion/Makefile b/bash-completion/Makefile new file mode 100644 index 0000000..d7a5849 --- /dev/null +++ b/bash-completion/Makefile @@ -0,0 +1,43 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=bash-completion +PKG_VERSION:=2.14.0 +PKG_RELEASE:=1 + +PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz +PKG_SOURCE_URL:=https://github.com/scop/bash-completion/releases/download/$(PKG_VERSION) +PKG_HASH:=5c7494f968280832d6adb5aa19f745a56f1a79df311e59338c5efa6f7285e168 + +PKG_MAINTAINER:=sbwml +PKG_LICENSE:=GPL-2.0 +PKG_LICENSE_FILES:=COPYING + +PKG_INSTALL:=1 +PKG_BUILD_PARALLEL:=1 + +include $(INCLUDE_DIR)/package.mk + +define Package/bash-completion + SECTION:=utils + CATEGORY:=Utilities + SUBMENU:=Shells + TITLE:=Programmable completion functions for bash + URL:=https://github.com/scop/bash-completion + DEPENDS:=+bash +endef + +define Package/bash-completion/description + bash-completion is a collection of command line command completions for the Bash shell, + collection of helper functions to assist in creating new completions, + and set of facilities for loading completions automatically on demand, as well as installing them. +endef + +define Package/bash-completion/install + $(INSTALL_DIR) $(1)/etc/profile.d + $(CP) $(PKG_INSTALL_DIR)/etc/profile.d/* $(1)/etc/profile.d/ + $(INSTALL_DIR) $(1)/usr/share/bash-completion + $(CP) $(PKG_INSTALL_DIR)/usr/share/bash-completion/* $(1)/usr/share/bash-completion/ + $(INSTALL_DIR) $(1)/etc/bash_completion.d +endef + +$(eval $(call BuildPackage,bash-completion)) diff --git a/coremark/Makefile b/coremark/Makefile new file mode 100644 index 0000000..91e2fe6 --- /dev/null +++ b/coremark/Makefile @@ -0,0 +1,57 @@ +# +# Copyright (C) 2018 Lim Guo Wei +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=coremark +PKG_VERSION:=2023.01.25~d5fad6bd +PKG_RELEASE:=1 + +ifeq ($(CONFIG_USE_MUSL),y) + PKG_LIBC:=musl +else + PKG_LIBC:=glibc +endif + +include $(INCLUDE_DIR)/package.mk + +define Package/coremark + SECTION:=utils + CATEGORY:=Utilities + TITLE:=CoreMark Embedded Microprocessor Benchmark + DEPENDS:=@(aarch64||x86_64) + URL:=https://github.com/eembc/coremark +endef + +define Package/coremark/description + Embedded Microprocessor Benchmark +endef + +define Package/coremark/conffiles +/etc/bench.log +endef + +define Build/Compile +endef + +define Package/coremark/install + $(INSTALL_DIR) $(1)/bin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/$(PKG_LIBC)/coremark.$(ARCH) $(1)/bin/coremark + $(INSTALL_DIR) $(1)/etc + $(INSTALL_BIN) ./coremark.sh $(1)/etc/ + $(INSTALL_DIR) $(1)/etc/uci-defaults + $(INSTALL_BIN) ./coremark $(1)/etc/uci-defaults/xxx-coremark +endef + +define Package/coremark/postinst +#!/bin/sh +[ -n "$${IPKG_INSTROOT}" ] || sed -i '/coremark/d' /etc/crontabs/root +[ -n "$${IPKG_INSTROOT}" ] || echo "0 4 * * * /etc/coremark.sh" >> /etc/crontabs/root +[ -n "$${IPKG_INSTROOT}" ] || crontab /etc/crontabs/root +endef + +$(eval $(call BuildPackage,coremark)) diff --git a/coremark/coremark b/coremark/coremark new file mode 100755 index 0000000..c8a71b0 --- /dev/null +++ b/coremark/coremark @@ -0,0 +1,7 @@ +#!/bin/sh + +sed -i '/coremark/d' /etc/crontabs/root +echo "0 4 * * * /etc/coremark.sh" >> /etc/crontabs/root +crontab /etc/crontabs/root + +touch /etc/bench.log diff --git a/coremark/coremark.sh b/coremark/coremark.sh new file mode 100755 index 0000000..4f041bb --- /dev/null +++ b/coremark/coremark.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +/bin/coremark > /tmp/coremark.log + +cat /tmp/coremark.log | grep "CoreMark 1.0" | cut -d "/" -f 1 > /etc/bench.log +sed -i 's/CoreMark 1.0/ (CpuMark/g' /etc/bench.log +echo " Scores)" >> /etc/bench.log + +if [ -f "/etc/bench.log" ]; then + sed -i '/coremark/d' /etc/crontabs/root + crontab /etc/crontabs/root +fi diff --git a/coremark/src/glibc/coremark.aarch64 b/coremark/src/glibc/coremark.aarch64 new file mode 100644 index 0000000..1d0ea16 Binary files /dev/null and b/coremark/src/glibc/coremark.aarch64 differ diff --git a/coremark/src/glibc/coremark.x86_64 b/coremark/src/glibc/coremark.x86_64 new file mode 100644 index 0000000..ca40807 Binary files /dev/null and b/coremark/src/glibc/coremark.x86_64 differ diff --git a/coremark/src/musl/coremark.aarch64 b/coremark/src/musl/coremark.aarch64 new file mode 100644 index 0000000..08a4b2c Binary files /dev/null and b/coremark/src/musl/coremark.aarch64 differ diff --git a/coremark/src/musl/coremark.x86_64 b/coremark/src/musl/coremark.x86_64 new file mode 100644 index 0000000..a6f125b Binary files /dev/null and b/coremark/src/musl/coremark.x86_64 differ diff --git a/ddns-scripts-aliyun/Makefile b/ddns-scripts-aliyun/Makefile new file mode 100644 index 0000000..b3926b6 --- /dev/null +++ b/ddns-scripts-aliyun/Makefile @@ -0,0 +1,56 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=ddns-scripts-aliyun +PKG_VERSION:=1.0.3 +PKG_RELEASE:=6 + +PKG_LICENSE:=GPLv2 +PKG_MAINTAINER:=Sense + +PKG_BUILD_PARALLEL:=1 + +include $(INCLUDE_DIR)/package.mk + +define Package/$(PKG_NAME) + SECTION:=net + CATEGORY:=Network + SUBMENU:=IP Addresses and Names + TITLE:=DDNS extension for AliYun.com + PKGARCH:=all + DEPENDS:=+ddns-scripts +curl +jsonfilter +openssl-util +endef + +define Package/$(PKG_NAME)/description + Dynamic DNS Client scripts extension for AliYun.com +endef + +define Build/Configure +endef + +define Build/Compile + $(CP) ./*.sh $(PKG_BUILD_DIR) + # remove comments, white spaces and empty lines + for FILE in `find $(PKG_BUILD_DIR) -type f`; do \ + $(SED) 's/^[[:space:]]*//' \ + -e '/^#[[:space:]]\|^#$$$$/d' \ + -e 's/[[:space:]]#[[:space:]].*$$$$//' \ + -e 's/[[:space:]]*$$$$//' \ + -e '/^\/\/[[:space:]]/d' \ + -e '/^[[:space:]]*$$$$/d' $$$$FILE; \ + done +endef + +define Package/$(PKG_NAME)/install + $(INSTALL_DIR) $(1)/usr/lib/ddns + $(INSTALL_BIN) $(PKG_BUILD_DIR)/update_aliyun_com.sh $(1)/usr/lib/ddns + $(INSTALL_DIR) $(1)/usr/share/ddns/default + $(INSTALL_DATA) ./aliyun.com.json $(1)/usr/share/ddns/default +endef + +define Package/$(PKG_NAME)/prerm + #!/bin/sh + [ -z "$${IPKG_INSTROOT}" ] && /etc/init.d/ddns stop >/dev/null 2>&1 + exit 0 # suppress errors +endef + +$(eval $(call BuildPackage,$(PKG_NAME))) diff --git a/ddns-scripts-aliyun/README.md b/ddns-scripts-aliyun/README.md new file mode 100644 index 0000000..3bf9d58 --- /dev/null +++ b/ddns-scripts-aliyun/README.md @@ -0,0 +1,2 @@ +# ddns-scripts-aliyun +基于https://github.com/sensec/ddns-scripts_aliyun 改进,将wget替换为curl,并且完善了逻辑判断,日志可以显示更新失败时的原因 diff --git a/ddns-scripts-aliyun/aliyun.com.json b/ddns-scripts-aliyun/aliyun.com.json new file mode 100644 index 0000000..c1ad8a5 --- /dev/null +++ b/ddns-scripts-aliyun/aliyun.com.json @@ -0,0 +1,9 @@ +{ + "name": "aliyun.com", + "ipv4": { + "url": "update_aliyun_com.sh" + }, + "ipv6": { + "url": "update_aliyun_com.sh" + } +} diff --git a/ddns-scripts-aliyun/update_aliyun_com.sh b/ddns-scripts-aliyun/update_aliyun_com.sh new file mode 100644 index 0000000..6f613bc --- /dev/null +++ b/ddns-scripts-aliyun/update_aliyun_com.sh @@ -0,0 +1,205 @@ +#!/bin/sh +# +# 用于阿里云解析的DNS更新脚本 +# 阿里云解析API文档 https://help.aliyun.com/document_detail/29739.html +# +# 本脚本由 dynamic_dns_functions.sh 内的函数 send_update() 调用 +# +# 需要在 /etc/config/ddns 中设置的选项 +# option username - 阿里云API访问账号 Access Key ID。可通过 aliyun.com 帐号管理的 accesskeys 获取, 或者访问 https://ak-console.aliyun.com +# option password - 阿里云API访问密钥 Access Key Secret +# option domain - 完整的域名。建议主机与域名之间使用 @符号 分隔,否则将以第一个 .符号 之前的内容作为主机名 +# + +# 检查传入参数 +[ -z "$username" ] && write_log 14 "Configuration error! The 'username' that holds the Alibaba Cloud API access account cannot be empty" +[ -z "$password" ] && write_log 14 "Configuration error! The 'password' that holds the Alibaba Cloud API access account cannot be empty" + +# 检查外部调用工具 +[ -n "$CURL_SSL" ] || write_log 13 "Alibaba Cloud API communication require cURL with SSL support. Please install" +[ -n "$CURL_PROXY" ] || write_log 13 "cURL: libcurl compiled without Proxy support" +command -v sed >/dev/null 2>&1 || write_log 13 "Sed support is required to use Alibaba Cloud API, please install first" +command -v openssl >/dev/null 2>&1 || write_log 13 "Openssl-util support is required to use Alibaba Cloud API, please install first" + +# 变量声明 +local __HOST __DOMAIN __TYPE __CMDBASE __RECID __TTL + +# 从 $domain 分离主机和域名 +[ "${domain:0:2}" = "@." ] && domain="${domain/./}" # 主域名处理 +[ "$domain" = "${domain/@/}" ] && domain="${domain/./@}" # 未找到分隔符,兼容常用域名格式 +__HOST="${domain%%@*}" +__DOMAIN="${domain#*@}" +[ -z "$__HOST" -o "$__HOST" = "$__DOMAIN" ] && __HOST=@ + +# 设置记录类型 +[ $use_ipv6 = 0 ] && __TYPE=A || __TYPE=AAAA + +# 构造基本通信命令 +build_command(){ + __CMDBASE="$CURL -Ss" + # 绑定用于通信的主机/IP + if [ -n "$bind_network" ];then + local __DEVICE + network_get_physdev __DEVICE $bind_network || write_log 13 "Can not detect local device using 'network_get_physdev $bind_network' - Error: '$?'" + write_log 7 "Force communication via device '$__DEVICE'" + __CMDBASE="$__CMDBASE --interface $__DEVICE" + fi + # 强制设定IP版本 + if [ $force_ipversion = 1 ];then + [ $use_ipv6 = 0 ] && __CMDBASE="$__CMDBASE -4" || __CMDBASE="$__CMDBASE -6" + fi + # 设置CA证书参数 + if [ $use_https = 1 ];then + if [ "$cacert" = IGNORE ];then + __CMDBASE="$__CMDBASE --insecure" + elif [ -f "$cacert" ];then + __CMDBASE="$__CMDBASE --cacert $cacert" + elif [ -d "$cacert" ];then + __CMDBASE="$__CMDBASE --capath $cacert" + elif [ -n "$cacert" ];then + write_log 14 "No valid certificate(s) found at '$cacert' for HTTPS communication" + fi + fi + # 如果没有设置,禁用代理 (这可能是 .wgetrc 或环境设置错误) + [ -z "$proxy" ] && __CMDBASE="$__CMDBASE --noproxy '*'" +} + +# 百分号编码 +percentEncode(){ + if [ -z "${1//[A-Za-z0-9_.~-]/}" ];then + echo -n "$1" + else + local string=$1;local i=0;local ret chr + while [ $i -lt ${#string} ];do + chr=${string:$i:1} + [ -z "${chr#[^A-Za-z0-9_.~-]}" ] && chr=$(printf '%%%02X' "'$chr") + ret="$ret$chr" + i=$(( $i + 1 )) + done + echo -n "$ret" + fi +} + +# 用于阿里云API的通信函数 +aliyun_transfer(){ + __CNT=0;__URLARGS= + [ $# = 0 ] && write_log 12 "'aliyun_transfer()' Error - wrong number of parameters" + # 添加请求参数 + for string in $*;do + case "${string%%=*}" in + Format|Version|AccessKeyId|SignatureMethod|Timestamp|SignatureVersion|SignatureNonce|Signature);; # 过滤公共参数 + *)__URLARGS="$__URLARGS&"$(percentEncode "${string%%=*}")"="$(percentEncode "${string#*=}");; + esac + done + __URLARGS="${__URLARGS:1}" + # 附加公共参数 + string="Format=JSON";__URLARGS="$__URLARGS&"$(percentEncode "${string%%=*}")"="$(percentEncode "${string#*=}") + string="Version=2015-01-09";__URLARGS="$__URLARGS&"$(percentEncode "${string%%=*}")"="$(percentEncode "${string#*=}") + string="AccessKeyId=$username";__URLARGS="$__URLARGS&"$(percentEncode "${string%%=*}")"="$(percentEncode "${string#*=}") + string="SignatureMethod=HMAC-SHA1";__URLARGS="$__URLARGS&"$(percentEncode "${string%%=*}")"="$(percentEncode "${string#*=}") + string="Timestamp="$(date -u '+%Y-%m-%dT%H:%M:%SZ');__URLARGS="$__URLARGS&"$(percentEncode "${string%%=*}")"="$(percentEncode "${string#*=}") + string="SignatureVersion=1.0";__URLARGS="$__URLARGS&"$(percentEncode "${string%%=*}")"="$(percentEncode "${string#*=}") + string="SignatureNonce="$(cat '/proc/sys/kernel/random/uuid');__URLARGS="$__URLARGS&"$(percentEncode "${string%%=*}")"="$(percentEncode "${string#*=}") + string="Line=default";__URLARGS="$__URLARGS&"$(percentEncode "${string%%=*}")"="$(percentEncode "${string#*=}") + # 对请求参数进行排序,用于生成签名 + string=$(echo -n "$__URLARGS" | sed 's/\'"&"'/\n/g' | sort | sed ':label; N; s/\n/\'"&"'/g; b label') + # 构造用于计算签名的字符串 + string="GET&"$(percentEncode "/")"&"$(percentEncode "$string") + # 字符串计算签名值 + local signature=$(echo -n "$string" | openssl dgst -sha1 -hmac "$password&" -binary | openssl base64) + # 附加签名参数 + string="Signature=$signature";__URLARGS="$__URLARGS&"$(percentEncode "${string%%=*}")"="$(percentEncode "${string#*=}") + __A="$__CMDBASE 'https://alidns.aliyuncs.com/?$__URLARGS'" + write_log 7 "#> $__A" + while ! __TMP=`eval $__A 2>&1`;do + write_log 3 "[$__TMP]" + if [ $VERBOSE -gt 1 ];then + write_log 4 "Transfer failed - detailed mode: $VERBOSE - Do not try again after an error" + return 1 + fi + __CNT=$(( $__CNT + 1 )) + [ $retry_count -gt 0 -a $__CNT -gt $retry_count ] && write_log 14 "Transfer failed after $retry_count retries" + write_log 4 "Transfer failed - $__CNT Try again in $RETRY_SECONDS seconds" + sleep $RETRY_SECONDS & + PID_SLEEP=$! + wait $PID_SLEEP + PID_SLEEP=0 + done + __ERR=`jsonfilter -s "$__TMP" -e "@.Code"` + [ -z "$__ERR" ] && return 0 + case $__ERR in + LastOperationNotFinished)printf "%s\n" " $(date +%H%M%S) : 最后一次操作未完成,2秒后重试" >> $LOGFILE;return 1;; + InvalidTimeStamp.Expired)printf "%s\n" " $(date +%H%M%S) : 时间戳错误,2秒后重试" >> $LOGFILE;return 1;; + InvalidAccessKeyId.NotFound)__ERR="无效AccessKey ID";; + SignatureDoesNotMatch)__ERR="无效AccessKey Secret";; + InvalidDomainName.NoExist)__ERR="无效域名";; + esac + local A="$(date +%H%M%S) ERROR : [$__ERR] - 终止进程" + logger -p user.err -t ddns-scripts[$$] $SECTION_ID: ${A:15} + printf "%s\n" " $A" >> $LOGFILE + exit 1 +} + +# 添加解析记录 +add_domain(){ + while ! aliyun_transfer "Action=AddDomainRecord" "DomainName=$__DOMAIN" "RR=$__HOST" "Type=$__TYPE" "Value=$__IP";do + sleep 2 + done + printf "%s\n" " $(date +%H%M%S) : 添加解析记录成功: [$([ "$__HOST" = @ ] || echo $__HOST.)$__DOMAIN],[IP:$__IP]" >> $LOGFILE +} + +# 启用解析记录 +enable_domain(){ + while ! aliyun_transfer "Action=SetDomainRecordStatus" "RecordId=$__RECID" "Status=Enable";do + sleep 2 + done + printf "%s\n" " $(date +%H%M%S) : 启用解析记录成功" >> $LOGFILE +} + +# 修改解析记录 +update_domain(){ + while ! aliyun_transfer "Action=UpdateDomainRecord" "RecordId=$__RECID" "RR=$__HOST" "Type=$__TYPE" "Value=$__IP" "TTL=$__TTL";do + sleep 2 + done + printf "%s\n" " $(date +%H%M%S) : 修改解析记录成功: [$([ "$__HOST" = @ ] || echo $__HOST.)$__DOMAIN],[IP:$__IP],[TTL:$__TTL]" >> $LOGFILE +} + +# 获取子域名解析记录列表 +describe_domain(){ + ret=0 + while ! aliyun_transfer "Action=DescribeSubDomainRecords" "SubDomain=$__HOST.$__DOMAIN" "Type=$__TYPE";do + sleep 2 + done + __TMP=`jsonfilter -s "$__TMP" -e "@.DomainRecords.Record[@]"` + if [ -z "$__TMP" ];then + printf "%s\n" " $(date +%H%M%S) : 解析记录不存在: [$([ "$__HOST" = @ ] || echo $__HOST.)$__DOMAIN]" >> $LOGFILE + ret=1 + else + __STATUS=`jsonfilter -s "$__TMP" -e "@.Status"` + __RECIP=`jsonfilter -s "$__TMP" -e "@.Value"` + if [ "$__STATUS" != ENABLE ];then + printf "%s\n" " $(date +%H%M%S) : 解析记录被禁用" >> $LOGFILE + ret=$(( $ret | 2 )) + fi + if [ "$__RECIP" != "$__IP" ];then + __TTL=`jsonfilter -s "$__TMP" -e "@.TTL"` + printf "%s\n" " $(date +%H%M%S) : 解析记录需要更新: [解析记录IP:$__RECIP] [本地IP:$__IP]" >> $LOGFILE + ret=$(( $ret | 4 )) + fi + fi +} + +build_command +describe_domain +if [ $ret = 0 ];then + printf "%s\n" " $(date +%H%M%S) : 解析记录不需要更新: [解析记录IP:$__RECIP] [本地IP:$__IP]" >> $LOGFILE +elif [ $ret = 1 ];then + sleep 3 + add_domain +else + __RECID=`jsonfilter -s "$__TMP" -e "@.RecordId"` + [ $(( $ret & 2 )) -ne 0 ] && sleep 3 && enable_domain + [ $(( $ret & 4 )) -ne 0 ] && sleep 3 && update_domain +fi + +return 0 diff --git a/filebrowser/Makefile b/filebrowser/Makefile new file mode 100644 index 0000000..1c15806 --- /dev/null +++ b/filebrowser/Makefile @@ -0,0 +1,78 @@ +# +# Copyright (C) 2015-2016 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v3. +# + +include $(TOPDIR)/rules.mk + +PKG_ARCH_filebrowser:=$(ARCH) + +PKG_NAME:=filebrowser +PKG_VERSION:=2.31.2 +PKG_RELEASE:=1 + +PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION) +PKG_CONFIG_DEPENDS:=CONFIG_FILEBROWSER_COMPRESS_UPX + +ifeq ($(ARCH),x86_64) + PKG_ARCH:=amd64 +endif + +ifeq ($(ARCH),aarch64) + PKG_ARCH:=arm64 +endif + +ifeq ($(ARCH),arm) + PKG_ARCH:=armv7 +endif + +include $(INCLUDE_DIR)/package.mk + +define Package/$(PKG_NAME) + SECTION:=net + CATEGORY:=Network + SUBMENU:=Web Servers/Proxies + TITLE:=filebrowser + DEPENDS:=@(arm||aarch64||x86_64) + URL:=https://filebrowser.org/ +endef + +define Package/$(PKG_NAME)/description + File Browser is a create-your-own-cloud-kind of software where you can install it on a server +endef + +define Package/$(PKG_NAME)/config +config FILEBROWSER_COMPRESS_UPX + bool "Compress executable files with UPX" + default n +endef + +define Download/$(PKG_NAME) + URL:=https://github.com/filebrowser/filebrowser/releases/download/v$(PKG_VERSION) + URL_FILE:=linux-$(PKG_ARCH)-filebrowser.tar.gz + FILE:=filebrowser-$(PKG_VERSION)-$(PKG_ARCH)_static.tar.gz + HASH:=skip +endef + +define Build/Configure +endef + +define Build/Compile + ( \ + pushd $(PKG_BUILD_DIR) ; \ + tar zxvf $(DL_DIR)/filebrowser-$(PKG_VERSION)-$(PKG_ARCH)_static.tar.gz -C . ; \ + popd ; \ + ) +ifneq ($(CONFIG_FILEBROWSER_COMPRESS_UPX),) + $(STAGING_DIR_HOST)/bin/upx --lzma --best $(PKG_BUILD_DIR)/filebrowser +endif +endef + +define Package/$(PKG_NAME)/install + $(INSTALL_DIR) $(1)/usr/sbin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/filebrowser $(1)/usr/sbin/filebrowser +endef + +$(eval $(call Download,$(PKG_NAME))) +$(eval $(call BuildPackage,$(PKG_NAME))) diff --git a/fw_download_tool/Makefile b/fw_download_tool/Makefile new file mode 100644 index 0000000..bc44aa5 --- /dev/null +++ b/fw_download_tool/Makefile @@ -0,0 +1,30 @@ +# +# Copyright (C) 2015-2016 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v3. +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=fw_download_tool +PKG_RELEASE:=1 + +PKG_LICENSE:=GPL-3.0 +PKG_LICENSE_FILE:=COPYING +PKG_MAINTAINER:=sbwml + +include $(INCLUDE_DIR)/package.mk + +define Package/$(PKG_NAME) + SECTION:=net + CATEGORY:=Network + TITLE:=Firmware downloader + DEPENDS:=+libcurl +endef + +define Package/$(PKG_NAME)/install + $(INSTALL_DIR) $(1)/usr/bin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/fw_download_tool $(1)/usr/bin/fw_download_tool +endef + +$(eval $(call BuildPackage,$(PKG_NAME))) diff --git a/fw_download_tool/src/COPYING b/fw_download_tool/src/COPYING new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/fw_download_tool/src/COPYING @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/fw_download_tool/src/Makefile b/fw_download_tool/src/Makefile new file mode 100644 index 0000000..5b9a0e3 --- /dev/null +++ b/fw_download_tool/src/Makefile @@ -0,0 +1,8 @@ +CC = gcc +CFLAGS += -lcurl + +program: fw_download_tool.c + $(CC) $(CFLAGS) -o fw_download_tool fw_download_tool.c + +clean: + rm -f fw_download_tool diff --git a/fw_download_tool/src/fw_download_tool.c b/fw_download_tool/src/fw_download_tool.c new file mode 100644 index 0000000..2ed4552 --- /dev/null +++ b/fw_download_tool/src/fw_download_tool.c @@ -0,0 +1,240 @@ +/*************************************************************************** + * + * OpenWrt OTA lightweight downloader - by sbwml + * + ***************************************************************************/ + +#include +#include +#include +#include + +static int progressCallback(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow) +{ + double progress = 0.0; + if (dltotal > 0.0) + { + progress = (dlnow / dltotal) * 100.0; + } + + printf("%.2f%%\r", progress); + fflush(stdout); + + return 0; +} + +long parseTimeout(const char *timeoutStr) +{ + long timeout = 0; + int len = strlen(timeoutStr); + if (len > 1) + { + char unit = timeoutStr[len - 1]; + char *endptr; + long value = strtol(timeoutStr, &endptr, 10); + if (endptr == timeoutStr) + { + fprintf(stderr, "Invalid timeout value: %s\n", timeoutStr); + return -1; + } + + switch (unit) + { + case 's': + timeout = value; + break; + case 'm': + timeout = value * 60; + break; + case 'h': + timeout = value * 60 * 60; + break; + case 'd': + timeout = value * 60 * 60 * 24; + break; + default: + fprintf(stderr, "Invalid timeout unit: %c\n", unit); + return -1; + } + } + else + { + timeout = strtol(timeoutStr, NULL, 10); + } + + return timeout; +} + +int downloadFile(const char *url, const char *outputPath, const char *userAgent, long timeout, int skipSSL, int followRedirects, int useIPv4, int useIPv6) +{ + CURL *curl; + CURLcode res; + + FILE *fp; + + curl = curl_easy_init(); + if (curl) + { + fp = fopen(outputPath, "wb"); + if (fp == NULL) + { + fprintf(stderr, "Failed to open file for writing\n"); + return 1; + } + + curl_easy_setopt(curl, CURLOPT_URL, url); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, NULL); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp); + curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L); + curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, progressCallback); + curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, NULL); + + curl_easy_setopt(curl, CURLOPT_USERAGENT, userAgent); + curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L); + + if (timeout > 0) + { + curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout); + } + + if (skipSSL) + { + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); + } + + if (followRedirects) + { + curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); + } + + if (useIPv4) + { + curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); + } + else if (useIPv6) + { + curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6); + } + + res = curl_easy_perform(curl); + if (res != CURLE_OK) + { + fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); + fclose(fp); + remove(outputPath); + return 255; + } + + curl_easy_cleanup(curl); + fclose(fp); + } + + return 0; +} + +int main(int argc, char *argv[]) +{ + const char *url; + const char *outputPath = NULL; + const char *userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36"; + long timeout = 0; + int skipSSL = 0; + int followRedirects = 0; + int useIPv4 = 0; + int useIPv6 = 0; + + int i; + + if (argc < 2) + { + fprintf(stderr, "Usage: %s [-o ] [-u ] [-t ] [-k] [-L] [-4] [-6]\n", argv[0]); + return 1; + } + + url = argv[1]; + + for (i = 2; i < argc; i++) + { + if (strcmp(argv[i], "-o") == 0) + { + if (i + 1 < argc) + { + outputPath = argv[i + 1]; + i++; + } + else + { + fprintf(stderr, "Invalid arguments. Use -o to specify the output path.\n"); + return 1; + } + } + else if (strcmp(argv[i], "-u") == 0) + { + if (i + 1 < argc) + { + userAgent = argv[i + 1]; + i++; + } + else + { + fprintf(stderr, "Invalid arguments. Use -u to specify the User-Agent.\n"); + return 1; + } + } + else if (strcmp(argv[i], "-t") == 0) + { + if (i + 1 < argc) + { + const char *timeoutStr = argv[i + 1]; + i++; + timeout = parseTimeout(timeoutStr); + if (timeout < 0) + { + return 1; + } + } + else + { + fprintf(stderr, "Invalid arguments. Use -t to specify the timeout.\n"); + return 1; + } + } + else if (strcmp(argv[i], "-k") == 0) + { + skipSSL = 1; + } + else if (strcmp(argv[i], "-L") == 0) + { + followRedirects = 1; + } + else if (strcmp(argv[i], "-4") == 0) + { + useIPv4 = 1; + } + else if (strcmp(argv[i], "-6") == 0) + { + useIPv6 = 1; + } + else + { + fprintf(stderr, "Invalid arguments.\n"); + return 1; + } + } + + if (outputPath == NULL) + { + outputPath = "/tmp/firmware.img.part"; + } + + int result = downloadFile(url, outputPath, userAgent, timeout, skipSSL, followRedirects, useIPv4, useIPv6); + if (result != 0) + { + fprintf(stderr, "Download failed.\n"); + remove(outputPath); + return 255; + } + + return 0; +} diff --git a/gowebdav/Makefile b/gowebdav/Makefile new file mode 100644 index 0000000..0c77801 --- /dev/null +++ b/gowebdav/Makefile @@ -0,0 +1,45 @@ +# SPDX-License-Identifier: GPL-3.0-only +# +# Copyright (C) 2021 ImmortalWrt.org + +include $(TOPDIR)/rules.mk + +PKG_NAME:=gowebdav +PKG_VERSION:=0.0.8 +PKG_RELEASE:=$(AUTORELEASE) + +PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz +PKG_SOURCE_URL:=https://codeload.github.com/sbwml/gowebdav/tar.gz/v$(PKG_VERSION)? +PKG_HASH:=0f689c745127163d88c7743e3217ad8bf55c5adf90da6ff4ddb3896bba23b055 + +PKG_MAINTAINER:=Tianling Shen + +PKG_BUILD_DEPENDS:=golang/host +PKG_BUILD_PARALLEL:=1 +PKG_USE_MIPS16:=0 + +GO_PKG:=github.com/sbwml/gowebdav + +include $(INCLUDE_DIR)/package.mk +include $(TOPDIR)/feeds/packages/lang/golang/golang-package.mk + +define Package/gowebdav + SECTION:=net + CATEGORY:=Network + SUBMENU:=File Transfer + TITLE:=A simple WebDav server written in Go + URL:=https://github.com/1715173329/gowebdav + DEPENDS:=$(GO_ARCH_DEPENDS) +endef + +define Package/gowebdav/install + $(call GoPackage/Package/Install/Bin,$(1)) + + $(INSTALL_DIR) $(1)/etc/config + $(INSTALL_CONF) $(CURDIR)/files/gowebdav.config $(1)/etc/config/gowebdav + $(INSTALL_DIR) $(1)/etc/init.d + $(INSTALL_BIN) $(CURDIR)/files/gowebdav.init $(1)/etc/init.d/gowebdav +endef + +$(eval $(call GoBinPackage,gowebdav)) +$(eval $(call BuildPackage,gowebdav)) diff --git a/gowebdav/files/gowebdav.config b/gowebdav/files/gowebdav.config new file mode 100644 index 0000000..96021af --- /dev/null +++ b/gowebdav/files/gowebdav.config @@ -0,0 +1,11 @@ + +config gowebdav 'config' + option enable '0' + option listen_port '6086' + option root_dir '/mnt' + option read_only '0' + option show_hidden '0' + option allow_wan '0' + option use_https '0' + option cert_cer '' + option cert_key '' diff --git a/gowebdav/files/gowebdav.init b/gowebdav/files/gowebdav.init new file mode 100755 index 0000000..28fe998 --- /dev/null +++ b/gowebdav/files/gowebdav.init @@ -0,0 +1,88 @@ +#!/bin/sh /etc/rc.common +# Copyright (C) 2021 ImmortalWrt + +START=99 +USE_PROCD=1 +PROG=/usr/bin/gowebdav + +get_config() { + config_load gowebdav + config_get "enable" "config" "enable" "0" + config_get "listen_port" "config" "listen_port" "6086" + config_get "username" "config" "username" + config_get "password" "config" "password" + config_get "root_dir" "config" "root_dir" "/mnt" + config_get "read_only" "config" "read_only" "0" + config_get "show_hidden" "config" "show_hidden" "0" + config_get "allow_wan" "config" "allow_wan" "0" + config_get "use_https" "config" "use_https" "0" + config_get "cert_cer" "config" "cert_cer" + config_get "cert_key" "config" "cert_key" + config_load network + config_get "lan_addr" "lan" "ipaddr" "0.0.0.0" +} + +set_firewall() { + if [ "$set_type" = "allow" ]; then + uci -q delete firewall.gowebdav + uci set firewall.gowebdav=rule + uci set firewall.gowebdav.name="gowebdav" + uci set firewall.gowebdav.target="ACCEPT" + uci set firewall.gowebdav.src="wan" + uci set firewall.gowebdav.proto="tcp" + uci set firewall.gowebdav.dest_port="$listen_port" + uci set firewall.gowebdav.enabled="1" + uci commit firewall + /etc/init.d/firewall reload >/dev/null 2>&1 + elif [ "$set_type" = "deny" ]; then + uci -q delete firewall.gowebdav + uci commit firewall + /etc/init.d/firewall reload >/dev/null 2>&1 + fi +} + +start_service() { + get_config + + [ "$enable" -ne "1" ] && return 1 + mkdir -p $root_dir + + if [ "$allow_wan" -eq "1" ]; then + listen_addr= + set_type="allow" + else + listen_addr=$lan_addr + set_type="deny" + fi + set_firewall + + { [ -n "$username" ] && [ -n "$password" ]; } && auth_arg="-user $username -password $password" + [ "$read_only" -eq "1" ] && readonly_arg="-read-only" + [ "$show_hidden" -eq "1" ] && showhidden_arg="-show-hidden" + { [ "$use_https" -eq "1" ] && [ -e "$cert_cer" ] && [ -e "$cert_key" ]; } && https_arg="-https-mode -https-cert-file $cert_cer -https-key-file $cert_key" + + procd_open_instance gowebdav + procd_set_param command $PROG + procd_append_param command -dir "$root_dir" -port "$listen_addr:$listen_port" $auth_arg $readonly_arg $showhidden_arg $https_arg + procd_set_param stdout 1 + procd_set_param stderr 1 + procd_set_param respawn + procd_close_instance gowebdav +} + +service_triggers() { + procd_add_reload_trigger "gowebdav" +} + +reload_service() { + stop + sleep 1 + start +} + +stop_service() { + get_config + pgrep -f /usr/bin/gowebdav | xargs kill -9 >/dev/null 2>&1 + set_type="deny" + set_firewall +} diff --git a/lshw/Makefile b/lshw/Makefile new file mode 100644 index 0000000..9015a76 --- /dev/null +++ b/lshw/Makefile @@ -0,0 +1,42 @@ +# +# Copyright (C) 2007-2016 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=lshw +PKG_RELEASE:=1 + +PKG_SOURCE_PROTO:=git +PKG_SOURCE_URL:=https://github.com/lyonel/lshw.git +PKG_SOURCE_DATE:=2023-03-20 +PKG_SOURCE_VERSION:=b4e067307906ec6f277cce5c8a882f5edd03cbbc +PKG_MIRROR_HASH:=947b521cbeabd991480e3f952dc148eef07d03cc5d797a3fb438c2978092e8bb + +PKG_MAINTAINER:=sbwml +PKG_LICENSE:=GPL-2.0 +PKG_LICENSE_FILES:=LICENSE + +include $(INCLUDE_DIR)/package.mk + +define Package/$(PKG_NAME) + SECTION:=utils + CATEGORY:=Utilities + TITLE:=lshw + URL:=http://lshw.ezix.org + DEPENDS:=+libstdcpp +endef + +define Package/$(PKG_NAME)/description + HardWare LiSter for Linux +endef + +define Package/$(PKG_NAME)/install + $(INSTALL_DIR) $(1)/usr/bin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/src/lshw $(1)/usr/bin/lshw +endef + +$(eval $(call BuildPackage,$(PKG_NAME))) diff --git a/luci-app-autoreboot/Makefile b/luci-app-autoreboot/Makefile new file mode 100644 index 0000000..966af6e --- /dev/null +++ b/luci-app-autoreboot/Makefile @@ -0,0 +1,18 @@ +# Copyright (C) 2016 Openwrt.org +# +# This is free software, licensed under the Apache License, Version 2.0 . +# + +include $(TOPDIR)/rules.mk + +LUCI_TITLE:=LuCI support for Scheduled Reboot +LUCI_DEPENDS:=+luci +LUCI_PKGARCH:=all + +PKG_NAME:=luci-app-autoreboot +PKG_VERSION:=1.0 +PKG_RELEASE:=8 + +include $(TOPDIR)/feeds/luci/luci.mk + +# call BuildPackage - OpenWrt buildroot signature diff --git a/luci-app-autoreboot/luasrc/controller/autoreboot.lua b/luci-app-autoreboot/luasrc/controller/autoreboot.lua new file mode 100644 index 0000000..871af23 --- /dev/null +++ b/luci-app-autoreboot/luasrc/controller/autoreboot.lua @@ -0,0 +1,9 @@ +module("luci.controller.autoreboot",package.seeall) + +function index() + if not nixio.fs.access("/etc/config/autoreboot") then + return + end + + entry({"admin", "system", "autoreboot"}, cbi("autoreboot"), _("Scheduled Reboot"),88) +end diff --git a/luci-app-autoreboot/luasrc/model/cbi/autoreboot.lua b/luci-app-autoreboot/luasrc/model/cbi/autoreboot.lua new file mode 100644 index 0000000..64fd86d --- /dev/null +++ b/luci-app-autoreboot/luasrc/model/cbi/autoreboot.lua @@ -0,0 +1,40 @@ +require("luci.sys") + +m = Map("autoreboot") +m.title = translate("Scheduled Reboot") +m.description = translate("Scheduled reboot Setting") + +s = m:section(TypedSection, "login") +s.addremove = false +s.anonymous = true + +enable = s:option(Flag,"enable" ,translate("Enable")) +enable.rmempty = false +enable.default = 0 + +week = s:option(ListValue, "week", translate("Week Day")) +week:value(7, translate("Everyday")) +week:value(1, translate("Monday")) +week:value(2, translate("Tuesday")) +week:value(3, translate("Wednesday")) +week:value(4, translate("Thursday")) +week:value(5, translate("Friday")) +week:value(6, translate("Saturday")) +week:value(0, translate("Sunday")) +week.default = 0 + +hour = s:option(Value, "hour", translate("Hour")) +hour.datatype = "range(0,23)" +hour.rmempty = false + +pass = s:option(Value, "minute", translate("Minute")) +pass.datatype = "range(0,59)" +pass.rmempty = false + + +local e = luci.http.formvalue("cbi.apply") +if e then + io.popen("/etc/init.d/autoreboot restart") +end + +return m diff --git a/luci-app-autoreboot/po/zh_Hans/autoreboot.po b/luci-app-autoreboot/po/zh_Hans/autoreboot.po new file mode 100644 index 0000000..dcd25f9 --- /dev/null +++ b/luci-app-autoreboot/po/zh_Hans/autoreboot.po @@ -0,0 +1,20 @@ +msgid "Scheduled Reboot" +msgstr "定时重启" + +msgid "Scheduled reboot Setting" +msgstr "定时重启设置" + +msgid "Week Day" +msgstr "星期" + +msgid "Everyday" +msgstr "每天" + +msgid "Day" +msgstr "天" + +msgid "Hour" +msgstr "小时" + +msgid "Minute" +msgstr "分钟" diff --git a/luci-app-autoreboot/root/etc/config/autoreboot b/luci-app-autoreboot/root/etc/config/autoreboot new file mode 100644 index 0000000..7755b57 --- /dev/null +++ b/luci-app-autoreboot/root/etc/config/autoreboot @@ -0,0 +1,6 @@ + +config login + option minute '0' + option hour '5' + option week '3' + option enable '0' diff --git a/luci-app-autoreboot/root/etc/init.d/autoreboot b/luci-app-autoreboot/root/etc/init.d/autoreboot new file mode 100755 index 0000000..6792533 --- /dev/null +++ b/luci-app-autoreboot/root/etc/init.d/autoreboot @@ -0,0 +1,39 @@ +#!/bin/sh /etc/rc.common + +START=90 + +run_reboot() +{ + local enable + config_get_bool enable $1 enable + + if [ $enable = 1 ]; then + local minute + local hour + config_get week $1 week + config_get minute $1 minute + config_get hour $1 hour + [ $week = 7 ] && week="*" + sed -i '/reboot/d' /etc/crontabs/root >/dev/null 2>&1 + echo "$minute $hour * * $week /bin/sync && /sbin/reboot" >> /etc/crontabs/root + /etc/init.d/cron restart + fi +} + +start() +{ + config_load autoreboot + config_foreach run_reboot login +} + +stop() +{ + sed -i '/reboot/d' /etc/crontabs/root >/dev/null 2>&1 + /etc/init.d/cron restart +} + +restart() +{ + stop + start +} diff --git a/luci-app-autoreboot/root/usr/share/rpcd/acl.d/luci-app-autoreboot.json b/luci-app-autoreboot/root/usr/share/rpcd/acl.d/luci-app-autoreboot.json new file mode 100644 index 0000000..154e0c1 --- /dev/null +++ b/luci-app-autoreboot/root/usr/share/rpcd/acl.d/luci-app-autoreboot.json @@ -0,0 +1,11 @@ +{ + "luci-app-autoreboot": { + "description": "Grant UCI access for luci-app-autoreboot", + "read": { + "uci": [ "autoreboot" ] + }, + "write": { + "uci": [ "autoreboot" ] + } + } +} diff --git a/luci-app-autoreboot/root/usr/share/ucitrack/luci-app-autoreboot.json b/luci-app-autoreboot/root/usr/share/ucitrack/luci-app-autoreboot.json new file mode 100644 index 0000000..e7296a9 --- /dev/null +++ b/luci-app-autoreboot/root/usr/share/ucitrack/luci-app-autoreboot.json @@ -0,0 +1,4 @@ +{ + "config": "autoreboot", + "init": "autoreboot" +} diff --git a/luci-app-cpufreq/Makefile b/luci-app-cpufreq/Makefile new file mode 100644 index 0000000..20e55e3 --- /dev/null +++ b/luci-app-cpufreq/Makefile @@ -0,0 +1,20 @@ +# SPDX-License-Identifier: GPL-3.0-only +# +# Copyright (C) 2021 ImmortalWrt.org + +include $(TOPDIR)/rules.mk + +LUCI_TITLE:=LuCI for CPU Freq Setting +LUCI_DEPENDS:=@TARGET_rockchip +irqbalance +luci-compat +kmod-hwmon-pwmfan + +PKG_NAME:=luci-app-cpufreq +PKG_VERSION:=1.1 +PKG_RELEASE:=1 + +define Package/$(PKG_NAME)/conffiles +/etc/config/cpufreq +endef + +include $(TOPDIR)/feeds/luci/luci.mk + +# call BuildPackage - OpenWrt buildroot signature diff --git a/luci-app-cpufreq/luasrc/controller/cpufreq.lua b/luci-app-cpufreq/luasrc/controller/cpufreq.lua new file mode 100644 index 0000000..0145d4c --- /dev/null +++ b/luci-app-cpufreq/luasrc/controller/cpufreq.lua @@ -0,0 +1,25 @@ +module("luci.controller.cpufreq", package.seeall) + +function index() + if not nixio.fs.access("/etc/config/cpufreq") or not nixio.fs.access("/etc/config/irqbalance") then + return + end + + local page = entry({"admin", "system", "cpufreq"}, alias("admin", "system", "cpufreq", "cpufreq"), _("CPU Freq"), 90) + page.dependent = true + page.acl_depends = { "luci-app-cpufreq" } + + entry({"admin", "system", "cpufreq", "cpufreq"}, cbi("cpufreq/cpufreq"), _("CPU Setting"), 1).leaf = true + entry({"admin", "system", "cpufreq", "pwmfan"}, cbi("cpufreq/pwmfan"), _("PWM Fan Controller"), 2).leaf = true + entry({"admin", "system", "cpufreq", "irqbalance"}, cbi("cpufreq/irqbalance"), _("Irqbalance"), 3).leaf = true + entry({"admin", "system", "cpufreq", "mglru"}, cbi("cpufreq/mglru"), _("Multi-Gen LRU"), 4).leaf = true + + entry({"admin", "system", "cpufreq", "irq_status"}, call("irq_status")).leaf = true +end + +function irq_status() + local log_data={} + log_data.syslog=luci.sys.exec("cat /proc/interrupts | egrep '^[ ]*(CPU|[0-9]*:)'") + luci.http.prepare_content("application/json") + luci.http.write_json(log_data) +end diff --git a/luci-app-cpufreq/luasrc/model/cbi/cpufreq/cpufreq.lua b/luci-app-cpufreq/luasrc/model/cbi/cpufreq/cpufreq.lua new file mode 100644 index 0000000..febb7ad --- /dev/null +++ b/luci-app-cpufreq/luasrc/model/cbi/cpufreq/cpufreq.lua @@ -0,0 +1,68 @@ +local fs = require "nixio.fs" + +function string.split(input, delimiter) + input = tostring(input) + delimiter = tostring(delimiter) + if (delimiter=='') then return false end + local pos,arr = 0, {} + for st,sp in function() return string.find(input, delimiter, pos, true) end do + table.insert(arr, string.sub(input, pos, st - 1)) + pos = sp + 1 + end + table.insert(arr, string.sub(input, pos)) + return arr +end + +mp = Map("cpufreq", translate("CPU Freq Settings")) +mp.description = translate("Set CPU Scaling Governor to Max Performance or Balance Mode") + +s = mp:section(NamedSection, "cpufreq", "settings") +s.anonymouse = true + +local policy_nums = luci.sys.exec("echo -n $(find /sys/devices/system/cpu/cpufreq/policy* -maxdepth 0 | grep -Eo '[0-9]+')") +for _, policy_num in ipairs(string.split(policy_nums, " ")) do + if not fs.access("/sys/devices/system/cpu/cpufreq/policy" .. policy_num .. "/scaling_available_frequencies") then return end + + cpu_freqs = fs.readfile("/sys/devices/system/cpu/cpufreq/policy" .. policy_num .. "/scaling_available_frequencies") + cpu_freqs = string.sub(cpu_freqs, 1, -3) + + cpu_governors = fs.readfile("/sys/devices/system/cpu/cpufreq/policy" .. policy_num .. "/scaling_available_governors") + cpu_governors = string.sub(cpu_governors, 1, -3) + + + freq_array = string.split(cpu_freqs, " ") + governor_array = string.split(cpu_governors, " ") + + s:tab(policy_num, translate("Policy " .. policy_num)) + + governor = s:taboption(policy_num, ListValue, "governor" .. policy_num, translate("CPU Scaling Governor")) + for _, e in ipairs(governor_array) do + if e ~= "" then governor:value(e, translate(e, string.upper(e))) end + end + + minfreq = s:taboption(policy_num, ListValue, "minfreq" .. policy_num, translate("Min Idle CPU Freq")) + for _, e in ipairs(freq_array) do + if e ~= "" then minfreq:value(e) end + end + + maxfreq = s:taboption(policy_num, ListValue, "maxfreq" .. policy_num, translate("Max Turbo Boost CPU Freq")) + for _, e in ipairs(freq_array) do + if e ~= "" then maxfreq:value(e) end + end + + sdfactor = s:taboption(policy_num, Value, "sdfactor" .. policy_num, translate("CPU Switching Sampling rate")) + sdfactor.datatype="range(1,100000)" + sdfactor.description = translate("The sampling rate determines how frequently the governor checks to tune the CPU (ms)") + sdfactor.placeholder = 10 + sdfactor.default = 10 + sdfactor:depends("governor" .. policy_num, "ondemand") + + upthreshold = s:taboption(policy_num, Value, "upthreshold" .. policy_num, translate("CPU Switching Threshold")) + upthreshold.datatype="range(1,99)" + upthreshold.description = translate("Kernel make a decision on whether it should increase the frequency (%)") + upthreshold.placeholder = 50 + upthreshold.default = 50 + upthreshold:depends("governor" .. policy_num, "ondemand") +end + +return mp diff --git a/luci-app-cpufreq/luasrc/model/cbi/cpufreq/irqbalance.lua b/luci-app-cpufreq/luasrc/model/cbi/cpufreq/irqbalance.lua new file mode 100644 index 0000000..1ddcfab --- /dev/null +++ b/luci-app-cpufreq/luasrc/model/cbi/cpufreq/irqbalance.lua @@ -0,0 +1,35 @@ +-- Copyright 2022 wulishui +-- Licensed to the public under the Apache License 2.0. +local utl = require "luci.util" +local sys = require "luci.sys" +local m, s +local button = "" + +if luci.sys.call("pidof irqbalance >/dev/null") == 0 then + status = translate("RUNNING") +else + status = translate("NOT RUNNING") +end + +m = Map("irqbalance", translate("Irqbalance"), translatef("Irqbalance is a Linux daemon that distributes interrupts over multiple logical CPUs. This design intent being to improve overall performance which can result in a balanced load and power consumption.
For more information, visiting: https://openwrt.org/docs/guide-user/services/irqbalance") .. button .. "

" .. translate("Running Status").. " : " .. status .. "
") + +s = m:section(TypedSection, "irqbalance", translate("Settings")) +s.anonymous = true + +enabled = s:option(Flag, "enabled", translate("Enable")) +enabled.rmempty = false + +deepestcache = s:option(Value, "deepestcache", translate("Level at which irqbalance partitions cache domains")) +deepestcache.placeholder='2' +deepestcache.rmempty = true + +interval = s:option(Value, "interval", translate("Interval (Seconds)")) +interval.placeholder='10' +interval.rmempty = true + +banirq = s:option(DynamicList, "banirq", translate("Ignore (ID of irq)")) +banirq.rmempty = true + +m:section(SimpleSection).template = "cpufreq/irq_status" + +return m diff --git a/luci-app-cpufreq/luasrc/model/cbi/cpufreq/mglru.lua b/luci-app-cpufreq/luasrc/model/cbi/cpufreq/mglru.lua new file mode 100644 index 0000000..dee1e6d --- /dev/null +++ b/luci-app-cpufreq/luasrc/model/cbi/cpufreq/mglru.lua @@ -0,0 +1,16 @@ +mp = Map("cpufreq", translate("Multi-Gen LRU")) +mp.description = translate("The multi-gen LRU is an alternative LRU implementation that optimizes page reclaim and improves performance under memory pressure. Page reclaim decides the kernel's caching policy and ability to overcommit memory. It directly impacts the kswapd CPU usage and RAM efficiency.") + +s = mp:section(NamedSection, "cpufreq", "settings") +s.anonymouse = true + +o = s:option(Flag, "mglru_enabled", translate("Enabled")) +o.default = true +o.rmempty = false + +o = s:option(Value, "mglru_min_ttl_ms", translate("Thrashing prevention (ms)"), translate("Set the thrashing prevention vaule to prevent the working set of N milliseconds from getting evicted. The OOM killer is triggered if this working set cannot be kept in memory. (0 means disabled, Default value 1000)")) +o.datatype = "and(uinteger,min(0))" +o.default = "1000" +o.rmempty = false + +return mp diff --git a/luci-app-cpufreq/luasrc/model/cbi/cpufreq/pwmfan.lua b/luci-app-cpufreq/luasrc/model/cbi/cpufreq/pwmfan.lua new file mode 100644 index 0000000..727c0cf --- /dev/null +++ b/luci-app-cpufreq/luasrc/model/cbi/cpufreq/pwmfan.lua @@ -0,0 +1,27 @@ +fan = Map("cpufreq", translate("PWM Fan Controller")) +fan.description = translate("Smart control PWM fan start/stop and fan speed based on CPU temperature.") + +s = fan:section(NamedSection, "cpufreq", "settings") +s.addremove = false +s.anonymous = true + +o = s:option(Flag, "pwm_fan", translate("Enabled")) +o.rmefanty = false + +o = s:option(Value, "pwm_fan_threshold", translate("Fan temperature activation (°C)")) +o.datatype = "and(uinteger,min(1),max(100))" +o.default = "35" + +o = s:option(Flag, "pwm_fan_strict", translate("Fan always on")) +o.default = true + +o = s:option(ListValue, "pwm_fan_enforce_level", translate("Fan speed")) +o:value("auto", translate("Auto")) +o:value("1", translate("Level 1")) +o:value("2", translate("Level 2")) +o:value("3", translate("Level 3")) +o:value("4", translate("Level 4")) +o.default = "auto" +o:depends("pwm_fan_strict", true) + +return fan diff --git a/luci-app-cpufreq/luasrc/view/cpufreq/irq_status.htm b/luci-app-cpufreq/luasrc/view/cpufreq/irq_status.htm new file mode 100644 index 0000000..00b8a58 --- /dev/null +++ b/luci-app-cpufreq/luasrc/view/cpufreq/irq_status.htm @@ -0,0 +1,37 @@ + + + +
+
+
+
+
+
+
+ + diff --git a/luci-app-cpufreq/po/zh_Hans/cpufreq.po b/luci-app-cpufreq/po/zh_Hans/cpufreq.po new file mode 100644 index 0000000..189d50a --- /dev/null +++ b/luci-app-cpufreq/po/zh_Hans/cpufreq.po @@ -0,0 +1,107 @@ +msgid "CPU Freq" +msgstr "CPU 性能调节" + +msgid "CPU Freq Settings" +msgstr "CPU 性能调节设置" + +msgid "CPU Setting" +msgstr "CPU 设置" + +msgid "Set CPU Scaling Governor to Max Performance or Balance Mode" +msgstr "设置路由器的 CPU 性能模式(省电/性能/均衡)" + +msgid "CPU Scaling Governor" +msgstr "CPU 工作模式" + +msgid "CPU Freq from 48000 to 716000 (Khz)" +msgstr "CPU 频率范围为 48000 到 716000 (Khz)" + +msgid "Min Idle CPU Freq" +msgstr "待机 CPU 最小频率" + +msgid "Max Turbo Boost CPU Freq" +msgstr "最大 Turbo Boost CPU 频率" + +msgid "CPU Switching Sampling rate" +msgstr "CPU 切换周期" + +msgid "The sampling rate determines how frequently the governor checks to tune the CPU (ms)" +msgstr "CPU 检查切换的周期 (ms)。注意:过于频繁的切换频率会引起网络延迟抖动" + +msgid "CPU Switching Threshold" +msgstr "CPU 切换频率触发阈值" + +msgid "Kernel make a decision on whether it should increase the frequency (%)" +msgstr "当 CPU 占用率超过 (%) 的情况下触发内核切换频率" + +msgid "PWM Fan Controller" +msgstr "PWM 风扇控制" + +msgid "Smart control PWM fan start/stop and fan speed based on CPU temperature." +msgstr "通过 CPU 温度值智能控制 PWM 风扇启停、转速。" + +msgid "Fan temperature activation (°C)" +msgstr "风扇启停温度 (°C)" + +msgid "Fan always on" +msgstr "风扇常转" + +msgid "Fan speed" +msgstr "风扇转速" + +msgid "Auto" +msgstr "自动" + +msgid "Level 1" +msgstr "等级 1" + +msgid "Level 2" +msgstr "等级 2" + +msgid "Level 3" +msgstr "等级 3" + +msgid "Level 4" +msgstr "等级 4" + +msgid "Irqbalance" +msgstr "中断均衡器" + +msgid "RUNNING" +msgstr "运行中" + +msgid "NOT RUNNING" +msgstr "未运行" + +msgid "No data." +msgstr "没有数据。" + +msgid "Read error, please refresh or wait." +msgstr "读取错误,请刷新或稍等。" + +msgid "Irqbalance is a Linux daemon that distributes interrupts over multiple logical CPUs. This design intent being to improve overall performance which can result in a balanced load and power consumption.
For more information, visiting: https://openwrt.org/docs/guide-user/services/irqbalance" +msgstr "Irqbalance 是一个 Linux 守护进程,它在多个逻辑 CPU 上分配中断。此设计旨在提高整体性能,从而实现平衡的负载和功耗。访问 https://openwrt.org/docs/guide-user/services/irqbalance 可获取更多信息。" + +msgid "Level at which irqbalance partitions cache domains" +msgstr "缓存域级别" + +msgid "Interval (Seconds)" +msgstr "间隔(秒)" + +msgid "Ignore (ID of irq)" +msgstr "忽略(中断ID)" + +msgid "Multi-Gen LRU" +msgstr "Multi-Gen LRU" + +msgid "The multi-gen LRU is an alternative LRU implementation that optimizes page reclaim and improves performance under memory pressure. Page reclaim decides the kernel's caching policy and ability to overcommit memory. It directly impacts the kswapd CPU usage and RAM efficiency." +msgstr "Multi-Gen LRU 是一种替代 LRU 实现,优化页面回收并在内存压力下提高性能,页面回收决定内核的缓存策略和超额提交内存的能力,它直接影响 kswapd CPU 使用率和 RAM 效率。" + +msgid "Enabled" +msgstr "启用" + +msgid "Thrashing prevention (ms)" +msgstr "预防颠簸(毫秒)" + +msgid "Set the thrashing prevention vaule to prevent the working set of N milliseconds from getting evicted. The OOM killer is triggered if this working set cannot be kept in memory. (0 means disabled, Default value 1000)" +msgstr "设置预防颠簸值以防止 N 毫秒的工作集被驱逐,如果无法将此工作集保留在内存中,则会触发 OOM killer。(0 表示禁用,默认值 1000)" diff --git a/luci-app-cpufreq/root/etc/config/cpufreq b/luci-app-cpufreq/root/etc/config/cpufreq new file mode 100644 index 0000000..50cc076 --- /dev/null +++ b/luci-app-cpufreq/root/etc/config/cpufreq @@ -0,0 +1,8 @@ + +config settings 'cpufreq' + option mglru_enabled '1' + option mglru_min_ttl_ms '1000' + option pwm_fan '1' + option pwm_fan_threshold '35' + option pwm_fan_strict '1' + option pwm_fan_enforce_level 'auto' diff --git a/luci-app-cpufreq/root/etc/init.d/cpufreq b/luci-app-cpufreq/root/etc/init.d/cpufreq new file mode 100755 index 0000000..5ba9f42 --- /dev/null +++ b/luci-app-cpufreq/root/etc/init.d/cpufreq @@ -0,0 +1,55 @@ +#!/bin/sh /etc/rc.common + +START=15 +USE_PROCD=1 + +config_get_cpufreq() { + config_get "cpufreq" "$1" +} + +start_service() { + config_load "cpufreq" + + # Multi-Gen LRU + if [ -e /sys/kernel/mm/lru_gen/enabled ]; then + if [ "$(config_get_cpufreq "mglru_enabled")" = 1 ]; then + echo y >/sys/kernel/mm/lru_gen/enabled + config_get_cpufreq "mglru_min_ttl_ms" > /sys/kernel/mm/lru_gen/min_ttl_ms + else + echo n >/sys/kernel/mm/lru_gen/enabled + fi + fi + + # cpufreq + for i in $(find /sys/devices/system/cpu/cpufreq/policy* -maxdepth 0 | grep -Eo '[0-9]+') + do + [ -z "$(config_get_cpufreq "governor$i")" ] && return + + config_get_cpufreq "governor$i" > "/sys/devices/system/cpu/cpufreq/policy$i/scaling_governor" + config_get_cpufreq "minfreq$i" > "/sys/devices/system/cpu/cpufreq/policy$i/scaling_min_freq" + config_get_cpufreq "maxfreq$i" > "/sys/devices/system/cpu/cpufreq/policy$i/scaling_max_freq" + if [ "$(config_get_cpufreq "governor$i")" = "ondemand" ]; then + config_get_cpufreq "sdfactor$i" > "/sys/devices/system/cpu/cpufreq/ondemand/sampling_down_factor" + config_get_cpufreq "upthreshold$i" > "/sys/devices/system/cpu/cpufreq/ondemand/up_threshold" + fi + done + + # pwm-fan + if [ "$(config_get_cpufreq "pwm_fan")" = 1 ]; then + procd_open_instance pwm-fan + procd_set_param command /usr/sbin/rockchip-pwm-fan + procd_append_param command -t "$(config_get_cpufreq "pwm_fan_threshold")" + [ "$(config_get_cpufreq "pwm_fan_strict")" != 1 ] && procd_append_param command -s + [ -n "$(config_get_cpufreq "pwm_fan_enforce_level")" ] && [ "$(config_get_cpufreq "pwm_fan_enforce_level")" != "auto" ] && procd_append_param command -k "$(config_get_cpufreq "pwm_fan_enforce_level")" + procd_set_param stdout 0 + procd_set_param stderr 0 + procd_set_param respawn + procd_close_instance pwm-fan + else + echo 0 > /sys/devices/virtual/thermal/cooling_device0/cur_state + fi +} + +service_triggers() { + procd_add_reload_trigger "cpufreq" +} diff --git a/luci-app-cpufreq/root/etc/uci-defaults/10-cpufreq b/luci-app-cpufreq/root/etc/uci-defaults/10-cpufreq new file mode 100755 index 0000000..5d7a3f2 --- /dev/null +++ b/luci-app-cpufreq/root/etc/uci-defaults/10-cpufreq @@ -0,0 +1,48 @@ +#!/bin/sh + +# Multi-Gen LRU +if [ -z $(uci -q get cpufreq.cpufreq.mglru_enabled) ]; then + uci -q set cpufreq.cpufreq.mglru_enabled="1" + uci -q set cpufreq.cpufreq.mglru_min_ttl_ms="1000" + uci -q commit cpufreq +fi + +# Cpufreq +if [ -z $(uci -q get cpufreq.cpufreq.governor0) ]; then + +uci_write_config() { + uci -q set cpufreq.cpufreq.governor$1="$2" + uci -q set cpufreq.cpufreq.minfreq$1="$3" + uci -q set cpufreq.cpufreq.maxfreq$1="$4" + [ -n "$5" ] && uci -q set cpufreq.cpufreq.sdfactor$1="$5" + [ -n "$6" ] && uci -q set cpufreq.cpufreq.upthreshold$1="$6" + uci -q commit cpufreq +} + +CPU_FREQS="$(cat '/sys/devices/system/cpu/cpufreq/policy0/scaling_available_frequencies')" +CPU_POLICYS="$(find '/sys/devices/system/cpu/cpufreq/policy'* -maxdepth 0 | grep -Eo '[0-9]+')" +source "/etc/openwrt_release" +case "$DISTRIB_TARGET" in + "rockchip/armv8") + uci_write_config 0 schedutil $(echo $CPU_FREQS | awk '{print $2}') $(echo $CPU_FREQS | awk '{print $NF}') + # big.Little + if echo "$CPU_POLICYS" | grep -q "4"; then + CPU_FREQS_PERFORMANCE="$(cat "/sys/devices/system/cpu/cpufreq/policy${CPU_POLICYS}/scaling_available_frequencies")" + uci_write_config 4 schedutil $(echo $CPU_FREQS_PERFORMANCE | awk '{print $2}') $(echo $CPU_FREQS_PERFORMANCE | awk '{print $NF}') + fi + ;; +esac + +fi + +[ -f "/etc/config/ucitrack" ] && { +uci -q batch <<-EOF >/dev/null + delete ucitrack.@cpufreq[-1] + add ucitrack cpufreq + set ucitrack.@cpufreq[-1].init=cpufreq + commit ucitrack +EOF +} + +rm -f /tmp/luci-indexcache* +exit 0 diff --git a/luci-app-cpufreq/root/usr/sbin/rockchip-pwm-fan b/luci-app-cpufreq/root/usr/sbin/rockchip-pwm-fan new file mode 100755 index 0000000..796302e Binary files /dev/null and b/luci-app-cpufreq/root/usr/sbin/rockchip-pwm-fan differ diff --git a/luci-app-cpufreq/root/usr/share/rpcd/acl.d/luci-app-cpufreq.json b/luci-app-cpufreq/root/usr/share/rpcd/acl.d/luci-app-cpufreq.json new file mode 100644 index 0000000..fae58ae --- /dev/null +++ b/luci-app-cpufreq/root/usr/share/rpcd/acl.d/luci-app-cpufreq.json @@ -0,0 +1,11 @@ +{ + "luci-app-cpufreq": { + "description": "Grant UCI access for luci-app-cpufreq", + "read": { + "uci": [ "cpufreq" ] + }, + "write": { + "uci": [ "cpufreq" ] + } + } +} diff --git a/luci-app-cpufreq/root/usr/share/ucitrack/luci-app-cpufreq.json b/luci-app-cpufreq/root/usr/share/ucitrack/luci-app-cpufreq.json new file mode 100644 index 0000000..cac6732 --- /dev/null +++ b/luci-app-cpufreq/root/usr/share/ucitrack/luci-app-cpufreq.json @@ -0,0 +1,4 @@ +{ + "config": "cpufreq", + "init": "cpufreq" +} diff --git a/luci-app-diskman/Makefile b/luci-app-diskman/Makefile new file mode 100644 index 0000000..e83417f --- /dev/null +++ b/luci-app-diskman/Makefile @@ -0,0 +1,47 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=luci-app-diskman +PKG_VERSION:=v0.2.13 +PKG_RELEASE:=2 + +PKG_MAINTAINER:=lisaac +PKG_LICENSE:=AGPL-3.0 + +LUCI_TITLE:=Disk Manager interface for LuCI + +LUCI_DEPENDS:=+e2fsprogs +parted +smartmontools +blkid +swap-utils \ + +PACKAGE_$(PKG_NAME)_INCLUDE_btrfs_progs:btrfs-progs \ + +PACKAGE_$(PKG_NAME)_INCLUDE_lsblk:lsblk \ + +PACKAGE_$(PKG_NAME)_INCLUDE_mdadm:mdadm \ + +PACKAGE_$(PKG_NAME)_INCLUDE_kmod_md_raid456:mdadm \ + +PACKAGE_$(PKG_NAME)_INCLUDE_kmod_md_raid456:kmod-md-raid456 \ + +PACKAGE_$(PKG_NAME)_INCLUDE_kmod_md_linears:mdadm \ + +PACKAGE_$(PKG_NAME)_INCLUDE_kmod_md_linears:kmod-md-linear + +define Package/$(PKG_NAME)/config +config PACKAGE_$(PKG_NAME)_INCLUDE_btrfs_progs + bool "Include btrfs-progs" + default y + +config PACKAGE_$(PKG_NAME)_INCLUDE_lsblk + bool "Include lsblk" + default y + +config PACKAGE_$(PKG_NAME)_INCLUDE_mdadm + bool "Include mdadm" + default n + +config PACKAGE_$(PKG_NAME)_INCLUDE_kmod_md_raid456 + depends on PACKAGE_$(PKG_NAME)_INCLUDE_mdadm + bool "Include kmod-md-raid456" + default n + +config PACKAGE_$(PKG_NAME)_INCLUDE_kmod_md_linears + depends on PACKAGE_$(PKG_NAME)_INCLUDE_mdadm + bool "Include kmod-md-linear" + default n +endef + +include $(TOPDIR)/feeds/luci/luci.mk + +# call BuildPackage - OpenWrt buildroot signature diff --git a/luci-app-diskman/luasrc/controller/diskman.lua b/luci-app-diskman/luasrc/controller/diskman.lua new file mode 100644 index 0000000..ba712e0 --- /dev/null +++ b/luci-app-diskman/luasrc/controller/diskman.lua @@ -0,0 +1,151 @@ +--[[ +LuCI - Lua Configuration Interface +Copyright 2019 lisaac +]]-- + +require "luci.util" +module("luci.controller.diskman",package.seeall) + +function index() + -- check all used executables in disk management are existed + local CMD = {"parted", "blkid", "smartctl"} + local executables_all_existed = true + for _, cmd in ipairs(CMD) do + local command = luci.sys.exec("/usr/bin/which " .. cmd) + if not command:match(cmd) then + executables_all_existed = false + break + end + end + + if not executables_all_existed then return end + -- entry(path, target, title, order) + -- set leaf attr to true to pass argument throughe url (e.g. admin/system/disk/partition/sda) + entry({"admin", "system", "diskman"}, alias("admin", "system", "diskman", "disks"), _("Disk Man"), 55) + entry({"admin", "system", "diskman", "disks"}, form("diskman/disks"), nil).leaf = true + entry({"admin", "system", "diskman", "partition"}, form("diskman/partition"), nil).leaf = true + entry({"admin", "system", "diskman", "btrfs"}, form("diskman/btrfs"), nil).leaf = true + entry({"admin", "system", "diskman", "format_partition"}, call("format_partition"), nil).leaf = true + entry({"admin", "system", "diskman", "get_disk_info"}, call("get_disk_info"), nil).leaf = true + entry({"admin", "system", "diskman", "mk_p_table"}, call("mk_p_table"), nil).leaf = true + entry({"admin", "system", "diskman", "smartdetail"}, call("smart_detail"), nil).leaf = true + entry({"admin", "system", "diskman", "smartattr"}, call("smart_attr"), nil).leaf = true +end + +function format_partition() + local partation_name = luci.http.formvalue("partation_name") + local fs = luci.http.formvalue("file_system") + if not partation_name then + luci.http.status(500, "Partition NOT found!") + luci.http.write_json("Partition NOT found!") + return + elseif not nixio.fs.access("/dev/"..partation_name) then + luci.http.status(500, "Partition NOT found!") + luci.http.write_json("Partition NOT found!") + return + elseif not fs then + luci.http.status(500, "no file system") + luci.http.write_json("no file system") + return + end + local dm = require "luci.model.diskman" + code, msg = dm.format_partition(partation_name, fs) + luci.http.status(code, msg) + luci.http.write_json(msg) +end + +function get_disk_info(dev) + if not dev then + luci.http.status(500, "no device") + luci.http.write_json("no device") + return + elseif not nixio.fs.access("/dev/"..dev) then + luci.http.status(500, "no device") + luci.http.write_json("no device") + return + end + local dm = require "luci.model.diskman" + local device_info = dm.get_disk_info(dev) + luci.http.status(200, "ok") + luci.http.prepare_content("application/json") + luci.http.write_json(device_info) +end + +function mk_p_table() + local p_table = luci.http.formvalue("p_table") + local dev = luci.http.formvalue("dev") + if not dev then + luci.http.status(500, "no device") + luci.http.write_json("no device") + return + elseif not nixio.fs.access("/dev/"..dev) then + luci.http.status(500, "no device") + luci.http.write_json("no device") + return + end + local dm = require "luci.model.diskman" + if p_table == "GPT" or p_table == "MBR" then + p_table = p_table == "MBR" and "msdos" or "gpt" + local res = luci.sys.call(dm.command.parted .. " -s /dev/" .. dev .. " mktable ".. p_table) + if res == 0 then + luci.http.status(200, "ok") + else + luci.http.status(500, "command exec error") + end + luci.http.prepare_content("application/json") + luci.http.write_json({code=res}) + else + luci.http.status(404, "not support") + luci.http.prepare_content("application/json") + luci.http.write_json({code="1"}) + end +end + +function smart_detail(dev) + luci.template.render("diskman/smart_detail", {dev=dev}) +end + +function smart_attr(dev) + local attr = { } + local dm = require "luci.model.diskman" + local cmd = io.popen(dm.command.smartctl .. " -H -A -i /dev/%s" % dev) + if cmd then + local content = cmd:read("*all") + local ln + cmd:close() + if content:match("NVMe Version:")then + for ln in string.gmatch(content,'[^\r\n]+') do + if ln:match("^(.-):%s+(.+)") then + local key, value = ln:match("^(.-):%s+(.+)") + attr[#attr+1]= { + key = key, + value = value + } + end + end + else + for ln in string.gmatch(content,'[^\r\n]+') do + if ln:match("^.*%d+%s+.+%s+.+%s+.+%s+.+%s+.+%s+.+%s+.+%s+.+%s+.+") then + local id,attrbute,flag,value,worst,thresh,type,updated,raw = ln:match("^%s*(%d+)%s+([%a%p]+)%s+(%w+)%s+(%d+)%s+(%d+)%s+(%d+)%s+([%a%p]+)%s+(%a+)%s+[%w%p]+%s+(.+)") + id= "%x" % id + if not id:match("^%w%w") then + id = "0%s" % id + end + attr[#attr+1]= { + id = id:upper(), + attrbute = attrbute, + flag = flag, + value = value, + worst = worst, + thresh = thresh, + type = type, + updated = updated, + raw = raw + } + end + end + end + end + luci.http.prepare_content("application/json") + luci.http.write_json(attr) +end diff --git a/luci-app-diskman/luasrc/model/cbi/diskman/btrfs.lua b/luci-app-diskman/luasrc/model/cbi/diskman/btrfs.lua new file mode 100644 index 0000000..0060078 --- /dev/null +++ b/luci-app-diskman/luasrc/model/cbi/diskman/btrfs.lua @@ -0,0 +1,210 @@ +--[[ +LuCI - Lua Configuration Interface +Copyright 2019 lisaac +]]-- + +require "luci.util" +require("luci.tools.webadmin") +local dm = require "luci.model.diskman" +local uuid = arg[1] + +if not uuid then luci.http.redirect(luci.dispatcher.build_url("admin/system/diskman")) end + +-- mount subv=/ to tempfs +mount_point = "/tmp/.btrfs_tmp" +nixio.fs.mkdirr(mount_point) +luci.util.exec(dm.command.umount .. " "..mount_point .. " >/dev/null 2>&1") +luci.util.exec(dm.command.mount .. " -t btrfs -o subvol=/ UUID="..uuid.." "..mount_point) + +m = SimpleForm("btrfs", translate("Btrfs"), translate("Manage Btrfs")) +m.template = "diskman/cbi/xsimpleform" +m.redirect = luci.dispatcher.build_url("admin/system/diskman") +m.submit = false +m.reset = false + +-- info +local btrfs_info = dm.get_btrfs_info(mount_point) +local table_btrfs_info = m:section(Table, {btrfs_info}, translate("Btrfs Info")) +table_btrfs_info:option(DummyValue, "uuid", translate("UUID")) +table_btrfs_info:option(DummyValue, "members", translate("Members")) +table_btrfs_info:option(DummyValue, "data_raid_level", translate("Data")) +table_btrfs_info:option(DummyValue, "metadata_raid_lavel", translate("Metadata")) +table_btrfs_info:option(DummyValue, "size_formated", translate("Size")) +table_btrfs_info:option(DummyValue, "used_formated", translate("Used")) +table_btrfs_info:option(DummyValue, "free_formated", translate("Free Space")) +table_btrfs_info:option(DummyValue, "usage", translate("Usage")) +local v_btrfs_label = table_btrfs_info:option(Value, "label", translate("Label")) +local value_btrfs_label = "" +v_btrfs_label.write = function(self, section, value) + value_btrfs_label = value or "" +end +local btn_update_label = table_btrfs_info:option(Button, "_update_label") +btn_update_label.inputtitle = translate("Update") +btn_update_label.inputstyle = "edit" +btn_update_label.write = function(self, section, value) + local cmd = dm.command.btrfs .. " filesystem label " .. mount_point .. " " .. value_btrfs_label + local res = luci.util.exec(cmd) + luci.http.redirect(luci.dispatcher.build_url("admin/system/diskman/btrfs/" .. uuid)) +end +-- subvolume +local subvolume_list = dm.get_btrfs_subv(mount_point) +subvolume_list["_"] = { ID = 0 } +table_subvolume = m:section(Table, subvolume_list, translate("SubVolumes")) +table_subvolume:option(DummyValue, "id", translate("ID")) +table_subvolume:option(DummyValue, "top_level", translate("Top Level")) +table_subvolume:option(DummyValue, "uuid", translate("UUID")) +table_subvolume:option(DummyValue, "otime", translate("Otime")) +table_subvolume:option(DummyValue, "snapshots", translate("Snapshots")) +local v_path = table_subvolume:option(Value, "path", translate("Path")) +v_path.forcewrite = true +v_path.render = function(self, section, scope) + if subvolume_list[section].ID == 0 then + self.template = "cbi/value" + self.placeholder = "/my_subvolume" + self.forcewrite = true + Value.render(self, section, scope) + else + self.template = "cbi/dvalue" + DummyValue.render(self, section, scope) + end +end +local value_path +v_path.write = function(self, section, value) + value_path = value +end +local btn_set_default = table_subvolume:option(Button, "_subv_set_default", translate("Set Default")) +btn_set_default.forcewrite = true +btn_set_default.inputstyle = "edit" +btn_set_default.template = "diskman/cbi/disabled_button" +btn_set_default.render = function(self, section, scope) + if subvolume_list[section].default_subvolume then + self.view_disabled = true + self.inputtitle = translate("Set Default") + elseif subvolume_list[section].ID == 0 then + self.template = "cbi/dvalue" + else + self.inputtitle = translate("Set Default") + self.view_disabled = false + end + Button.render(self, section, scope) +end +btn_set_default.write = function(self, section, value) + local cmd + if value == translate("Set Default") then + cmd = dm.command.btrfs .. " subvolume set-default " .. mount_point..subvolume_list[section].path + else + cmd = dm.command.btrfs .. " subvolume set-default " .. mount_point.."/" + end + local res = luci.util.exec(cmd.. " 2>&1") + if res and (res:match("ERR") or res:match("not enough arguments")) then + m.errmessage = res + else + luci.http.redirect(luci.dispatcher.build_url("admin/system/diskman/btrfs/" .. uuid)) + end +end +local btn_remove = table_subvolume:option(Button, "_subv_remove") +btn_remove.template = "diskman/cbi/disabled_button" +btn_remove.forcewrite = true +btn_remove.render = function(self, section, scope) + if subvolume_list[section].ID == 0 then + btn_remove.inputtitle = translate("Create") + btn_remove.inputstyle = "add" + self.view_disabled = false + elseif subvolume_list[section].path == "/" or subvolume_list[section].default_subvolume then + btn_remove.inputtitle = translate("Delete") + btn_remove.inputstyle = "remove" + self.view_disabled = true + else + btn_remove.inputtitle = translate("Delete") + btn_remove.inputstyle = "remove" + self.view_disabled = false + end + Button.render(self, section, scope) +end + +btn_remove.write = function(self, section, value) + local cmd + if value == translate("Delete") then + cmd = dm.command.btrfs .. " subvolume delete " .. mount_point .. subvolume_list[section].path + elseif value == translate("Create") then + if value_path and value_path:match("^/") then + cmd = dm.command.btrfs .. " subvolume create " .. mount_point .. value_path + else + m.errmessage = translate("Please input Subvolume Path, Subvolume must start with '/'") + return + end + end + local res = luci.util.exec(cmd.. " 2>&1") + if res and (res:match("ERR") or res:match("not enough arguments")) then + m.errmessage = luci.util.pcdata(res) + else + luci.http.redirect(luci.dispatcher.build_url("admin/system/diskman/btrfs/" .. uuid)) + end +end +-- snapshot +-- local snapshot_list = dm.get_btrfs_subv(mount_point, 1) +-- table_snapshot = m:section(Table, snapshot_list, translate("Snapshots")) +-- table_snapshot:option(DummyValue, "id", translate("ID")) +-- table_snapshot:option(DummyValue, "top_level", translate("Top Level")) +-- table_snapshot:option(DummyValue, "uuid", translate("UUID")) +-- table_snapshot:option(DummyValue, "otime", translate("Otime")) +-- table_snapshot:option(DummyValue, "path", translate("Path")) +-- local snp_remove = table_snapshot:option(Button, "_snp_remove") +-- snp_remove.inputtitle = translate("Delete") +-- snp_remove.inputstyle = "remove" +-- snp_remove.write = function(self, section, value) +-- local cmd = dm.command.btrfs .. " subvolume delete " .. mount_point .. snapshot_list[section].path +-- local res = luci.util.exec(cmd.. " 2>&1") +-- if res and (res:match("ERR") or res:match("not enough arguments")) then +-- m.errmessage = luci.util.pcdata(res) +-- else +-- luci.http.redirect(luci.dispatcher.build_url("admin/system/diskman/btrfs/" .. uuid)) +-- end +-- end + +-- new snapshots +local s_snapshot = m:section(SimpleSection, translate("New Snapshot")) +local value_sorce, value_dest, value_readonly +local v_sorce = s_snapshot:option(Value, "_source", translate("Source Path"), translate("The source path for create the snapshot")) +v_sorce.placeholder = "/data" +v_sorce.forcewrite = true +v_sorce.write = function(self, section, value) + value_sorce = value +end + +local v_readonly = s_snapshot:option(Flag, "_readonly", translate("Readonly"), translate("The path where you want to store the snapshot")) +v_readonly.forcewrite = true +v_readonly.rmempty = false +v_readonly.disabled = 0 +v_readonly.enabled = 1 +v_readonly.default = 1 +v_readonly.write = function(self, section, value) + value_readonly = value +end +local v_dest = s_snapshot:option(Value, "_dest", translate("Destination Path (optional)")) +v_dest.forcewrite = true +v_dest.placeholder = "/.snapshot/202002051538" +v_dest.write = function(self, section, value) + value_dest = value +end +local btn_snp_create = s_snapshot:option(Button, "_snp_create") +btn_snp_create.title = " " +btn_snp_create.inputtitle = translate("New Snapshot") +btn_snp_create.inputstyle = "add" +btn_snp_create.write = function(self, section, value) + if value_sorce and value_sorce:match("^/") then + if not value_dest then value_dest = "/.snapshot"..value_sorce.."/"..os.date("%Y%m%d%H%M%S") end + nixio.fs.mkdirr(mount_point..value_dest:match("(.-)[^/]+$")) + local cmd = dm.command.btrfs .. " subvolume snapshot" .. (value_readonly == 1 and " -r " or " ") .. mount_point..value_sorce .. " " .. mount_point..value_dest + local res = luci.util.exec(cmd .. " 2>&1") + if res and (res:match("ERR") or res:match("not enough arguments")) then + m.errmessage = luci.util.pcdata(res) + else + luci.http.redirect(luci.dispatcher.build_url("admin/system/diskman/btrfs/" .. uuid)) + end + else + m.errmessage = translate("Please input Source Path of snapshot, Source Path must start with '/'") + end +end + +return m diff --git a/luci-app-diskman/luasrc/model/cbi/diskman/disks.lua b/luci-app-diskman/luasrc/model/cbi/diskman/disks.lua new file mode 100644 index 0000000..f49e89f --- /dev/null +++ b/luci-app-diskman/luasrc/model/cbi/diskman/disks.lua @@ -0,0 +1,360 @@ +--[[ +LuCI - Lua Configuration Interface +Copyright 2019 lisaac +]]-- + +require "luci.util" +require("luci.tools.webadmin") +local dm = require "luci.model.diskman" + +-- Use (non-UCI) SimpleForm since we have no related config file +m = SimpleForm("diskman", translate("DiskMan"), translate("Manage Disks over LuCI.")) +m.template = "diskman/cbi/xsimpleform" +m:append(Template("diskman/disk_info")) +-- disable submit and reset button +m.submit = false +m.reset = false +-- rescan disks +rescan = m:section(SimpleSection) +rescan_button = rescan:option(Button, "_rescan") +rescan_button.inputtitle= translate("Rescan Disks") +rescan_button.template = "diskman/cbi/inlinebutton" +rescan_button.inputstyle = "add" +rescan_button.forcewrite = true +rescan_button.write = function(self, section, value) + luci.util.exec("echo '- - -' | tee /sys/class/scsi_host/host*/scan > /dev/null") + if dm.command.mdadm then + luci.util.exec(dm.command.mdadm .. " --assemble --scan") + end + luci.http.redirect(luci.dispatcher.build_url("admin/system/diskman")) +end + +-- disks +local disks = dm.list_devices() +d = m:section(Table, disks, translate("Disks")) +d.config = "disk" +-- option(type, id(key of table), text) +d:option(DummyValue, "path", translate("Path")) +d:option(DummyValue, "model", translate("Model")) +d:option(DummyValue, "sn", translate("Serial Number")) +d:option(DummyValue, "size_formated", translate("Size")) +d:option(DummyValue, "temp", translate("Temp")) +-- d:option(DummyValue, "sec_size", translate("Sector Size ")) +d:option(DummyValue, "p_table", translate("Partition Table")) +d:option(DummyValue, "sata_ver", translate("SATA Version")) +-- d:option(DummyValue, "rota_rate", translate("Rotation Rate")) +d:option(DummyValue, "health_status", translate("Health") .. "
" .. translate("Status")) +-- d:option(DummyValue, "status", translate("Status")) + +local btn_eject = d:option(Button, "_eject") +btn_eject.template = "diskman/cbi/disabled_button" +btn_eject.inputstyle = "remove" +btn_eject.inputtitle = translate("Eject") +btn_eject.forcewrite = true +btn_eject.write = function(self, section, value) + local dev = section + local disk_info = dm.get_disk_info(dev, true) + if disk_info.p_table:match("Raid") then + m.errmessage = translate("Unsupported raid reject!") + return + end + for i, p in ipairs(disk_info.partitions) do + if p.mount_point ~= "-" then + m.errmessage = p.name .. translate("is in use! please unmount it first!") + return + end + end + if disk_info.type:match("md") then + luci.util.exec(dm.command.mdadm .. " --stop /dev/" .. dev) + luci.util.exec(dm.command.mdadm .. " --remove /dev/" .. dev) + for _, disk in ipairs(disk_info.members) do + luci.util.exec(dm.command.mdadm .. " --zero-superblock " .. disk) + end + dm.gen_mdadm_config() + else + luci.util.exec("echo 1 > /sys/block/" .. dev .. "/device/delete") + end + luci.http.redirect(luci.dispatcher.build_url("admin/system/diskman")) +end + +d.extedit = luci.dispatcher.build_url("admin/system/diskman/partition/%s") + +-- raid devices +if dm.command.mdadm then + local raid_devices = dm.list_raid_devices() + -- raid_devices = diskmanager.getRAIDdevices() + if next(raid_devices) ~= nil then + local r = m:section(Table, raid_devices, translate("RAID Devices")) + r.config = "_raid" + r:option(DummyValue, "path", translate("Path")) + r:option(DummyValue, "level", translate("RAID mode")) + r:option(DummyValue, "size_formated", translate("Size")) + r:option(DummyValue, "p_table", translate("Partition Table")) + r:option(DummyValue, "status", translate("Status")) + r:option(DummyValue, "members_str", translate("Members")) + r:option(DummyValue, "active", translate("Active")) + r.extedit = luci.dispatcher.build_url("admin/system/diskman/partition/%s") + end +end + +-- btrfs devices +if dm.command.btrfs then + btrfs_devices = dm.list_btrfs_devices() + if next(btrfs_devices) ~= nil then + local table_btrfs = m:section(Table, btrfs_devices, translate("Btrfs")) + table_btrfs:option(DummyValue, "uuid", translate("UUID")) + table_btrfs:option(DummyValue, "label", translate("Label")) + table_btrfs:option(DummyValue, "members", translate("Members")) + -- sieze is error, since there is RAID + -- table_btrfs:option(DummyValue, "size_formated", translate("Size")) + table_btrfs:option(DummyValue, "used_formated", translate("Usage")) + table_btrfs.extedit = luci.dispatcher.build_url("admin/system/diskman/btrfs/%s") + end +end + +-- mount point +local mount_point = dm.get_mount_points() +local _mount_point = {} +table.insert( mount_point, { device = 0 } ) +local table_mp = m:section(Table, mount_point, translate("Mount Point")) +local v_device = table_mp:option(Value, "device", translate("Device")) +v_device.render = function(self, section, scope) + if mount_point[section].device == 0 then + self.template = "cbi/value" + self.forcewrite = true + for dev, info in pairs(disks) do + for i, v in ipairs(info.partitions) do + self:value("/dev/".. v.name, "/dev/".. v.name .. " ".. v.size_formated) + end + end + Value.render(self, section, scope) + else + self.template = "cbi/dvalue" + DummyValue.render(self, section, scope) + end +end +v_device.write = function(self, section, value) + _mount_point.device = value and value:gsub("%s+", "") or "" +end +local v_fs = table_mp:option(Value, "fs", translate("File System")) +v_fs.render = function(self, section, scope) + if mount_point[section].device == 0 then + self.template = "cbi/value" + self:value("auto", "auto") + self.default = "auto" + self.forcewrite = true + Value.render(self, section, scope) + else + self.template = "cbi/dvalue" + DummyValue.render(self, section, scope) + end +end +v_fs.write = function(self, section, value) + _mount_point.fs = value and value:gsub("%s+", "") or "" +end +local v_mount_option = table_mp:option(Value, "mount_options", translate("Mount Options")) +v_mount_option.render = function(self, section, scope) + if mount_point[section].device == 0 then + self.template = "cbi/value" + self.placeholder = "rw,noauto" + self.forcewrite = true + Value.render(self, section, scope) + else + self.template = "cbi/dvalue" + local mp = mount_point[section].mount_options + mount_point[section].mount_options = nil + local length = 0 + for k in mp:gmatch("([^,]+)") do + mount_point[section].mount_options = mount_point[section].mount_options and (mount_point[section].mount_options .. ",") or "" + if length > 20 then + mount_point[section].mount_options = mount_point[section].mount_options.. "
" + length = 0 + end + mount_point[section].mount_options = mount_point[section].mount_options .. k + length = length + #k + end + self.rawhtml = true + -- mount_point[section].mount_options = #mount_point[section].mount_options > 50 and mount_point[section].mount_options:sub(1,50) .. "..." or mount_point[section].mount_options + DummyValue.render(self, section, scope) + end +end +v_mount_option.write = function(self, section, value) + _mount_point.mount_options = value and value:gsub("%s+", "") or "" +end +local v_mount_point = table_mp:option(Value, "mount_point", translate("Mount Point")) +v_mount_point.render = function(self, section, scope) + if mount_point[section].device == 0 then + self.template = "cbi/value" + self.placeholder = "/media/diskX" + self.forcewrite = true + Value.render(self, section, scope) + else + self.template = "cbi/dvalue" + local new_mp = "" + local v_mp_d + for v_mp_d in self["section"]["data"][section]["mount_point"]:gmatch('[^/]+') do + if #v_mp_d > 12 then + new_mp = new_mp .. "/" .. v_mp_d:sub(1,7) .. ".." .. v_mp_d:sub(-4) + else + new_mp = new_mp .."/".. v_mp_d + end + end + self["section"]["data"][section]["mount_point"] = ''..new_mp..'' + self.rawhtml = true + DummyValue.render(self, section, scope) + end +end +v_mount_point.write = function(self, section, value) + _mount_point.mount_point = value +end +local btn_umount = table_mp:option(Button, "_mount", translate("Mount")) +btn_umount.forcewrite = true +btn_umount.render = function(self, section, scope) + if mount_point[section].device == 0 then + self.inputtitle = translate("Mount") + btn_umount.inputstyle = "add" + else + self.inputtitle = translate("Umount") + btn_umount.inputstyle = "remove" + end + Button.render(self, section, scope) +end +btn_umount.write = function(self, section, value) + local res + if value == translate("Mount") then + if not _mount_point.mount_point or not _mount_point.device then return end + luci.util.exec("mkdir -p ".. _mount_point.mount_point) + res = luci.util.exec(dm.command.mount .. " ".. _mount_point.device .. (_mount_point.fs and (" -t ".. _mount_point.fs )or "") .. (_mount_point.mount_options and (" -o " .. _mount_point.mount_options.. " ") or " ").._mount_point.mount_point .. " 2>&1") + elseif value == translate("Umount") then + res = luci.util.exec(dm.command.umount .. " "..mount_point[section].mount_point .. " 2>&1") + end + if res:match("^mount:") or res:match("^umount:") then + m.errmessage = luci.util.pcdata(res) + else + luci.http.redirect(luci.dispatcher.build_url("admin/system/diskman")) + end +end + +if dm.command.mdadm or dm.command.btrfs then +local creation_section = m:section(TypedSection, "_creation") +creation_section.cfgsections=function() + return {translate("Creation")} +end +creation_section:tab("raid", translate("RAID"), translate("RAID Creation")) +creation_section:tab("btrfs", translate("Btrfs"), translate("Multiple Devices Btrfs Creation")) + +-- raid functions +if dm.command.mdadm then + + local rname, rmembers, rlevel + local r_name = creation_section:taboption("raid", Value, "_rname", translate("Raid Name")) + r_name.placeholder = dm.find_free_md_device() + r_name.write = function(self, section, value) + rname = value + end + local r_level = creation_section:taboption("raid", ListValue, "_rlevel", translate("Raid Level")) + local valid_raid = luci.util.exec("grep -m1 'Personalities :' /proc/mdstat") + if valid_raid:match("%[linear%]") then + r_level:value("linear", "Linear") + end + if valid_raid:match("%[raid5%]") then + r_level:value("5", "Raid 5") + end + if valid_raid:match("%[raid6%]") then + r_level:value("6", "Raid 6") + end + if valid_raid:match("%[raid1%]") then + r_level:value("1", "Raid 1") + end + if valid_raid:match("%[raid0%]") then + r_level:value("0", "Raid 0") + end + if valid_raid:match("%[raid10%]") then + r_level:value("10", "Raid 10") + end + r_level.write = function(self, section, value) + rlevel = value + end + local r_member = creation_section:taboption("raid", DynamicList, "_rmember", translate("Raid Member")) + for dev, info in pairs(disks) do + if not info.inuse and #info.partitions == 0 then + r_member:value(info.path, info.path.. " ".. info.size_formated) + end + for i, v in ipairs(info.partitions) do + if not v.inuse then + r_member:value("/dev/".. v.name, "/dev/".. v.name .. " ".. v.size_formated) + end + end + end + r_member.write = function(self, section, value) + rmembers = value + end + local r_create = creation_section:taboption("raid", Button, "_rcreate") + r_create.render = function(self, section, scope) + self.title = " " + self.inputtitle = translate("Create Raid") + self.inputstyle = "add" + Button.render(self, section, scope) + end + r_create.write = function(self, section, value) + -- mdadm --create --verbose /dev/md0 --level=stripe --raid-devices=2 /dev/sdb6 /dev/sdc5 + local res = dm.create_raid(rname, rlevel, rmembers) + if res and res:match("^ERR") then + m.errmessage = luci.util.pcdata(res) + return + end + dm.gen_mdadm_config() + luci.http.redirect(luci.dispatcher.build_url("admin/system/diskman")) + end +end + +-- btrfs +if dm.command.btrfs then + local blabel, bmembers, blevel + local btrfs_label = creation_section:taboption("btrfs", Value, "_blabel", translate("Btrfs Label")) + btrfs_label.write = function(self, section, value) + blabel = value + end + local btrfs_level = creation_section:taboption("btrfs", ListValue, "_blevel", translate("Btrfs Raid Level")) + btrfs_level:value("single", "Single") + btrfs_level:value("raid0", "Raid 0") + btrfs_level:value("raid1", "Raid 1") + btrfs_level:value("raid10", "Raid 10") + btrfs_level.write = function(self, section, value) + blevel = value + end + + local btrfs_member = creation_section:taboption("btrfs", DynamicList, "_bmember", translate("Btrfs Member")) + for dev, info in pairs(disks) do + if not info.inuse and #info.partitions == 0 then + btrfs_member:value(info.path, info.path.. " ".. info.size_formated) + end + for i, v in ipairs(info.partitions) do + if not v.inuse then + btrfs_member:value("/dev/".. v.name, "/dev/".. v.name .. " ".. v.size_formated) + end + end + end + btrfs_member.write = function(self, section, value) + bmembers = value + end + local btrfs_create = creation_section:taboption("btrfs", Button, "_bcreate") + btrfs_create.render = function(self, section, scope) + self.title = " " + self.inputtitle = translate("Create Btrfs") + self.inputstyle = "add" + Button.render(self, section, scope) + end + btrfs_create.write = function(self, section, value) + -- mkfs.btrfs -L label -d blevel /dev/sda /dev/sdb + local res = dm.create_btrfs(blabel, blevel, bmembers) + if res and res:match("^ERR") then + m.errmessage = luci.util.pcdata(res) + return + end + luci.http.redirect(luci.dispatcher.build_url("admin/system/diskman")) + end +end +end + +return m diff --git a/luci-app-diskman/luasrc/model/cbi/diskman/partition.lua b/luci-app-diskman/luasrc/model/cbi/diskman/partition.lua new file mode 100644 index 0000000..1428eb6 --- /dev/null +++ b/luci-app-diskman/luasrc/model/cbi/diskman/partition.lua @@ -0,0 +1,366 @@ +--[[ +LuCI - Lua Configuration Interface +Copyright 2019 lisaac +]]-- + +require "luci.util" +require("luci.tools.webadmin") +local dm = require "luci.model.diskman" +local dev = arg[1] + +if not dev then + luci.http.redirect(luci.dispatcher.build_url("admin/system/diskman")) +elseif not nixio.fs.access("/dev/"..dev) then + luci.http.redirect(luci.dispatcher.build_url("admin/system/diskman")) +end + +m = SimpleForm("partition", translate("Partition Management"), translate("Partition Disk over LuCI.")) +m.template = "diskman/cbi/xsimpleform" +m.redirect = luci.dispatcher.build_url("admin/system/diskman") +m:append(Template("diskman/partition_info")) +-- disable submit and reset button +m.submit = false +m.reset = false + +local disk_info = dm.get_disk_info(dev, true) +local format_cmd = dm.get_format_cmd() + +s = m:section(Table, {disk_info}, translate("Device Info")) +-- s:option(DummyValue, "key") +-- s:option(DummyValue, "value") +s:option(DummyValue, "path", translate("Path")) +s:option(DummyValue, "model", translate("Model")) +s:option(DummyValue, "sn", translate("Serial Number")) +s:option(DummyValue, "size_formated", translate("Size")) +s:option(DummyValue, "sec_size", translate("Sector Size")) +local dv_p_table = s:option(ListValue, "p_table", translate("Partition Table")) +dv_p_table.render = function(self, section, scope) + -- create table only if not used by raid and no partitions on disk + if not disk_info.p_table:match("Raid") and (#disk_info.partitions == 0 or (#disk_info.partitions == 1 and disk_info.partitions[1].number == -1) or (disk_info.p_table:match("LOOP") and not disk_info.partitions[1].inuse)) then + self:value(disk_info.p_table, disk_info.p_table) + self:value("GPT", "GPT") + self:value("MBR", "MBR") + self.default = disk_info.p_table + ListValue.render(self, section, scope) + else + self.template = "cbi/dvalue" + DummyValue.render(self, section, scope) + end +end +if disk_info.type:match("md") then + s:option(DummyValue, "level", translate("Level")) + s:option(DummyValue, "members_str", translate("Members")) +else + s:option(DummyValue, "temp", translate("Temp")) + s:option(DummyValue, "sata_ver", translate("SATA Version")) + s:option(DummyValue, "rota_rate", translate("Rotation Rate")) +end +s:option(DummyValue, "status", translate("Status")) +local btn_health = s:option(Button, "health", translate("Health")) +btn_health.render = function(self, section, scope) + if disk_info.health then + self.inputtitle = disk_info.health + if disk_info.health == "PASSED" then + self.inputstyle = "add" + else + self.inputstyle = "remove" + end + Button.render(self, section, scope) + else + self.template = "cbi/dvalue" + DummyValue.render(self, section, scope) + end +end + +local btn_eject = s:option(Button, "_eject") +btn_eject.template = "diskman/cbi/disabled_button" +btn_eject.inputstyle = "remove" +btn_eject.render = function(self, section, scope) + for i, p in ipairs(disk_info.partitions) do + if p.mount_point ~= "-" then + self.view_disabled = true + break + end + end + if disk_info.p_table:match("Raid") then + self.view_disabled = true + end + if disk_info.type:match("md") then + btn_eject.inputtitle = translate("Remove") + else + btn_eject.inputtitle = translate("Eject") + end + Button.render(self, section, scope) +end +btn_eject.forcewrite = true +btn_eject.write = function(self, section, value) + for i, p in ipairs(disk_info.partitions) do + if p.mount_point ~= "-" then + m.errmessage = p.name .. translate("is in use! please unmount it first!") + return + end + end + if disk_info.type:match("md") then + luci.util.exec(dm.command.mdadm .. " --stop /dev/" .. dev) + luci.util.exec(dm.command.mdadm .. " --remove /dev/" .. dev) + for _, disk in ipairs(disk_info.members) do + luci.util.exec(dm.command.mdadm .. " --zero-superblock " .. disk) + end + dm.gen_mdadm_config() + else + luci.util.exec("echo 1 > /sys/block/" .. dev .. "/device/delete") + end + luci.http.redirect(luci.dispatcher.build_url("admin/system/diskman")) +end +-- eject: echo 1 > /sys/block/(device)/device/delete +-- rescan: echo '- - -' | tee /sys/class/scsi_host/host*/scan > /dev/null + + +-- partitions info +if not disk_info.p_table:match("Raid") then + s_partition_table = m:section(Table, disk_info.partitions, translate("Partitions Info"), translate("Default 2048 sector alignment, support +size{b,k,m,g,t} in End Sector")) + + -- s_partition_table:option(DummyValue, "number", translate("Number")) + s_partition_table:option(DummyValue, "name", translate("Name")) + local val_sec_start = s_partition_table:option(Value, "sec_start", translate("Start Sector")) + val_sec_start.render = function(self, section, scope) + -- could create new partition + if disk_info.partitions[section].number == -1 and disk_info.partitions[section].size > 1 * 1024 * 1024 then + self.template = "cbi/value" + Value.render(self, section, scope) + else + self.template = "cbi/dvalue" + DummyValue.render(self, section, scope) + end + end + local val_sec_end = s_partition_table:option(Value, "sec_end", translate("End Sector")) + val_sec_end.render = function(self, section, scope) + -- could create new partition + if disk_info.partitions[section].number == -1 and disk_info.partitions[section].size > 1 * 1024 * 1024 then + self.template = "cbi/value" + Value.render(self, section, scope) + else + self.template = "cbi/dvalue" + DummyValue.render(self, section, scope) + end + end + val_sec_start.forcewrite = true + val_sec_start.write = function(self, section, value) + disk_info.partitions[section]._sec_start = value + end + val_sec_end.forcewrite = true + val_sec_end.write = function(self, section, value) + disk_info.partitions[section]._sec_end = value + end + s_partition_table:option(DummyValue, "size_formated", translate("Size")) + if disk_info.p_table == "MBR" then + s_partition_table:option(DummyValue, "type", translate("Type")) + end + s_partition_table:option(DummyValue, "used_formated", translate("Used")) + s_partition_table:option(DummyValue, "free_formated", translate("Free Space")) + s_partition_table:option(DummyValue, "usage", translate("Usage")) + local dv_mount_point = s_partition_table:option(DummyValue, "mount_point", translate("Mount Point")) + dv_mount_point.rawhtml = true + dv_mount_point.render = function(self, section, scope) + local new_mp = "" + local v_mp_d + for line in self["section"]["data"][section]["mount_point"]:gmatch("[^%s]+") do + if line == '-' then + new_mp = line + break + end + for v_mp_d in line:gmatch('[^/]+') do + if #v_mp_d > 12 then + new_mp = new_mp .. "/" .. v_mp_d:sub(1,7) .. ".." .. v_mp_d:sub(-4) + else + new_mp = new_mp .."/".. v_mp_d + end + end + new_mp = '' ..new_mp ..'' .. "
" + end + self["section"]["data"][section]["mount_point"] = new_mp + DummyValue.render(self, section, scope) + end + local val_fs = s_partition_table:option(Value, "fs", translate("File System")) + val_fs.forcewrite = true + val_fs.partitions = disk_info.partitions + for k, v in pairs(format_cmd) do + val_fs.format_cmd = val_fs.format_cmd and (val_fs.format_cmd .. "," .. k) or k + end + + val_fs.write = function(self, section, value) + disk_info.partitions[section]._fs = value + end + val_fs.render = function(self, section, scope) + -- use listvalue when partition not mounted + if disk_info.partitions[section].mount_point == "-" and disk_info.partitions[section].number ~= -1 and disk_info.partitions[section].type ~= "extended" then + self.template = "diskman/cbi/format_button" + self.inputstyle = "reset" + self.inputtitle = disk_info.partitions[section].fs == "raw" and translate("Format") or disk_info.partitions[section].fs + Button.render(self, section, scope) + -- self:reset_values() + -- self.keylist = {} + -- self.vallist = {} + -- for k, v in pairs(format_cmd) do + -- self:value(k,k) + -- end + -- self.default = disk_info.partitions[section].fs + else + -- self:reset_values() + -- self.keylist = {} + -- self.vallist = {} + self.template = "cbi/dvalue" + DummyValue.render(self, section, scope) + end + end + -- btn_format = s_partition_table:option(Button, "_format") + -- btn_format.template = "diskman/cbi/format_button" + -- btn_format.partitions = disk_info.partitions + -- btn_format.render = function(self, section, scope) + -- if disk_info.partitions[section].mount_point == "-" and disk_info.partitions[section].number ~= -1 and disk_info.partitions[section].type ~= "extended" then + -- self.inputtitle = translate("Format") + -- self.template = "diskman/cbi/disabled_button" + -- self.view_disabled = false + -- self.inputstyle = "reset" + -- for k, v in pairs(format_cmd) do + -- self:depends("val_fs", "k") + -- end + -- -- elseif disk_info.partitions[section].mount_point ~= "-" and disk_info.partitions[section].number ~= -1 then + -- -- self.inputtitle = "Format" + -- -- self.template = "diskman/cbi/disabled_button" + -- -- self.view_disabled = true + -- -- self.inputstyle = "reset" + -- else + -- self.inputtitle = "" + -- self.template = "cbi/dvalue" + -- end + -- Button.render(self, section, scope) + -- end + -- btn_format.forcewrite = true + -- btn_format.write = function(self, section, value) + -- local partition_name = "/dev/".. disk_info.partitions[section].name + -- if not nixio.fs.access(partition_name) then + -- m.errmessage = translate("Partition NOT found!") + -- return + -- end + -- local fs = disk_info.partitions[section]._fs + -- if not format_cmd[fs] then + -- m.errmessage = translate("Filesystem NOT support!") + -- return + -- end + -- local cmd = format_cmd[fs].cmd .. " " .. format_cmd[fs].option .. " " .. partition_name + -- local res = luci.util.exec(cmd .. " 2>&1") + -- if res and res:lower():match("error+") then + -- m.errmessage = luci.util.pcdata(res) + -- else + -- luci.http.redirect(luci.dispatcher.build_url("admin/system/diskman/partition/" .. dev)) + -- end + -- end + + local btn_action = s_partition_table:option(Button, "_action") + btn_action.forcewrite = true + btn_action.template = "diskman/cbi/disabled_button" + btn_action.render = function(self, section, scope) + -- if partition is mounted or the size < 1mb, then disable the add action + if disk_info.partitions[section].mount_point ~= "-" or (disk_info.partitions[section].type ~= "extended" and disk_info.partitions[section].number == -1 and disk_info.partitions[section].size <= 1 * 1024 * 1024) then + self.view_disabled = true + -- self.inputtitle = "" + -- self.template = "cbi/dvalue" + elseif disk_info.partitions[section].type == "extended" and next(disk_info.partitions[section]["logicals"]) ~= nil then + self.view_disabled = true + else + -- self.template = "diskman/cbi/disabled_button" + self.view_disabled = false + end + if disk_info.partitions[section].number ~= -1 then + self.inputtitle = translate("Remove") + self.inputstyle = "remove" + else + self.inputtitle = translate("New") + self.inputstyle = "add" + end + Button.render(self, section, scope) + end + btn_action.write = function(self, section, value) + if value == translate("New") then + local start_sec = disk_info.partitions[section]._sec_start and tonumber(disk_info.partitions[section]._sec_start) or tonumber(disk_info.partitions[section].sec_start) + local end_sec = disk_info.partitions[section]._sec_end + + if start_sec then + -- for sector alignment + local align = tonumber(disk_info.phy_sec) / tonumber(disk_info.logic_sec) + align = (align < 2048) and 2048 + if start_sec < 2048 then + start_sec = "2048" .. "s" + elseif math.fmod( start_sec, align ) ~= 0 then + start_sec = tostring(start_sec + align - math.fmod( start_sec, align )) .. "s" + else + start_sec = start_sec .. "s" + end + else + m.errmessage = translate("Invalid Start Sector!") + return + end + -- support +size format for End sector + local end_size, end_unit = end_sec:match("^+(%d-)([bkmgtsBKMGTS])$") + if tonumber(end_size) and end_unit then + local unit ={ + B=1, + S=512, + K=1024, + M=1048576, + G=1073741824, + T=1099511627776 + } + end_unit = end_unit:upper() + end_sec = tostring(tonumber(end_size) * unit[end_unit] / unit["S"] + tonumber(start_sec:sub(1,-2)) - 1 ) .. "s" + elseif tonumber(end_sec) then + end_sec = end_sec .. "s" + else + m.errmessage = translate("Invalid End Sector!") + return + end + local part_type = "primary" + + if disk_info.p_table == "MBR" and disk_info["extended_partition_index"] then + if tonumber(disk_info.partitions[disk_info["extended_partition_index"]].sec_start) <= tonumber(start_sec:sub(1,-2)) and tonumber(disk_info.partitions[disk_info["extended_partition_index"]].sec_end) >= tonumber(end_sec:sub(1,-2)) then + part_type = "logical" + if tonumber(start_sec:sub(1,-2)) - tonumber(disk_info.partitions[section].sec_start) < 2048 then + start_sec = tonumber(start_sec:sub(1,-2)) + 2048 + start_sec = start_sec .."s" + end + end + elseif disk_info.p_table == "GPT" then + -- AUTOMATIC FIX GPT PARTITION TABLE + -- Not all of the space available to /dev/sdb appears to be used, you can fix the GPT to use all of the space (an extra 16123870 blocks) or continue with the current setting? + local cmd = ' printf "ok\nfix\n" | parted ---pretend-input-tty /dev/'.. dev ..' print' + luci.util.exec(cmd .. " 2>&1") + end + + -- partiton + local cmd = dm.command.parted .. " -s -a optimal /dev/" .. dev .. " mkpart " .. part_type .." " .. start_sec .. " " .. end_sec + local res = luci.util.exec(cmd .. " 2>&1") + if res and res:lower():match("error+") then + m.errmessage = luci.util.pcdata(res) + else + luci.http.redirect(luci.dispatcher.build_url("admin/system/diskman/partition/" .. dev)) + end + elseif value == translate("Remove") then + -- remove partition + local number = tostring(disk_info.partitions[section].number) + if (not number) or (number == "") then + m.errmessage = translate("Partition not exists!") + return + end + local cmd = dm.command.parted .. " -s /dev/" .. dev .. " rm " .. number + local res = luci.util.exec(cmd .. " 2>&1") + if res and res:lower():match("error+") then + m.errmessage = luci.util.pcdata(res) + else + luci.http.redirect(luci.dispatcher.build_url("admin/system/diskman/partition/" .. dev)) + end + end + end +end + +return m diff --git a/luci-app-diskman/luasrc/model/diskman.lua b/luci-app-diskman/luasrc/model/diskman.lua new file mode 100644 index 0000000..263b280 --- /dev/null +++ b/luci-app-diskman/luasrc/model/diskman.lua @@ -0,0 +1,746 @@ +--[[ +LuCI - Lua Configuration Interface +Copyright 2019 lisaac +]]-- + +require "luci.util" +local ver = require "luci.version" + +local CMD = {"parted", "mdadm", "blkid", "smartctl", "df", "btrfs", "lsblk"} + +local d = {command ={}} +for _, cmd in ipairs(CMD) do + local command = luci.sys.exec("/usr/bin/which " .. cmd) + d.command[cmd] = command:match("^.+"..cmd) or nil +end + +d.command.mount = nixio.fs.access("/usr/bin/mount") and "/usr/bin/mount" or "/bin/mount" +d.command.umount = nixio.fs.access("/usr/bin/umount") and "/usr/bin/umount" or "/bin/umount" + +local proc_mounts = nixio.fs.readfile("/proc/mounts") or "" +local mounts = luci.util.exec(d.command.mount .. " 2>/dev/null") or "" +local swaps = nixio.fs.readfile("/proc/swaps") or "" +local df = luci.sys.exec(d.command.df .. " 2>/dev/null") or "" + +function byte_format(byte) + local suff = {"B", "KB", "MB", "GB", "TB"} + for i=1, 5 do + if byte > 1024 and i < 5 then + byte = byte / 1024 + else + return string.format("%.2f %s", byte, suff[i]) + end + end +end + +local get_smart_info = function(device) + local section + local smart_info = {} + for _, line in ipairs(luci.util.execl(d.command.smartctl .. " -H -A -i -n standby -f brief /dev/" .. device)) do + local attrib, val + if section == 1 then + attrib, val = line:match "^(.-):%s+(.+)" + elseif section == 2 and smart_info.nvme_ver then + attrib, val = line:match("^(.-):%s+(.+)") + if not smart_info.health then smart_info.health = line:match(".-overall%-health.-: (.+)") end + elseif section == 2 then + attrib, val = line:match("^([0-9 ]+)%s+[^ ]+%s+[POSRCK-]+%s+[0-9-]+%s+[0-9-]+%s+[0-9-]+%s+[0-9-]+%s+([0-9-]+)") + if not smart_info.health then smart_info.health = line:match(".-overall%-health.-: (.+)") end + else + attrib = line:match "^=== START OF (.*) SECTION ===" + if attrib and attrib:match("INFORMATION") then + section = 1 + elseif attrib and attrib:match("SMART DATA") then + section = 2 + elseif not smart_info.status then + val = line:match "^Device is in (.*) mode" + if val then smart_info.status = val end + end + end + + if not attrib then + if section ~= 2 then section = 0 end + elseif (attrib == "Power mode is") or + (attrib == "Power mode was") then + smart_info.status = val:match("(%S+)") + -- elseif attrib == "Sector Sizes" then + -- -- 512 bytes logical, 4096 bytes physical + -- smart_info.phy_sec = val:match "([0-9]*) bytes physical" + -- smart_info.logic_sec = val:match "([0-9]*) bytes logical" + -- elseif attrib == "Sector Size" then + -- -- 512 bytes logical/physical + -- smart_info.phy_sec = val:match "([0-9]*)" + -- smart_info.logic_sec = smart_info.phy_sec + elseif attrib == "Serial Number" then + smart_info.sn = val + elseif attrib == "194" or attrib == "Temperature" then + if val ~= "-" then + smart_info.temp = (val:match("(%d+)") or "?") .. "°C" + end + elseif attrib == "Rotation Rate" then + smart_info.rota_rate = val + elseif attrib == "SATA Version is" then + smart_info.sata_ver = val + elseif attrib == "NVMe Version" then + smart_info.nvme_ver = val + end + end + return smart_info +end + +local parse_parted_info = function(keys, line) + -- parse the output of parted command (machine parseable format) + -- /dev/sda:5860533168s:scsi:512:4096:gpt:ATA ST3000DM001-1ER1:; + -- 1:34s:2047s:2014s:free; + -- 1:2048s:1073743872s:1073741825s:ext4:primary:; + local result = {} + local values = {} + + for value in line:gmatch("(.-)[:;]") do table.insert(values, value) end + for i = 1,#keys do + result[keys[i]] = values[i] or "" + end + return result +end + +local is_raid_member = function(partition) + -- check if inuse as raid member + if nixio.fs.access("/proc/mdstat") then + for _, result in ipairs(luci.util.execl("grep md /proc/mdstat | sed 's/[][]//g'")) do + local md, buf + md, buf = result:match("(md.-):(.+)") + if buf:match(partition) then + return "Raid Member: ".. md + end + end + end + return nil +end + +local get_mount_point = function(partition) + local mount_point + for m in mounts:gmatch("/dev/"..partition.." on ([^ ]*)") do + mount_point = (mount_point and (mount_point .. " ") or "") .. m + end + if mount_point then return mount_point end + -- result = luci.sys.exec('cat /proc/mounts | awk \'{if($1=="/dev/'.. partition ..'") print $2}\'') + -- if result ~= "" then return result end + + if swaps:match("\n/dev/" .. partition .."%s") then return "swap" end + -- result = luci.sys.exec("cat /proc/swaps | grep /dev/" .. partition) + -- if result ~= "" then return "swap" end + + return is_raid_member(partition) + +end + +-- return used, free, usage +local get_partition_usage = function(partition) + if not nixio.fs.access("/dev/"..partition) then return false end + local used, free, usage = df:match("\n/dev/" .. partition .. "%s+%d+%s+(%d+)%s+(%d+)%s+(%d+)%%%s-") + + usage = usage and (usage .. "%") or "-" + used = used and (tonumber(used) * 1024) or 0 + free = free and (tonumber(free) * 1024) or 0 + + return used, free, usage +end + +local get_parted_info = function(device) + if not device then return end + local result = {partitions={}} + local DEVICE_INFO_KEYS = { "path", "size", "type", "logic_sec", "phy_sec", "p_table", "model", "flags" } + local PARTITION_INFO_KEYS = { "number", "sec_start", "sec_end", "size", "fs", "tag_name", "flags" } + local partition_temp + local partitions_temp = {} + local disk_temp + + for line in luci.util.execi(d.command.parted .. " -s -m /dev/" .. device .. " unit s print free", "r") do + if line:find("^/dev/"..device..":.+") then + disk_temp = parse_parted_info(DEVICE_INFO_KEYS, line) + disk_temp.partitions = {} + if disk_temp["size"] then + local length = disk_temp["size"]:gsub("^(%d+)s$", "%1") + local newsize = tostring(tonumber(length)*tonumber(disk_temp["logic_sec"])) + disk_temp["size"] = newsize + end + if disk_temp["p_table"] == "msdos" then + disk_temp["p_table"] = "MBR" + else + disk_temp["p_table"] = disk_temp["p_table"]:upper() + end + elseif line:find("^%d-:.+") then + partition_temp = parse_parted_info(PARTITION_INFO_KEYS, line) + -- use human-readable form instead of sector number + if partition_temp["size"] then + local length = partition_temp["size"]:gsub("^(%d+)s$", "%1") + local newsize = (tonumber(length) * tonumber(disk_temp["logic_sec"])) + partition_temp["size"] = newsize + partition_temp["size_formated"] = byte_format(newsize) + end + partition_temp["number"] = tonumber(partition_temp["number"]) or -1 + if partition_temp["fs"] == "free" then + partition_temp["number"] = -1 + partition_temp["fs"] = "Free Space" + partition_temp["name"] = "-" + elseif device:match("sd") or device:match("sata") or device:match("vd") then + partition_temp["name"] = device..partition_temp["number"] + elseif device:match("mmcblk") or device:match("md") or device:match("nvme") then + partition_temp["name"] = device.."p"..partition_temp["number"] + end + if partition_temp["number"] > 0 and partition_temp["fs"] == "" and d.command.lsblk then + partition_temp["fs"] = (luci.util.exec(d.command.lsblk .. " /dev/" .. partition_temp["name"] .. " -no fstype") or ""):match("([^%s]+)") or "" + end + partition_temp["fs"] = partition_temp["fs"] == "" and "raw" or partition_temp["fs"] + partition_temp["sec_start"] = partition_temp["sec_start"] and partition_temp["sec_start"]:sub(1,-2) + partition_temp["sec_end"] = partition_temp["sec_end"] and partition_temp["sec_end"]:sub(1,-2) + partition_temp["mount_point"] = partition_temp["name"]~="-" and get_mount_point(partition_temp["name"]) or "-" + if partition_temp["mount_point"]~="-" then + partition_temp["used"], partition_temp["free"], partition_temp["usage"] = get_partition_usage(partition_temp["name"]) + partition_temp["used_formated"] = partition_temp["used"] and byte_format(partition_temp["used"]) or "-" + partition_temp["free_formated"] = partition_temp["free"] and byte_format(partition_temp["free"]) or "-" + else + partition_temp["used"], partition_temp["free"], partition_temp["usage"] = 0,0,"-" + partition_temp["used_formated"] = "-" + partition_temp["free_formated"] = "-" + end + -- if disk_temp["p_table"] == "MBR" and (partition_temp["number"] < 4) and (partition_temp["number"] > 0) then + -- local real_size_sec = tonumber(nixio.fs.readfile("/sys/block/"..device.."/"..partition_temp["name"].."/size")) * tonumber(disk_temp.phy_sec) + -- if real_size_sec ~= partition_temp["size"] then + -- disk_temp["extended_partition_index"] = partition_temp["number"] + -- partition_temp["type"] = "extended" + -- partition_temp["size"] = real_size_sec + -- partition_temp["fs"] = "-" + -- partition_temp["logicals"] = {} + -- else + -- partition_temp["type"] = "primary" + -- end + -- end + + table.insert(partitions_temp, partition_temp) + end + end + if disk_temp and disk_temp["p_table"] == "MBR" then + for i, p in ipairs(partitions_temp) do + if disk_temp["extended_partition_index"] and p["number"] > 4 then + if tonumber(p["sec_end"]) <= tonumber(partitions_temp[disk_temp["extended_partition_index"]]["sec_end"]) and tonumber(p["sec_start"]) >= tonumber(partitions_temp[disk_temp["extended_partition_index"]]["sec_start"]) then + p["type"] = "logical" + table.insert(partitions_temp[disk_temp["extended_partition_index"]]["logicals"], i) + end + elseif (p["number"] <= 4) and (p["number"] > 0) then + local s = nixio.fs.readfile("/sys/block/"..device.."/"..p["name"].."/size") + if s then + local real_size_sec = tonumber(s) * tonumber(disk_temp.logic_sec) + -- if size not equal, it's an extended + if real_size_sec ~= p["size"] then + disk_temp["extended_partition_index"] = i + p["type"] = "extended" + p["size"] = real_size_sec + p["fs"] = "-" + p["logicals"] = {} + else + p["type"] = "primary" + end + else + -- if not found in "/sys/block" + p["type"] = "primary" + end + end + end + end + result = disk_temp or result + result.partitions = partitions_temp + + return result +end + +local mddetail = function(mdpath) + local detail = {} + local path = mdpath:match("^/dev/md%d+$") + if path then + local mdadm = io.popen(d.command.mdadm .. " --detail "..path, "r") + for line in mdadm:lines() do + local key, value = line:match("^%s*(.+) : (.+)") + if key then + detail[key] = value + end + end + mdadm:close() + end + return detail +end + +-- return {{device="", mount_points="", fs="", mount_options="", dump="", pass=""}..} +d.get_mount_points = function() + local mount + local res = {} + local h ={"device", "mount_point", "fs", "mount_options", "dump", "pass"} + for mount in proc_mounts:gmatch("[^\n]+") do + local device = mount:match("^([^%s]+)%s+.+") + -- only show /dev/xxx device + if device and device:match("/dev/") then + res[#res+1] = {} + local i = 0 + for v in mount:gmatch("[^%s]+") do + i = i + 1 + res[#res][h[i]] = v + end + end + end + return res +end + +d.get_disk_info = function(device, wakeup) + --[[ return: + { + path, model, sn, size, size_mounted, flags, type, temp, p_table, logic_sec, phy_sec, sec_size, sata_ver, rota_rate, status, health, + partitions = { + 1 = { number, name, sec_start, sec_end, size, size_mounted, fs, tag_name, type, flags, mount_point, usage, used, free, used_formated, free_formated}, + 2 = { number, name, sec_start, sec_end, size, size_mounted, fs, tag_name, type, flags, mount_point, usage, used, free, used_formated, free_formated}, + ... + } + --raid devices only + level, members, members_str + } + --]] + if not device then return end + local disk_info + local smart_info = get_smart_info(device) + + -- check if divice is the member of raid + smart_info["p_table"] = is_raid_member(device..'0') + -- if status is not active(standby), only check smart_info. + -- if only weakup == true, weakup the disk and check parted_info. + if smart_info.status ~= "STANDBY" or wakeup or (smart_info["p_table"] and not smart_info["p_table"]:match("Raid")) or device:match("^md") then + disk_info = get_parted_info(device) + disk_info["sec_size"] = disk_info["logic_sec"] .. "/" .. disk_info["phy_sec"] + disk_info["size_formated"] = byte_format(tonumber(disk_info["size"])) + -- if status is standby, after get part info, the disk is weakuped, then get smart_info again for more informations + if smart_info.status ~= "ACTIVE" then smart_info = get_smart_info(device) end + else + disk_info = {} + end + + for k, v in pairs(smart_info) do + disk_info[k] = v + end + + if disk_info.type and disk_info.type:match("md") then + local raid_info = d.list_raid_devices()[disk_info["path"]:match("/dev/(.+)")] + for k, v in pairs(raid_info) do + disk_info[k] = v + end + end + return disk_info +end + +d.list_raid_devices = function() + local fs = require "nixio.fs" + + local raid_devices = {} + if not fs.access("/proc/mdstat") then return raid_devices end + local mdstat = io.open("/proc/mdstat", "r") + for line in mdstat:lines() do + + -- md1 : active raid1 sdb2[1] sda2[0] + -- md127 : active raid5 sdh1[6] sdg1[4] sdf1[3] sde1[2] sdd1[1] sdc1[0] + local device_info = {} + local mdpath, list = line:match("^(md%d+) : (.+)") + if mdpath then + local members = {} + for member in string.gmatch(list, "%S+") do + member_path = member:match("^(%S+)%[%d+%]") + if member_path then + member = '/dev/'..member_path + end + table.insert(members, member) + end + local active = table.remove(members, 1) + local level = "-" + if active == "active" then + level = table.remove(members, 1) + end + + local size = tonumber(fs.readfile(string.format("/sys/class/block/%s/size", mdpath))) + local ss = tonumber(fs.readfile(string.format("/sys/class/block/%s/queue/logical_block_size", mdpath))) + + device_info["path"] = "/dev/"..mdpath + device_info["size"] = size*ss + device_info["size_formated"] = byte_format(size*ss) + device_info["active"] = active:upper() + device_info["level"] = level + device_info["members"] = members + device_info["members_str"] = table.concat(members, ", ") + + -- Get more info from output of mdadm --detail + local detail = mddetail(device_info["path"]) + device_info["status"] = detail["State"]:upper() + + raid_devices[mdpath] = device_info + end + end + mdstat:close() + + return raid_devices +end + +-- Collect Devices information + --[[ return: + { + sda={ + path, model, inuse, size_formated, + partitions={ + { name, inuse, size_formated } + ... + } + } + .. + } + --]] +d.list_devices = function() + local fs = require "nixio.fs" + + -- get all device names (sdX and mmcblkX) + local target_devnames = {} + for dev in fs.dir("/dev") do + if dev:match("^sd[a-z]$") + or dev:match("^mmcblk%d+$") + or dev:match("^sata[a-z]$") + or dev:match("^nvme%d+n%d+$") + or dev:match("^vd[a-z]$") + then + table.insert(target_devnames, dev) + end + end + + local devices = {} + for i, bname in pairs(target_devnames) do + local device_info = {} + local device = "/dev/" .. bname + local size = tonumber(fs.readfile(string.format("/sys/class/block/%s/size", bname)) or "0") + local ss = tonumber(fs.readfile(string.format("/sys/class/block/%s/queue/logical_block_size", bname)) or "0") + local model = fs.readfile(string.format("/sys/class/block/%s/device/model", bname)) + local partitions = {} + for part in nixio.fs.glob("/sys/block/" .. bname .."/" .. bname .. "*") do + local pname = nixio.fs.basename(part) + local psize = byte_format(tonumber(nixio.fs.readfile(part .. "/size"))*ss) + local mount_point = get_mount_point(pname) + if mount_point then device_info["inuse"] = true end + table.insert(partitions, {name = pname, size_formated = psize, inuse = mount_point}) + end + + device_info["path"] = device + device_info["size_formated"] = byte_format(size*ss) + device_info["model"] = model + device_info["partitions"] = partitions + -- true or false + device_info["inuse"] = device_info["inuse"] or get_mount_point(bname) + + local udevinfo = {} + if luci.sys.exec("which udevadm") ~= "" then + local udevadm = io.popen("udevadm info --query=property --name="..device) + for attr in udevadm:lines() do + local k, v = attr:match("(%S+)=(%S+)") + udevinfo[k] = v + end + udevadm:close() + + device_info["info"] = udevinfo + if udevinfo["ID_MODEL"] then device_info["model"] = udevinfo["ID_MODEL"] end + end + devices[bname] = device_info + end + -- luci.util.perror(luci.util.serialize_json(devices)) + return devices +end + +-- get formart cmd +d.get_format_cmd = function() + local AVAILABLE_FMTS = { + btrfs = { cmd = "mkfs.btrfs", option = "-f" }, + exfat = { cmd = "mkfs.exfat", option = "" }, + ext2 = { cmd = "mkfs.ext2", option = "-F -E lazy_itable_init=1" }, + ext3 = { cmd = "mkfs.ext3", option = "-F -E lazy_itable_init=1" }, + ext4 = { cmd = "mkfs.ext4", option = "-F -E lazy_itable_init=1" }, + f2fs = { cmd = "mkfs.f2fs", option = "-f" }, + fat32 = { cmd = "mkfs.fat", option = "-F 32" }, + hfs = { cmd = "mkfs.hfs", option = "-h" }, + hfsplus = { cmd = "mkfs.hfs", option = "" }, + ntfs = { cmd = "mkntfs", option = "-f" }, + swap = { cmd = "mkswap", option = "" }, + xfs = { cmd = "mkfs.xfs", option = "-f -m bigtime=1" } + } + result = {} + for fmt, obj in pairs(AVAILABLE_FMTS) do + local cmd = luci.sys.exec("/usr/bin/which " .. obj["cmd"]) + if cmd:match(obj["cmd"]) then + result[fmt] = { cmd = cmd:match("^.+"..obj["cmd"]) ,option = obj["option"] } + end + end + return result +end + +d.find_free_md_device = function() + for num=0,127 do + local md = io.open("/dev/md"..tostring(num), "r") + if md == nil then + return "/dev/md"..tostring(num) + else + io.close(md) + end + end + return nil +end + +d.create_raid = function(rname, rlevel, rmembers) + local mb = {} + for _, v in ipairs(rmembers) do + mb[v]=v + end + rmembers = {} + for _, v in pairs(mb) do + table.insert(rmembers, v) + end + if type(rname) == "string" then + if rname:match("^md%d-%s+") then + rname = "/dev/"..rname:match("^(md%d-)%s+") + elseif rname:match("^/dev/md%d-%s+") then + rname = "/dev/"..rname:match("^(/dev/md%d-)%s+") + elseif not rname:match("/") then + rname = "/dev/md/".. rname + else + return "ERR: Invalid raid name" + end + else + rname = d.find_free_md_device() + if rname == nil then return "ERR: Cannot find free md device" end + end + + if rlevel == "5" or rlevel == "6" then + if #rmembers < 3 then return "ERR: Not enough members" end + end + if rlevel == "10" then + if #rmembers < 4 then return "ERR: Not enough members" end + end + if #rmembers < 2 then return "ERR: Not enough members" end + local cmd = d.command.mdadm .. " --create "..rname.." --run --assume-clean --homehost=any --level=" .. rlevel .. " --raid-devices=" .. #rmembers .. " " .. table.concat(rmembers, " ") + local res = luci.util.exec(cmd) + return res +end + +d.gen_mdadm_config = function() + if not nixio.fs.access("/etc/config/mdadm") then return end + local uci = require "luci.model.uci" + local x = uci.cursor() + -- delete all array sections + x:foreach("mdadm", "array", function(s) x:delete("mdadm",s[".name"]) end) + local cmd = d.command.mdadm .. " -D -s" + --ARRAY /dev/md1 metadata=1.2 name=any:1 UUID=f998ae14:37621b27:5c49e850:051f6813 + --ARRAY /dev/md3 metadata=1.2 name=any:3 UUID=c068c141:4b4232ca:f48cbf96:67d42feb + for _, v in ipairs(luci.util.execl(cmd)) do + local device, uuid = v:match("^ARRAY%s-([^%s]+)%s-[^%s]-%s-[^%s]-%s-UUID=([^%s]+)%s-") + if device and uuid then + local section_name = x:add("mdadm", "array") + x:set("mdadm", section_name, "device", device) + x:set("mdadm", section_name, "uuid", uuid) + end + end + x:commit("mdadm") + -- enable mdadm + luci.util.exec("/etc/init.d/mdadm enable") +end + +-- list btrfs filesystem device +-- {uuid={uuid, label, members, size, used}...} +d.list_btrfs_devices = function() + local btrfs_device = {} + if not d.command.btrfs then return btrfs_device end + local line, _uuid + for _, line in ipairs(luci.util.execl(d.command.btrfs .. " filesystem show -d --raw")) + do + local label, uuid = line:match("^Label:%s+([^%s]+)%s+uuid:%s+([^%s]+)") + if label and uuid then + _uuid = uuid + local _label = label:match("^'([^']+)'") + btrfs_device[_uuid] = {label = _label or label, uuid = uuid} + -- table.insert(btrfs_device, {label = label, uuid = uuid}) + end + local used = line:match("Total devices[%w%s]+used%s+(%d+)$") + if used then + btrfs_device[_uuid]["used"] = tonumber(used) + btrfs_device[_uuid]["used_formated"] = byte_format(tonumber(used)) + end + local size, device = line:match("devid[%w.%s]+size%s+(%d+)[%w.%s]+path%s+([^%s]+)$") + if size and device then + btrfs_device[_uuid]["size"] = btrfs_device[_uuid]["size"] and btrfs_device[_uuid]["size"] + tonumber(size) or tonumber(size) + btrfs_device[_uuid]["size_formated"] = byte_format(btrfs_device[_uuid]["size"]) + btrfs_device[_uuid]["members"] = btrfs_device[_uuid]["members"] and btrfs_device[_uuid]["members"]..", "..device or device + end + end + return btrfs_device +end + +d.create_btrfs = function(blabel, blevel, bmembers) + -- mkfs.btrfs -L label -d blevel /dev/sda /dev/sdb + if not d.command.btrfs or type(bmembers) ~= "table" or next(bmembers) == nil then return "ERR no btrfs support or no members" end + local label = blabel and " -L " .. blabel or "" + local cmd = "mkfs.btrfs -f " .. label .. " -d " .. blevel .. " " .. table.concat(bmembers, " ") + return luci.util.exec(cmd) +end + +-- get btrfs info +-- {uuid, label, members, data_raid_level,metadata_raid_lavel, size, used, size_formated, used_formated, free, free_formated, usage} +d.get_btrfs_info = function(m_point) + local btrfs_info = {} + if not m_point or not d.command.btrfs then return btrfs_info end + local cmd = d.command.btrfs .. " filesystem show --raw " .. m_point + local _, line, uuid, _label, members + for _, line in ipairs(luci.util.execl(cmd)) do + if not uuid and not _label then + _label, uuid = line:match("^Label:%s+([^%s]+)%s+uuid:%s+([^s]+)") + else + local mb = line:match("%s+devid.+path%s+([^%s]+)") + if mb then + members = members and (members .. ", ".. mb) or mb + end + end + end + + if not _label or not uuid then return btrfs_info end + local label = _label:match("^'([^']+)'") + cmd = d.command.btrfs .. " filesystem usage -b " .. m_point + local used, free, data_raid_level, metadata_raid_lavel + for _, line in ipairs(luci.util.execl(cmd)) do + if not used then + used = line:match("^%s+Used:%s+(%d+)") + elseif not free then + free = line:match("^%s+Free %(estimated%):%s+(%d+)") + elseif not data_raid_level then + data_raid_level = line:match("^Data,%s-(%w+)") + elseif not metadata_raid_lavel then + metadata_raid_lavel = line:match("^Metadata,%s-(%w+)") + end + end + if used and free and data_raid_level and metadata_raid_lavel then + used = tonumber(used) + free = tonumber(free) + btrfs_info = { + uuid = uuid, + label = label, + data_raid_level = data_raid_level, + metadata_raid_lavel = metadata_raid_lavel, + used = used, + free = free, + size = used + free, + size_formated = byte_format(used + free), + used_formated = byte_format(used), + free_formated = byte_format(free), + members = members, + usage = string.format("%.2f",(used / (free+used) * 100)) .. "%" + } + end + return btrfs_info +end + +-- get btrfs subvolume +-- {id={id, gen, top_level, path, snapshots, otime, default_subvolume}...} +d.get_btrfs_subv = function(m_point, snapshot) +local subvolume = {} +if not m_point or not d.command.btrfs then return subvolume end + +-- get default subvolume +local cmd = d.command.btrfs .. " subvolume get-default " .. m_point +local res = luci.util.exec(cmd) +local default_subvolume_id = res:match("^ID%s+([^%s]+)") + +-- get the root subvolume +if not snapshot then + local _, line, section_snap, _uuid, _otime, _id, _snap + cmd = d.command.btrfs .. " subvolume show ".. m_point + for _, line in ipairs(luci.util.execl(cmd)) do + if not section_snap then + if not _uuid then + _uuid = line:match("^%s-UUID:%s+([^%s]+)") + elseif not _otime then + _otime = line:match("^%s+Creation time:%s+(.+)") + elseif not _id then + _id = line:match("^%s+Subvolume ID:%s+([^%s]+)") + elseif line:match("^%s+(Snapshot%(s%):)") then + section_snap = true + end + else + local snapshot = line:match("^%s+(.+)") + if snapshot then + _snap = _snap and (_snap ..", /".. snapshot) or ("/"..snapshot) + end + end + end + if _uuid and _otime and _id then + subvolume["0".._id] = {id = _id , uuid = _uuid, otime = _otime, snapshots = _snap, path = "/"} + if default_subvolume_id == _id then + subvolume["0".._id].default_subvolume = 1 + end + end +end + +-- get subvolume of btrfs +cmd = d.command.btrfs .. " subvolume list -gcu" .. (snapshot and "s " or " ") .. m_point +for _, line in ipairs(luci.util.execl(cmd)) do + -- ID 259 gen 11 top level 258 uuid 26ae0c59-199a-cc4d-bd58-644eb4f65d33 path 1a/2b' + local id, gen, top_level, uuid, path, otime, otime2 + if snapshot then + id, gen, top_level, otime, otime2, uuid, path = line:match("^ID%s+([^%s]+)%s+gen%s+([^%s]+)%s+cgen.-top level%s+([^%s]+)%s+otime%s+([^%s]+)%s+([^%s]+)%s+uuid%s+([^%s]+)%s+path%s+([^%s]+)%s-$") + else + id, gen, top_level, uuid, path = line:match("^ID%s+([^%s]+)%s+gen%s+([^%s]+)%s+cgen.-top level%s+([^%s]+)%s+uuid%s+([^%s]+)%s+path%s+([^%s]+)%s-$") + end + if id and gen and top_level and uuid and path then + subvolume[id] = {id = id, gen = gen, top_level = top_level, otime = (otime and otime or "") .." ".. (otime2 and otime2 or ""), uuid = uuid, path = '/'.. path} + if not snapshot then + -- use btrfs subv show to get snapshots + local show_cmd = d.command.btrfs .. " subvolume show "..m_point.."/"..path + local __, line_show, section_snap + for __, line_show in ipairs(luci.util.execl(show_cmd)) do + if not section_snap then + local create_time = line_show:match("^%s+Creation time:%s+(.+)") + if create_time then + subvolume[id]["otime"] = create_time + elseif line_show:match("^%s+(Snapshot%(s%):)") then + section_snap = "true" + end + else + local snapshot = line_show:match("^%s+(.+)") + subvolume[id]["snapshots"] = subvolume[id]["snapshots"] and (subvolume[id]["snapshots"] .. ", /".. snapshot) or ("/"..snapshot) + end + end + end + end +end +if subvolume[default_subvolume_id] then + subvolume[default_subvolume_id].default_subvolume = 1 +end +-- if m_point == "/tmp/.btrfs_tmp" then +-- luci.util.exec("umount " .. m_point) +-- end +return subvolume +end + +d.format_partition = function(partition, fs) + local partition_name = "/dev/".. partition + if not nixio.fs.access(partition_name) then + return 500, "Partition NOT found!" + end + + local format_cmd = d.get_format_cmd() + if not format_cmd[fs] then + return 500, "Filesystem NOT support!" + end + local cmd = format_cmd[fs].cmd .. " " .. format_cmd[fs].option .. " " .. partition_name + local res = luci.util.exec(cmd .. " 2>&1") + if res and res:lower():match("error+") then + return 500, res + else + return 200, "OK" + end +end + +return d diff --git a/luci-app-diskman/luasrc/view/diskman/cbi/disabled_button.htm b/luci-app-diskman/luasrc/view/diskman/cbi/disabled_button.htm new file mode 100644 index 0000000..1ad4eca --- /dev/null +++ b/luci-app-diskman/luasrc/view/diskman/cbi/disabled_button.htm @@ -0,0 +1,7 @@ +<%+cbi/valueheader%> + <% if self:cfgvalue(section) ~= false then %> + " type="submit"<%= attr("name", cbid) .. attr("id", cbid) .. attr("value", self.inputtitle or self.title)%> <% if self.view_disabled then %> disabled <% end %>/> + <% else %> + - + <% end %> +<%+cbi/valuefooter%> \ No newline at end of file diff --git a/luci-app-diskman/luasrc/view/diskman/cbi/format_button.htm b/luci-app-diskman/luasrc/view/diskman/cbi/format_button.htm new file mode 100644 index 0000000..18e306e --- /dev/null +++ b/luci-app-diskman/luasrc/view/diskman/cbi/format_button.htm @@ -0,0 +1,7 @@ +<%+cbi/valueheader%> + <% if self:cfgvalue(section) ~= false then %> + " onclick="event.preventDefault();partition_format('<%=self.partitions[section].name%>', '<%=self.format_cmd%>', '<%=self.inputtitle%>');" type="submit"<%= attr("name", cbid) .. attr("id", cbid) .. attr("value", self.inputtitle or self.title)%> <% if self.view_disabled then %> disabled <% end %>/> + <% else %> + - + <% end %> +<%+cbi/valuefooter%> diff --git a/luci-app-diskman/luasrc/view/diskman/cbi/inlinebutton.htm b/luci-app-diskman/luasrc/view/diskman/cbi/inlinebutton.htm new file mode 100644 index 0000000..b1b1932 --- /dev/null +++ b/luci-app-diskman/luasrc/view/diskman/cbi/inlinebutton.htm @@ -0,0 +1,7 @@ +
+ <% if self:cfgvalue(section) ~= false then %> + " type="submit"" <% if self.disable then %>disabled <% end %><%= attr("name", cbid) .. attr("id", cbid) .. attr("value", self.inputtitle or self.title)%> /> + <% else %> + - + <% end %> +
diff --git a/luci-app-diskman/luasrc/view/diskman/cbi/xnullsection.htm b/luci-app-diskman/luasrc/view/diskman/cbi/xnullsection.htm new file mode 100644 index 0000000..69aa65e --- /dev/null +++ b/luci-app-diskman/luasrc/view/diskman/cbi/xnullsection.htm @@ -0,0 +1,37 @@ +
+ <% if self.title and #self.title > 0 then -%> + <%=self.title%> + <%- end %> + <% if self.description and #self.description > 0 then -%> +
<%=self.description%>
+ <%- end %> +
+
+ <% self:render_children(1, scope or {}) %> +
+ <% if self.error and self.error[1] then -%> +
+
    <% for _, e in ipairs(self.error[1]) do -%> +
  • + <%- if e == "invalid" then -%> + <%:One or more fields contain invalid values!%> + <%- elseif e == "missing" then -%> + <%:One or more required fields have no value!%> + <%- else -%> + <%=pcdata(e)%> + <%- end -%> +
  • + <%- end %>
+
+ <%- end %> +
+
+<%- + if type(self.hidden) == "table" then + for k, v in pairs(self.hidden) do +-%> + +<%- + end + end +%> \ No newline at end of file diff --git a/luci-app-diskman/luasrc/view/diskman/cbi/xsimpleform.htm b/luci-app-diskman/luasrc/view/diskman/cbi/xsimpleform.htm new file mode 100644 index 0000000..72a21f5 --- /dev/null +++ b/luci-app-diskman/luasrc/view/diskman/cbi/xsimpleform.htm @@ -0,0 +1,87 @@ +<% if not self.embedded then %> +
> + + <% + end + + %>
<% + + if self.title and #self.title > 0 then + %>

<%=self.title%>

<% + end + + if self.description and #self.description > 0 then + %>
<%=self.description%>
<% + end + + if self.message then + %>
<%=self.message%>
<% + end + + if self.errmessage then + %>
<%=self.errmessage%>
<% + end + + self:render_children() + + %>
<% + + if not self.embedded then + if type(self.hidden) == "table" then + local k, v + for k, v in pairs(self.hidden) do + %><% + end + end + + local display_back = (self.redirect) + local display_cancel = (self.cancel ~= false and self.on_cancel) + local display_skip = (self.flow and self.flow.skip) + local display_submit = (self.submit ~= false) + local display_reset = (self.reset ~= false) + + if display_back or display_cancel or display_skip or display_submit or display_reset then + %>
<% + + if display_back then + %> <% + end + + if display_cancel then + local label = pcdata(self.cancel or translate("Cancel")) + %> <% + end + + if display_skip then + %> <% + end + + if display_submit then + local label = pcdata(self.submit or translate("Submit")) + %> <% + end + + if display_reset then + local label = pcdata(self.reset or translate("Reset")) + %> <% + end + + %>
<% + end + + %>
<% + end +%> + + diff --git a/luci-app-diskman/luasrc/view/diskman/disk_info.htm b/luci-app-diskman/luasrc/view/diskman/disk_info.htm new file mode 100644 index 0000000..10ba3e7 --- /dev/null +++ b/luci-app-diskman/luasrc/view/diskman/disk_info.htm @@ -0,0 +1,110 @@ + diff --git a/luci-app-diskman/luasrc/view/diskman/partition_info.htm b/luci-app-diskman/luasrc/view/diskman/partition_info.htm new file mode 100644 index 0000000..1957c8e --- /dev/null +++ b/luci-app-diskman/luasrc/view/diskman/partition_info.htm @@ -0,0 +1,145 @@ + + diff --git a/luci-app-diskman/luasrc/view/diskman/smart_detail.htm b/luci-app-diskman/luasrc/view/diskman/smart_detail.htm new file mode 100644 index 0000000..ffb4f7d --- /dev/null +++ b/luci-app-diskman/luasrc/view/diskman/smart_detail.htm @@ -0,0 +1,78 @@ + + + S.M.A.R.T detail of <%=dev%> + + + +
+
+ <%:S.M.A.R.T Attrbutes%>: /dev/<%=dev%> + + + <% if dev:match("nvme") then %> + + <% else %> + + + + + + + + + + <% end %> + + + + +
<%:ID%><%:Attrbute%><%:Flag%><%:Value%><%:Worst%><%:Thresh%><%:Type%><%:Updated%><%:Raw%>

<%:Collecting data...%>
+
+
+ + \ No newline at end of file diff --git a/luci-app-diskman/po/zh_Hans/diskman.po b/luci-app-diskman/po/zh_Hans/diskman.po new file mode 100644 index 0000000..61d32dd --- /dev/null +++ b/luci-app-diskman/po/zh_Hans/diskman.po @@ -0,0 +1,242 @@ +msgid "" +msgstr "Content-Type: text/plain; charset=UTF-8\n" + +msgid "DiskMan" +msgstr "DiskMan 磁盘管理" + +msgid "Manage Disks over LuCI." +msgstr "通过 LuCI 管理磁盘" + +msgid "Rescan Disks" +msgstr "重新扫描磁盘" + +msgid "Disks" +msgstr "磁盘" + +msgid "Path" +msgstr "路径" + +msgid "Serial Number" +msgstr "序列号" + +msgid "Temp" +msgstr "温度" + +msgid "Partition Table" +msgstr "分区表" + +msgid "SATA Version" +msgstr "SATA 版本" + +msgid "Health" +msgstr "健康" + +msgid "File System" +msgstr "文件系统" + +msgid "Mount Options" +msgstr "挂载选项" + +msgid "Mount" +msgstr "挂载" + +msgid "Umount" +msgstr "卸载" + +msgid "Eject" +msgstr "弹出" + +msgid "New" +msgstr "新建" + +msgid "Remove" +msgstr "移除" + +msgid "Format" +msgstr "格式化" + +msgid "Start Sector" +msgstr "起始扇区" + +msgid "End Sector" +msgstr "中止扇区" + +msgid "Usage" +msgstr "用量" + +msgid "Used" +msgstr "已使用" + +msgid "Free Space" +msgstr "空闲空间" + +msgid "Model" +msgstr "型号" + +msgid "Size" +msgstr "容量" + +msgid "Status" +msgstr "状态" + +msgid "Mount Point" +msgstr "挂载点" + +msgid "Sector Size" +msgstr "扇区/物理扇区大小" + +msgid "Rotation Rate" +msgstr "转速" + +msgid "RAID Devices" +msgstr "RAID 设备" + +msgid "RAID mode" +msgstr "RAID 模式" + +msgid "Members" +msgstr "成员" + +msgid "Active" +msgstr "活动" + +msgid "RAID Creation" +msgstr "RAID 创建" + +msgid "Raid Name" +msgstr "RAID 名称" + +msgid "Raid Level" +msgstr "RAID 级别" + +msgid "Raid Member" +msgstr "磁盘阵列成员" + +msgid "Create Raid" +msgstr "创建 RAID" + +msgid "Partition Management" +msgstr "分区管理" + +msgid "Partition Disk over LuCI." +msgstr "通过LuCI分区磁盘。" + +msgid "Device Info" +msgstr "设备信息" + +msgid "Disk Man" +msgstr "磁盘管理" + +msgid "Partitions Info" +msgstr "分区信息" + +msgid "Default 2048 sector alignment, support +size{b,k,m,g,t} in End Sector" +msgstr "默认2048扇区对齐,【中止扇区】支持 +容量{b,k,m,g,t} 格式,例:+500m +10g +1t" + +msgid "Multiple Devices Btrfs Creation" +msgstr "Btrfs 阵列创建" + +msgid "Label" +msgstr "卷标" + +msgid "Btrfs Label" +msgstr "Btrfs 卷标" + +msgid "Btrfs Raid Level" +msgstr "Btrfs Raid 级别" + +msgid "Btrfs Member" +msgstr "Btrfs 阵列成员" + +msgid "Create Btrfs" +msgstr "创建 Btrfs" + +msgid "New Snapshot" +msgstr "新建快照" + +msgid "SubVolumes" +msgstr "子卷" + +msgid "Top Level" +msgstr "父ID" + +msgid "Manage Btrfs" +msgstr "Btrfs 管理" + +msgid "Otime" +msgstr "创建时间" + +msgid "Snapshots" +msgstr "快照" + +msgid "Set Default" +msgstr "默认子卷" + +msgid "Source Path" +msgstr "源目录" + +msgid "Readonly" +msgstr "只读" + +msgid "Delete" +msgstr "删除" + +msgid "Create" +msgstr "创建" + +msgid "Destination Path (optional)" +msgstr "目标目录(可选)" + +msgid "Metadata" +msgstr "元数据" + +msgid "Data" +msgstr "数据" + +msgid "Btrfs Info" +msgstr "Btrfs 信息" + +msgid "The source path for create the snapshot" +msgstr "创建快照的源数据目录" + +msgid "The path where you want to store the snapshot" +msgstr "存放快照数据目录" + +msgid "Please input Source Path of snapshot, Source Path must start with '/'" +msgstr "请输入快照源路径,源路径必须以'/'开头" + +msgid "Please input Subvolume Path, Subvolume must start with '/'" +msgstr "请输入子卷路径,子卷路径必须以'/'开头" + +msgid "is in use! please unmount it first!" +msgstr "正在被使用!请先卸载!" + +msgid "Partition NOT found!" +msgstr "分区未找到!" + +msgid "Filesystem NOT support!" +msgstr "文件系统不支持!" + +msgid "Invalid Start Sector!" +msgstr "无效的起始扇区!" + +msgid "Invalid End Sector" +msgstr "无效的终止扇区!" + +msgid "Partition not exists!" +msgstr "分区不存在!" + +msgid "Creation" +msgstr "创建" + +msgid "Please select file system!" +msgstr "请选择文件系统!" + +msgid "Format partation:" +msgstr "格式化分区:" + +msgid "Formatting.." +msgstr "正在格式化..." + +msgid "Warnning !! \nTHIS WILL OVERWRITE EXISTING PARTITIONS!! \nModify the partition table?" +msgstr "警告!!\n此操作会覆盖现有分区\n确定修改分区表?" diff --git a/luci-app-eqos/Makefile b/luci-app-eqos/Makefile new file mode 100644 index 0000000..ed8d0c8 --- /dev/null +++ b/luci-app-eqos/Makefile @@ -0,0 +1,10 @@ +include $(TOPDIR)/rules.mk + +LUCI_TITLE:=LuCI support for Easy QoS +LUCI_DEPENDS:=+tc +kmod-sched-core +kmod-ifb + +PKG_MAINTAINER:=Jianhui Zhao + +include $(TOPDIR)/feeds/luci/luci.mk + +# call BuildPackage - OpenWrt buildroot signature diff --git a/luci-app-eqos/htdocs/luci-static/resources/view/eqos.js b/luci-app-eqos/htdocs/luci-static/resources/view/eqos.js new file mode 100644 index 0000000..d711aa4 --- /dev/null +++ b/luci-app-eqos/htdocs/luci-static/resources/view/eqos.js @@ -0,0 +1,67 @@ +'use strict'; +'require form'; +'require network'; +'require uci'; +'require view'; + +return view.extend({ + load: function() { + return Promise.all([ + uci.load('eqos'), + network.getHostHints() + ]); + }, + + render: function(data) { + var m, s, o; + + m = new form.Map('eqos', _('EQoS'), + _('Network speed control service. Not compatible with Software flow offloading.')); + + s = m.section(form.NamedSection, 'config', 'eqos'); + + o = s.option(form.Flag, 'enabled', _('Enable')); + o.default = o.disabled; + o.rmempty = false; + + o = s.option(form.Value, 'download', _('Download speed (Mbit/s)'), + _('Total download bandwidth.')); + o.datatype = 'and(uinteger,min(1))'; + o.rmempty = false; + + o = s.option(form.Value, 'upload', _('Upload speed (Mbit/s)'), + _('Total upload bandwidth.')); + o.datatype = 'and(uinteger,min(1))'; + o.rmempty = false; + + s = m.section(form.TableSection, 'device', _('Speed limit based on IP address')); + s.addremove = true; + s.anonymous = true; + s.sortable = true; + + o = s.option(form.Flag, 'enabled', _('Enable')); + o.default = o.enabled; + + o = s.option(form.Value, 'ip', _('IP address')); + o.datatype = 'ip4addr'; + for (var i of Object.entries(data[1]?.hosts)) + for (var v in i[1].ipaddrs) + if (i[1].ipaddrs[v]) { + var ip_addr = i[1].ipaddrs[v], ip_host = i[1].name; + o.value(ip_addr, ip_host ? String.format('%s (%s)', ip_host, ip_addr) : ip_addr) + } + o.rmempty = false; + + o = s.option(form.Value, 'download', _('Download speed (Mbit/s)')); + o.datatype = 'and(uinteger,min(1))'; + o.rmempty = false; + + o = s.option(form.Value, 'upload', _('Upload speed (Mbit/s)')); + o.datatype = 'and(uinteger,min(1))'; + o.rmempty = false; + + o = s.option(form.Value, 'comment', _('Comment')); + + return m.render(); + } +}); diff --git a/luci-app-eqos/po/templates/eqos.pot b/luci-app-eqos/po/templates/eqos.pot new file mode 100644 index 0000000..b900056 --- /dev/null +++ b/luci-app-eqos/po/templates/eqos.pot @@ -0,0 +1,50 @@ +msgid "" +msgstr "Content-Type: text/plain; charset=UTF-8" + +#: applications/luci-app-eqos/htdocs/luci-static/resources/view/eqos.js:64 +msgid "Comment" +msgstr "" + +#: applications/luci-app-eqos/htdocs/luci-static/resources/view/eqos.js:28 +#: applications/luci-app-eqos/htdocs/luci-static/resources/view/eqos.js:56 +msgid "Download speed (Mbit/s)" +msgstr "" + +#: applications/luci-app-eqos/htdocs/luci-static/resources/view/eqos.js:18 +#: applications/luci-app-eqos/root/usr/share/luci/menu.d/luci-app-eqos.json:3 +msgid "EQoS" +msgstr "" + +#: applications/luci-app-eqos/htdocs/luci-static/resources/view/eqos.js:24 +#: applications/luci-app-eqos/htdocs/luci-static/resources/view/eqos.js:43 +msgid "Enable" +msgstr "" + +#: applications/luci-app-eqos/root/usr/share/rpcd/acl.d/luci-app-eqos.json:3 +msgid "Grant UCI access for luci-app-eqos" +msgstr "" + +#: applications/luci-app-eqos/htdocs/luci-static/resources/view/eqos.js:46 +msgid "IP address" +msgstr "" + +#: applications/luci-app-eqos/htdocs/luci-static/resources/view/eqos.js:19 +msgid "Network speed control service." +msgstr "" + +#: applications/luci-app-eqos/htdocs/luci-static/resources/view/eqos.js:38 +msgid "Speed limit based on IP address" +msgstr "" + +#: applications/luci-app-eqos/htdocs/luci-static/resources/view/eqos.js:29 +msgid "Total download bandwidth." +msgstr "" + +#: applications/luci-app-eqos/htdocs/luci-static/resources/view/eqos.js:34 +msgid "Total upload bandwidth." +msgstr "" + +#: applications/luci-app-eqos/htdocs/luci-static/resources/view/eqos.js:33 +#: applications/luci-app-eqos/htdocs/luci-static/resources/view/eqos.js:60 +msgid "Upload speed (Mbit/s)" +msgstr "" diff --git a/luci-app-eqos/po/zh_Hans/eqos.po b/luci-app-eqos/po/zh_Hans/eqos.po new file mode 100644 index 0000000..b18f103 --- /dev/null +++ b/luci-app-eqos/po/zh_Hans/eqos.po @@ -0,0 +1,58 @@ +msgid "" +msgstr "" +"Project-Id-Version: LuCi Chinese Translation\n" +"Report-Msgid-Bugs-To: \n" +"Language: zh_Hans\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Pootle 2.0.6\n" + +#: applications/luci-app-eqos/htdocs/luci-static/resources/view/eqos.js:64 +msgid "Comment" +msgstr "注释" + +#: applications/luci-app-eqos/htdocs/luci-static/resources/view/eqos.js:28 +#: applications/luci-app-eqos/htdocs/luci-static/resources/view/eqos.js:56 +msgid "Download speed (Mbit/s)" +msgstr "下载速度 (Mbit/s)" + +#: applications/luci-app-eqos/htdocs/luci-static/resources/view/eqos.js:18 +#: applications/luci-app-eqos/root/usr/share/luci/menu.d/luci-app-eqos.json:3 +msgid "EQoS" +msgstr "网速控制" + +#: applications/luci-app-eqos/htdocs/luci-static/resources/view/eqos.js:24 +#: applications/luci-app-eqos/htdocs/luci-static/resources/view/eqos.js:43 +msgid "Enable" +msgstr "启用" + +#: applications/luci-app-eqos/root/usr/share/rpcd/acl.d/luci-app-eqos.json:3 +msgid "Grant UCI access for luci-app-eqos" +msgstr "授予 luci-app-eqos 访问 UCI 配置的权限" + +#: applications/luci-app-eqos/htdocs/luci-static/resources/view/eqos.js:46 +msgid "IP address" +msgstr "IP 地址" + +#: applications/luci-app-eqos/htdocs/luci-static/resources/view/eqos.js:19 +msgid "Network speed control service. Not compatible with Software flow offloading." +msgstr "网速控制服务。(与软件流量分载不兼容)" + +#: applications/luci-app-eqos/htdocs/luci-static/resources/view/eqos.js:38 +msgid "Speed limit based on IP address" +msgstr "基于 IP 限速" + +#: applications/luci-app-eqos/htdocs/luci-static/resources/view/eqos.js:29 +msgid "Total download bandwidth." +msgstr "总下载带宽。" + +#: applications/luci-app-eqos/htdocs/luci-static/resources/view/eqos.js:34 +msgid "Total upload bandwidth." +msgstr "总上传带宽。" + +#: applications/luci-app-eqos/htdocs/luci-static/resources/view/eqos.js:33 +#: applications/luci-app-eqos/htdocs/luci-static/resources/view/eqos.js:60 +msgid "Upload speed (Mbit/s)" +msgstr "上传速度 (Mbit/s)" diff --git a/luci-app-eqos/root/etc/config/eqos b/luci-app-eqos/root/etc/config/eqos new file mode 100644 index 0000000..39a1772 --- /dev/null +++ b/luci-app-eqos/root/etc/config/eqos @@ -0,0 +1,12 @@ +# The bandwidth unit is Mbit/s +config eqos 'config' + option enabled 0 + option download 100 + option upload 20 + +# Limiting the bandwidth of a single Device +#config device +# option ip "192.168.1.100" +# option download 10 +# option upload 5 +# option comment "test" diff --git a/luci-app-eqos/root/etc/hotplug.d/iface/10-eqos b/luci-app-eqos/root/etc/hotplug.d/iface/10-eqos new file mode 100755 index 0000000..d70034a --- /dev/null +++ b/luci-app-eqos/root/etc/hotplug.d/iface/10-eqos @@ -0,0 +1,5 @@ +#!/bin/sh +[ "$ACTION" = "ifup" ] || exit 0 +[ "$INTERFACE" = "lan" ] || exit 0 + +/etc/init.d/eqos start diff --git a/luci-app-eqos/root/etc/init.d/eqos b/luci-app-eqos/root/etc/init.d/eqos new file mode 100755 index 0000000..d770543 --- /dev/null +++ b/luci-app-eqos/root/etc/init.d/eqos @@ -0,0 +1,83 @@ +#!/bin/sh /etc/rc.common +# Copyright (C) 2006 OpenWrt.org + +START=50 +USE_PROCD=1 + +disable_offload() { + if [ $(uci -q show firewall.@defaults[0] | grep -c flow_offloading) -ge 1 ]; then + echo flow_offloading > /etc/.eqos_offload + uci -q del firewall.@defaults[0].flow_offloading + uci commit firewall + /etc/init.d/firewall reload >/dev/null 2>&1 + elif [ $(uci -q show firewall.@defaults[0] | grep -c shortcut_fe) -ge 1 ]; then + uci -q get firewall.@defaults[0].shortcut_fe_module > /etc/.eqos_offload + uci -q del firewall.@defaults[0].shortcut_fe + uci -q del firewall.@defaults[0].shortcut_fe_module + uci commit firewall + /etc/init.d/firewall reload >/dev/null 2>&1 + /etc/init.d/shortcut-fe restart + fi +} + +enable_offload() { + offload_mode=$(cat /etc/.eqos_offload) + rm -f /etc/.eqos_offload + if [ "$offload_mode" = "flow_offloading" ]; then + uci set firewall.@defaults[0].flow_offloading='1' + uci commit firewall + /etc/init.d/firewall reload >/dev/null 2>&1 + else + uci set firewall.@defaults[0].shortcut_fe='1' + uci set firewall.@defaults[0].shortcut_fe_module="$offload_mode" + uci commit firewall + /etc/init.d/firewall reload >/dev/null 2>&1 + /etc/init.d/shortcut-fe restart + fi +} + +parse_device() { + local cfg="$1" + + local enabled + config_get_bool enabled "$cfg" "enabled" "1" + [ "$enabled" -eq "1" ] || return 1 + + local ip download upload + config_get ip "$cfg" "ip" + config_get download "$cfg" "download" + config_get upload "$cfg" "upload" + + eqos add "$ip" "$download" "$upload" +} + +start_service() { + config_load "eqos" + + local enabled + config_get_bool enabled "config" "enabled" "0" + [ "$enabled" -eq "1" ] || return 1 + disable_offload + + local download upload + config_get download "config" "download" + config_get upload "config" "upload" + + eqos start "$download" "$upload" + + config_foreach parse_device "device" +} + +stop_service() { + eqos stop + [ -f "/etc/.eqos_offload" ] && enable_offload +} + +reload_service() { + stop + start +} + +service_triggers() { + procd_add_reload_trigger "eqos" +} diff --git a/luci-app-eqos/root/usr/sbin/eqos b/luci-app-eqos/root/usr/sbin/eqos new file mode 100755 index 0000000..6185a14 --- /dev/null +++ b/luci-app-eqos/root/usr/sbin/eqos @@ -0,0 +1,60 @@ +#!/bin/sh + +dev=br-lan + +stop_qos() { + tc qdisc del dev $dev root 2>/dev/null + tc qdisc del dev $dev ingress 2>/dev/null + tc qdisc del dev ${dev}-ifb root 2>/dev/null + ip link del dev ${dev}-ifb 2>/dev/null +} + +start_qos() { + local dl=$1 + local up=$2 + + tc qdisc add dev $dev root handle 1: htb + tc class add dev $dev parent 1: classid 1:1 htb rate ${dl}mbit + + ip link add dev ${dev}-ifb name ${dev}-ifb type ifb + ip link set dev ${dev}-ifb up + + tc qdisc add dev ${dev}-ifb root handle 1: htb + tc class add dev ${dev}-ifb parent 1: classid 1:1 htb rate ${up}mbit + + tc qdisc add dev $dev ingress + tc filter add dev $dev parent ffff: protocol ip u32 match u32 0 0 flowid 1:1 action mirred egress redirect dev ${dev}-ifb +} + +case "$1" in + "stop") + stop_qos + ;; + "start") + stop_qos + start_qos $2 $3 + ;; + "add") + ip="$2" + dl="$3" + up="$4" + + cnt=$(tc class show dev $dev | wc -l) + + tc class add dev $dev parent 1:1 classid 1:1$cnt htb rate ${dl}mbit ceil ${dl}mbit + tc filter add dev $dev parent 1:0 protocol ip u32 match ip dst $ip flowid 1:1$cnt + + tc class add dev ${dev}-ifb parent 1:1 classid 1:1$cnt htb rate ${up}mbit ceil ${up}mbit + tc filter add dev ${dev}-ifb parent 1:0 protocol ip u32 match ip src $ip flowid 1:1$cnt + ;; + *) + echo "Usage: $0 [options]" + echo "Commands:" + echo " start dl_rate up_rate #Total bandwidth (Mbit/s)" + echo " stop" + echo " add ip dl_rate up_rate #Limiting the bandwidth of a single IP (Mbit/s)" + echo "Example:" + echo " $0 start 30 20 # Total bandwidth: down 30Mbit/s up 20Mbit/s" + echo " $0 add 192.168.22.12 10 2 # down 10Mbit/s up 2Mbit/s" + ;; +esac diff --git a/luci-app-eqos/root/usr/share/luci/menu.d/luci-app-eqos.json b/luci-app-eqos/root/usr/share/luci/menu.d/luci-app-eqos.json new file mode 100644 index 0000000..cefc5c1 --- /dev/null +++ b/luci-app-eqos/root/usr/share/luci/menu.d/luci-app-eqos.json @@ -0,0 +1,13 @@ +{ + "admin/network/eqos": { + "title": "EQoS", + "action": { + "type": "view", + "path": "eqos" + }, + "depends": { + "acl": [ "luci-app-eqos" ], + "uci": { "eqos": true } + } + } +} diff --git a/luci-app-eqos/root/usr/share/rpcd/acl.d/luci-app-eqos.json b/luci-app-eqos/root/usr/share/rpcd/acl.d/luci-app-eqos.json new file mode 100644 index 0000000..6870274 --- /dev/null +++ b/luci-app-eqos/root/usr/share/rpcd/acl.d/luci-app-eqos.json @@ -0,0 +1,11 @@ +{ + "luci-app-eqos": { + "description": "Grant UCI access for luci-app-eqos", + "read": { + "uci": [ "eqos" ] + }, + "write": { + "uci": [ "eqos" ] + } + } +} diff --git a/luci-app-filebrowser-go/Makefile b/luci-app-filebrowser-go/Makefile new file mode 100644 index 0000000..2afc20c --- /dev/null +++ b/luci-app-filebrowser-go/Makefile @@ -0,0 +1,24 @@ +# Copyright (C) 2018-2020 Lienol +# +# This is free software, licensed under the Apache License, Version 2.0 . +# +# Improve by xiaozhuai +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=luci-app-filebrowser-go +PKG_VERSION:=1.1 +PKG_RELEASE:=2 + +LUCI_TITLE:=LuCI support for FileBrowser +LUCI_PKGARCH:=all +LUCI_DEPENDS:=+filebrowser +luci-compat + +define Package/$(PKG_NAME)/conffiles +/etc/filebrowser.db +endef + +include $(TOPDIR)/feeds/luci/luci.mk + +# call BuildPackage - OpenWrt buildroot signature diff --git a/luci-app-filebrowser-go/luasrc/controller/filebrowser.lua b/luci-app-filebrowser-go/luasrc/controller/filebrowser.lua new file mode 100644 index 0000000..74b21ee --- /dev/null +++ b/luci-app-filebrowser-go/luasrc/controller/filebrowser.lua @@ -0,0 +1,41 @@ +-- Copyright 2018-2020 Lienol +-- Improve by xiaozhuai +module("luci.controller.filebrowser", package.seeall) + +local http = require "luci.http" + +function index() + if not nixio.fs.access("/etc/config/filebrowser") then + return + end + + local page = entry({"admin", "services", "filebrowser"}, alias("admin", "services", "filebrowser", "settings"), _("File Browser"), 100) + page.dependent = true + page.acl_depends = { "luci-app-filebrowser-go" } + + entry({"admin", "services", "filebrowser", "settings"}, cbi("filebrowser/settings"), _("Settings"), 1).leaf = true + entry({"admin", "services", "filebrowser", "log"}, cbi("filebrowser/log"), _("Log"), 2).leaf = true + entry({"admin", "services", "filebrowser", "check"}, call("action_check")).leaf = true + entry({"admin", "services", "filebrowser", "status"}, call("act_status")).leaf = true + entry({"admin", "services", "filebrowser", "get_log"}, call("get_log")).leaf = true + entry({"admin", "services", "filebrowser", "clear_log"}, call("clear_log")).leaf = true +end + +function http_write_json(content) + http.prepare_content("application/json") + http.write_json(content or {code = 1}) +end + +function act_status() + local e = {} + e.running = luci.sys.call("pgrep filebrowser >/dev/null") == 0 + http_write_json(e) +end + +function get_log() + luci.http.write(luci.sys.exec("[ -f '/var/log/filebrowser.log' ] && cat /var/log/filebrowser.log")) +end + +function clear_log() + luci.sys.call("echo '' > /var/log/filebrowser.log") +end diff --git a/luci-app-filebrowser-go/luasrc/model/cbi/filebrowser/log.lua b/luci-app-filebrowser-go/luasrc/model/cbi/filebrowser/log.lua new file mode 100644 index 0000000..ef496db --- /dev/null +++ b/luci-app-filebrowser-go/luasrc/model/cbi/filebrowser/log.lua @@ -0,0 +1,5 @@ +m = Map("filebrowser") + +m:append(Template("filebrowser/filebrowser_log")) + +return m diff --git a/luci-app-filebrowser-go/luasrc/model/cbi/filebrowser/settings.lua b/luci-app-filebrowser-go/luasrc/model/cbi/filebrowser/settings.lua new file mode 100644 index 0000000..9691d70 --- /dev/null +++ b/luci-app-filebrowser-go/luasrc/model/cbi/filebrowser/settings.lua @@ -0,0 +1,47 @@ +m = Map("filebrowser") +m.title = translate("File Browser") +m.description = translate("File explorer is software that creates your own cloud that you can install on a server, point it to a path, and then access your files through a beautiful web interface. You have many features available!") + +m:section(SimpleSection).template = "filebrowser/filebrowser_status" + +s = m:section(TypedSection, "global") +s.anonymous = true +s.addremove = false + +o = s:option(Flag, "enable", translate("Enable")) +o.rmempty = false + +o = s:option(Value, "address", translate("Listen address")) +o.default = "0.0.0.0" +o.rmempty = false + +o = s:option(Value, "port", translate("Listen port")) +o.datatype = "port" +o.default = 8088 +o.rmempty = false + +o = s:option(Value, "database", translate("Database path")) +o.default = "/etc/filebrowser.db" +o.rmempty = false + +o = s:option(Value, "username", translate("Initial username")) +o.default = "admin" +o.rmempty = false + +o = s:option(Value, "password", translate("Initial password")) +o.default = "admin" +o.rmempty = false +o.password = true + +o = s:option(Value, "ssl_cert", translate("SSL cert")) +o.default = "" + +o = s:option(Value, "ssl_key", translate("SSL key")) +o.default = "" + +o = s:option(Value, "root_path", translate("Root path")) +o.description = translate("Point to a path to access your files in the web interface, default is /") +o.default = "/" +o.rmempty = false + +return m diff --git a/luci-app-filebrowser-go/luasrc/view/filebrowser/filebrowser_log.htm b/luci-app-filebrowser-go/luasrc/view/filebrowser/filebrowser_log.htm new file mode 100644 index 0000000..22828d4 --- /dev/null +++ b/luci-app-filebrowser-go/luasrc/view/filebrowser/filebrowser_log.htm @@ -0,0 +1,28 @@ + +
+ + +
diff --git a/luci-app-filebrowser-go/luasrc/view/filebrowser/filebrowser_status.htm b/luci-app-filebrowser-go/luasrc/view/filebrowser/filebrowser_status.htm new file mode 100644 index 0000000..0283f41 --- /dev/null +++ b/luci-app-filebrowser-go/luasrc/view/filebrowser/filebrowser_status.htm @@ -0,0 +1,22 @@ + + +
+

+ <%:Collecting data...%> +

+
diff --git a/luci-app-filebrowser-go/po/zh-cn/filebrowser.po b/luci-app-filebrowser-go/po/zh-cn/filebrowser.po new file mode 100644 index 0000000..5d9d0a3 --- /dev/null +++ b/luci-app-filebrowser-go/po/zh-cn/filebrowser.po @@ -0,0 +1,56 @@ +msgid "File Browser" +msgstr "文件浏览器" + +msgid "File explorer is software that creates your own cloud that you can install on a server, point it to a path, and then access your files through a beautiful web interface. You have many features available!" +msgstr "文件浏览器是一种创建你自己的云的软件,你可以在服务器上安装它,将它指向一个路径,然后通过一个漂亮的web界面访问你的文件。您有许多可用的特性!" + +msgid "Settings" +msgstr "设置" + +msgid "Log" +msgstr "日志" + +msgid "RUNNING" +msgstr "运行中" + +msgid "NOT RUNNING" +msgstr "未运行" + +msgid "Enter interface" +msgstr "进入界面" + +msgid "Enable" +msgstr "启用" + +msgid "Listen address" +msgstr "监听地址" + +msgid "Listen port" +msgstr "监听端口" + +msgid "Initial username" +msgstr "初始账户" + +msgid "Initial password" +msgstr "初始密码" + +msgid "SSL cert" +msgstr "SSL 证书" + +msgid "SSL key" +msgstr "SSL 私钥" + +msgid "Database path" +msgstr "数据库路径" + +msgid "Root path" +msgstr "指向路径" + +msgid "Point to a path to access your files in the web interface, default is /" +msgstr "指向一个路径,可在web界面访问你的文件,默认为 /" + +msgid "Logs" +msgstr "日志" + +msgid "Clear logs" +msgstr "清空日志" diff --git a/luci-app-filebrowser-go/po/zh_Hans b/luci-app-filebrowser-go/po/zh_Hans new file mode 120000 index 0000000..41451e4 --- /dev/null +++ b/luci-app-filebrowser-go/po/zh_Hans @@ -0,0 +1 @@ +zh-cn \ No newline at end of file diff --git a/luci-app-filebrowser-go/root/etc/config/filebrowser b/luci-app-filebrowser-go/root/etc/config/filebrowser new file mode 100644 index 0000000..467a863 --- /dev/null +++ b/luci-app-filebrowser-go/root/etc/config/filebrowser @@ -0,0 +1,12 @@ + +config global + option address '0.0.0.0' + option port '8088' + option database '/etc/filebrowser.db' + option username 'admin' + option password 'admin' + option ssl_cert '' + option ssl_key '' + option root_path '/' + option enable '0' + diff --git a/luci-app-filebrowser-go/root/etc/init.d/filebrowser b/luci-app-filebrowser-go/root/etc/init.d/filebrowser new file mode 100755 index 0000000..f1f9736 --- /dev/null +++ b/luci-app-filebrowser-go/root/etc/init.d/filebrowser @@ -0,0 +1,47 @@ +#!/bin/sh /etc/rc.common +# Copyright (C) 2018-2022 Lienol +# Improve by xiaozhuai + +START=99 +USE_PROCD=1 +PROG=/usr/sbin/filebrowser +LOG_PATH="/var/log/filebrowser.log" + +get_config() { + config_get_bool enable $1 enable 1 + config_get address $1 address "0.0.0.0" + config_get port $1 port 8088 + config_get database $1 database "/etc/filebrowser.db" + config_get username $1 username "admin" + config_get password $1 password "admin" + config_get ssl_cert $1 ssl_cert "" + config_get ssl_key $1 ssl_key "" + config_get root_path $1 root_path "/" +} + +start_service() { + config_load filebrowser + config_foreach get_config global + [ $enable != 1 ] && return 1 + rm -f $LOG_PATH + ssl_params="" + [ -n "$ssl_cert" ] && [ -n "$ssl_key" ] && ssl_params="-t $ssl_cert -k $ssl_key" + password=$($PROG hash "$password") + procd_open_instance filebrowser + procd_set_param command $PROG + procd_append_param command -a $address -p $port -r $root_path -d "$database" --username $username --password $password $ssl_params -l $LOG_PATH + procd_set_param stdout 0 + procd_set_param stderr 0 + procd_set_param respawn + procd_close_instance filebrowser +} + +service_triggers() { + procd_add_reload_trigger "filebrowser" +} + +reload_service() { + stop + sleep 1 + start +} diff --git a/luci-app-filebrowser-go/root/etc/uci-defaults/luci-filebrowser b/luci-app-filebrowser-go/root/etc/uci-defaults/luci-filebrowser new file mode 100755 index 0000000..df11e72 --- /dev/null +++ b/luci-app-filebrowser-go/root/etc/uci-defaults/luci-filebrowser @@ -0,0 +1,11 @@ +#!/bin/sh + +uci -q batch <<-EOF >/dev/null + delete ucitrack.@filebrowser[-1] + add ucitrack filebrowser + set ucitrack.@filebrowser[-1].init=filebrowser + commit ucitrack +EOF + +rm -f /tmp/luci-indexcache +exit 0 diff --git a/luci-app-filebrowser-go/root/usr/share/rpcd/acl.d/luci-app-filebrowser-go.json b/luci-app-filebrowser-go/root/usr/share/rpcd/acl.d/luci-app-filebrowser-go.json new file mode 100644 index 0000000..bcc7944 --- /dev/null +++ b/luci-app-filebrowser-go/root/usr/share/rpcd/acl.d/luci-app-filebrowser-go.json @@ -0,0 +1,11 @@ +{ + "luci-app-filebrowser-go": { + "description": "Grant UCI access for luci-app-filebrowser", + "read": { + "uci": [ "filebrowser" ] + }, + "write": { + "uci": [ "filebrowser" ] + } + } +} diff --git a/luci-app-gowebdav/Makefile b/luci-app-gowebdav/Makefile new file mode 100644 index 0000000..1c79b62 --- /dev/null +++ b/luci-app-gowebdav/Makefile @@ -0,0 +1,22 @@ +# Copyright (C) 2016 Openwrt.org +# +# This is a free software, use it under GNU General Public License v3.0. +# +# Created By ImmortalWrt +# https://github.com/project-openwrt + +include $(TOPDIR)/rules.mk + +PKG_NAME:=luci-app-gowebdav +PKG_VERSION:=1.0 +PKG_RELEASE:=1 + +LUCI_TITLE:=LuCI support for GoWebDav +LUCI_DEPENDS:=+gowebdav +LUCI_PKGARCH:=all + +PKG_MAINTAINER:=CN_SZTL + +include $(TOPDIR)/feeds/luci/luci.mk + +# call BuildPackage - OpenWrt buildroot signature diff --git a/luci-app-gowebdav/luasrc/controller/gowebdav.lua b/luci-app-gowebdav/luasrc/controller/gowebdav.lua new file mode 100644 index 0000000..ae9f03a --- /dev/null +++ b/luci-app-gowebdav/luasrc/controller/gowebdav.lua @@ -0,0 +1,22 @@ +module("luci.controller.gowebdav", package.seeall) + +function index() + if not nixio.fs.access("/etc/config/gowebdav") then + return + end + + entry({"admin", "nas"}, firstchild(), _("NAS"), 45).dependent = false + + local page = entry({"admin", "nas", "gowebdav"}, cbi("gowebdav"), _("GoWebDav"), 100) + page.dependent = true + page.acl_depends = { "luci-app-gowebdav" } + + entry({"admin", "nas", "gowebdav", "status"}, call("act_status")).leaf = true +end + +function act_status() + local e = {} + e.running = luci.sys.call("pgrep gowebdav >/dev/null") == 0 + luci.http.prepare_content("application/json") + luci.http.write_json(e) +end diff --git a/luci-app-gowebdav/luasrc/model/cbi/gowebdav.lua b/luci-app-gowebdav/luasrc/model/cbi/gowebdav.lua new file mode 100644 index 0000000..1b693bb --- /dev/null +++ b/luci-app-gowebdav/luasrc/model/cbi/gowebdav.lua @@ -0,0 +1,60 @@ +-- Created By ImmortalWrt +-- https://github.com/immortalwrt + +m = Map("gowebdav", translate("GoWebDav")) +m.description = translate("GoWebDav is a tiny, simple, fast WevDav server.") + +m:section(SimpleSection).template = "gowebdav/gowebdav_status" + +s = m:section(TypedSection, "gowebdav") +s.addremove = false +s.anonymous = true + +o = s:option(Flag, "enable", translate("Enable")) +o.rmempty = false + +o = s:option(Value, "listen_port", translate("Listen Port")) +o.placeholder = 6086 +o.default = 6086 +o.datatype = "port" +o.rmempty = false + +o = s:option(Value, "username", translate("Username")) +o.description = translate("Leave blank to disable auth.") +o.datatype = "string" + +o = s:option(Value, "password", translate("Password")) +o.description = translate("Leave blank to disable auth.") +o.datatype = "string" +o.password = true + +o = s:option(Value, "root_dir", translate("Root Directory")) +o.placeholder = "/mnt" +o.default = "/mnt" +o.rmempty = false + +o = s:option(Flag, "read_only", translate("Read-Only Mode")) +o.rmempty = false + +o = s:option(Flag, "show_hidden", translate("Show Hidden Files")) +o.rmempty = false + +o = s:option(Flag, "allow_wan", translate("Allow Access From Internet")) +o.rmempty = false + +o = s:option(Flag, "use_https", translate("Use HTTPS instead of HTTP")) +o.rmempty = false + +o = s:option(Value, "cert_cer", translate("Path to Certificate")) +o.datatype = "file" +o:depends("use_https", 1) + +o = s:option(Value, "cert_key", translate("Path to Certificate Key")) +o.datatype = "file" +o:depends("use_https", 1) + +o = s:option(Button, "download_reg", translate("Download Reg File")) +o.template = "gowebdav/download_reg" +o.description = translate("Windows doesn't allow HTTP auth by default, you need to import this reg key to enable it (Reboot needed).") + +return m diff --git a/luci-app-gowebdav/luasrc/view/gowebdav/download_reg.htm b/luci-app-gowebdav/luasrc/view/gowebdav/download_reg.htm new file mode 100644 index 0000000..a550652 --- /dev/null +++ b/luci-app-gowebdav/luasrc/view/gowebdav/download_reg.htm @@ -0,0 +1,15 @@ +<%+cbi/valueheader%> + + +<%+cbi/valuefooter%> diff --git a/luci-app-gowebdav/luasrc/view/gowebdav/gowebdav_status.htm b/luci-app-gowebdav/luasrc/view/gowebdav/gowebdav_status.htm new file mode 100644 index 0000000..bac47e4 --- /dev/null +++ b/luci-app-gowebdav/luasrc/view/gowebdav/gowebdav_status.htm @@ -0,0 +1,27 @@ + + +
+

+ <%:Collecting data...%> +

+
diff --git a/luci-app-gowebdav/po/zh_Hans/gowebdav.po b/luci-app-gowebdav/po/zh_Hans/gowebdav.po new file mode 100644 index 0000000..37bf391 --- /dev/null +++ b/luci-app-gowebdav/po/zh_Hans/gowebdav.po @@ -0,0 +1,53 @@ +msgid "GoWebDav" +msgstr "GoWebDav" + +msgid "GoWebDav is a tiny, simple, fast WevDav server." +msgstr "GoWebDav 是一个轻巧、简单、快速的 WebDav 服务端程序。" + +msgid "Enable" +msgstr "启用" + +msgid "Listen Port" +msgstr "监听端口" + +msgid "Username" +msgstr "用户名" + +msgid "Password" +msgstr "密码" + +msgid "Leave blank to disable auth." +msgstr "留空以禁用身份验证。" + +msgid "Root Directory" +msgstr "开放目录" + +msgid "Read-Only Mode" +msgstr "只读模式" + +msgid "Show Hidden Files" +msgstr "显示隐藏文件" + +msgid "Download Reg File" +msgstr "下载注册表文件" + +msgid "Click Download" +msgstr "点击下载" + +msgid "Windows doesn't allow HTTP auth by default, you need to import this reg key to enable it (Reboot needed)." +msgstr "Windows 系统默认不允许 HTTP 鉴权,您需要手动导入注册表文件以开启此功能(需重启)。" + +msgid "Allow Access From Internet" +msgstr "允许从外网访问" + +msgid "Use HTTPS instead of HTTP" +msgstr "使用 HTTPS 模式" + +msgid "Path to Certificate" +msgstr "证书位置" + +msgid "Path to Certificate Key" +msgstr "密钥位置" + +msgid "Open Web Interface" +msgstr "打开 Web 界面" diff --git a/luci-app-gowebdav/root/etc/uci-defaults/luci-gowebdav b/luci-app-gowebdav/root/etc/uci-defaults/luci-gowebdav new file mode 100755 index 0000000..2cb52d3 --- /dev/null +++ b/luci-app-gowebdav/root/etc/uci-defaults/luci-gowebdav @@ -0,0 +1,17 @@ +#!/bin/sh + +uci -q batch <<-EOF >/dev/null + delete ucitrack.@gowebdav[-1] + add ucitrack gowebdav + set ucitrack.@gowebdav[-1].init=gowebdav + commit ucitrack + delete firewall.gowebdav + set firewall.gowebdav=include + set firewall.gowebdav.type=script + set firewall.gowebdav.path=/var/etc/gowebdav.include + set firewall.gowebdav.reload=1 + commit firewall +EOF + +rm -f /tmp/luci-indexcache +exit 0 diff --git a/luci-app-gowebdav/root/usr/share/rpcd/acl.d/luci-app-gowebdav.json b/luci-app-gowebdav/root/usr/share/rpcd/acl.d/luci-app-gowebdav.json new file mode 100644 index 0000000..9db3a3d --- /dev/null +++ b/luci-app-gowebdav/root/usr/share/rpcd/acl.d/luci-app-gowebdav.json @@ -0,0 +1,11 @@ +{ + "luci-app-gowebdav": { + "description": "Grant UCI access for luci-app-gowebdav", + "read": { + "uci": [ "gowebdav" ] + }, + "write": { + "uci": [ "gowebdav" ] + } + } +} diff --git a/luci-app-netdata/Makefile b/luci-app-netdata/Makefile new file mode 100644 index 0000000..de3b866 --- /dev/null +++ b/luci-app-netdata/Makefile @@ -0,0 +1,18 @@ +# Copyright (C) 2016 Openwrt.org +# +# This is free software, licensed under the Apache License, Version 2.0 . +# + +include $(TOPDIR)/rules.mk + +LUCI_TITLE:=LuCI support for Netdata +LUCI_DEPENDS:=+netdata +LUCI_PKGARCH:=all + +PKG_NAME:=luci-app-netdata +PKG_VERSION:=1.0 +PKG_RELEASE:=3 + +include $(TOPDIR)/feeds/luci/luci.mk + +# call BuildPackage - OpenWrt buildroot signature diff --git a/luci-app-netdata/luasrc/controller/netdata.lua b/luci-app-netdata/luasrc/controller/netdata.lua new file mode 100644 index 0000000..09e9943 --- /dev/null +++ b/luci-app-netdata/luasrc/controller/netdata.lua @@ -0,0 +1,6 @@ +module("luci.controller.netdata", package.seeall) + +function index() + + entry({"admin", "status", "netdata"}, template("netdata/netdata"), _("NetData"), 10).leaf = true +end diff --git a/luci-app-netdata/luasrc/view/netdata/netdata.htm b/luci-app-netdata/luasrc/view/netdata/netdata.htm new file mode 100644 index 0000000..da7ff7c --- /dev/null +++ b/luci-app-netdata/luasrc/view/netdata/netdata.htm @@ -0,0 +1,9 @@ +<%+header%> +
+

<%=translate("NetData")%>

+ +
+ +<%+footer%> diff --git a/luci-app-netdata/po/zh_Hans/netdata.po b/luci-app-netdata/po/zh_Hans/netdata.po new file mode 100644 index 0000000..e8966b8 --- /dev/null +++ b/luci-app-netdata/po/zh_Hans/netdata.po @@ -0,0 +1,5 @@ +msgid "" +msgstr "Content-Type: text/plain; charset=UTF-8" + +msgid "NetData" +msgstr "实时监控" diff --git a/luci-app-netspeedtest/Makefile b/luci-app-netspeedtest/Makefile new file mode 100644 index 0000000..0036626 --- /dev/null +++ b/luci-app-netspeedtest/Makefile @@ -0,0 +1,16 @@ +include $(TOPDIR)/rules.mk + +LUCI_NAME:=luci-app-netspeedtest +PKG_VERSION:=1.0 + +LUCI_TITLE:=LuCI Net Speedtest +LUCI_DEPENDS:=+iperf3 +speedtest-cli +curl +jsonfilter +taskset +bash + +define Package/$(LUCI_NAME)/conffiles +/etc/config/netspeedtest +/etc/speedtest +endef + +include $(TOPDIR)/feeds/luci/luci.mk + +# call BuildPackage - OpenWrt buildroot signature diff --git a/luci-app-netspeedtest/htdocs/luci-static/resources/view/netspeedtest/iperf3.js b/luci-app-netspeedtest/htdocs/luci-static/resources/view/netspeedtest/iperf3.js new file mode 100644 index 0000000..92a3411 --- /dev/null +++ b/luci-app-netspeedtest/htdocs/luci-static/resources/view/netspeedtest/iperf3.js @@ -0,0 +1,105 @@ +'use strict'; +'require view'; +'require poll'; +'require fs'; +'require rpc'; +'require uci'; +'require ui'; +'require form'; + +var conf = 'netspeedtest'; +var instance = 'iperf3'; + +var callServiceList = rpc.declare({ + object: 'service', + method: 'list', + params: ['name'], + expect: { '': {} } +}); + +function getServiceStatus() { + return L.resolveDefault(callServiceList(conf), {}) + .then(function (res) { + var isrunning = false; + try { + isrunning = res[conf]['instances'][instance]['running']; + } catch (e) { } + return isrunning; + }); +} + +return view.extend({ +// handleSaveApply: null, +// handleSave: null, +// handleReset: null, + + load: function() { + return Promise.all([ + getServiceStatus(), + uci.load('netspeedtest') + ]); + }, + + poll_status: function(nodes, stat) { + var isRunning = stat[0], + view = nodes.querySelector('#service_status'); + + if (isRunning) { + view.innerHTML = "" + instance + " - " + _("RUNNING") + ""; + } else { + view.innerHTML = "" + instance + " - " + _("NOT RUNNING") + ""; + } + return; + }, + + render: function(res) { + var isRunning = res[0]; + + var m, s, o; + + m = new form.Map('netspeedtest', _('iPerf3 Bandwidth Performance Test'), + _('iPerf3 is a tool for active measurements of the maximum achievable bandwidth on IP networks.')); + + s = m.section(form.NamedSection, '_status'); + s.anonymous = true; + s.render = function (section_id) { + return E('div', { class: 'cbi-section' }, [ + E('div', { id: 'service_status' }, _('Collecting data ...')) + ]); + }; + + s = m.section(form.NamedSection, 'config', 'netspeedtest'); + s.anonymous = true; + + o = s.option(form.Flag, 'iperf3_enabled', _('Enable')); + o.default = o.disabled; + o.rmempty = false; + + s = m.section(form.TypedSection, '_cmd_ref'); + s.anonymous = true; + s.render = function (section_id) { + return E('div', { 'class': 'cbi-section' }, [ + E('h3', {}, _('iPerf3 Common commands reference')), + E('pre', {}, [ +" -c, --client \n\ + -u, --udp UDP mode\n\ + -b, --bandwidth [KMG] target bandwidth in bits/sec (0 for unlimited)\n\ + -t, --time time in seconds to transmit for (default 10 secs)\n\ + -i, --interval seconds between periodic bandwidth reports\n\ + -P, --parallel number of parallel client streams to run\n\ + -R, --reverse run in reverse mode (server sends, client receives)\n" + ]) + ]); + }; + + return m.render() + .then(L.bind(function(m, nodes) { + poll.add(L.bind(function() { + return Promise.all([ + getServiceStatus() + ]).then(L.bind(this.poll_status, this, nodes)); + }, this), 3); + return nodes; + }, this, m)); + } +}); diff --git a/luci-app-netspeedtest/htdocs/luci-static/resources/view/netspeedtest/speedtest.js b/luci-app-netspeedtest/htdocs/luci-static/resources/view/netspeedtest/speedtest.js new file mode 100644 index 0000000..e7504dd --- /dev/null +++ b/luci-app-netspeedtest/htdocs/luci-static/resources/view/netspeedtest/speedtest.js @@ -0,0 +1,128 @@ +'use strict'; +'require view'; +'require poll'; +'require dom'; +'require fs'; +'require rpc'; +'require uci'; +'require ui'; +'require form'; + +var TestTimeout = 240 * 1000; // 4 Minutes + +return view.extend({ +// handleSaveApply: null, +// handleSave: null, +// handleReset: null, + + load: function() { + return Promise.all([ + L.resolveDefault(fs.stat('/usr/bin/speedtest'), {}), + L.resolveDefault(fs.read('/etc/speedtest/speedtest_result'), null), + L.resolveDefault(fs.stat('/etc/speedtest/speedtest_result'), {}), + uci.load('netspeedtest') + ]); + }, + + poll_status: function(nodes, res) { + var has_ookla = res[0].path, + result_content = res[1] ? res[1].trim().split("\n") : []; + var ookla_stat = nodes.querySelector('#ookla_status'), + result_stat = nodes.querySelector('#speedtest_result'); + if (has_ookla) { + ookla_stat.style.color = 'green'; + dom.content(ookla_stat, [ _('Installed') ]); + } else { + ookla_stat.style.color = 'red'; + dom.content(ookla_stat, [ _('Not Installed') ]); + }; + if (result_content.length) { + if (result_content[0] == 'Testing') { + result_stat.innerHTML = "" + + '  ' + + "" + + ' ' + + _('Testing in progress...') + + ""; + }; + if (result_content[0].match(/https?:\S+/)) { + result_stat.innerHTML = "
"; + }; + if (result_content[0] == 'Test failed') { + result_stat.innerHTML = "" + _('Test failed.') + ""; + } + } else { + result_stat.innerHTML = "" + _('No result.') + ""; + }; + return; + }, + + render: function(res) { + var has_ookla = res[0].path, + result_content = res[1] ? res[1].trim().split("\n") : [], + result_mtime = res[2] ? res[2].mtime * 1000 : 0, + date = new Date(); + + var m, s, o; + + m = new form.Map('netspeedtest', _('Speedtest by Ookla')); + + s = m.section(form.TypedSection, '_result'); + s.anonymous = true; + s.render = function (section_id) { + if (result_content.length) { + if (result_content[0] == 'Testing') { + return E('div', { 'id': 'speedtest_result' }, [ E('span', { 'style': 'color:yellow;font-weight:bold' }, [ + E('img', { 'src': L.resource(['icons/loading.gif']), 'height': '20', 'style': 'vertical-align:middle' }, []), + _('Testing in progress...') + ]) ]) + }; + if (result_content[0].match(/https?:\S+/)) { + return E('div', { 'id': 'speedtest_result' }, [ E('div', { 'style': 'max-width:500px' }, [ + E('a', { 'href': result_content[0], 'target': '_blank' }, [ + E('img', { 'src': result_content[0] + '.png', 'style': 'max-width:100%;max-height:100%;vertical-align:middle' }, []) + ]) ]) ]) + }; + if (result_content[0] == 'Test failed') { + return E('div', { 'id': 'speedtest_result' }, [ E('span', { 'style': 'color:red;font-weight:bold' }, [ _('Test failed.') ]) ]) + } + } else { + return E('div', { 'id': 'speedtest_result' }, [ E('span', { 'style': 'color:red;font-weight:bold;display:none' }, [ _('No result.') ]) ]) + } + }; + + s = m.section(form.NamedSection, 'config', 'speedtest', _('Internet Speedtest')); + + o = s.option(form.Button, '_start', _('Start Test')); + o.inputtitle = _('Start Test'); + o.inputstyle = 'apply'; + if (result_content.length && result_content[0] == 'Testing' && (date.getTime() - result_mtime) < TestTimeout) + o.readonly = true; + o.onclick = function() { + return fs.exec_direct('/usr/lib/netspeedtest/speedtest') + .then(function(res) { return window.location = window.location.href.split('#')[0] }) + .catch(function(e) { ui.addNotification(null, E('p', e.message), 'error') }); + }; + + o = s.option(form.DummyValue, '_ookla_status', _('Speedtest® CLI')); + o.rawhtml = true; + o.cfgvalue = function(s) { + if (has_ookla) { + return E('span', { 'id': 'ookla_status', 'style': 'color:green;font-weight:bold' }, [ _('Installed') ]); + } else { + return E('span', { 'id': 'ookla_status', 'style': 'color:red;font-weight:bold' }, [ _('Not Installed') ]); + } + }; + + return m.render() + .then(L.bind(function(m, nodes) { + poll.add(L.bind(function() { + return Promise.all([ + L.resolveDefault(fs.stat('/usr/bin/speedtest'), {}), + L.resolveDefault(fs.read('/etc/speedtest/speedtest_result'), null) + ]).then(L.bind(this.poll_status, this, nodes)); + }, this), 5); + return nodes; + }, this, m)); + } +}); diff --git a/luci-app-netspeedtest/po/zh_Hans/netspeedtest.po b/luci-app-netspeedtest/po/zh_Hans/netspeedtest.po new file mode 100644 index 0000000..7584795 --- /dev/null +++ b/luci-app-netspeedtest/po/zh_Hans/netspeedtest.po @@ -0,0 +1,59 @@ +msgid "iPerf3 Server" +msgstr "iPerf3 服务器" + +msgid "iPerf3 Bandwidth Performance Test" +msgstr "iPerf3 带宽性能测试" + +msgid "iPerf3 Common commands reference" +msgstr "iPerf3 常用命令参考" + +msgid "iPerf3 is a tool for active measurements of the maximum achievable bandwidth on IP networks." +msgstr "iPerf3 是一种主动测量 IP 网络最大可达带宽的工具。" + +msgid "Collecting data ..." +msgstr "正在收集数据..." + +msgid "NOT RUNNING" +msgstr "未运行" + +msgid "RUNNING" +msgstr "运行中" + +msgid "Enable" +msgstr "启用" + +msgid "No result." +msgstr "无结果." + +msgid "Ookla SpeedTest" +msgstr "" + +msgid "Speedtest by Ookla" +msgstr "" + +msgid "Speedtest CLI" +msgstr "" + +msgid "Speedtest® CLI" +msgstr "" + +msgid "Installed" +msgstr "已安装" + +msgid "Not Installed" +msgstr "未安装" + +msgid "SpeedTest" +msgstr "网速测试" + +msgid "Internet Speedtest" +msgstr "互联网测速" + +msgid "Start Test" +msgstr "启动测试" + +msgid "Test failed." +msgstr "测试失败." + +msgid "Testing in progress..." +msgstr "测试进行中..." diff --git a/luci-app-netspeedtest/root/etc/init.d/netspeedtest b/luci-app-netspeedtest/root/etc/init.d/netspeedtest new file mode 100755 index 0000000..a3e96f8 --- /dev/null +++ b/luci-app-netspeedtest/root/etc/init.d/netspeedtest @@ -0,0 +1,31 @@ +#!/bin/sh /etc/rc.common + +START=99 +USE_PROCD=1 + +get_config() { + config_load netspeedtest + config_get "iperf3_enabled" "config" "iperf3_enabled" "0" +} + +start_service() { + get_config + [ "$iperf3_enabled" -ne "1" ] && return 1 + procd_open_instance "iperf3" + procd_set_param command /usr/bin/taskset -c 0-1 /usr/bin/iperf3 + procd_append_param command -s + procd_set_param respawn + procd_set_param stdout 0 + procd_set_param stderr 0 + procd_close_instance "iperf3" +} + +service_triggers() { + procd_add_reload_trigger "netspeedtest" +} + +reload_service() { + stop + sleep 1 + start +} diff --git a/luci-app-netspeedtest/root/etc/uci-defaults/99_netspeedtest b/luci-app-netspeedtest/root/etc/uci-defaults/99_netspeedtest new file mode 100755 index 0000000..680dc79 --- /dev/null +++ b/luci-app-netspeedtest/root/etc/uci-defaults/99_netspeedtest @@ -0,0 +1,6 @@ +#!/bin/sh +touch /etc/config/netspeedtest +uci -q batch <<-EOF >/dev/null + set netspeedtest.config=netspeedtest + commit netspeedtest +EOF diff --git a/luci-app-netspeedtest/root/usr/lib/netspeedtest/speedtest b/luci-app-netspeedtest/root/usr/lib/netspeedtest/speedtest new file mode 100755 index 0000000..da2f734 --- /dev/null +++ b/luci-app-netspeedtest/root/usr/lib/netspeedtest/speedtest @@ -0,0 +1,40 @@ +#!/bin/bash + +mkdir -p /etc/speedtest + +export HOME='/etc/speedtest' +SPEEDTEST_CLI='/usr/bin/speedtest' +SPEEDTEST_RESULT='/etc/speedtest/speedtest_result' + +[ -n "$(pgrep -f "$SPEEDTEST_CLI")" ] && exit 1 + +LOCAL_IP=$(curl -s -4 --connect-timeout 3 http://ip.3322.net) + +BAIDU_SK="LHHGlmhcb4ENvIXpR9QQ2tBYa6ooUowX hYCENCEx1nXO0Nt46ldexfG9oI49xBGh 0kKZnWWhXEPfzIkklmzAa3dZ" +if [ -n "$LOCAL_IP" ]; then + for SK in $BAIDU_SK + do + INFO=$(curl -sk --connect-timeout 3 "https://api.map.baidu.com/location/ip?ip="$LOCAL_IP"&coor=bd09ll&ak=$SK") + if [ "$(echo $INFO | jsonfilter -e "@['status']")" = 0 ]; then + status=0 + break + fi + done + if [ "$status" = 0 ]; then + lon=$(echo $INFO | jsonfilter -e "@['content']['point']['x']") + lat=$(echo $INFO | jsonfilter -e "@['content']['point']['y']") + server_id=$(curl -sk --connect-timeout 3 "https://www.speedtest.net/api/ios-config.php?lon=$lon&lat=$lat" | grep "server url" | head -n1 | sed 's/.*id="//;s/".*//') + [ -n "$server_id" ] && ARG="-s $server_id" + fi +fi + +echo "Testing" > "$SPEEDTEST_RESULT" + +RUNTEST=$($SPEEDTEST_CLI --accept-gdpr --accept-license --progress=no $ARG 2>&1) +if [ $(echo $RUNTEST | grep -c "No servers defined") -ge 1 ] || [ $(echo $RUNTEST | grep -c "error") -ge 1 ]; then + RUNTEST=$($SPEEDTEST_CLI --accept-gdpr --accept-license --progress=no 2>&1) +fi + +RESULT=$(echo "$RUNTEST" | grep "Result URL" | awk '{print $NF}') + +[ -n "$RESULT" ] && echo "$RESULT" > "$SPEEDTEST_RESULT" || echo "Test failed" > "$SPEEDTEST_RESULT" diff --git a/luci-app-netspeedtest/root/usr/share/luci/menu.d/luci-app-netspeedtest.json b/luci-app-netspeedtest/root/usr/share/luci/menu.d/luci-app-netspeedtest.json new file mode 100644 index 0000000..c78be29 --- /dev/null +++ b/luci-app-netspeedtest/root/usr/share/luci/menu.d/luci-app-netspeedtest.json @@ -0,0 +1,29 @@ +{ + "admin/network/netspeedtest": { + "title": "SpeedTest", + "order": 55, + "action": { + "type": "firstchild" + }, + "depends": { + "acl": [ "luci-app-netspeedtest" ], + "uci": { "netspeedtest": true } + } + }, + "admin/network/netspeedtest/iperf3": { + "title": "iPerf3 Server", + "order": 1, + "action": { + "type": "view", + "path": "netspeedtest/iperf3" + } + }, + "admin/network/netspeedtest/speedtest": { + "title": "Internet Speedtest", + "order": 2, + "action": { + "type": "view", + "path": "netspeedtest/speedtest" + } + } +} diff --git a/luci-app-netspeedtest/root/usr/share/rpcd/acl.d/luci-app-netspeedtest.json b/luci-app-netspeedtest/root/usr/share/rpcd/acl.d/luci-app-netspeedtest.json new file mode 100644 index 0000000..b53a043 --- /dev/null +++ b/luci-app-netspeedtest/root/usr/share/rpcd/acl.d/luci-app-netspeedtest.json @@ -0,0 +1,19 @@ +{ + "luci-app-netspeedtest": { + "description": "Grant access to netspeedtest procedures", + "read": { + "file": { + "/etc/init.d/netspeedtest": [ "exec" ], + "/usr/lib/netspeedtest/speedtest": [ "exec" ], + "/etc/speedtest/speedtest_result": [ "read" ] + }, + "ubus": { + "service": [ "list" ] + }, + "uci": [ "netspeedtest" ] + }, + "write": { + "uci": [ "netspeedtest" ] + } + } +} diff --git a/luci-app-ota/Makefile b/luci-app-ota/Makefile new file mode 100755 index 0000000..aa797b6 --- /dev/null +++ b/luci-app-ota/Makefile @@ -0,0 +1,13 @@ + +include $(TOPDIR)/rules.mk + +LUCI_TITLE:=LuCI for OTA upgrade +LUCI_PKGARCH:=all +LUCI_DEPENDS:=+fw_download_tool +jsonfilter +PKG_VERSION:=1.2 +PKG_RELEASE:=1 +PKG_MAINTAINER:=jjm2473 + +include $(TOPDIR)/feeds/luci/luci.mk + +# call BuildPackage - OpenWrt buildroot signature diff --git a/luci-app-ota/luasrc/controller/admin/ota.lua b/luci-app-ota/luasrc/controller/admin/ota.lua new file mode 100644 index 0000000..01e2e03 --- /dev/null +++ b/luci-app-ota/luasrc/controller/admin/ota.lua @@ -0,0 +1,175 @@ +--[[ +LuCI - Lua Configuration Interface +Copyright 2021 jjm2473 +]]-- + +require "luci.util" +module("luci.controller.admin.ota",package.seeall) + +function index() + if nixio.fs.access("/rom/bin/ota") then + entry({"admin", "system", "ota"}, call("action_ota"), _("OTA"), 69) + entry({"admin", "system", "ota", "check"}, post("action_check")) + entry({"admin", "system", "ota", "download"}, post("action_download")) + entry({"admin", "system", "ota", "progress"}, call("action_progress")) + entry({"admin", "system", "ota", "cancel"}, post("action_cancel")) + end +end + +local function ota_exec(cmd) + local nixio = require "nixio" + local os = require "os" + local fs = require "nixio.fs" + local rshift = nixio.bit.rshift + + local oflags = nixio.open_flags("wronly", "creat") + local lock, code, msg = nixio.open("/var/lock/ota_api.lock", oflags) + if not lock then + return 255, "", "Open stdio lock failed: " .. msg + end + + -- Acquire lock + local stat, code, msg = lock:lock("tlock") + if not stat then + lock:close() + return 255, "", "Lock stdio failed: " .. msg + end + + local r = os.execute(cmd .. " >/var/log/ota.stdout 2>/var/log/ota.stderr") + local e = fs.readfile("/var/log/ota.stderr") + local o = fs.readfile("/var/log/ota.stdout") + + fs.unlink("/var/log/ota.stderr") + fs.unlink("/var/log/ota.stdout") + + lock:lock("ulock") + lock:close() + + e = e or "" + if r == 256 and e == "" then + e = "os.execute failed, is /var/log full or not existed?" + end + return rshift(r, 8), o or "", e or "" +end + +local function image_supported(image) + return (os.execute("sysupgrade -T %q >/dev/null" % image) == 0) +end + +function action_ota() + local image_tmp = "/tmp/firmware.img" + local http = require "luci.http" + if http.formvalue("apply") == "1" then + if not image_supported(image_tmp) then + luci.template.render("admin_system/ota", {image_invalid = true}) + return + end + local keep = (http.formvalue("keep") == "1") and "" or "-n" + luci.template.render("admin_system/ota_flashing", { + title = luci.i18n.translate("Flashing…"), + msg = luci.i18n.translate("The system is flashing now.
DO NOT POWER OFF THE DEVICE!
Wait a few minutes before you try to reconnect. It might be necessary to renew the address of your computer to reach the device again, depending on your settings."), + addr = (#keep > 0) and "10.0.0.1" or nil + }) + fork_exec("sleep 1; killall dropbear uhttpd nginx; sleep 1; sync; /sbin/sysupgrade %s %q" %{ keep, image_tmp }) + else + luci.template.render("admin_system/ota") + end +end + +function action_check() + local r,o,e = ota_exec("ota check") + local ret = { + code = 500, + msg = "Unknown" + } + if r == 0 then + ret.code = 0 + ret.msg = o + elseif r == 1 then + ret.code = 1 + ret.msg = "Already the latest firmware" + else + ret.code = 500 + ret.msg = e + end + luci.http.prepare_content("application/json") + luci.http.write_json(ret) +end + +function action_download() + local r,o,e = ota_exec("ota download") + local ret = { + code = 500, + msg = "Unknown" + } + if r == 0 then + ret.code = 0 + ret.msg = "" + else + ret.code = 500 + ret.msg = e + end + luci.http.prepare_content("application/json") + luci.http.write_json(ret) +end + +function action_progress() + local r,o,e = ota_exec("ota progress") + local ret = { + code = 500, + msg = "Unknown" + } + if r == 0 then + ret.code = 0 + ret.msg = "done" + elseif r == 1 or r == 2 then + ret.code = r + ret.msg = o + else + ret.code = 500 + ret.msg = e + end + luci.http.prepare_content("application/json") + luci.http.write_json(ret) +end + +function action_cancel() + local r,o,e = ota_exec("ota cancel") + local ret = { + code = 500, + msg = "Unknown" + } + if r == 0 then + ret.code = 0 + ret.msg = "ok" + else + ret.code = 500 + ret.msg = e + end + luci.http.prepare_content("application/json") + luci.http.write_json(ret) +end + +function fork_exec(command) + local pid = nixio.fork() + if pid > 0 then + return + elseif pid == 0 then + -- change to root dir + nixio.chdir("/") + + -- patch stdin, out, err to /dev/null + local null = nixio.open("/dev/null", "w+") + if null then + nixio.dup(null, nixio.stderr) + nixio.dup(null, nixio.stdout) + nixio.dup(null, nixio.stdin) + if null:fileno() > 2 then + null:close() + end + end + + -- replace with target command + nixio.exec("/bin/sh", "-c", command) + end +end diff --git a/luci-app-ota/luasrc/view/admin_system/ota.htm b/luci-app-ota/luasrc/view/admin_system/ota.htm new file mode 100644 index 0000000..ee7dd73 --- /dev/null +++ b/luci-app-ota/luasrc/view/admin_system/ota.htm @@ -0,0 +1,218 @@ +<%# + Licensed to the public under the Apache License 2.0. +-%> + +<%+header%> + +<% + local fs = require "nixio.fs" +-%> + +

<%:OTA%>

+ + +
+
+ <%:Upgrade firmware On the Air%> +
<%:Check and upgrade firmware from the Internet%>
+ <% if image_invalid then %> +
<%:The image file does not contain a supported format. Maybe try again later.%>
+ <% end %> +
+
+
+
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+
+
+
+
+
+
+ +
+ +
+
+
+
+
+ <% if fs.access("/usr/lib/lua/luci/controller/admin/system.lua") then %> +
+ + +
+ +
+ +
+
+
+ <% else %> +
+ + +
+ +
+ +
+
+
+ +
+ +
+
+
+ <% end %> +
+
+
+
+

<%:The latest firmware%>:

+
+
+
+
+ + + +
+ +<%+footer%> diff --git a/luci-app-ota/luasrc/view/admin_system/ota_flashing.htm b/luci-app-ota/luasrc/view/admin_system/ota_flashing.htm new file mode 100644 index 0000000..cf516df --- /dev/null +++ b/luci-app-ota/luasrc/view/admin_system/ota_flashing.htm @@ -0,0 +1,111 @@ +<%# + Copyright 2008 Steven Barth + Copyright 2008 Jo-Philipp Wich + Licensed to the public under the Apache License 2.0. +-%> + + + + <%=luci.sys.hostname()%> - <%= title or translate("Rebooting...") %> + + + + + +
+
+ +
+

<%:System%> - <%= title or translate("Rebooting...") %>

+

+
+

<%= msg or translate("Changes applied.") %>

+
+
+ <%:Loading%> + <%:Waiting for device...%> +
+
+
+ + diff --git a/luci-app-ota/po/zh_Hans/ota.po b/luci-app-ota/po/zh_Hans/ota.po new file mode 100644 index 0000000..c330bca --- /dev/null +++ b/luci-app-ota/po/zh_Hans/ota.po @@ -0,0 +1,53 @@ +msgid "" +msgstr "Content-Type: text/plain; charset=UTF-8" + +msgid "OTA" +msgstr "在线升级" + +msgid "Already the latest firmware" +msgstr "已经是最新固件" + +msgid "Check update" +msgstr "检查更新" + +msgid "Found new firmware" +msgstr "发现新固件" + +msgid "Download firmware" +msgstr "下载固件" + +msgid "Cancel download" +msgstr "取消下载" + +msgid "Firmware downloaded" +msgstr "固件已下载" + +msgid "Flash image..." +msgstr "刷写固件..." + +msgid "Checking..." +msgstr "检查中..." + +msgid "Check failed" +msgstr "检查失败" + +msgid "Downloading" +msgstr "下载中" + +msgid "Download canceled" +msgstr "下载已取消" + +msgid "Download failed" +msgstr "下载失败" + +msgid "Upgrade firmware On the Air" +msgstr "在线升级固件" + +msgid "Check and upgrade firmware from the Internet" +msgstr "通过网络检查和更新固件" + +msgid "The latest firmware" +msgstr "最新固件" + +msgid "The image file does not contain a supported format. Maybe try again later." +msgstr "镜像文件格式不支持或损坏。也许稍候再试试" diff --git a/luci-app-ota/root/bin/ota b/luci-app-ota/root/bin/ota new file mode 100755 index 0000000..c682ddc --- /dev/null +++ b/luci-app-ota/root/bin/ota @@ -0,0 +1,156 @@ +#!/bin/sh + +. /etc/os-release +. /lib/functions/uci-defaults.sh + +API=$(uci -q get ota.config.api_url) +WRLOCK=/var/lock/ota_background.lock + +# armsr/armv8 +[ "$OPENWRT_BOARD" = "armsr/armv8" ] && alias board_name="echo armsr,armv8" + +# x86_64 +[ $(uname -m) = "x86_64" ] && alias board_name="echo x86_64" + +action=${1} +shift + +sha256() { + sha256sum $1 | cut -d' ' -f1 +} + +download() { + read_json + if [ -f /tmp/firmware.img ]; then + echo "Checking existed firmware.img..." >> /tmp/firmware.img.progress + if [ "`sha256 /tmp/firmware.img`" = "$FW_SHA256SUM" ]; then + return 0; + else + echo "Check failed, redownload" >> /tmp/firmware.img.progress + rm -f /tmp/firmware.img + fi + fi + touch /tmp/firmware.img.progress + fw_download_tool "$FW_URL" -o /tmp/firmware.img.part -k -L -4 > /tmp/firmware.img.progress 2>&1 & + echo "$! $PPID" > /var/run/ota/download.pid + while true; do + progress=$(grep -c "100.00%" /tmp/firmware.img.progress) + if [ "$progress" -ge "1" ]; then + echo "Checking new firmware.img.part..." > /tmp/firmware.img.progress + break + fi + sleep 1 + done + if [ "`sha256 /tmp/firmware.img.part`" = "$FW_SHA256SUM" ]; then + mv /tmp/firmware.img.part /tmp/firmware.img && echo $FW_SHA256SUM > /tmp/firmware.img.sha256sum + rm -f /tmp/firmware.img.progress + return 0 + else + echo "Checksum failed!" >>/tmp/firmware.img.progress + sleep 1 + rm -rf /tmp/firmware.img.part + return 1 + fi +} + +lock_download() { + local lock="$WRLOCK" + exec 200>$lock + flock -n 200 || return + download + flock -u 200 +} + +# 0: found newer fw, 1: already newest fw, *: err +do_check() { + url_check=$(curl -I -o /dev/null -s -w %{http_code} "$API") + [ $url_check -ne 200 ] && exit 255 + curl -s "$API" > /var/run/ota/fw.json + read_json + NEW_VERSION=$(basename $FW_URL | awk -F- '{if (NF >= 3 && $3 ~ /^rc/) {print $2 "-" $3} else {print $2}}') + if [ "$BUILD_DATE" -lt "$FW_BUILD_DATE" ]; then + echo "

Model:  $(board_name)
Current Version:  $PRETTY_NAME
Build Date:  $(date "+%Y-%m-%d %H:%M:%S" -d "@$BUILD_DATE")

" + echo "

New Version:  OpenWrt $NEW_VERSION
Build Date:  $(date "+%Y-%m-%d %H:%M:%S" -d "@$FW_BUILD_DATE")

" + return 0 + elif [ "$BUILD_DATE" -ge "$FW_BUILD_DATE" ]; then + return 1 + else + return 255 + fi +} + +# async download +do_download(){ + [ ! -f "/var/run/ota/fw.json" ] && { echo "do check first" >&2 ; return 254; } + lock_download & + return 0 +} + +# 0: done, 1: downloading, 2: failed, *: err +do_progress() { + read_json + [ -f /tmp/firmware.img.sha256sum ] && [ "`cat /tmp/firmware.img.sha256sum`" = "$FW_SHA256SUM" ] && return 0 + [ -f /tmp/firmware.img.progress ] || { echo "download not in progress" >&2 ; return 254; } + [ -f /tmp/firmware.img.part ] && { cat /tmp/firmware.img.progress | tr '\r' '\n' | tail -n1; return 1; } + tail -1 /tmp/firmware.img.progress | grep -Fq 'Canceled!' && { echo "Canceled"; return 2; } + tail -1 /tmp/firmware.img.progress | grep -Fq 'Checksum failed!' && { echo "Checksum failed!"; return 254; } + grep -v '\r' /tmp/firmware.img.progress >&2 + return 1 +} + +do_cancel() { + if [ -f /var/run/ota/download.pid ]; then + local pid=`cat /var/run/ota/download.pid` + if [ -n "$pid" ]; then + kill -TERM $pid; + while kill -9 $pid >/dev/null 2>&1; do + if ! sleep 1; then + break + fi + done + rm -rf /tmp/firmware.img* /var/lock/ota_background.lock /var/lock/ota_api.lock /var/run/ota/download.pid + echo "" >> /tmp/firmware.img.progress + echo "Canceled!" >> /tmp/firmware.img.progress + fi + fi + return 0 +} + +read_json(){ + FW_BUILD_DATE=$(jsonfilter -i /var/run/ota/fw.json -e "@['$(board_name)'][0]['build_date']") + FW_SHA256SUM=$(jsonfilter -i /var/run/ota/fw.json -e "@['$(board_name)'][0]['sha256sum']") + FW_URL=$(jsonfilter -i /var/run/ota/fw.json -e "@['$(board_name)'][0]['url']") +} + +ota_init(){ + mkdir -p /var/run/ota >/dev/null 2>&1 || true +} + +usage() { + echo "usage: ota sub-command" + echo "where sub-command is one of:" + echo " check Check firmware upgrade" + echo " download Download latest firmware" + echo " progress Download progress" + echo " cancel Cancel download" +} + +ota_init || exit 255 + +case $action in + "check") + do_check + ;; + "download") + do_download + ;; + "progress") + do_progress + ;; + "cancel") + do_cancel + ;; + *) + usage + ;; +esac diff --git a/luci-app-ota/root/etc/config/ota b/luci-app-ota/root/etc/config/ota new file mode 100644 index 0000000..cbbfb86 --- /dev/null +++ b/luci-app-ota/root/etc/config/ota @@ -0,0 +1,3 @@ + +config ota 'config' + option api_url '' diff --git a/luci-app-ramfree/Makefile b/luci-app-ramfree/Makefile new file mode 100644 index 0000000..448526c --- /dev/null +++ b/luci-app-ramfree/Makefile @@ -0,0 +1,17 @@ +# Copyright (C) 2016 Openwrt.org +# +# This is free software, licensed under the Apache License, Version 2.0 . +# + +include $(TOPDIR)/rules.mk + +LUCI_TITLE:=LuCI support for ramfree +LUCI_PKGARCH:=all + +PKG_NAME:=luci-app-ramfree +PKG_VERSION:=1.0 +PKG_RELEASE:=1 + +include $(TOPDIR)/feeds/luci/luci.mk + +# call BuildPackage - OpenWrt buildroot signature diff --git a/luci-app-ramfree/htdocs/luci-static/resources/view/ramfree.js b/luci-app-ramfree/htdocs/luci-static/resources/view/ramfree.js new file mode 100644 index 0000000..f1e2827 --- /dev/null +++ b/luci-app-ramfree/htdocs/luci-static/resources/view/ramfree.js @@ -0,0 +1,20 @@ +'use strict'; +'require fs'; +'require view'; + +return view.extend({ + handleSaveApply: null, + handleSave: null, + handleReset: null, + + load: function() { + return Promise.all([ + L.resolveDefault(fs.exec('/bin/sync', null), null), + L.resolveDefault(fs.exec('/sbin/sysctl', ['-w', 'vm.drop_caches=3']), null), + ]); + }, + + render: function () { + window.location.href = '/cgi-bin/luci/'; + } +}); diff --git a/luci-app-ramfree/po/zh_Hans/ramfree.po b/luci-app-ramfree/po/zh_Hans/ramfree.po new file mode 100644 index 0000000..961e463 --- /dev/null +++ b/luci-app-ramfree/po/zh_Hans/ramfree.po @@ -0,0 +1,12 @@ +msgid "" +msgstr "" +"Content-Type: text/plain; charset=UTF-8\n" +"Project-Id-Version: PACKAGE VERSION\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: zh_Hans\n" +"MIME-Version: 1.0\n" +"Content-Transfer-Encoding: 8bit\n" + +msgid "Freeping Memory Cache" +msgstr "释放内存" diff --git a/luci-app-ramfree/root/usr/share/luci/menu.d/luci-app-ramfree.json b/luci-app-ramfree/root/usr/share/luci/menu.d/luci-app-ramfree.json new file mode 100644 index 0000000..04994ac --- /dev/null +++ b/luci-app-ramfree/root/usr/share/luci/menu.d/luci-app-ramfree.json @@ -0,0 +1,13 @@ +{ + "admin/status/ramfree": { + "title": "Freeping Memory Cache", + "order": 9999, + "action": { + "type": "view", + "path": "ramfree" + }, + "depends": { + "acl": [ "luci-app-ramfree" ] + } + } +} diff --git a/luci-app-ramfree/root/usr/share/rpcd/acl.d/luci-app-ramfree.json b/luci-app-ramfree/root/usr/share/rpcd/acl.d/luci-app-ramfree.json new file mode 100644 index 0000000..00334aa --- /dev/null +++ b/luci-app-ramfree/root/usr/share/rpcd/acl.d/luci-app-ramfree.json @@ -0,0 +1,11 @@ +{ + "luci-app-ramfree": { + "description": "Grant UCI access for luci-app-ramfree", + "read": { + "file": { + "/bin/sync": [ "exec" ], + "/sbin/sysctl": [ "exec" ] + } + } + } +} diff --git a/luci-app-socat/Makefile b/luci-app-socat/Makefile new file mode 100644 index 0000000..2bd4185 --- /dev/null +++ b/luci-app-socat/Makefile @@ -0,0 +1,20 @@ +# Copyright (C) 2020 Lienol +# +# This is free software, licensed under the GNU General Public License v3. +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=luci-app-socat +PKG_VERSION:=1.0 +PKG_RELEASE:=6 + +PKG_MAINTAINER:=Lienol + +LUCI_TITLE:=LuCI support for Socat +LUCI_DEPENDS:=+socat +LUCI_PKGARCH:=all + +include $(TOPDIR)/feeds/luci/luci.mk + +# call BuildPackage - OpenWrt buildroot signature diff --git a/luci-app-socat/luasrc/controller/socat.lua b/luci-app-socat/luasrc/controller/socat.lua new file mode 100644 index 0000000..db4482b --- /dev/null +++ b/luci-app-socat/luasrc/controller/socat.lua @@ -0,0 +1,21 @@ +-- Copyright 2020 Lienol +module("luci.controller.socat", package.seeall) + +function index() + if not nixio.fs.access("/etc/config/socat") then + return + end + + entry({"admin", "network", "socat"}, alias("admin", "network", "socat", "index"), _("Socat"), 100).dependent = true + entry({"admin", "network", "socat", "index"}, cbi("socat/index")).leaf = true + entry({"admin", "network", "socat", "config"}, cbi("socat/config")).leaf = true + entry({"admin", "network", "socat", "status"}, call("act_status")).leaf = true +end + +function act_status() + local e = {} + e.index = luci.http.formvalue("index") + e.status = luci.sys.call(string.format("busybox ps -w | grep -v 'grep' | grep '/var/etc/socat/%s' >/dev/null", luci.http.formvalue("id"))) == 0 + luci.http.prepare_content("application/json") + luci.http.write_json(e) +end diff --git a/luci-app-socat/luasrc/model/cbi/socat/config.lua b/luci-app-socat/luasrc/model/cbi/socat/config.lua new file mode 100644 index 0000000..0a04ce6 --- /dev/null +++ b/luci-app-socat/luasrc/model/cbi/socat/config.lua @@ -0,0 +1,82 @@ +local d = require "luci.dispatcher" + +m = Map("socat", translate("Socat Config")) +m.redirect = d.build_url("admin", "network", "socat") + +s = m:section(NamedSection, arg[1], "config", "") +s.addremove = false +s.dynamic = false + +o = s:option(Flag, "enable", translate("Enable")) +o.default = "1" +o.rmempty = false + +o = s:option(Value, "remarks", translate("Remarks")) +o.default = translate("Remarks") +o.rmempty = false + +o = s:option(ListValue, "protocol", translate("Protocol")) +o:value("port_forwards", translate("Port Forwards")) + +o = s:option(ListValue, "family", translate("Restrict to address family")) +o:value("", translate("IPv4 and IPv6")) +o:value("4", translate("IPv4 only")) +o:value("6", translate("IPv6 only")) +o:depends("protocol", "port_forwards") + +o = s:option(ListValue, "proto", translate("Protocol")) +o:value("tcp", "TCP") +o:value("udp", "UDP") +o:depends("protocol", "port_forwards") + +o = s:option(Value, "listen_port", translate("Listen port")) +o.datatype = "portrange" +o.rmempty = false +o:depends("protocol", "port_forwards") + +o = s:option(Flag, "reuseaddr", translate("REUSEADDR"), translate("Bind to a port local")) +o.default = "1" +o.rmempty = false + +o = s:option(ListValue, "dest_proto", translate("Destination Protocol")) +o:value("tcp4", "IPv4-TCP") +o:value("udp4", "IPv4-UDP") +o:value("tcp6", "IPv6-TCP") +o:value("udp6", "IPv6-UDP") +o:depends("protocol", "port_forwards") + +dest_ipv4 = s:option(Value, "dest_ipv4", translate("Destination address")) +luci.sys.net.ipv4_hints(function(ip, name) + dest_ipv4:value(ip, "%s (%s)" %{ ip, name }) +end) +function dest_ipv4.cfgvalue(self, section) + return m:get(section, "dest_ip") +end +function dest_ipv4.write(self, section, value) + m:set(section, "dest_ip", value) +end +dest_ipv4:depends("dest_proto", "tcp4") +dest_ipv4:depends("dest_proto", "udp4") + +dest_ipv6 = s:option(Value, "dest_ipv6", translate("Destination address")) +luci.sys.net.ipv6_hints(function(ip, name) + dest_ipv6:value(ip, "%s (%s)" %{ ip, name }) +end) +function dest_ipv6.cfgvalue(self, section) + return m:get(section, "dest_ip") +end +function dest_ipv6.write(self, section, value) + m:set(section, "dest_ip", value) +end +dest_ipv6:depends("dest_proto", "tcp6") +dest_ipv6:depends("dest_proto", "udp6") + +o = s:option(Value, "dest_port", translate("Destination port")) +o.datatype = "portrange" +o.rmempty = false + +o = s:option(Flag, "firewall_accept", translate("Open firewall port")) +o.default = "1" +o.rmempty = false + +return m diff --git a/luci-app-socat/luasrc/model/cbi/socat/index.lua b/luci-app-socat/luasrc/model/cbi/socat/index.lua new file mode 100644 index 0000000..d44d197 --- /dev/null +++ b/luci-app-socat/luasrc/model/cbi/socat/index.lua @@ -0,0 +1,78 @@ +local d = require "luci.dispatcher" +local e = luci.model.uci.cursor() + +m = Map("socat") +m.title = translate("Socat") +m.description = translate("Socat is a relay for bidirectional data transfer between two independent data channels.") + +s = m:section(NamedSection, "global", "global") +s.anonymous = true +s.addremove = false + +o = s:option(Flag, "enable", translate("Enable")) +o.rmempty = false + +s = m:section(TypedSection, "config", translate("Port Forwards")) +s.anonymous = true +s.addremove = true +s.template = "cbi/tblsection" +s.extedit = d.build_url("admin", "network", "socat", "config", "%s") +function s.filter(e, t) + if m:get(t, "protocol") == "port_forwards" then + return true + end +end +function s.create(e, t) + local uuid = string.gsub(luci.sys.exec("echo -n $(cat /proc/sys/kernel/random/uuid)"), "-", "") + t = uuid + TypedSection.create(e, t) + luci.http.redirect(e.extedit:format(t)) +end +function s.remove(e, t) + e.map.proceed = true + e.map:del(t) + luci.http.redirect(d.build_url("admin", "network", "socat")) +end + +o = s:option(Flag, "enable", translate("Enable")) +o.width = "5%" +o.rmempty = false + +o = s:option(DummyValue, "status", translate("Status")) +o.template = "socat/status" +o.value = translate("Collecting data...") + +o = s:option(DummyValue, "remarks", translate("Remarks")) + +o = s:option(DummyValue, "family", translate("Listen Protocol")) +o.cfgvalue = function(t, n) + local listen = Value.cfgvalue(t, n) or "" + local protocol = (m:get(n, "proto") or ""):upper() + if listen == "" then + return protocol + else + return "IPv" .. listen .. "-" .. protocol + end +end + +o = s:option(DummyValue, "listen_port", translate("Listen port")) + +o = s:option(DummyValue, "dest_proto", translate("Destination Protocol")) +o.cfgvalue = function(t, n) + local listen = Value.cfgvalue(t, n) + local protocol = listen:sub(0, #listen - 1):upper() + local ip_type = "IPv" .. listen:sub(#listen) + return ip_type .. "-" .. protocol +end + +o = s:option(DummyValue, "dest_ip", translate("Destination address")) + +o = s:option(DummyValue, "dest_port", translate("Destination port")) + +o = s:option(Flag, "firewall_accept", translate("Open firewall port")) +o.default = "1" +o.rmempty = false + +m:append(Template("socat/list_status")) + +return m diff --git a/luci-app-socat/luasrc/view/socat/list_status.htm b/luci-app-socat/luasrc/view/socat/list_status.htm new file mode 100644 index 0000000..4da041e --- /dev/null +++ b/luci-app-socat/luasrc/view/socat/list_status.htm @@ -0,0 +1,19 @@ + diff --git a/luci-app-socat/luasrc/view/socat/status.htm b/luci-app-socat/luasrc/view/socat/status.htm new file mode 100644 index 0000000..241baae --- /dev/null +++ b/luci-app-socat/luasrc/view/socat/status.htm @@ -0,0 +1,3 @@ +<%+cbi/valueheader%> +-- +<%+cbi/valuefooter%> diff --git a/luci-app-socat/po/zh_Hans/socat.po b/luci-app-socat/po/zh_Hans/socat.po new file mode 100644 index 0000000..f92b0d4 --- /dev/null +++ b/luci-app-socat/po/zh_Hans/socat.po @@ -0,0 +1,53 @@ +msgid "Socat" +msgstr "Socat" + +msgid "Socat is a relay for bidirectional data transfer between two independent data channels." +msgstr "Socat 是用于在两个独立数据通道之间进行双向数据传输的中继器。" + +msgid "Socat Config" +msgstr "Socat 配置" + +msgid "Status" +msgstr "状态" + +msgid "Enabled" +msgstr "启用" + +msgid "Remarks" +msgstr "备注" + +msgid "Protocol" +msgstr "协议" + +msgid "IPv6 Only" +msgstr "仅 IPv6" + +msgid "When checked, only IPv6 ports are listen for, otherwise IPv4 will also be listened for." +msgstr "当勾选时,仅监听 IPv6,否则将会同时监听 IPv4。" + +msgid "Port Forwards" +msgstr "端口转发" + +msgid "Listen Protocol" +msgstr "监听协议" + +msgid "Listen port" +msgstr "监听端口" + +msgid "REUSEADDR" +msgstr "地址重用" + +msgid "Bind to a port local" +msgstr "绑定到本地端口" + +msgid "Destination Protocol" +msgstr "目标协议" + +msgid "Destination address" +msgstr "目标地址" + +msgid "Destination port" +msgstr "目标端口" + +msgid "Open firewall port" +msgstr "打开防火墙端口" diff --git a/luci-app-socat/root/etc/init.d/luci_socat b/luci-app-socat/root/etc/init.d/luci_socat new file mode 100755 index 0000000..98df330 --- /dev/null +++ b/luci-app-socat/root/etc/init.d/luci_socat @@ -0,0 +1,104 @@ +#!/bin/sh /etc/rc.common +# Copyright (C) 2020 Lienol + +START=99 + +CONFIG=socat +CONFIG_PATH=/var/etc/$CONFIG + +add_rule() { + accept_port=$(cat /var/etc/$CONFIG.port | tr "\n" " ") + if [ "$accept_port" ]; then + uci -q delete firewall.socat + uci set firewall.socat=rule + uci set firewall.socat.name="socat" + uci set firewall.socat.target="ACCEPT" + uci set firewall.socat.src="wan" + uci set firewall.socat.dest_port="$accept_port" + uci set firewall.socat.enabled="1" + uci commit firewall + /etc/init.d/firewall reload >/dev/null 2>&1 + else + del_rule + fi +} + +del_rule() { + uci -q delete firewall.socat + uci commit firewall + /etc/init.d/firewall reload >/dev/null 2>&1 +} + +run_service() { + config_get enable $1 enable + [ "$enable" = "0" ] && return 0 + config_get remarks $1 remarks + config_get protocol $1 protocol + config_get family $1 family + config_get proto $1 proto + config_get listen_port $1 listen_port + config_get reuseaddr $1 reuseaddr + config_get dest_proto $1 dest_proto + config_get dest_ip $1 dest_ip + config_get dest_port $1 dest_port + config_get firewall_accept $1 firewall_accept + ln -s /usr/bin/socat ${CONFIG_PATH}/$1 + + if [ "$reuseaddr" == "1" ]; then + reuseaddr=",reuseaddr" + else + reuseaddr="" + fi + + if [ "$family" == "6" ]; then + ipv6only_params=",ipv6-v6only" + else + ipv6only_params="" + fi + + # 端口转发 + if [ "$protocol" == "port_forwards" ]; then + listen=${proto}${family} + [ "$family" == "" ] && listen=${proto}6 + ${CONFIG_PATH}/$1 ${listen}-listen:${listen_port}${ipv6only_params}${reuseaddr},fork ${dest_proto}:${dest_ip}:${dest_port} >/dev/null 2>&1 & + fi + + [ "$firewall_accept" == "1" ] && { + echo $listen_port >> /var/etc/$CONFIG.port + } +} + +stop_service() { + busybox ps -w | grep "$CONFIG_PATH/" | grep -v "grep" | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1 & + del_rule + rm -rf $CONFIG_PATH /var/etc/$CONFIG.port +} + +start() { + [ -f "/etc/config/socat" ] && [ $(grep -c global /etc/config/socat) -eq 0 ] && { + uci add socat global + uci rename socat.@global[0]='global' + uci set socat.global.enable="$(grep -q "enable '1'" /etc/config/socat && echo '1' || echo '0')" + uci commit socat + } + enable=$(uci -q get $CONFIG.@global[0].enable) + if [ "$enable" = "0" ];then + stop_service + else + mkdir -p $CONFIG_PATH + rm -f /var/etc/$CONFIG.port + config_load $CONFIG + config_foreach run_service "config" + add_rule + fi +} + +stop() { + stop_service +} + +reload_service() { + stop + sleep 1 + start +} diff --git a/luci-app-socat/root/etc/uci-defaults/luci-app-socat b/luci-app-socat/root/etc/uci-defaults/luci-app-socat new file mode 100755 index 0000000..10013d7 --- /dev/null +++ b/luci-app-socat/root/etc/uci-defaults/luci-app-socat @@ -0,0 +1,13 @@ +#!/bin/sh + +[ -f "/etc/config/ucitrack" ] && { +uci -q batch <<-EOF >/dev/null + delete ucitrack.@socat[-1] + add ucitrack socat + set ucitrack.@socat[-1].init=luci_socat + commit ucitrack +EOF +} + +rm -rf /tmp/luci-*cache* +exit 0 diff --git a/luci-app-socat/root/usr/share/rpcd/acl.d/luci-app-socat.json b/luci-app-socat/root/usr/share/rpcd/acl.d/luci-app-socat.json new file mode 100644 index 0000000..a79e14a --- /dev/null +++ b/luci-app-socat/root/usr/share/rpcd/acl.d/luci-app-socat.json @@ -0,0 +1,11 @@ +{ + "luci-app-socat": { + "description": "Grant UCI access for luci-app-socat", + "read": { + "uci": [ "socat" ] + }, + "write": { + "uci": [ "socat" ] + } + } +} diff --git a/luci-app-socat/root/usr/share/ucitrack/luci-app-socat.json b/luci-app-socat/root/usr/share/ucitrack/luci-app-socat.json new file mode 100644 index 0000000..c43834e --- /dev/null +++ b/luci-app-socat/root/usr/share/ucitrack/luci-app-socat.json @@ -0,0 +1,4 @@ +{ + "config": "socat", + "init": "luci_socat" +} diff --git a/luci-app-usb-printer/Makefile b/luci-app-usb-printer/Makefile new file mode 100644 index 0000000..efe16ba --- /dev/null +++ b/luci-app-usb-printer/Makefile @@ -0,0 +1,18 @@ +# +# Copyright (C) 2008-2014 The LuCI Team +# +# This is free software, licensed under the Apache License, Version 2.0 . +# + +include $(TOPDIR)/rules.mk + +LUCI_TITLE:=USB Printer Share via TCP/IP +LUCI_DEPENDS:=+p910nd +kmod-usb-printer + +PKG_NAME:=luci-app-usb-printer +PKG_VERSION:=1.0 +PKG_RELEASE:=2 + +include $(TOPDIR)/feeds/luci/luci.mk + +# call BuildPackage - OpenWrt buildroot signature diff --git a/luci-app-usb-printer/ipkg/postinst b/luci-app-usb-printer/ipkg/postinst new file mode 100755 index 0000000..97a343c --- /dev/null +++ b/luci-app-usb-printer/ipkg/postinst @@ -0,0 +1,6 @@ +#!/bin/sh +[ -n "${IPKG_INSTROOT}" ] || { + ( . /etc/uci-defaults/luci-usb-printer ) && rm -f /etc/uci-defaults/luci-usb-printer + exit 0 +} + diff --git a/luci-app-usb-printer/luasrc/controller/usb_printer.lua b/luci-app-usb-printer/luasrc/controller/usb_printer.lua new file mode 100644 index 0000000..c678858 --- /dev/null +++ b/luci-app-usb-printer/luasrc/controller/usb_printer.lua @@ -0,0 +1,26 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2008 Steven Barth + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id$ +]]-- + +require("luci.sys") + +module("luci.controller.usb_printer", package.seeall) + +function index() + if not nixio.fs.access("/etc/config/usb_printer") then + return + end + + entry({"admin", "nas"}, firstchild(), "NAS", 44).dependent = false + entry({"admin", "nas", "usb_printer"}, cbi("usb_printer"), _("USB Printer Server"), 50) +end diff --git a/luci-app-usb-printer/luasrc/model/cbi/usb_printer.lua b/luci-app-usb-printer/luasrc/model/cbi/usb_printer.lua new file mode 100644 index 0000000..3cc7526 --- /dev/null +++ b/luci-app-usb-printer/luasrc/model/cbi/usb_printer.lua @@ -0,0 +1,130 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2008 Steven Barth +Copyright 2005-2013 hackpascal + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id$ +]]-- + +require "luci.util" +local uci = luci.model.uci.cursor_state() +local net = require "luci.model.network" + +m = Map("usb_printer", translate("USB Printer Server"), + translate("Shares multiple USB printers via TCP/IP.
When modified bingings, re-plug usb connectors to take effect.
This module requires kmod-usb-printer.")) + +function hex_align(hex, num) + local len = num - string.len(hex) + + return string.rep("0", len) .. hex +end + +function detect_usb_printers() + local data = {} + + local lps = luci.util.execi("/usr/bin/detectlp") + + for value in lps do + local row = {} + + --[[ + detectlp 的输出格式: + 设备名,VID/PID/?,描述,型号 + ]]-- + + local pos = string.find(value, ",") + + local devname = string.sub(value, 1, pos - 1) + + local value = string.sub(value, pos + 1, string.len(value)) + + pos = string.find(value, ",") + local product = string.sub(value, 1, pos - 1) + + value = string.sub(value, pos + 1, string.len(value)) + + pos = string.find(value, ",") + local model = string.sub(value, 1, pos - 1) + + local name = string.sub(value, pos + 1, string.len(value)) + + pos = string.find(product, "/"); + + local vid = string.sub(product, 1, pos - 1) + + local pid = string.sub(product, pos + 1, string.len(product)) + + pos = string.find(pid, "/") + pid = string.sub(pid, 1, pos - 1) + + row["description"] = name + row["model"] = model + row["id"] = hex_align(vid, 4) .. ":" .. hex_align(pid, 4) + row["name"] = devname + row["product"] = product + + table.insert(data, row) + end + + return data +end + +local printers = detect_usb_printers() + +v = m:section(Table, printers, translate("Detected printers")) + +v:option(DummyValue, "description", translate("Description")) +v:option(DummyValue, "model", translate("Printer Model")) +v:option(DummyValue, "id", translate("VID/PID")) +v:option(DummyValue, "name", translate("Device Name")) + +net = net.init(m.uci) + +s = m:section(TypedSection, "printer", translate("Bindings")) +s.addremove = true +s.anonymous = true + +s:option(Flag, "enabled", translate("enable")) + +d = s:option(Value, "device", translate("Device")) +d.rmempty = true + +for key, item in ipairs(printers) do + d:value(item["product"], item["description"] .. " [" .. item["id"] .. "]") +end + +b = s:option(Value, "bind", translate("Interface"), translate("Specifies the interface to listen on.")) +b.template = "cbi/network_netlist" +b.nocreate = true +b.unspecified = true + +function b.cfgvalue(...) + local v = Value.cfgvalue(...) + if v then + return (net:get_status_by_address(v)) + end +end + +function b.write(self, section, value) + local n = net:get_network(value) + if n and n:ipaddr() then + Value.write(self, section, n:ipaddr()) + end +end + +p = s:option(ListValue, "port", translate("Port"), translate("TCP listener port.")) +p.rmempty = true +for i = 0, 9 do + p:value(i, 9100 + i) +end + +s:option(Flag, "bidirectional", translate("Bidirectional mode")) + +return m diff --git a/luci-app-usb-printer/po/zh_Hans/usb-printer.po b/luci-app-usb-printer/po/zh_Hans/usb-printer.po new file mode 100644 index 0000000..d1544e4 --- /dev/null +++ b/luci-app-usb-printer/po/zh_Hans/usb-printer.po @@ -0,0 +1,65 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2014-05-18 01:34+0800\n" +"PO-Revision-Date: 2014-05-18 01:34+0800\n" +"Last-Translator: hackpascal \n" +"Language-Team: \n" +"Language: zh_Hans\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Pootle 2.0.6\n" + +msgid "Bidirectional mode" +msgstr "双向模式" + +msgid "Bindings" +msgstr "绑定" + +msgid "Device" +msgstr "设备" + +msgid "Device Name" +msgstr "设备名" + +msgid "Detected printers" +msgstr "检测到的打印机" + +msgid "" +"Shares multiple USB printers via TCP/IP.
" +"When modified bingings, re-plug usb connectors to take effect.
" +"This module requires kmod-usb-printer." +msgstr "" +"通过 TCP/IP 共享 USB 打印机。
修改设置后,请重新连接打印机以使设置生效。
" +"此模块需要 kmod-usb-printer 支持。" + +msgid "Port" +msgstr "端口" + +msgid "Printer Model" +msgstr "打印机型号" + +msgid "Settings" +msgstr "设置" + +msgid "TCP listener port." +msgstr "TCP 监听端口。" + +msgid "enable" +msgstr "启用" + +msgid "USB Printer Server" +msgstr "USB 打印服务器" + +msgid "Specifies the interface to listen on." +msgstr "指定要监听的接口。" + +msgid "NAS" +msgstr "网络存储" + +msgid "Architecture" +msgstr "架构" + diff --git a/luci-app-usb-printer/root/etc/config/usb_printer b/luci-app-usb-printer/root/etc/config/usb_printer new file mode 100644 index 0000000..e69de29 diff --git a/luci-app-usb-printer/root/etc/hotplug.d/usb/10-usb_printer b/luci-app-usb-printer/root/etc/hotplug.d/usb/10-usb_printer new file mode 100755 index 0000000..c250fe7 --- /dev/null +++ b/luci-app-usb-printer/root/etc/hotplug.d/usb/10-usb_printer @@ -0,0 +1,7 @@ +#!/bin/sh +# Copyright (C) 2005-2014 NowRush Studio +# Author: hackpascal + +if [ x"$INTERFACE" = x"7/1/1" ] || [ x"$INTERFACE" = x"7/1/2" ]; then + /usr/bin/usb_printer_hotplug "$PRODUCT" "$ACTION" +fi diff --git a/luci-app-usb-printer/root/etc/init.d/usb_printer b/luci-app-usb-printer/root/etc/init.d/usb_printer new file mode 100755 index 0000000..4da5e34 --- /dev/null +++ b/luci-app-usb-printer/root/etc/init.d/usb_printer @@ -0,0 +1,22 @@ +#!/bin/sh /etc/rc.common +# Copyright (C) 2005-2013 NowRush Studio +# Author: hackpascal + +START=70 + +stop() { + killall p910nd 2>/dev/null +} + +start() { + for lps in `/usr/bin/detectlp`; do + product=`echo $lps | cut -d , -f 2` + + /usr/bin/usb_printer_hotplug "$product" add + done +} + +restart() { + stop + start +} diff --git a/luci-app-usb-printer/root/etc/uci-defaults/luci-usb-printer b/luci-app-usb-printer/root/etc/uci-defaults/luci-usb-printer new file mode 100755 index 0000000..38c214f --- /dev/null +++ b/luci-app-usb-printer/root/etc/uci-defaults/luci-usb-printer @@ -0,0 +1,12 @@ +#!/bin/sh + +uci -q batch <<-EOF >/dev/null + delete ucitrack.@usb_printer[-1] + add ucitrack usb_printer + set ucitrack.@usb_printer[-1].init=usb_printer + commit ucitrack +EOF + +[ -f /etc/init.d/p910nd ] && /etc/init.d/p910nd disable + +exit 0 diff --git a/luci-app-usb-printer/root/usr/bin/detectlp b/luci-app-usb-printer/root/usr/bin/detectlp new file mode 100755 index 0000000..b69385b --- /dev/null +++ b/luci-app-usb-printer/root/usr/bin/detectlp @@ -0,0 +1,20 @@ +#!/bin/sh + +lp_path=/sys/class/usbmisc + +if ! [ -d "$lp_path" ]; then + exit +fi + +cd $lp_path + +for lps in `ls`; do + desc_file=$lp_path/$lps/device/ieee1284_id + uevent_file=$lp_path/$lps/device/uevent + + name=`cat $desc_file | sed 's/.*DES:\(.*\);.*/\1/' | cut -d ';' -f 1` + model=`cat $desc_file | sed 's/.*MDL:\(.*\);.*/\1/' | cut -d ';' -f 1` + product=`cat $uevent_file | grep PRODUCT= | sed 's/PRODUCT=\(.*\)/\1/'` + + echo $lps,$product,$model,$name; +done diff --git a/luci-app-usb-printer/root/usr/bin/usb_printer_hotplug b/luci-app-usb-printer/root/usr/bin/usb_printer_hotplug new file mode 100755 index 0000000..16b4ccc --- /dev/null +++ b/luci-app-usb-printer/root/usr/bin/usb_printer_hotplug @@ -0,0 +1,72 @@ +#!/bin/sh +# Copyright (C) 2005-2014 NowRush Studio +# Author: hackpascal + +. $IPKG_INSTROOT/lib/functions.sh + +PRODUCT=$1 +ACTION=$2 + +DEVICES= + +check_printer() { + local cfg=$1 + local enabled + local device_id + local bind_ip + local port + local bidirect + local device_file + local args="" + local pid_file + + config_get_bool enabled "$cfg" enabled 0 + [ "$enabled" -eq 0 ] && return 0 + + config_get device_id "$cfg" device "" + config_get bind_ip "$cfg" bind "0.0.0.0" + config_get port "$cfg" port "" + config_get_bool bidirect "$cfg" bidirectional "0" + + if [ -z "$device_id" ] || [ -z "$port" ]; then + return + fi + + if [ x"$PRODUCT" != x"$device_id" ]; then + return + fi + + device_file=`echo "$DEVICES" | grep $device_id | cut -d , -f 1` + + if [ "$ACTION" = "add" ] && [ -z "$device_file" ]; then + return + fi + + pid_file=/var/run/p910${port}d.pid + [ -f $pid_file ] && kill `cat $pid_file` 2>/dev/null + + if [ "$ACTION" = "add" ]; then + if [ "$bidirect" != 0 ]; then + args='-b' + fi + + logger "usb_printer: start p910nd on $bind_ip:$port for /dev/usb/$device_file" + /usr/sbin/p910nd $args -f /dev/usb/$device_file -i $bind_ip $port + fi +} + +if [ -z "$PRODUCT" ] || [ -z "$ACTION" ]; then + echo "Arguements required" + exit 1 +fi + +if [ "$ACTION" != "add" ] && [ "$ACTION" != "remove" ]; then + echo "Invalid action arguement" + exit 1 +fi + +DEVICES=`/usr/bin/detectlp` + +config_load usb_printer + +config_foreach check_printer printer diff --git a/luci-app-usb-printer/root/usr/share/rpcd/acl.d/luci-app-usb-printer.json b/luci-app-usb-printer/root/usr/share/rpcd/acl.d/luci-app-usb-printer.json new file mode 100644 index 0000000..4a43d9e --- /dev/null +++ b/luci-app-usb-printer/root/usr/share/rpcd/acl.d/luci-app-usb-printer.json @@ -0,0 +1,11 @@ +{ + "luci-app-usb-printer": { + "description": "Grant UCI access for luci-app-usb-printer", + "read": { + "uci": [ "usb_printer" ] + }, + "write": { + "uci": [ "usb_printer" ] + } + } +} diff --git a/luci-app-vlmcsd/Makefile b/luci-app-vlmcsd/Makefile new file mode 100644 index 0000000..6f7eec6 --- /dev/null +++ b/luci-app-vlmcsd/Makefile @@ -0,0 +1,20 @@ +# Copyright (C) 2016 Openwrt.org +# +# This is free software, licensed under the Apache License, Version 2.0 . +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=luci-app-vlmcsd +PKG_VERSION:=1.0.0 +PKG_RELEASE:=1 + +LUCI_TITLE:=LuCI support for vlmcsd +LUCI_DEPENDS:=+vlmcsd +LUCI_PKGARCH:=all + +PKG_MAINTAINER:=sbwml + +include $(TOPDIR)/feeds/luci/luci.mk + +# call BuildPackage - OpenWrt buildroot signature diff --git a/luci-app-vlmcsd/htdocs/luci-static/resources/view/vlmcsd/config.js b/luci-app-vlmcsd/htdocs/luci-static/resources/view/vlmcsd/config.js new file mode 100644 index 0000000..6da1f20 --- /dev/null +++ b/luci-app-vlmcsd/htdocs/luci-static/resources/view/vlmcsd/config.js @@ -0,0 +1,41 @@ +'use strict'; +'require form'; +'require fs'; +'require ui'; +'require view'; + +return view.extend({ + render: function () { + var m, s, o; + + m = new form.Map("vlmcsd", _("Config File")); + + s = m.section(form.TypedSection); + s.anonymous = true; + s.sortable = true; + + o = s.option(form.TextValue, '_vlmcsd', null, _('This file is /etc/vlmcsd/vlmcsd.ini.')); + o.rows = 25; + o.cfgvalue = function (section_id) { + return fs.trimmed('/etc/vlmcsd/vlmcsd.ini').catch(function (e) { + return ""; + }); + }; + o.write = function (section_id, formvalue) { + return this.cfgvalue(section_id).then(function (value) { + if (value == formvalue) { + return; + } + return fs.write('/etc/vlmcsd/vlmcsd.ini', formvalue.trim().replace(/\r\n/g, '\n') + '\n') + }); + }; + + return m.render(); + }, + + handleSaveApply: function (ev) { + onclick = L.bind(this.handleSave, this, ev); + return fs.exec('/etc/init.d/vlmcsd', ['restart']); + }, + handleReset: null +}); diff --git a/luci-app-vlmcsd/htdocs/luci-static/resources/view/vlmcsd/vlmcsd.js b/luci-app-vlmcsd/htdocs/luci-static/resources/view/vlmcsd/vlmcsd.js new file mode 100644 index 0000000..c35f36d --- /dev/null +++ b/luci-app-vlmcsd/htdocs/luci-static/resources/view/vlmcsd/vlmcsd.js @@ -0,0 +1,75 @@ +'use strict'; +'require form'; +'require poll'; +'require rpc'; +'require uci'; +'require view'; + +var callServiceList = rpc.declare({ + object: 'service', + method: 'list', + params: ['name'], + expect: { '': {} } +}); + +function getServiceStatus() { + return L.resolveDefault(callServiceList('vlmcsd'), {}).then(function (res) { + var isRunning = false; + try { + isRunning = res['vlmcsd']['instances']['vlmcsd']['running']; + } catch (e) { } + return isRunning; + }); +} + +function renderStatus(isRunning) { + var spanTemp = '%s %s'; + var renderHTML; + if (isRunning) { + renderHTML = spanTemp.format('green', 'VLMCSD', _('RUNNING')); + } else { + renderHTML = spanTemp.format('red', 'VLMCSD', _('NOT RUNNING')); + } + + return renderHTML; +} + +return view.extend({ + render: function() { + var m, s, o; + + m = new form.Map('vlmcsd', _('KMS Server'), + _('A KMS Server Emulator to active your Windows or Office.')); + + s = m.section(form.TypedSection); + s.anonymous = true; + s.render = function () { + poll.add(function () { + return L.resolveDefault(getServiceStatus()).then(function (res) { + var view = document.getElementById('service_status'); + view.innerHTML = renderStatus(res); + }); + }); + + return E('div', { class: 'cbi-section', id: 'status_bar' }, [ + E('p', { id: 'service_status' }, _('Collecting data...')) + ]); + } + + s = m.section(form.NamedSection, 'config', 'vlmcsd'); + + o = s.option(form.Flag, 'enabled', _('Enabled')); + o.default = o.disabled; + o.rmempty = false; + + o = s.option(form.Flag, 'autoactivate', _('Auto activate')); + o.default = o.disabled; + o.rmempty = false; + + o = s.option(form.Flag, 'firewall', _('Open firewall port')); + o.default = o.disabled; + o.rmempty = false; + + return m.render(); + } +}); diff --git a/luci-app-vlmcsd/po/zh_Hans/vlmcsd.po b/luci-app-vlmcsd/po/zh_Hans/vlmcsd.po new file mode 100644 index 0000000..0b573e6 --- /dev/null +++ b/luci-app-vlmcsd/po/zh_Hans/vlmcsd.po @@ -0,0 +1,42 @@ +msgid "" +msgstr "" +"Content-Type: text/plain; charset=UTF-8\n" +"Project-Id-Version: PACKAGE VERSION\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: zh_Hans\n" +"MIME-Version: 1.0\n" +"Content-Transfer-Encoding: 8bit\n" + +msgid "KMS Server" +msgstr "KMS 服务器" + +msgid "A KMS Server Emulator to active your Windows or Office." +msgstr "KMS服务器可用于激活 Windows 或 Office。" + +msgid "RUNNING" +msgstr "运行中" + +msgid "NOT RUNNING" +msgstr "未运行" + +msgid "Collecting data..." +msgstr "获取数据中..." + +msgid "Basic Setting" +msgstr "基本设置" + +msgid "Config File" +msgstr "配置文件" + +msgid "Enabled" +msgstr "启用" + +msgid "Auto activate" +msgstr "自动激活局域网客户端" + +msgid "Open firewall port" +msgstr "打开防火墙端口" + +msgid "This file is /etc/vlmcsd/vlmcsd.ini." +msgstr "这个文件在 /etc/vlmcsd/vlmcsd.ini 下,可以增加新的产品主密钥。" diff --git a/luci-app-vlmcsd/root/etc/uci-defaults/luci-vlmcsd b/luci-app-vlmcsd/root/etc/uci-defaults/luci-vlmcsd new file mode 100644 index 0000000..8b0e745 --- /dev/null +++ b/luci-app-vlmcsd/root/etc/uci-defaults/luci-vlmcsd @@ -0,0 +1,13 @@ +#!/bin/sh + +[ -f "/etc/config/ucitrack" ] && { +uci -q batch <<-EOF >/dev/null + delete ucitrack.@vlmcsd[-1] + add ucitrack vlmcsd + set ucitrack.@vlmcsd[-1].init=vlmcsd + commit ucitrack +EOF +} + +rm -rf /tmp/luci-indexcache* +exit 0 diff --git a/luci-app-vlmcsd/root/usr/share/luci/menu.d/luci-app-vlmcsd.json b/luci-app-vlmcsd/root/usr/share/luci/menu.d/luci-app-vlmcsd.json new file mode 100644 index 0000000..2c279f2 --- /dev/null +++ b/luci-app-vlmcsd/root/usr/share/luci/menu.d/luci-app-vlmcsd.json @@ -0,0 +1,29 @@ +{ + "admin/services/vlmcsd": { + "title": "KMS Server", + "order": 60, + "action": { + "type": "firstchild" + }, + "depends": { + "acl": [ "luci-app-vlmcsd" ], + "uci": { "vlmcsd": true } + } + }, + "admin/services/vlmcsd/vlmcsd": { + "title": "Basic Setting", + "order": 10, + "action": { + "type": "view", + "path": "vlmcsd/vlmcsd" + } + }, + "admin/services/vlmcsd/config": { + "title": "Config File", + "order": 20, + "action": { + "type": "view", + "path": "vlmcsd/config" + } + } +} diff --git a/luci-app-vlmcsd/root/usr/share/rpcd/acl.d/luci-app-vlmcsd.json b/luci-app-vlmcsd/root/usr/share/rpcd/acl.d/luci-app-vlmcsd.json new file mode 100644 index 0000000..3f92eab --- /dev/null +++ b/luci-app-vlmcsd/root/usr/share/rpcd/acl.d/luci-app-vlmcsd.json @@ -0,0 +1,21 @@ +{ + "luci-app-vlmcsd": { + "description": "Grant UCI access for luci-app-vlmcsd", + "read": { + "file": { + "/etc/init.d/vlmcsd": [ "exec" ], + "/etc/vlmcsd/vlmcsd.ini": [ "read" ] + }, + "ubus": { + "service": [ "list" ] + }, + "uci": [ "vlmcsd" ] + }, + "write": { + "file": { + "/etc/vlmcsd/vlmcsd.ini": [ "write" ] + }, + "uci": [ "vlmcsd" ] + } + } +} diff --git a/luci-app-vlmcsd/root/usr/share/ucitrack/luci-app-vlmcsd.json b/luci-app-vlmcsd/root/usr/share/ucitrack/luci-app-vlmcsd.json new file mode 100644 index 0000000..7ceb3db --- /dev/null +++ b/luci-app-vlmcsd/root/usr/share/ucitrack/luci-app-vlmcsd.json @@ -0,0 +1,4 @@ +{ + "config": "vlmcsd", + "init": "vlmcsd" +} diff --git a/luci-app-wolplus/Makefile b/luci-app-wolplus/Makefile new file mode 100644 index 0000000..4281482 --- /dev/null +++ b/luci-app-wolplus/Makefile @@ -0,0 +1,17 @@ +# Copyright (C) 2016 Openwrt.org +# +# This is free software, licensed under the Apache License, Version 2.0 . +# + +include $(TOPDIR)/rules.mk + +LUCI_TITLE:=LuCI support for wolplus From sundaqiang +LUCI_DEPENDS:=+etherwake +LUCI_PKGARCH:=all +PKG_VERSION:=1.0 +PKG_RELEASE:=20201225 +PKG_MAINTAINER:=sundaqiang + +include $(TOPDIR)/feeds/luci/luci.mk + +# call BuildPackage - OpenWrt buildroot signature diff --git a/luci-app-wolplus/luasrc/controller/wolplus.lua b/luci-app-wolplus/luasrc/controller/wolplus.lua new file mode 100644 index 0000000..cc1e184 --- /dev/null +++ b/luci-app-wolplus/luasrc/controller/wolplus.lua @@ -0,0 +1,33 @@ +module("luci.controller.wolplus", package.seeall) +local t, a +local x = luci.model.uci.cursor() + +function index() + if not nixio.fs.access("/etc/config/wolplus") then return end + entry({"admin", "services", "wolplus"}, cbi("wolplus"), _("Wake on LAN")).dependent = true + entry( {"admin", "services", "wolplus", "awake"}, post("awake") ).leaf = true +end + +function awake(sections) + lan = x:get("wolplus",sections,"maceth") + mac = x:get("wolplus",sections,"macaddr") + local e = {} + cmd = "/usr/bin/etherwake -D -i " .. lan .. " -b " .. mac .. " 2>&1" + local p = io.popen(cmd) + local msg = "" + if p then + while true do + local l = p:read("*l") + if l then + if #l > 100 then l = l:sub(1, 100) .. "..." end + msg = msg .. l + else + break + end + end + p:close() + end + e["data"] = msg + luci.http.prepare_content("application/json") + luci.http.write_json(e) +end diff --git a/luci-app-wolplus/luasrc/model/cbi/wolplus.lua b/luci-app-wolplus/luasrc/model/cbi/wolplus.lua new file mode 100644 index 0000000..01c8e36 --- /dev/null +++ b/luci-app-wolplus/luasrc/model/cbi/wolplus.lua @@ -0,0 +1,35 @@ +local i = require "luci.sys" +local t, e +t = Map("wolplus", translate("Wake on LAN"), translate("Wake on LAN is a mechanism to remotely boot computers in the local network.")) +t.template = "wolplus/index" +e = t:section(TypedSection, "macclient", translate("Host list")) +e.template = "cbi/tblsection" +e.anonymous = true +e.addremove = true +a = e:option(Value, "name", translate("Name")) +a.optional = false +nolimit_mac = e:option(Value, "macaddr", translate("Mac Address")) +nolimit_mac.rmempty = false +i.net.mac_hints(function(e, t) nolimit_mac:value(e, "%s (%s)" % {e, t}) end) +nolimit_eth = e:option(Value, "maceth", translate("Network interface")) +nolimit_eth.rmempty = false +for t, e in ipairs(i.net.devices()) do if e ~= "lo" then nolimit_eth:value(e) end end +btn = e:option(Button, "_awake",translate("Wake up host")) +btn.inputtitle = translate("Wake up host") +btn.inputstyle = "apply" +btn.disabled = false +btn.template = "wolplus/awake" +function gen_uuid(format) + local uuid = i.exec("echo -n $(cat /proc/sys/kernel/random/uuid)") + if format == nil then + uuid = string.gsub(uuid, "-", "") + end + return uuid +end +function e.create(e, t) + local uuid = gen_uuid() + t = uuid + TypedSection.create(e, t) +end + +return t diff --git a/luci-app-wolplus/luasrc/view/wolplus/awake.htm b/luci-app-wolplus/luasrc/view/wolplus/awake.htm new file mode 100644 index 0000000..91cd71b --- /dev/null +++ b/luci-app-wolplus/luasrc/view/wolplus/awake.htm @@ -0,0 +1,3 @@ +<%+cbi/valueheader%> + " style="font-size: 100%;" type="button" onclick="onclick_awake(this.id)" <%=attr("name", section) .. attr("id", cbid) .. attr("value", self.inputtitle)%> /> +<%+cbi/valuefooter%> diff --git a/luci-app-wolplus/luasrc/view/wolplus/index.htm b/luci-app-wolplus/luasrc/view/wolplus/index.htm new file mode 100644 index 0000000..c83d394 --- /dev/null +++ b/luci-app-wolplus/luasrc/view/wolplus/index.htm @@ -0,0 +1,22 @@ +<% include("cbi/map") %> + + diff --git a/luci-app-wolplus/po/zh_Hans/wolplus.po b/luci-app-wolplus/po/zh_Hans/wolplus.po new file mode 100644 index 0000000..05c307c --- /dev/null +++ b/luci-app-wolplus/po/zh_Hans/wolplus.po @@ -0,0 +1,23 @@ +msgid "Wake on LAN" +msgstr "网络唤醒" + +msgid "Wake on LAN is a mechanism to remotely boot computers in the local network." +msgstr "网络唤醒是一个远程启动本地网络内计算机的机制。" + +msgid "Host list" +msgstr "主机列表" + +msgid "Name" +msgstr "名称" + +msgid "Mac Address" +msgstr "客户端 MAC" + +msgid "Network interface" +msgstr "网络接口" + +msgid "Wake up host" +msgstr "唤醒主机" + +msgid "Please [Save & Apply] changes first" +msgstr "请先保存并应用设置" diff --git a/luci-app-wolplus/root/etc/config/wolplus b/luci-app-wolplus/root/etc/config/wolplus new file mode 100644 index 0000000..e69de29 diff --git a/luci-app-wolplus/root/etc/uci-defaults/luci-app-wolplus b/luci-app-wolplus/root/etc/uci-defaults/luci-app-wolplus new file mode 100644 index 0000000..61c4b1e --- /dev/null +++ b/luci-app-wolplus/root/etc/uci-defaults/luci-app-wolplus @@ -0,0 +1,11 @@ +#!/bin/sh + +uci -q batch <<-EOF >/dev/null + delete ucitrack.@wolplus[-1] + add ucitrack wolplus + set ucitrack.@wolplus[-1].init=wolplus + commit ucitrack +EOF + +rm -f /tmp/luci-indexcache +exit 0 diff --git a/luci-app-wolplus/root/usr/share/rpcd/acl.d/luci-app-wolplus.json b/luci-app-wolplus/root/usr/share/rpcd/acl.d/luci-app-wolplus.json new file mode 100644 index 0000000..3aed4ca --- /dev/null +++ b/luci-app-wolplus/root/usr/share/rpcd/acl.d/luci-app-wolplus.json @@ -0,0 +1,11 @@ +{ + "luci-app-wolplus": { + "description": "Grant UCI access for luci-app-wolplus", + "read": { + "uci": [ "wolplus" ] + }, + "write": { + "uci": [ "wolplus" ] + } + } +} diff --git a/speedtest-cli/Makefile b/speedtest-cli/Makefile new file mode 100644 index 0000000..7e0faae --- /dev/null +++ b/speedtest-cli/Makefile @@ -0,0 +1,61 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=speedtest-cli +PKG_VERSION:=1.2.0 +PKG_RELEASE:=1 + +ifeq ($(ARCH),aarch64) + PKG_HASH:=3953d231da3783e2bf8904b6dd72767c5c6e533e163d3742fd0437affa431bd3 +else ifeq ($(ARCH),arm) + ARM_CPU_FEATURES:=$(word 2,$(subst +,$(space),$(call qstrip,$(CONFIG_CPU_TYPE)))) + ifeq ($(ARM_CPU_FEATURES),) + ARCH:=armel + PKG_HASH:=629a455a2879224bd0dbd4b36d8c721dda540717937e4660b4d2c966029466bf + else + ARCH:=armhf + PKG_HASH:=e45fcdebbd8a185553535533dd032d6b10bc8c64eee4139b1147b9c09835d08d + endif +else ifeq ($(ARCH),i386) + PKG_HASH:=9ff7e18dbae7ee0e03c66108445a2fb6ceea6c86f66482e1392f55881b772fe8 +else ifeq ($(ARCH),x86_64) + PKG_HASH:=5690596c54ff9bed63fa3732f818a05dbc2db19ad36ed68f21ca5f64d5cfeeb7 +endif + +PKG_SOURCE:=ookla-speedtest-$(PKG_VERSION)-linux-$(ARCH).tgz +PKG_SOURCE_URL:=https://install.speedtest.net/app/cli + +PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION) + +PKG_MAINTAINER:=sbwml + +include $(INCLUDE_DIR)/package.mk + +define Package/$(PKG_NAME) + SECTION:=net + CATEGORY:=Network + TITLE:=Speedtest CLI by Ookla + DEPENDS:=@(aarch64||arm||i386||x86_64) +ca-certificates + URL:=https://www.speedtest.net/ +endef + +define Package/$(PKG_NAME)/description + The Global Broadband Speed Test +endef + +define Build/Prepare + ( \ + pushd $(PKG_BUILD_DIR) ; \ + $(TAR) -zxf $(DL_DIR)/ookla-speedtest-$(PKG_VERSION)-linux-$(ARCH).tgz -C . ; \ + popd ; \ + ) +endef + +define Build/Compile +endef + +define Package/$(PKG_NAME)/install + $(INSTALL_DIR) $(1)/usr/bin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/speedtest $(1)/usr/bin +endef + +$(eval $(call BuildPackage,$(PKG_NAME))) diff --git a/vlmcsd/Makefile b/vlmcsd/Makefile new file mode 100644 index 0000000..66eefba --- /dev/null +++ b/vlmcsd/Makefile @@ -0,0 +1,37 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=vlmcsd +PKG_VERSION:=2023.7.28 +PKG_RELEASE:=1 + +PKG_BUILD_PARALLEL:=1 +PKG_MAINTAINER:=sbwml + +include $(INCLUDE_DIR)/package.mk + +define Package/vlmcsd + SECTION:=net + CATEGORY:=Network + TITLE:=KMS Emulator in C + URL:=https://github.com/Wind4/vlmcsd + DEPENDS:=+libpthread +endef + +define Package/vlmcsd/description + vlmcsd is an open-source KMS (Key Management Service) server emulator that allows + for the activation of Microsoft products such as Windows and Office within a local network, + without needing to connect to Microsoft's official KMS servers. +endef + +define Package/vlmcsd/install + $(INSTALL_DIR) $(1)/usr/bin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/bin/vlmcsd $(1)/usr/bin/vlmcsd + $(INSTALL_DIR) $(1)/etc/vlmcsd + $(INSTALL_BIN) ./files/vlmcsd.ini $(1)/etc/vlmcsd/vlmcsd.ini + $(INSTALL_DIR) $(1)/etc/config + $(INSTALL_CONF) ./files/vlmcsd.config $(1)/etc/config/vlmcsd + $(INSTALL_DIR) $(1)/etc/init.d + $(INSTALL_BIN) ./files/vlmcsd.init $(1)/etc/init.d/vlmcsd +endef + +$(eval $(call BuildPackage,vlmcsd)) diff --git a/vlmcsd/files/vlmcsd.config b/vlmcsd/files/vlmcsd.config new file mode 100644 index 0000000..878f98e --- /dev/null +++ b/vlmcsd/files/vlmcsd.config @@ -0,0 +1,5 @@ + +config vlmcsd 'config' + option enabled '0' + option autoactivate '0' + diff --git a/vlmcsd/files/vlmcsd.ini b/vlmcsd/files/vlmcsd.ini new file mode 100644 index 0000000..68f5034 --- /dev/null +++ b/vlmcsd/files/vlmcsd.ini @@ -0,0 +1,149 @@ +# +# +# Sample vlmcsd.ini +# +# An ini file for vlmcsd is normally not required. It is for advanced users only. +# vlmcsd uses an ini file only if specified using the -i option in the command line parameters. +# There is no default ini file because vlmcsd is designed to run on many platforms. +# +# Every line starting with a number sign (#) or semicolon (;) is treated as a comment. +# If a key word is used more than once, the last occurrence is used. The only exception +# to this is Listen. You can use Listen=[:port] more than once. +# + +# Set ePID/HwId for Windows explicitly +;Windows = 06401-00206-471-111111-03-1033-17763.0000-2822018 / 01 02 03 04 05 06 07 08 + +# Set ePID for Office 2010 (including Visio and Project) explicitly +;Office2010 = 06401-00096-199-222222-03-1033-17763.0000-2822018 + +# Set ePID/HwId for Office 2013 (including Visio and Project) explicitly +;Office2013 = 06401-00206-234-333333-03-1033-17763.0000-2822018 / 01 02 03 04 05 06 07 08 + +# Set ePID/HwId for Office 2016 (including Visio and Project) explicitly +;Office2016 = 06401-00206-437-444444-03-1033-17763.0000-2822018 / 01 02 03 04 05 06 07 08 + +# Set ePID/HwId for Office 2019 (including Visio and Project) explicitly +;Office2019 = 06401-00206-666-666666-03-1033-17763.0000-2822018 / 01 02 03 04 05 06 07 08 + +# Set ePID/HwId for Windows China Government (Enterprise G/GN) explicitly +;WinChinaGov = 06401-03858-000-555555-03-1033-17763.0000-2822018 / 01 02 03 04 05 06 07 08 + +# Use a compatible VPN device to create a hidden local IPv4 address +# Command line: -O +# VPN = [=][/][:] +# Use VPN adapter "KMS Mirror" give it IP address 192.168.123.100 with a lease duration of one day and make entire 192.168.128.x a hidden local IPv4 address. +;VPN = KMS Mirror=192.168.123.100/24:1d + +# Use custom TCP port +# Command line: -P +# ***The Port directive only works if vlmcsd was compiled to use MS RPC or simple sockets +# ***Use Listen otherwise +;Port = 1234 + +# Listen on all IPv4 addresses (default port 1688) +# Command line: -L +# Does not work with MS RPC or simple sockets, use Port= +;Listen = 0.0.0.0:1688 + +# Listen on all IPv6 addresses (default port 1688) +# Command line: -L +;Listen = [::]:1688 + +# Listen on all private IP addresses and reject incoming requests from public IP addresses +# Command line: -o +# PublicIPProtectionLevel = 3 + +# Allow binding to foreign IP addresses +# Command line: -F0 and -F1 +;FreeBind = true + +# Randomize ePIDs at program start up (only those that are not explicitly specified) +# Command line: -r +;RandomizationLevel = 1 + +# Use a specific host build in ePIDs even if the ePID is randomized +# Command line: -H +;HostBuild = 17763 + +# Use a specific culture (1033 = English US) in ePIDs even if the ePID is randomized +# Command line: -C +;LCID = 1033 + +# Set a maximum of 4 workers (forked processes or threads) +# Command line: -m +;MaxWorkers = 4 + +# Disconnect users after 30 seconds of inactivity +# Command line: -t +;ConnectionTimeout = 30 + +# Disconnect clients immediately after each request +# Command line: -d and -k +;DisconnectClientsImmediately = yes + +# Write a pid file (a file containing the process id of vlmcsd) +# Command line: -p +;PidFile = /var/run/vlmcsd.pid + +# Load a KMS data file +# Command line: -j +;KmsData = /etc/vlmcsd.kmd + +# Write log to /var/log/vlmcsd.log +# Command line: -l (-e and -f also override this directive) +;LogFile = /var/log/vlmcsd.log + +# Don't include date and time in logs (default is true) +# Command line: -T0 and -T1 +;LogDateAndTime = false + +# Create a verbose log +# Command line: -v and -q +;LogVerbose = true + +# Whitelist known products +# Command line: -K0, -K1, -K2, -K3 +;WhiteListingLevel = 0 + +# Check that the client time is within +/- 4 hours of the system time +# Command line: -c0, -c1 +;CheckClientTime = false + +# Maintain a list of CMIDs +# Command line: -M0, -M1 +;MaintainClients = false + +# Start with empty CMID list (Requires MaintainClients = true) +# Command line: -E0, -E1 +;StartEmpty = false + +# Set activation interval to 2 hours +# Command line: -A +;ActivationInterval = 2h + +# Set renewal interval to 7 days +# Command line: -R +;RenewalInterval = 7d + +# Exit vlmcsd if warning of certain level has been reached +# Command line: -x +# 0 = Never +# 1 = Exit, if any listening socket could not be established or TAP error occurs +;ExitLevel = 0 + +# Run program as user vlmcsduser +# Command line: -u +;user = vlmcsduser + +# Run program as group vlmcsdgroup +# Command line: -g +;group = vlmcsdgroup + +# Disable or enable the NDR64 transfer syntax in RPC (default enabled) +# Command line: -N0 and -N1 +;UseNDR64 = true + +# Disable or enable bind time feature negotiation in RPC (default enabled) +# Command line: -B0 and -B1 +;UseBTFN = true diff --git a/vlmcsd/files/vlmcsd.init b/vlmcsd/files/vlmcsd.init new file mode 100644 index 0000000..609c8e6 --- /dev/null +++ b/vlmcsd/files/vlmcsd.init @@ -0,0 +1,107 @@ +#!/bin/sh /etc/rc.common +# Copyright (c) 2011-2015 OpenWrt.org + +START=99 +USE_PROCD=1 +PROG=/usr/bin/vlmcsd + +get_config() { + config_get_bool enabled $1 enabled 0 + config_get autoactivate $1 autoactivate 0 + config_get firewall $1 firewall 0 +} + +add_vlmcs_entry() { + local new_hostname="$1" + + uci -q batch <<-EOF >/dev/null + add dhcp srvhost + set dhcp.@srvhost[-1].srv=_vlmcs._tcp + set dhcp.@srvhost[-1].target=$new_hostname + set dhcp.@srvhost[-1].port=1688 + set dhcp.@srvhost[-1].class=0 + set dhcp.@srvhost[-1].weight=100 + commit dhcp + EOF + + /etc/init.d/dnsmasq reload +} + +set_firewall() { + if [ "$external_access" = "allow" ]; then + uci -q delete firewall.vlmcsd + uci set firewall.vlmcsd=rule + uci set firewall.vlmcsd.name="vlmcsd" + uci set firewall.vlmcsd.target="ACCEPT" + uci set firewall.vlmcsd.src="*" + uci set firewall.vlmcsd.proto="tcp" + uci set firewall.vlmcsd.dest_port="1688" + uci set firewall.vlmcsd.enabled="1" + uci commit firewall + /etc/init.d/firewall reload >/dev/null 2>&1 + elif [ "$external_access" = "deny" ]; then + uci -q delete firewall.vlmcsd + uci commit firewall + /etc/init.d/firewall reload >/dev/null 2>&1 + fi +} + +start_service() { + config_load vlmcsd + config_foreach get_config vlmcsd + + [ $enabled -eq 0 ] && return 0 + + [ "$firewall" -eq "1" ] && external_access="allow" || external_access="deny" + set_firewall + + procd_open_instance vlmcsd + procd_set_param command $PROG + procd_append_param command -D + procd_append_param command -i "/etc/vlmcsd/vlmcsd.ini" + procd_append_param command -L "0.0.0.0:1688" + procd_append_param command -L "[::]:1688" + procd_set_param stdout 1 + procd_set_param stderr 1 + procd_set_param respawn + procd_close_instance vlmcsd + + if [ $autoactivate -eq 1 ]; then + local HOSTNAME=`uci get system.@system[0].hostname` + + local index=$(uci -q show dhcp |grep "].srv='_vlmcs._tcp'") \ + || add_vlmcs_entry $HOSTNAME + index=${index#*[} + index=${index%]*} + + local host_name=$(uci -q get dhcp.@srvhost[$index].target) + + if [ "$HOSTNAME" != "$host_name" ]; then + uci delete dhcp.@srvhost[$index] + add_vlmcs_entry $HOSTNAME + fi + else + uci -q show dhcp | grep 'srvhost\[[0-9]\].srv.*vlmcs' && { + index=$(uci -q show dhcp |grep "].srv='_vlmcs._tcp'") + index=${index#*[} + index=${index%]*} + uci delete dhcp.@srvhost[$index] + /etc/init.d/dnsmasq reload + } + fi +} + +service_triggers() { + procd_add_reload_trigger "vlmcsd" +} + +stop_service() { + external_access="deny" + set_firewall +} + +reload_service() { + stop + sleep 1 + start +} diff --git a/vlmcsd/src/KMSServer.idl b/vlmcsd/src/KMSServer.idl new file mode 100644 index 0000000..361c5b9 --- /dev/null +++ b/vlmcsd/src/KMSServer.idl @@ -0,0 +1,14 @@ +[ + uuid(51C82175-844E-4750-B0D8-EC255555BC06), + version(1.0), +] +interface KMSServer +{ + int RequestActivation + ( + [in] int requestSize, + [in, size_is(requestSize)] unsigned char* request, + [out] int* responseSize, + [out, size_is( , *responseSize)] unsigned char** response + ); +} \ No newline at end of file diff --git a/vlmcsd/src/KMSServer_c_mingw_gcc.c b/vlmcsd/src/KMSServer_c_mingw_gcc.c new file mode 100644 index 0000000..24a5f45 --- /dev/null +++ b/vlmcsd/src/KMSServer_c_mingw_gcc.c @@ -0,0 +1,279 @@ + + +/* this ALWAYS GENERATED file contains the RPC client stubs */ + + + /* File created by MIDL compiler version 8.00.0595 */ +/* at Thu Oct 18 15:24:14 2012 + */ +/* Compiler settings for KMSServer.idl: + Oicf, W1, Zp8, env=Win32 (32b run), target_arch=X86 8.00.0595 + protocol : dce , ms_ext, c_ext, robust + error checks: allocation ref bounds_check enum stub_data + VC __declspec() decoration level: + __declspec(uuid()), __declspec(selectany), __declspec(novtable) + DECLSPEC_UUID(), MIDL_INTERFACE() +*/ +/* @@MIDL_FILE_HEADING( ) */ + +#if !defined(_M_IA64) && !defined(_M_AMD64) && !defined(_ARM_) + + +#pragma warning( disable: 4049 ) /* more than 64k source lines */ +#if _MSC_VER >= 1200 +#pragma warning(push) +#endif + +#pragma warning( disable: 4211 ) /* redefine extern to static */ +#pragma warning( disable: 4232 ) /* dllimport identity*/ +#pragma warning( disable: 4024 ) /* array to pointer mapping*/ +#pragma warning( disable: 4100 ) /* unreferenced arguments in x86 call */ + +#pragma optimize("", off ) + +#include + +#include "KMSServer_h.h" + +#define TYPE_FORMAT_STRING_SIZE 43 +#define PROC_FORMAT_STRING_SIZE 59 +#define EXPR_FORMAT_STRING_SIZE 1 +#define TRANSMIT_AS_TABLE_SIZE 0 +#define WIRE_MARSHAL_TABLE_SIZE 0 + +#if !MULTI_CALL_BINARY + +typedef struct _KMSServer_MIDL_TYPE_FORMAT_STRING + { + short Pad; + unsigned char Format[ TYPE_FORMAT_STRING_SIZE ]; + } KMSServer_MIDL_TYPE_FORMAT_STRING; + +typedef struct _KMSServer_MIDL_PROC_FORMAT_STRING + { + short Pad; + unsigned char Format[ PROC_FORMAT_STRING_SIZE ]; + } KMSServer_MIDL_PROC_FORMAT_STRING; + +typedef struct _KMSServer_MIDL_EXPR_FORMAT_STRING + { + long Pad; + unsigned char Format[ EXPR_FORMAT_STRING_SIZE ]; + } KMSServer_MIDL_EXPR_FORMAT_STRING; + + +static const RPC_SYNTAX_IDENTIFIER _RpcTransferSyntax = +{{0x8A885D04,0x1CEB,0x11C9,{0x9F,0xE8,0x08,0x00,0x2B,0x10,0x48,0x60}},{2,0}}; + + +extern const KMSServer_MIDL_TYPE_FORMAT_STRING KMSServer__MIDL_TypeFormatString; +extern const KMSServer_MIDL_PROC_FORMAT_STRING KMSServer__MIDL_ProcFormatString; +extern const KMSServer_MIDL_EXPR_FORMAT_STRING KMSServer__MIDL_ExprFormatString; + +#endif // !MULTI_CALL_BINARY + +#define GENERIC_BINDING_TABLE_SIZE 0 + + +/* Standard interface: KMSServer, ver. 1.0, + GUID={0x51C82175,0x844E,0x4750,{0xB0,0xD8,0xEC,0x25,0x55,0x55,0xBC,0x06}} */ + + + +static const RPC_CLIENT_INTERFACE KMSServer___RpcClientInterface = + { + sizeof(RPC_CLIENT_INTERFACE), + {{0x51C82175,0x844E,0x4750,{0xB0,0xD8,0xEC,0x25,0x55,0x55,0xBC,0x06}},{1,0}}, + {{0x8A885D04,0x1CEB,0x11C9,{0x9F,0xE8,0x08,0x00,0x2B,0x10,0x48,0x60}},{2,0}}, + 0, + 0, + 0, + 0, + 0, + 0x00000000 + }; +RPC_IF_HANDLE KMSServer_v1_0_c_ifspec = (RPC_IF_HANDLE)& KMSServer___RpcClientInterface; + +extern const MIDL_STUB_DESC KMSServer_StubDesc; + +static RPC_BINDING_HANDLE KMSServer__MIDL_AutoBindHandle; + + +int RequestActivation( + /* [in] */ handle_t IDL_handle, + /* [in] */ int requestSize, + /* [size_is][in] */ unsigned char *request, + /* [out] */ int *responseSize, + /* [size_is][size_is][out] */ unsigned char **response) +{ + + CLIENT_CALL_RETURN _RetVal; + + _RetVal = NdrClientCall2( + ( PMIDL_STUB_DESC )&KMSServer_StubDesc, + (PFORMAT_STRING) &KMSServer__MIDL_ProcFormatString.Format[0], + ( unsigned char * )&IDL_handle); + return ( int )_RetVal.Simple; + +} + + +#if !defined(__RPC_WIN32__) +#error Invalid build platform for this stub. +#endif + +#if !(TARGET_IS_NT50_OR_LATER) +#error You need Windows 2000 or later to run this stub because it uses these features: +#error /robust command line switch. +#error However, your C/C++ compilation flags indicate you intend to run this app on earlier systems. +#error This app will fail with the RPC_X_WRONG_STUB_VERSION error. +#endif + +#if !MULTI_CALL_BINARY +/*static*/ const KMSServer_MIDL_PROC_FORMAT_STRING KMSServer__MIDL_ProcFormatString = + { + 0, + { + + /* Procedure RequestActivation */ + + 0x0, /* 0 */ + 0x48, /* Old Flags: */ +/* 2 */ NdrFcLong( 0x0 ), /* 0 */ +/* 6 */ NdrFcShort( 0x0 ), /* 0 */ +/* 8 */ NdrFcShort( 0x18 ), /* x86 Stack size/offset = 24 */ +/* 10 */ 0x32, /* FC_BIND_PRIMITIVE */ + 0x0, /* 0 */ +/* 12 */ NdrFcShort( 0x0 ), /* x86 Stack size/offset = 0 */ +/* 14 */ NdrFcShort( 0x8 ), /* 8 */ +/* 16 */ NdrFcShort( 0x24 ), /* 36 */ +/* 18 */ 0x47, /* Oi2 Flags: srv must size, clt must size, has return, has ext, */ + 0x5, /* 5 */ +/* 20 */ 0x8, /* 8 */ + 0x7, /* Ext Flags: new corr desc, clt corr check, srv corr check, */ +/* 22 */ NdrFcShort( 0x1 ), /* 1 */ +/* 24 */ NdrFcShort( 0x1 ), /* 1 */ +/* 26 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter IDL_handle */ + +/* 28 */ NdrFcShort( 0x48 ), /* Flags: in, base type, */ +/* 30 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 32 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Parameter requestSize */ + +/* 34 */ NdrFcShort( 0x10b ), /* Flags: must size, must free, in, simple ref, */ +/* 36 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */ +/* 38 */ NdrFcShort( 0x6 ), /* Type Offset=6 */ + + /* Parameter request */ + +/* 40 */ NdrFcShort( 0x2150 ), /* Flags: out, base type, simple ref, srv alloc size=8 */ +/* 42 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */ +/* 44 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Parameter responseSize */ + +/* 46 */ NdrFcShort( 0x2013 ), /* Flags: must size, must free, out, srv alloc size=8 */ +/* 48 */ NdrFcShort( 0x10 ), /* x86 Stack size/offset = 16 */ +/* 50 */ NdrFcShort( 0x16 ), /* Type Offset=22 */ + + /* Parameter response */ + +/* 52 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 54 */ NdrFcShort( 0x14 ), /* x86 Stack size/offset = 20 */ +/* 56 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + 0x0 + } + }; + +/*static*/ const KMSServer_MIDL_TYPE_FORMAT_STRING KMSServer__MIDL_TypeFormatString = + { + 0, + { + NdrFcShort( 0x0 ), /* 0 */ +/* 2 */ + 0x11, 0x0, /* FC_RP */ +/* 4 */ NdrFcShort( 0x2 ), /* Offset= 2 (6) */ +/* 6 */ + 0x1b, /* FC_CARRAY */ + 0x0, /* 0 */ +/* 8 */ NdrFcShort( 0x1 ), /* 1 */ +/* 10 */ 0x28, /* Corr desc: parameter, FC_LONG */ + 0x0, /* */ +/* 12 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 14 */ NdrFcShort( 0x1 ), /* Corr flags: early, */ +/* 16 */ 0x2, /* FC_CHAR */ + 0x5b, /* FC_END */ +/* 18 */ + 0x11, 0xc, /* FC_RP [alloced_on_stack] [simple_pointer] */ +/* 20 */ 0x8, /* FC_LONG */ + 0x5c, /* FC_PAD */ +/* 22 */ + 0x11, 0x14, /* FC_RP [alloced_on_stack] [pointer_deref] */ +/* 24 */ NdrFcShort( 0x2 ), /* Offset= 2 (26) */ +/* 26 */ + 0x12, 0x0, /* FC_UP */ +/* 28 */ NdrFcShort( 0x2 ), /* Offset= 2 (30) */ +/* 30 */ + 0x1b, /* FC_CARRAY */ + 0x0, /* 0 */ +/* 32 */ NdrFcShort( 0x1 ), /* 1 */ +/* 34 */ 0x28, /* Corr desc: parameter, FC_LONG */ + 0x54, /* FC_DEREFERENCE */ +/* 36 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */ +/* 38 */ NdrFcShort( 0x1 ), /* Corr flags: early, */ +/* 40 */ 0x2, /* FC_CHAR */ + 0x5b, /* FC_END */ + + 0x0 + } + }; + +static const unsigned short KMSServer_FormatStringOffsetTable[] = + { + 0 + }; + +//typedef void *(__RPC_API midl_user_allocate_t)(size_t); +typedef void *(__RPC_API *midl_allocate_t)(size_t); + +/*static*/ const MIDL_STUB_DESC KMSServer_StubDesc = + { + (void *)& KMSServer___RpcClientInterface, + (midl_allocate_t)MIDL_user_allocate, + MIDL_user_free, + &KMSServer__MIDL_AutoBindHandle, + 0, + 0, + 0, + 0, + KMSServer__MIDL_TypeFormatString.Format, + 1, /* -error bounds_check flag */ + 0x50002, /* Ndr library version */ + 0, + 0x8000253, /* MIDL Version 8.0.595 */ + 0, + 0, + 0, /* notify & notify_flag routine table */ + 0x1, /* MIDL flag */ + 0, /* cs routines */ + 0, /* proxy/server info */ + 0 + }; + +#endif // !MULTI_CALL_BINARY + +#pragma optimize("", on ) +#if _MSC_VER >= 1200 +#pragma warning(pop) +#endif + + +#endif /* !defined(_M_IA64) && !defined(_M_AMD64) && !defined(_ARM_) */ + diff --git a/vlmcsd/src/KMSServer_c_x64_mingw_gcc.c b/vlmcsd/src/KMSServer_c_x64_mingw_gcc.c new file mode 100644 index 0000000..c3c1056 --- /dev/null +++ b/vlmcsd/src/KMSServer_c_x64_mingw_gcc.c @@ -0,0 +1,735 @@ + + +/* this ALWAYS GENERATED file contains the RPC client stubs */ + + + /* File created by MIDL compiler version 8.00.0603 */ +/* at Fri Feb 20 04:17:07 2015 + * modified by Hotbird64 to work with MingW-w64 and gcc + */ +/* Compiler settings for KMSServer.idl: + Oicf, W1, Zp8, env=Win64 (32b run), target_arch=AMD64 8.00.0603 + protocol : all , ms_ext, c_ext, robust + error checks: allocation ref bounds_check enum stub_data + VC __declspec() decoration level: + __declspec(uuid()), __declspec(selectany), __declspec(novtable) + DECLSPEC_UUID(), MIDL_INTERFACE() +*/ +/* @@MIDL_FILE_HEADING( ) */ + +#if defined(_M_AMD64) + + +#pragma warning( disable: 4049 ) /* more than 64k source lines */ +#if _MSC_VER >= 1200 +#pragma warning(push) +#endif + +#pragma warning( disable: 4211 ) /* redefine extern to static */ +#pragma warning( disable: 4232 ) /* dllimport identity*/ +#pragma warning( disable: 4024 ) /* array to pointer mapping*/ + +#include + +#include "KMSServer_h.h" + +#if !MULTI_CALL_BINARY + +#define TYPE_FORMAT_STRING_SIZE 43 +#define PROC_FORMAT_STRING_SIZE 61 +#define EXPR_FORMAT_STRING_SIZE 1 +#define TRANSMIT_AS_TABLE_SIZE 0 +#define WIRE_MARSHAL_TABLE_SIZE 0 + +typedef struct _KMSServer_MIDL_TYPE_FORMAT_STRING + { + short Pad; + unsigned char Format[ TYPE_FORMAT_STRING_SIZE ]; + } KMSServer_MIDL_TYPE_FORMAT_STRING; + +typedef struct _KMSServer_MIDL_PROC_FORMAT_STRING + { + short Pad; + unsigned char Format[ PROC_FORMAT_STRING_SIZE ]; + } KMSServer_MIDL_PROC_FORMAT_STRING; + +typedef struct _KMSServer_MIDL_EXPR_FORMAT_STRING + { + long Pad; + unsigned char Format[ EXPR_FORMAT_STRING_SIZE ]; + } KMSServer_MIDL_EXPR_FORMAT_STRING; + + +static const RPC_SYNTAX_IDENTIFIER _RpcTransferSyntax = +{{0x8A885D04,0x1CEB,0x11C9,{0x9F,0xE8,0x08,0x00,0x2B,0x10,0x48,0x60}},{2,0}}; + +static const RPC_SYNTAX_IDENTIFIER _NDR64_RpcTransferSyntax = +{{0x71710533,0xbeba,0x4937,{0x83,0x19,0xb5,0xdb,0xef,0x9c,0xcc,0x36}},{1,0}}; + + + +extern const KMSServer_MIDL_TYPE_FORMAT_STRING KMSServer__MIDL_TypeFormatString; +extern const KMSServer_MIDL_PROC_FORMAT_STRING KMSServer__MIDL_ProcFormatString; +extern const KMSServer_MIDL_EXPR_FORMAT_STRING KMSServer__MIDL_ExprFormatString; + +#endif // !MULTI_CALL_BINARY + +#define GENERIC_BINDING_TABLE_SIZE 0 + + +/* Standard interface: KMSServer, ver. 1.0, + GUID={0x51C82175,0x844E,0x4750,{0xB0,0xD8,0xEC,0x25,0x55,0x55,0xBC,0x06}} */ + + extern const MIDL_STUBLESS_PROXY_INFO KMSServer_ProxyInfo; + + +static const RPC_CLIENT_INTERFACE KMSServer___RpcClientInterface = + { + sizeof(RPC_CLIENT_INTERFACE), + {{0x51C82175,0x844E,0x4750,{0xB0,0xD8,0xEC,0x25,0x55,0x55,0xBC,0x06}},{1,0}}, + {{0x8A885D04,0x1CEB,0x11C9,{0x9F,0xE8,0x08,0x00,0x2B,0x10,0x48,0x60}},{2,0}}, + 0, + 0, + 0, + 0, + &KMSServer_ProxyInfo, + 0x02000000 + }; +RPC_IF_HANDLE KMSServer_v1_0_c_ifspec = (RPC_IF_HANDLE)& KMSServer___RpcClientInterface; + +extern const MIDL_STUB_DESC KMSServer_StubDesc; + +static RPC_BINDING_HANDLE KMSServer__MIDL_AutoBindHandle; + + +int RequestActivation( + /* [in] */ handle_t IDL_handle, + /* [in] */ int requestSize, + /* [size_is][in] */ unsigned char *request, + /* [out] */ int *responseSize, + /* [size_is][size_is][out] */ unsigned char **response) +{ + + CLIENT_CALL_RETURN _RetVal; + + _RetVal = NdrClientCall3( + ( PMIDL_STUBLESS_PROXY_INFO )&KMSServer_ProxyInfo, + 0, + 0, + IDL_handle, + requestSize, + request, + responseSize, + response); + return ( int )_RetVal.Simple; + +} + + +#if !defined(__RPC_WIN64__) +#error Invalid build platform for this stub. +#endif + +#if !MULTI_CALL_BINARY +/*static*/ const KMSServer_MIDL_PROC_FORMAT_STRING KMSServer__MIDL_ProcFormatString = + { + 0, + { + + /* Procedure RequestActivation */ + + 0x0, /* 0 */ + 0x48, /* Old Flags: */ +/* 2 */ NdrFcLong( 0x0 ), /* 0 */ +/* 6 */ NdrFcShort( 0x0 ), /* 0 */ +/* 8 */ NdrFcShort( 0x30 ), /* X64 Stack size/offset = 48 */ +/* 10 */ 0x32, /* FC_BIND_PRIMITIVE */ + 0x0, /* 0 */ +/* 12 */ NdrFcShort( 0x0 ), /* X64 Stack size/offset = 0 */ +/* 14 */ NdrFcShort( 0x8 ), /* 8 */ +/* 16 */ NdrFcShort( 0x24 ), /* 36 */ +/* 18 */ 0x47, /* Oi2 Flags: srv must size, clt must size, has return, has ext, */ + 0x5, /* 5 */ +/* 20 */ 0xa, /* 10 */ + 0x7, /* Ext Flags: new corr desc, clt corr check, srv corr check, */ +/* 22 */ NdrFcShort( 0x1 ), /* 1 */ +/* 24 */ NdrFcShort( 0x1 ), /* 1 */ +/* 26 */ NdrFcShort( 0x0 ), /* 0 */ +/* 28 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter IDL_handle */ + +/* 30 */ NdrFcShort( 0x48 ), /* Flags: in, base type, */ +/* 32 */ NdrFcShort( 0x8 ), /* X64 Stack size/offset = 8 */ +/* 34 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Parameter requestSize */ + +/* 36 */ NdrFcShort( 0x10b ), /* Flags: must size, must free, in, simple ref, */ +/* 38 */ NdrFcShort( 0x10 ), /* X64 Stack size/offset = 16 */ +/* 40 */ NdrFcShort( 0x6 ), /* Type Offset=6 */ + + /* Parameter request */ + +/* 42 */ NdrFcShort( 0x2150 ), /* Flags: out, base type, simple ref, srv alloc size=8 */ +/* 44 */ NdrFcShort( 0x18 ), /* X64 Stack size/offset = 24 */ +/* 46 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Parameter responseSize */ + +/* 48 */ NdrFcShort( 0x2013 ), /* Flags: must size, must free, out, srv alloc size=8 */ +/* 50 */ NdrFcShort( 0x20 ), /* X64 Stack size/offset = 32 */ +/* 52 */ NdrFcShort( 0x16 ), /* Type Offset=22 */ + + /* Parameter response */ + +/* 54 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 56 */ NdrFcShort( 0x28 ), /* X64 Stack size/offset = 40 */ +/* 58 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + 0x0 + } + }; + +/*static*/ const KMSServer_MIDL_TYPE_FORMAT_STRING KMSServer__MIDL_TypeFormatString = + { + 0, + { + NdrFcShort( 0x0 ), /* 0 */ +/* 2 */ + 0x11, 0x0, /* FC_RP */ +/* 4 */ NdrFcShort( 0x2 ), /* Offset= 2 (6) */ +/* 6 */ + 0x1b, /* FC_CARRAY */ + 0x0, /* 0 */ +/* 8 */ NdrFcShort( 0x1 ), /* 1 */ +/* 10 */ 0x28, /* Corr desc: parameter, FC_LONG */ + 0x0, /* */ +/* 12 */ NdrFcShort( 0x8 ), /* X64 Stack size/offset = 8 */ +/* 14 */ NdrFcShort( 0x1 ), /* Corr flags: early, */ +/* 16 */ 0x2, /* FC_CHAR */ + 0x5b, /* FC_END */ +/* 18 */ + 0x11, 0xc, /* FC_RP [alloced_on_stack] [simple_pointer] */ +/* 20 */ 0x8, /* FC_LONG */ + 0x5c, /* FC_PAD */ +/* 22 */ + 0x11, 0x14, /* FC_RP [alloced_on_stack] [pointer_deref] */ +/* 24 */ NdrFcShort( 0x2 ), /* Offset= 2 (26) */ +/* 26 */ + 0x12, 0x0, /* FC_UP */ +/* 28 */ NdrFcShort( 0x2 ), /* Offset= 2 (30) */ +/* 30 */ + 0x1b, /* FC_CARRAY */ + 0x0, /* 0 */ +/* 32 */ NdrFcShort( 0x1 ), /* 1 */ +/* 34 */ 0x28, /* Corr desc: parameter, FC_LONG */ + 0x54, /* FC_DEREFERENCE */ +/* 36 */ NdrFcShort( 0x18 ), /* X64 Stack size/offset = 24 */ +/* 38 */ NdrFcShort( 0x1 ), /* Corr flags: early, */ +/* 40 */ 0x2, /* FC_CHAR */ + 0x5b, /* FC_END */ + + 0x0 + } + }; + +static const unsigned short KMSServer_FormatStringOffsetTable[] = + { + 0 + }; + +#endif //!MULTI_CALL_BINARY + +#endif /* defined(_M_AMD64)*/ + + + +/* this ALWAYS GENERATED file contains the RPC client stubs */ + + + /* File created by MIDL compiler version 8.00.0603 */ +/* at Fri Feb 20 04:17:07 2015 + */ +/* Compiler settings for KMSServer.idl: + Oicf, W1, Zp8, env=Win64 (32b run), target_arch=AMD64 8.00.0603 + protocol : all , ms_ext, c_ext, robust + error checks: allocation ref bounds_check enum stub_data + VC __declspec() decoration level: + __declspec(uuid()), __declspec(selectany), __declspec(novtable) + DECLSPEC_UUID(), MIDL_INTERFACE() +*/ +/* @@MIDL_FILE_HEADING( ) */ + +#if defined(_M_AMD64) + + +#pragma warning( disable: 4049 ) /* more than 64k source lines */ + + +#if !defined(__RPC_WIN64__) +#error Invalid build platform for this stub. +#endif + + +#include "ndr64types.h" +#include "pshpack8.h" + +#if !MULTI_CALL_BINARY + +typedef +struct +{ + NDR64_FORMAT_UINT32 frag1; + struct _NDR64_EXPR_OPERATOR frag2; + struct _NDR64_EXPR_VAR frag3; +} +__midl_frag13_t; + +extern const __midl_frag13_t __midl_frag13; + +typedef +struct +{ + struct _NDR64_CONF_ARRAY_HEADER_FORMAT frag1; + struct _NDR64_ARRAY_ELEMENT_INFO frag2; +} +__midl_frag12_t; +extern const __midl_frag12_t __midl_frag12; + +typedef +struct _NDR64_POINTER_FORMAT +__midl_frag11_t; +extern const __midl_frag11_t __midl_frag11; + +typedef +struct _NDR64_POINTER_FORMAT +__midl_frag10_t; +extern const __midl_frag10_t __midl_frag10; + +typedef +struct _NDR64_POINTER_FORMAT +__midl_frag8_t; +extern const __midl_frag8_t __midl_frag8; + +typedef +NDR64_FORMAT_CHAR +__midl_frag7_t; +extern const __midl_frag7_t __midl_frag7; + +typedef +struct +{ + NDR64_FORMAT_UINT32 frag1; + struct _NDR64_EXPR_VAR frag2; +} +__midl_frag6_t; +extern const __midl_frag6_t __midl_frag6; + +typedef +struct +{ + struct _NDR64_CONF_ARRAY_HEADER_FORMAT frag1; + struct _NDR64_ARRAY_ELEMENT_INFO frag2; +} +__midl_frag5_t; +extern const __midl_frag5_t __midl_frag5; + +typedef +struct _NDR64_POINTER_FORMAT +__midl_frag4_t; +extern const __midl_frag4_t __midl_frag4; + +typedef +NDR64_FORMAT_CHAR +__midl_frag3_t; +extern const __midl_frag3_t __midl_frag3; + +typedef +struct +{ + struct _NDR64_PROC_FORMAT frag1; + struct _NDR64_BIND_AND_NOTIFY_EXTENSION frag2; + struct _NDR64_PARAM_FORMAT frag3; + struct _NDR64_PARAM_FORMAT frag4; + struct _NDR64_PARAM_FORMAT frag5; + struct _NDR64_PARAM_FORMAT frag6; + struct _NDR64_PARAM_FORMAT frag7; +} +__midl_frag2_t; +extern const __midl_frag2_t __midl_frag2; + +typedef +NDR64_FORMAT_UINT32 +__midl_frag1_t; +extern const __midl_frag1_t __midl_frag1; + +/*static*/ const __midl_frag13_t __midl_frag13 = +{ +/* */ + (NDR64_UINT32) 1 /* 0x1 */, + { + /* struct _NDR64_EXPR_OPERATOR */ + 0x4, /* FC_EXPR_OPER */ + 0x5, /* OP_UNARY_INDIRECTION */ + 0x5, /* FC64_INT32 */ + (NDR64_UINT8) 0 /* 0x0 */ + }, + { + /* struct _NDR64_EXPR_VAR */ + 0x3, /* FC_EXPR_VAR */ + 0x7, /* FC64_INT64 */ + (NDR64_UINT16) 0 /* 0x0 */, + (NDR64_UINT32) 24 /* 0x18 */ /* Offset */ + } +}; + +/*static*/ const __midl_frag12_t __midl_frag12 = +{ +/* *char */ + { + /* *char */ + 0x41, /* FC64_CONF_ARRAY */ + (NDR64_UINT8) 0 /* 0x0 */, + { + /* *char */ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + }, + (NDR64_UINT8) 0 /* 0x0 */, + (NDR64_UINT32) 1 /* 0x1 */, + &__midl_frag13 + }, + { + /* struct _NDR64_ARRAY_ELEMENT_INFO */ + (NDR64_UINT32) 1 /* 0x1 */, + &__midl_frag7 + } +}; + +/*static*/ const __midl_frag11_t __midl_frag11 = +{ +/* *char */ + 0x21, /* FC64_UP */ + (NDR64_UINT8) 0 /* 0x0 */, + (NDR64_UINT16) 0 /* 0x0 */, + &__midl_frag12 +}; + +/*static*/ const __midl_frag10_t __midl_frag10 = +{ +/* **char */ + 0x20, /* FC64_RP */ + (NDR64_UINT8) 20 /* 0x14 */, + (NDR64_UINT16) 0 /* 0x0 */, + &__midl_frag11 +}; + +/*static*/ const __midl_frag8_t __midl_frag8 = +{ +/* *int */ + 0x20, /* FC64_RP */ + (NDR64_UINT8) 12 /* 0xc */, + (NDR64_UINT16) 0 /* 0x0 */, + &__midl_frag3 +}; + +/*static*/ const __midl_frag7_t __midl_frag7 = +0x10 /* FC64_CHAR */; + +/*static*/ const __midl_frag6_t __midl_frag6 = +{ +/* */ + (NDR64_UINT32) 1 /* 0x1 */, + { + /* struct _NDR64_EXPR_VAR */ + 0x3, /* FC_EXPR_VAR */ + 0x5, /* FC64_INT32 */ + (NDR64_UINT16) 0 /* 0x0 */, + (NDR64_UINT32) 8 /* 0x8 */ /* Offset */ + } +}; + +/*static*/ const __midl_frag5_t __midl_frag5 = +{ +/* *char */ + { + /* *char */ + 0x41, /* FC64_CONF_ARRAY */ + (NDR64_UINT8) 0 /* 0x0 */, + { + /* *char */ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + }, + (NDR64_UINT8) 0 /* 0x0 */, + (NDR64_UINT32) 1 /* 0x1 */, + &__midl_frag6 + }, + { + /* struct _NDR64_ARRAY_ELEMENT_INFO */ + (NDR64_UINT32) 1 /* 0x1 */, + &__midl_frag7 + } +}; + +/*static*/ const __midl_frag4_t __midl_frag4 = +{ +/* *char */ + 0x20, /* FC64_RP */ + (NDR64_UINT8) 0 /* 0x0 */, + (NDR64_UINT16) 0 /* 0x0 */, + &__midl_frag5 +}; + +/*static*/ const __midl_frag3_t __midl_frag3 = +0x5 /* FC64_INT32 */; + +/*static*/ const __midl_frag2_t __midl_frag2 = +{ +/* RequestActivation */ + { + /* RequestActivation */ /* procedure RequestActivation */ + (NDR64_UINT32) 23986240 /* 0x16e0040 */, /* explicit handle */ /* IsIntrepreted, ServerMustSize, ClientMustSize, HasReturn, ServerCorrelation, ClientCorrelation, HasExtensions */ + (NDR64_UINT32) 48 /* 0x30 */ , /* Stack size */ + (NDR64_UINT32) 8 /* 0x8 */, + (NDR64_UINT32) 40 /* 0x28 */, + (NDR64_UINT16) 0 /* 0x0 */, + (NDR64_UINT16) 0 /* 0x0 */, + (NDR64_UINT16) 5 /* 0x5 */, + (NDR64_UINT16) 8 /* 0x8 */ + }, + { + /* struct _NDR64_BIND_AND_NOTIFY_EXTENSION */ + { + /* struct _NDR64_BIND_AND_NOTIFY_EXTENSION */ + 0x72, /* FC64_BIND_PRIMITIVE */ + (NDR64_UINT8) 0 /* 0x0 */, + 0 /* 0x0 */, /* Stack offset */ + (NDR64_UINT8) 0 /* 0x0 */, + (NDR64_UINT8) 0 /* 0x0 */ + }, + (NDR64_UINT16) 0 /* 0x0 */ /* Notify index */ + }, + { + /* requestSize */ /* parameter requestSize */ + &__midl_frag3, + { + /* requestSize */ + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + (NDR64_UINT16) 0 /* 0x0 */, + 0 + }, /* [in], Basetype, ByValue */ + (NDR64_UINT16) 0 /* 0x0 */, + 8 /* 0x8 */, /* Stack offset */ + }, + { + /* request */ /* parameter request */ + &__midl_frag5, + { + /* request */ + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + (NDR64_UINT16) 0 /* 0x0 */, + 0 + }, /* MustSize, MustFree, [in], SimpleRef */ + (NDR64_UINT16) 0 /* 0x0 */, + 16 /* 0x10 */, /* Stack offset */ + }, + { + /* responseSize */ /* parameter responseSize */ + &__midl_frag3, + { + /* responseSize */ + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + (NDR64_UINT16) 0 /* 0x0 */, + 1 + }, /* [out], Basetype, SimpleRef, UseCache */ + (NDR64_UINT16) 0 /* 0x0 */, + 24 /* 0x18 */, /* Stack offset */ + }, + { + /* response */ /* parameter response */ + &__midl_frag10, + { + /* response */ + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + (NDR64_UINT16) 0 /* 0x0 */, + 1 + }, /* MustSize, MustFree, [out], UseCache */ + (NDR64_UINT16) 0 /* 0x0 */, + 32 /* 0x20 */, /* Stack offset */ + }, + { + /* int */ /* parameter int */ + &__midl_frag3, + { + /* int */ + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + (NDR64_UINT16) 0 /* 0x0 */, + 0 + }, /* [out], IsReturn, Basetype, ByValue */ + (NDR64_UINT16) 0 /* 0x0 */, + 40 /* 0x28 */, /* Stack offset */ + } +}; + +/*static*/ const __midl_frag1_t __midl_frag1 = +(NDR64_UINT32) 0 /* 0x0 */; + +#endif // !MULTI_CALL_BINARY + +#include "poppack.h" + +#if !MULTI_CALL_BINARY + +static const FormatInfoRef KMSServer_Ndr64ProcTable[] = + { + &__midl_frag2 + }; + +//typedef void *__RPC_USER MIDL_user_allocate_t(SIZE_T) +typedef void *(__RPC_API *midl_allocate_t)(size_t); + +/*static*/ const MIDL_STUB_DESC KMSServer_StubDesc = + { + (void *)& KMSServer___RpcClientInterface, + (midl_allocate_t)MIDL_user_allocate, + MIDL_user_free, + &KMSServer__MIDL_AutoBindHandle, + 0, + 0, + 0, + 0, + KMSServer__MIDL_TypeFormatString.Format, + 1, /* -error bounds_check flag */ + 0x60000, /* Ndr library version */ + 0, + 0x800025b, /* MIDL Version 8.0.603 */ + 0, + 0, + 0, /* notify & notify_flag routine table */ + 0x2000001, /* MIDL flag */ + 0, /* cs routines */ + (void *)& KMSServer_ProxyInfo, /* proxy/server info */ + 0 + }; + +static const MIDL_SYNTAX_INFO KMSServer_SyntaxInfo [ 2 ] = + { + { + {{0x8A885D04,0x1CEB,0x11C9,{0x9F,0xE8,0x08,0x00,0x2B,0x10,0x48,0x60}},{2,0}}, + 0, + KMSServer__MIDL_ProcFormatString.Format, + KMSServer_FormatStringOffsetTable, + KMSServer__MIDL_TypeFormatString.Format, + 0, + 0, + 0 + } + ,{ + {{0x71710533,0xbeba,0x4937,{0x83,0x19,0xb5,0xdb,0xef,0x9c,0xcc,0x36}},{1,0}}, + 0, + 0 , + (unsigned short *) KMSServer_Ndr64ProcTable, + 0, + 0, + 0, + 0 + } + }; + +#endif // !MULTI_CALL_BINARY + +/*static*/ const MIDL_STUBLESS_PROXY_INFO KMSServer_ProxyInfo = + { + &KMSServer_StubDesc, + KMSServer__MIDL_ProcFormatString.Format, + KMSServer_FormatStringOffsetTable, + (RPC_SYNTAX_IDENTIFIER*)&_RpcTransferSyntax, + 2, + (MIDL_SYNTAX_INFO*)KMSServer_SyntaxInfo + + }; + +#if _MSC_VER >= 1200 +#pragma warning(pop) +#endif + + +#endif /* defined(_M_AMD64)*/ + diff --git a/vlmcsd/src/KMSServer_h.h b/vlmcsd/src/KMSServer_h.h new file mode 100644 index 0000000..ba9f7c1 --- /dev/null +++ b/vlmcsd/src/KMSServer_h.h @@ -0,0 +1,84 @@ + + +/* this ALWAYS GENERATED file contains the definitions for the interfaces */ + +/* Modified by Hotbird64 for use with MingW and gcc */ + + + /* File created by MIDL compiler version 8.00.0595 */ +/* at Thu Oct 18 15:24:14 2012 + */ +/* Compiler settings for KMSServer.idl: + Oicf, W1, Zp8, env=Win32 (32b run), target_arch=X86 8.00.0595 + protocol : dce , ms_ext, c_ext, robust + error checks: allocation ref bounds_check enum stub_data + VC __declspec() decoration level: + __declspec(uuid()), __declspec(selectany), __declspec(novtable) + DECLSPEC_UUID(), MIDL_INTERFACE() +*/ +/* @@MIDL_FILE_HEADING( ) */ + +#if _WIN32 +#include "winsock2.h" +#endif + +#pragma warning( disable: 4049 ) /* more than 64k source lines */ + + +/* verify that the version is high enough to compile this file*/ +#ifndef __REQUIRED_RPCNDR_H_VERSION__ +#define __REQUIRED_RPCNDR_H_VERSION__ 475 +#endif + +//#include "rpc.h" +#include "rpcndr.h" + +#ifndef __RPCNDR_H_VERSION__ +#error this stub requires an updated version of +#endif // __RPCNDR_H_VERSION__ + + +#ifndef __KMSServer_h_h__ +#define __KMSServer_h_h__ + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +#pragma once +#endif + +/* Forward Declarations */ + +#ifdef __cplusplus +extern "C"{ +#endif + + +#ifndef __KMSServer_INTERFACE_DEFINED__ +#define __KMSServer_INTERFACE_DEFINED__ + +/* interface KMSServer */ +/* [version][uuid] */ + +int RequestActivation( + /* [in] */ handle_t IDL_handle, + /* [in] */ int requestSize, + /* [size_is][in] */ unsigned char *request, + /* [out] */ int *responseSize, + /* [size_is][size_is][out] */ unsigned char **response); + + + +extern RPC_IF_HANDLE KMSServer_v1_0_c_ifspec; +extern RPC_IF_HANDLE KMSServer_v1_0_s_ifspec; +#endif /* __KMSServer_INTERFACE_DEFINED__ */ + +/* Additional Prototypes for ALL interfaces */ + +/* end of Additional Prototypes */ + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/vlmcsd/src/KMSServer_s2_mingw_gcc.c b/vlmcsd/src/KMSServer_s2_mingw_gcc.c new file mode 100644 index 0000000..492c6ba --- /dev/null +++ b/vlmcsd/src/KMSServer_s2_mingw_gcc.c @@ -0,0 +1,282 @@ + + +/* this ALWAYS GENERATED file contains the RPC server stubs */ + +/* WARNING! manually edited by Hotbird64 to work with MingW */ + + /* File created by MIDL compiler version 8.00.0595 */ +/* at Thu Oct 18 15:24:14 2012 + */ +/* Compiler settings for KMSServer.idl: + Oicf, W1, Zp8, env=Win32 (32b run), target_arch=X86 8.00.0595 + protocol : dce , ms_ext, c_ext, robust + error checks: allocation ref bounds_check enum stub_data + VC __declspec() decoration level: + __declspec(uuid()), __declspec(selectany), __declspec(novtable) + DECLSPEC_UUID(), MIDL_INTERFACE() +*/ +/* @@MIDL_FILE_HEADING( ) */ + +#if !defined(_M_IA64) && !defined(_M_AMD64) && !defined(_ARM_) + + +#pragma warning( disable: 4049 ) /* more than 64k source lines */ +#if _MSC_VER >= 1200 +#pragma warning(push) +#endif + +#pragma warning( disable: 4211 ) /* redefine extern to static */ +#pragma warning( disable: 4232 ) /* dllimport identity*/ +#pragma warning( disable: 4024 ) /* array to pointer mapping*/ +#pragma warning( disable: 4100 ) /* unreferenced arguments in x86 call */ + +#pragma optimize("", off ) + +#include +#include "KMSServer_h.h" + +#define TYPE_FORMAT_STRING_SIZE 43 +#define PROC_FORMAT_STRING_SIZE 59 +#define EXPR_FORMAT_STRING_SIZE 1 +#define TRANSMIT_AS_TABLE_SIZE 0 +#define WIRE_MARSHAL_TABLE_SIZE 0 + +typedef struct _KMSServer_MIDL_TYPE_FORMAT_STRING + { + short Pad; + unsigned char Format[ TYPE_FORMAT_STRING_SIZE ]; + } KMSServer_MIDL_TYPE_FORMAT_STRING; + +typedef struct _KMSServer_MIDL_PROC_FORMAT_STRING + { + short Pad; + unsigned char Format[ PROC_FORMAT_STRING_SIZE ]; + } KMSServer_MIDL_PROC_FORMAT_STRING; + +typedef struct _KMSServer_MIDL_EXPR_FORMAT_STRING + { + long Pad; + unsigned char Format[ EXPR_FORMAT_STRING_SIZE ]; + } KMSServer_MIDL_EXPR_FORMAT_STRING; + + +static const RPC_SYNTAX_IDENTIFIER _RpcTransferSyntax = +{{0x8A885D04,0x1CEB,0x11C9,{0x9F,0xE8,0x08,0x00,0x2B,0x10,0x48,0x60}},{2,0}}; + +extern const KMSServer_MIDL_TYPE_FORMAT_STRING KMSServer__MIDL_TypeFormatString; +extern const KMSServer_MIDL_PROC_FORMAT_STRING KMSServer__MIDL_ProcFormatString; +extern const KMSServer_MIDL_EXPR_FORMAT_STRING KMSServer__MIDL_ExprFormatString; + +/* Standard interface: KMSServer, ver. 1.0, + GUID={0x51C82175,0x844E,0x4750,{0xB0,0xD8,0xEC,0x25,0x55,0x55,0xBC,0x06}} */ + + +extern const MIDL_SERVER_INFO KMSServer_ServerInfo; + +extern const RPC_DISPATCH_TABLE KMSServer_v1_0_DispatchTable; + + int ProcessActivationRequest( + /* [in] */ handle_t IDL_handle, + /* [in] */ int requestSize, + /* [size_is][in] */ unsigned char *request, + /* [out] */ int *responseSize, + /* [size_is][size_is][out] */ unsigned char **response); + + static const RPC_SERVER_INTERFACE KMSServer___RpcServerInterface = + { + sizeof(RPC_SERVER_INTERFACE), + {{0x51C82175,0x844E,0x4750,{0xB0,0xD8,0xEC,0x25,0x55,0x55,0xBC,0x06}},{1,0}}, + {{0x8A885D04,0x1CEB,0x11C9,{0x9F,0xE8,0x08,0x00,0x2B,0x10,0x48,0x60}},{2,0}}, + (RPC_DISPATCH_TABLE*)&KMSServer_v1_0_DispatchTable, + 0, + 0, + 0, + &KMSServer_ServerInfo, + 0x04000000 + }; +RPC_IF_HANDLE KMSServer_v1_0_s_ifspec = (RPC_IF_HANDLE)& KMSServer___RpcServerInterface; + +extern const MIDL_STUB_DESC KMSServer_StubDesc; + + +#if !defined(__RPC_WIN32__) +#error Invalid build platform for this stub. +#endif + +#if !(TARGET_IS_NT50_OR_LATER) +#error You need Windows 2000 or later to run this stub because it uses these features: +#error /robust command line switch. +#error However, your C/C++ compilation flags indicate you intend to run this app on earlier systems. +#error This app will fail with the RPC_X_WRONG_STUB_VERSION error. +#endif + +const KMSServer_MIDL_PROC_FORMAT_STRING KMSServer__MIDL_ProcFormatString = + { + 0, + { + + /* Procedure RequestActivation */ + + 0x0, /* 0 */ + 0x48, /* Old Flags: */ +/* 2 */ NdrFcLong( 0x0 ), /* 0 */ +/* 6 */ NdrFcShort( 0x0 ), /* 0 */ +/* 8 */ NdrFcShort( 0x18 ), /* x86 Stack size/offset = 24 */ +/* 10 */ 0x32, /* FC_BIND_PRIMITIVE */ + 0x0, /* 0 */ +/* 12 */ NdrFcShort( 0x0 ), /* x86 Stack size/offset = 0 */ +/* 14 */ NdrFcShort( 0x8 ), /* 8 */ +/* 16 */ NdrFcShort( 0x24 ), /* 36 */ +/* 18 */ 0x47, /* Oi2 Flags: srv must size, clt must size, has return, has ext, */ + 0x5, /* 5 */ +/* 20 */ 0x8, /* 8 */ + 0x7, /* Ext Flags: new corr desc, clt corr check, srv corr check, */ +/* 22 */ NdrFcShort( 0x1 ), /* 1 */ +/* 24 */ NdrFcShort( 0x1 ), /* 1 */ +/* 26 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter IDL_handle */ + +/* 28 */ NdrFcShort( 0x48 ), /* Flags: in, base type, */ +/* 30 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 32 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Parameter requestSize */ + +/* 34 */ NdrFcShort( 0x10b ), /* Flags: must size, must free, in, simple ref, */ +/* 36 */ NdrFcShort( 0x8 ), /* x86 Stack size/offset = 8 */ +/* 38 */ NdrFcShort( 0x6 ), /* Type Offset=6 */ + + /* Parameter request */ + +/* 40 */ NdrFcShort( 0x2150 ), /* Flags: out, base type, simple ref, srv alloc size=8 */ +/* 42 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */ +/* 44 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Parameter responseSize */ + +/* 46 */ NdrFcShort( 0x2013 ), /* Flags: must size, must free, out, srv alloc size=8 */ +/* 48 */ NdrFcShort( 0x10 ), /* x86 Stack size/offset = 16 */ +/* 50 */ NdrFcShort( 0x16 ), /* Type Offset=22 */ + + /* Parameter response */ + +/* 52 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 54 */ NdrFcShort( 0x14 ), /* x86 Stack size/offset = 20 */ +/* 56 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + 0x0 + } + }; + +const KMSServer_MIDL_TYPE_FORMAT_STRING KMSServer__MIDL_TypeFormatString = + { + 0, + { + NdrFcShort( 0x0 ), /* 0 */ +/* 2 */ + 0x11, 0x0, /* FC_RP */ +/* 4 */ NdrFcShort( 0x2 ), /* Offset= 2 (6) */ +/* 6 */ + 0x1b, /* FC_CARRAY */ + 0x0, /* 0 */ +/* 8 */ NdrFcShort( 0x1 ), /* 1 */ +/* 10 */ 0x28, /* Corr desc: parameter, FC_LONG */ + 0x0, /* */ +/* 12 */ NdrFcShort( 0x4 ), /* x86 Stack size/offset = 4 */ +/* 14 */ NdrFcShort( 0x1 ), /* Corr flags: early, */ +/* 16 */ 0x2, /* FC_CHAR */ + 0x5b, /* FC_END */ +/* 18 */ + 0x11, 0xc, /* FC_RP [alloced_on_stack] [simple_pointer] */ +/* 20 */ 0x8, /* FC_LONG */ + 0x5c, /* FC_PAD */ +/* 22 */ + 0x11, 0x14, /* FC_RP [alloced_on_stack] [pointer_deref] */ +/* 24 */ NdrFcShort( 0x2 ), /* Offset= 2 (26) */ +/* 26 */ + 0x12, 0x0, /* FC_UP */ +/* 28 */ NdrFcShort( 0x2 ), /* Offset= 2 (30) */ +/* 30 */ + 0x1b, /* FC_CARRAY */ + 0x0, /* 0 */ +/* 32 */ NdrFcShort( 0x1 ), /* 1 */ +/* 34 */ 0x28, /* Corr desc: parameter, FC_LONG */ + 0x54, /* FC_DEREFERENCE */ +/* 36 */ NdrFcShort( 0xc ), /* x86 Stack size/offset = 12 */ +/* 38 */ NdrFcShort( 0x1 ), /* Corr flags: early, */ +/* 40 */ 0x2, /* FC_CHAR */ + 0x5b, /* FC_END */ + + 0x0 + } + }; + +static const unsigned short KMSServer_FormatStringOffsetTable[] = + { + 0 + }; + +typedef void *(__RPC_API *midl_allocate_t)(size_t); + +const MIDL_STUB_DESC KMSServer_StubDesc = + { + (void *)& KMSServer___RpcServerInterface, + (midl_allocate_t)MIDL_user_allocate, + MIDL_user_free, + 0, + 0, + 0, + 0, + 0, + KMSServer__MIDL_TypeFormatString.Format, + 1, /* -error bounds_check flag */ + 0x50002, /* Ndr library version */ + 0, + 0x8000253, /* MIDL Version 8.0.595 */ + 0, + 0, + 0, /* notify & notify_flag routine table */ + 0x1, /* MIDL flag */ + 0, /* cs routines */ + 0, /* proxy/server info */ + 0 + }; + +static const RPC_DISPATCH_FUNCTION KMSServer_table[] = + { + NdrServerCall2, + 0 + }; +const RPC_DISPATCH_TABLE KMSServer_v1_0_DispatchTable = + { + 1, + (RPC_DISPATCH_FUNCTION*)KMSServer_table + }; + +static const SERVER_ROUTINE KMSServer_ServerRoutineTable[] = + { + (SERVER_ROUTINE)ProcessActivationRequest + }; + +const MIDL_SERVER_INFO KMSServer_ServerInfo = + { + &KMSServer_StubDesc, + KMSServer_ServerRoutineTable, + KMSServer__MIDL_ProcFormatString.Format, + KMSServer_FormatStringOffsetTable, + 0, + 0, + 0, + 0}; +#pragma optimize("", on ) +#if _MSC_VER >= 1200 +#pragma warning(pop) +#endif + + +#endif /* !defined(_M_IA64) && !defined(_M_AMD64) && !defined(_ARM_) */ + diff --git a/vlmcsd/src/KMSServer_s2_x64_mingw_gcc.c b/vlmcsd/src/KMSServer_s2_x64_mingw_gcc.c new file mode 100644 index 0000000..9cf4bae --- /dev/null +++ b/vlmcsd/src/KMSServer_s2_x64_mingw_gcc.c @@ -0,0 +1,730 @@ + + +/* this ALWAYS GENERATED file contains the RPC server stubs */ + + + /* File created by MIDL compiler version 8.00.0603 */ +/* at Fri Feb 20 04:17:07 2015 + * Modified by Hotbird64 to work with gcc and MingW-w64 + */ +/* Compiler settings for KMSServer.idl: + Oicf, W1, Zp8, env=Win64 (32b run), target_arch=AMD64 8.00.0603 + protocol : all , ms_ext, c_ext, robust + error checks: allocation ref bounds_check enum stub_data + VC __declspec() decoration level: + __declspec(uuid()), __declspec(selectany), __declspec(novtable) + DECLSPEC_UUID(), MIDL_INTERFACE() +*/ +/* @@MIDL_FILE_HEADING( ) */ + +#if defined(_M_AMD64) + +int ProcessActivationRequest( + /* [in] */ handle_t IDL_handle, + /* [in] */ int requestSize, + /* [size_is][in] */ unsigned char *request, + /* [out] */ int *responseSize, + /* [size_is][size_is][out] */ unsigned char **response); + + +#pragma warning( disable: 4049 ) /* more than 64k source lines */ +#if _MSC_VER >= 1200 +#pragma warning(push) +#endif + +#pragma warning( disable: 4211 ) /* redefine extern to static */ +#pragma warning( disable: 4232 ) /* dllimport identity*/ +#pragma warning( disable: 4024 ) /* array to pointer mapping*/ + +#include +#include "KMSServer_h.h" + +#define TYPE_FORMAT_STRING_SIZE 43 +#define PROC_FORMAT_STRING_SIZE 61 +#define EXPR_FORMAT_STRING_SIZE 1 +#define TRANSMIT_AS_TABLE_SIZE 0 +#define WIRE_MARSHAL_TABLE_SIZE 0 + +typedef struct _KMSServer_MIDL_TYPE_FORMAT_STRING + { + short Pad; + unsigned char Format[ TYPE_FORMAT_STRING_SIZE ]; + } KMSServer_MIDL_TYPE_FORMAT_STRING; + +typedef struct _KMSServer_MIDL_PROC_FORMAT_STRING + { + short Pad; + unsigned char Format[ PROC_FORMAT_STRING_SIZE ]; + } KMSServer_MIDL_PROC_FORMAT_STRING; + +typedef struct _KMSServer_MIDL_EXPR_FORMAT_STRING + { + long Pad; + unsigned char Format[ EXPR_FORMAT_STRING_SIZE ]; + } KMSServer_MIDL_EXPR_FORMAT_STRING; + + +static const RPC_SYNTAX_IDENTIFIER _RpcTransferSyntax = +{{0x8A885D04,0x1CEB,0x11C9,{0x9F,0xE8,0x08,0x00,0x2B,0x10,0x48,0x60}},{2,0}}; + +static const RPC_SYNTAX_IDENTIFIER _NDR64_RpcTransferSyntax = +{{0x71710533,0xbeba,0x4937,{0x83,0x19,0xb5,0xdb,0xef,0x9c,0xcc,0x36}},{1,0}}; + + +extern const KMSServer_MIDL_TYPE_FORMAT_STRING KMSServer__MIDL_TypeFormatString; +extern const KMSServer_MIDL_PROC_FORMAT_STRING KMSServer__MIDL_ProcFormatString; +extern const KMSServer_MIDL_EXPR_FORMAT_STRING KMSServer__MIDL_ExprFormatString; + +/* Standard interface: KMSServer, ver. 1.0, + GUID={0x51C82175,0x844E,0x4750,{0xB0,0xD8,0xEC,0x25,0x55,0x55,0xBC,0x06}} */ + + +extern const MIDL_SERVER_INFO KMSServer_ServerInfo; + +extern const RPC_DISPATCH_TABLE KMSServer_v1_0_DispatchTable; + +static const RPC_SERVER_INTERFACE KMSServer___RpcServerInterface = + { + sizeof(RPC_SERVER_INTERFACE), + {{0x51C82175,0x844E,0x4750,{0xB0,0xD8,0xEC,0x25,0x55,0x55,0xBC,0x06}},{1,0}}, + {{0x8A885D04,0x1CEB,0x11C9,{0x9F,0xE8,0x08,0x00,0x2B,0x10,0x48,0x60}},{2,0}}, + (RPC_DISPATCH_TABLE*)&KMSServer_v1_0_DispatchTable, + 0, + 0, + 0, + &KMSServer_ServerInfo, + 0x06000000 + }; +RPC_IF_HANDLE KMSServer_v1_0_s_ifspec = (RPC_IF_HANDLE)& KMSServer___RpcServerInterface; + +extern const MIDL_STUB_DESC KMSServer_StubDesc; + + +#if !defined(__RPC_WIN64__) +#error Invalid build platform for this stub. +#endif + +/*static*/ const KMSServer_MIDL_PROC_FORMAT_STRING KMSServer__MIDL_ProcFormatString = + { + 0, + { + + /* Procedure RequestActivation */ + + 0x0, /* 0 */ + 0x48, /* Old Flags: */ +/* 2 */ NdrFcLong( 0x0 ), /* 0 */ +/* 6 */ NdrFcShort( 0x0 ), /* 0 */ +/* 8 */ NdrFcShort( 0x30 ), /* X64 Stack size/offset = 48 */ +/* 10 */ 0x32, /* FC_BIND_PRIMITIVE */ + 0x0, /* 0 */ +/* 12 */ NdrFcShort( 0x0 ), /* X64 Stack size/offset = 0 */ +/* 14 */ NdrFcShort( 0x8 ), /* 8 */ +/* 16 */ NdrFcShort( 0x24 ), /* 36 */ +/* 18 */ 0x47, /* Oi2 Flags: srv must size, clt must size, has return, has ext, */ + 0x5, /* 5 */ +/* 20 */ 0xa, /* 10 */ + 0x7, /* Ext Flags: new corr desc, clt corr check, srv corr check, */ +/* 22 */ NdrFcShort( 0x1 ), /* 1 */ +/* 24 */ NdrFcShort( 0x1 ), /* 1 */ +/* 26 */ NdrFcShort( 0x0 ), /* 0 */ +/* 28 */ NdrFcShort( 0x0 ), /* 0 */ + + /* Parameter IDL_handle */ + +/* 30 */ NdrFcShort( 0x48 ), /* Flags: in, base type, */ +/* 32 */ NdrFcShort( 0x8 ), /* X64 Stack size/offset = 8 */ +/* 34 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Parameter requestSize */ + +/* 36 */ NdrFcShort( 0x10b ), /* Flags: must size, must free, in, simple ref, */ +/* 38 */ NdrFcShort( 0x10 ), /* X64 Stack size/offset = 16 */ +/* 40 */ NdrFcShort( 0x6 ), /* Type Offset=6 */ + + /* Parameter request */ + +/* 42 */ NdrFcShort( 0x2150 ), /* Flags: out, base type, simple ref, srv alloc size=8 */ +/* 44 */ NdrFcShort( 0x18 ), /* X64 Stack size/offset = 24 */ +/* 46 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + /* Parameter responseSize */ + +/* 48 */ NdrFcShort( 0x2013 ), /* Flags: must size, must free, out, srv alloc size=8 */ +/* 50 */ NdrFcShort( 0x20 ), /* X64 Stack size/offset = 32 */ +/* 52 */ NdrFcShort( 0x16 ), /* Type Offset=22 */ + + /* Parameter response */ + +/* 54 */ NdrFcShort( 0x70 ), /* Flags: out, return, base type, */ +/* 56 */ NdrFcShort( 0x28 ), /* X64 Stack size/offset = 40 */ +/* 58 */ 0x8, /* FC_LONG */ + 0x0, /* 0 */ + + 0x0 + } + }; + +/*static*/ const KMSServer_MIDL_TYPE_FORMAT_STRING KMSServer__MIDL_TypeFormatString = + { + 0, + { + NdrFcShort( 0x0 ), /* 0 */ +/* 2 */ + 0x11, 0x0, /* FC_RP */ +/* 4 */ NdrFcShort( 0x2 ), /* Offset= 2 (6) */ +/* 6 */ + 0x1b, /* FC_CARRAY */ + 0x0, /* 0 */ +/* 8 */ NdrFcShort( 0x1 ), /* 1 */ +/* 10 */ 0x28, /* Corr desc: parameter, FC_LONG */ + 0x0, /* */ +/* 12 */ NdrFcShort( 0x8 ), /* X64 Stack size/offset = 8 */ +/* 14 */ NdrFcShort( 0x1 ), /* Corr flags: early, */ +/* 16 */ 0x2, /* FC_CHAR */ + 0x5b, /* FC_END */ +/* 18 */ + 0x11, 0xc, /* FC_RP [alloced_on_stack] [simple_pointer] */ +/* 20 */ 0x8, /* FC_LONG */ + 0x5c, /* FC_PAD */ +/* 22 */ + 0x11, 0x14, /* FC_RP [alloced_on_stack] [pointer_deref] */ +/* 24 */ NdrFcShort( 0x2 ), /* Offset= 2 (26) */ +/* 26 */ + 0x12, 0x0, /* FC_UP */ +/* 28 */ NdrFcShort( 0x2 ), /* Offset= 2 (30) */ +/* 30 */ + 0x1b, /* FC_CARRAY */ + 0x0, /* 0 */ +/* 32 */ NdrFcShort( 0x1 ), /* 1 */ +/* 34 */ 0x28, /* Corr desc: parameter, FC_LONG */ + 0x54, /* FC_DEREFERENCE */ +/* 36 */ NdrFcShort( 0x18 ), /* X64 Stack size/offset = 24 */ +/* 38 */ NdrFcShort( 0x1 ), /* Corr flags: early, */ +/* 40 */ 0x2, /* FC_CHAR */ + 0x5b, /* FC_END */ + + 0x0 + } + }; + +static const unsigned short KMSServer_FormatStringOffsetTable[] = + { + 0 + }; + + +static const RPC_DISPATCH_FUNCTION KMSServer_table[] = + { + NdrServerCall2, + 0 + }; +/*static*/ const RPC_DISPATCH_TABLE KMSServer_v1_0_DispatchTable = + { + 1, + (RPC_DISPATCH_FUNCTION*)KMSServer_table + }; + + +#endif /* defined(_M_AMD64)*/ + + + +/* this ALWAYS GENERATED file contains the RPC server stubs */ + + + /* File created by MIDL compiler version 8.00.0603 */ +/* at Fri Feb 20 04:17:07 2015 + */ +/* Compiler settings for KMSServer.idl: + Oicf, W1, Zp8, env=Win64 (32b run), target_arch=AMD64 8.00.0603 + protocol : all , ms_ext, c_ext, robust + error checks: allocation ref bounds_check enum stub_data + VC __declspec() decoration level: + __declspec(uuid()), __declspec(selectany), __declspec(novtable) + DECLSPEC_UUID(), MIDL_INTERFACE() +*/ +/* @@MIDL_FILE_HEADING( ) */ + +#if defined(_M_AMD64) + + +#pragma warning( disable: 4049 ) /* more than 64k source lines */ + + +#if !defined(__RPC_WIN64__) +#error Invalid build platform for this stub. +#endif + + +#include "ndr64types.h" +#include "pshpack8.h" + + +typedef +struct +{ + NDR64_FORMAT_UINT32 frag1; + struct _NDR64_EXPR_OPERATOR frag2; + struct _NDR64_EXPR_VAR frag3; +} +__midl_frag13_t; +extern const __midl_frag13_t __midl_frag13; + +typedef +struct +{ + struct _NDR64_CONF_ARRAY_HEADER_FORMAT frag1; + struct _NDR64_ARRAY_ELEMENT_INFO frag2; +} +__midl_frag12_t; +extern const __midl_frag12_t __midl_frag12; + +typedef +struct _NDR64_POINTER_FORMAT +__midl_frag11_t; +extern const __midl_frag11_t __midl_frag11; + +typedef +struct _NDR64_POINTER_FORMAT +__midl_frag10_t; +extern const __midl_frag10_t __midl_frag10; + +typedef +struct _NDR64_POINTER_FORMAT +__midl_frag8_t; +extern const __midl_frag8_t __midl_frag8; + +typedef +NDR64_FORMAT_CHAR +__midl_frag7_t; +extern const __midl_frag7_t __midl_frag7; + +typedef +struct +{ + NDR64_FORMAT_UINT32 frag1; + struct _NDR64_EXPR_VAR frag2; +} +__midl_frag6_t; +extern const __midl_frag6_t __midl_frag6; + +typedef +struct +{ + struct _NDR64_CONF_ARRAY_HEADER_FORMAT frag1; + struct _NDR64_ARRAY_ELEMENT_INFO frag2; +} +__midl_frag5_t; +extern const __midl_frag5_t __midl_frag5; + +typedef +struct _NDR64_POINTER_FORMAT +__midl_frag4_t; +extern const __midl_frag4_t __midl_frag4; + +typedef +NDR64_FORMAT_CHAR +__midl_frag3_t; +extern const __midl_frag3_t __midl_frag3; + +typedef +struct +{ + struct _NDR64_PROC_FORMAT frag1; + struct _NDR64_BIND_AND_NOTIFY_EXTENSION frag2; + struct _NDR64_PARAM_FORMAT frag3; + struct _NDR64_PARAM_FORMAT frag4; + struct _NDR64_PARAM_FORMAT frag5; + struct _NDR64_PARAM_FORMAT frag6; + struct _NDR64_PARAM_FORMAT frag7; +} +__midl_frag2_t; +extern const __midl_frag2_t __midl_frag2; + +typedef +NDR64_FORMAT_UINT32 +__midl_frag1_t; +extern const __midl_frag1_t __midl_frag1; + +/*static*/ const __midl_frag13_t __midl_frag13 = +{ +/* */ + (NDR64_UINT32) 1 /* 0x1 */, + { + /* struct _NDR64_EXPR_OPERATOR */ + 0x4, /* FC_EXPR_OPER */ + 0x5, /* OP_UNARY_INDIRECTION */ + 0x5, /* FC64_INT32 */ + (NDR64_UINT8) 0 /* 0x0 */ + }, + { + /* struct _NDR64_EXPR_VAR */ + 0x3, /* FC_EXPR_VAR */ + 0x7, /* FC64_INT64 */ + (NDR64_UINT16) 0 /* 0x0 */, + (NDR64_UINT32) 24 /* 0x18 */ /* Offset */ + } +}; + +/*static*/ const __midl_frag12_t __midl_frag12 = +{ +/* *char */ + { + /* *char */ + 0x41, /* FC64_CONF_ARRAY */ + (NDR64_UINT8) 0 /* 0x0 */, + { + /* *char */ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + }, + (NDR64_UINT8) 0 /* 0x0 */, + (NDR64_UINT32) 1 /* 0x1 */, + &__midl_frag13 + }, + { + /* struct _NDR64_ARRAY_ELEMENT_INFO */ + (NDR64_UINT32) 1 /* 0x1 */, + &__midl_frag7 + } +}; + +/*static*/ const __midl_frag11_t __midl_frag11 = +{ +/* *char */ + 0x21, /* FC64_UP */ + (NDR64_UINT8) 0 /* 0x0 */, + (NDR64_UINT16) 0 /* 0x0 */, + &__midl_frag12 +}; + +/*static*/ const __midl_frag10_t __midl_frag10 = +{ +/* **char */ + 0x20, /* FC64_RP */ + (NDR64_UINT8) 20 /* 0x14 */, + (NDR64_UINT16) 0 /* 0x0 */, + &__midl_frag11 +}; + +/*static*/ const __midl_frag8_t __midl_frag8 = +{ +/* *int */ + 0x20, /* FC64_RP */ + (NDR64_UINT8) 12 /* 0xc */, + (NDR64_UINT16) 0 /* 0x0 */, + &__midl_frag3 +}; + +/*static*/ const __midl_frag7_t __midl_frag7 = +0x10 /* FC64_CHAR */; + +/*static*/ const __midl_frag6_t __midl_frag6 = +{ +/* */ + (NDR64_UINT32) 1 /* 0x1 */, + { + /* struct _NDR64_EXPR_VAR */ + 0x3, /* FC_EXPR_VAR */ + 0x5, /* FC64_INT32 */ + (NDR64_UINT16) 0 /* 0x0 */, + (NDR64_UINT32) 8 /* 0x8 */ /* Offset */ + } +}; + +/*static*/ const __midl_frag5_t __midl_frag5 = +{ +/* *char */ + { + /* *char */ + 0x41, /* FC64_CONF_ARRAY */ + (NDR64_UINT8) 0 /* 0x0 */, + { + /* *char */ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + }, + (NDR64_UINT8) 0 /* 0x0 */, + (NDR64_UINT32) 1 /* 0x1 */, + &__midl_frag6 + }, + { + /* struct _NDR64_ARRAY_ELEMENT_INFO */ + (NDR64_UINT32) 1 /* 0x1 */, + &__midl_frag7 + } +}; + +/*static*/ const __midl_frag4_t __midl_frag4 = +{ +/* *char */ + 0x20, /* FC64_RP */ + (NDR64_UINT8) 0 /* 0x0 */, + (NDR64_UINT16) 0 /* 0x0 */, + &__midl_frag5 +}; + +/*static*/ const __midl_frag3_t __midl_frag3 = +0x5 /* FC64_INT32 */; + +/*static*/ const __midl_frag2_t __midl_frag2 = +{ +/* RequestActivation */ + { + /* RequestActivation */ /* procedure RequestActivation */ + (NDR64_UINT32) 23986240 /* 0x16e0040 */, /* explicit handle */ /* IsIntrepreted, ServerMustSize, ClientMustSize, HasReturn, ServerCorrelation, ClientCorrelation, HasExtensions */ + (NDR64_UINT32) 48 /* 0x30 */ , /* Stack size */ + (NDR64_UINT32) 8 /* 0x8 */, + (NDR64_UINT32) 40 /* 0x28 */, + (NDR64_UINT16) 0 /* 0x0 */, + (NDR64_UINT16) 0 /* 0x0 */, + (NDR64_UINT16) 5 /* 0x5 */, + (NDR64_UINT16) 8 /* 0x8 */ + }, + { + /* struct _NDR64_BIND_AND_NOTIFY_EXTENSION */ + { + /* struct _NDR64_BIND_AND_NOTIFY_EXTENSION */ + 0x72, /* FC64_BIND_PRIMITIVE */ + (NDR64_UINT8) 0 /* 0x0 */, + 0 /* 0x0 */, /* Stack offset */ + (NDR64_UINT8) 0 /* 0x0 */, + (NDR64_UINT8) 0 /* 0x0 */ + }, + (NDR64_UINT16) 0 /* 0x0 */ /* Notify index */ + }, + { + /* requestSize */ /* parameter requestSize */ + &__midl_frag3, + { + /* requestSize */ + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + (NDR64_UINT16) 0 /* 0x0 */, + 0 + }, /* [in], Basetype, ByValue */ + (NDR64_UINT16) 0 /* 0x0 */, + 8 /* 0x8 */, /* Stack offset */ + }, + { + /* request */ /* parameter request */ + &__midl_frag5, + { + /* request */ + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + (NDR64_UINT16) 0 /* 0x0 */, + 0 + }, /* MustSize, MustFree, [in], SimpleRef */ + (NDR64_UINT16) 0 /* 0x0 */, + 16 /* 0x10 */, /* Stack offset */ + }, + { + /* responseSize */ /* parameter responseSize */ + &__midl_frag3, + { + /* responseSize */ + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + (NDR64_UINT16) 0 /* 0x0 */, + 1 + }, /* [out], Basetype, SimpleRef, UseCache */ + (NDR64_UINT16) 0 /* 0x0 */, + 24 /* 0x18 */, /* Stack offset */ + }, + { + /* response */ /* parameter response */ + &__midl_frag10, + { + /* response */ + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + (NDR64_UINT16) 0 /* 0x0 */, + 1 + }, /* MustSize, MustFree, [out], UseCache */ + (NDR64_UINT16) 0 /* 0x0 */, + 32 /* 0x20 */, /* Stack offset */ + }, + { + /* int */ /* parameter int */ + &__midl_frag3, + { + /* int */ + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + (NDR64_UINT16) 0 /* 0x0 */, + 0 + }, /* [out], IsReturn, Basetype, ByValue */ + (NDR64_UINT16) 0 /* 0x0 */, + 40 /* 0x28 */, /* Stack offset */ + } +}; + +/*static*/ const __midl_frag1_t __midl_frag1 = +(NDR64_UINT32) 0 /* 0x0 */; + + +#include "poppack.h" + + +static const FormatInfoRef KMSServer_Ndr64ProcTable[] = + { + &__midl_frag2 + }; + +//typedef void *__RPC_USER MIDL_user_allocate_t(SIZE_T); +typedef void *(__RPC_API *midl_allocate_t)(size_t); + +/*static*/ const MIDL_STUB_DESC KMSServer_StubDesc = + { + (void *)& KMSServer___RpcServerInterface, + (midl_allocate_t)MIDL_user_allocate, + MIDL_user_free, + 0, + 0, + 0, + 0, + 0, + KMSServer__MIDL_TypeFormatString.Format, + 1, /* -error bounds_check flag */ + 0x60000, /* Ndr library version */ + 0, + 0x800025b, /* MIDL Version 8.0.603 */ + 0, + 0, + 0, /* notify & notify_flag routine table */ + 0x2000001, /* MIDL flag */ + 0, /* cs routines */ + (void *)& KMSServer_ServerInfo, /* proxy/server info */ + 0 + }; + +static const RPC_DISPATCH_FUNCTION KMSServer_NDR64__table[] = + { + NdrServerCallAll, + 0 + }; +static const RPC_DISPATCH_TABLE KMSServer_NDR64__v1_0_DispatchTable = + { + 1, + (RPC_DISPATCH_FUNCTION*)KMSServer_NDR64__table + }; + +static const MIDL_SYNTAX_INFO KMSServer_SyntaxInfo [ 2 ] = + { + { + {{0x8A885D04,0x1CEB,0x11C9,{0x9F,0xE8,0x08,0x00,0x2B,0x10,0x48,0x60}},{2,0}}, + (RPC_DISPATCH_TABLE*)&KMSServer_v1_0_DispatchTable, + KMSServer__MIDL_ProcFormatString.Format, + KMSServer_FormatStringOffsetTable, + KMSServer__MIDL_TypeFormatString.Format, + 0, + 0, + 0 + } + ,{ + {{0x71710533,0xbeba,0x4937,{0x83,0x19,0xb5,0xdb,0xef,0x9c,0xcc,0x36}},{1,0}}, + (RPC_DISPATCH_TABLE*)&KMSServer_NDR64__v1_0_DispatchTable, + 0 , + (unsigned short *) KMSServer_Ndr64ProcTable, + 0, + 0, + 0, + 0 + } + }; + + +static const SERVER_ROUTINE KMSServer_ServerRoutineTable[] = + { + (SERVER_ROUTINE)ProcessActivationRequest + }; + +/*static*/ const MIDL_SERVER_INFO KMSServer_ServerInfo = + { + &KMSServer_StubDesc, + KMSServer_ServerRoutineTable, + KMSServer__MIDL_ProcFormatString.Format, + (unsigned short *) KMSServer_FormatStringOffsetTable, + 0, + (RPC_SYNTAX_IDENTIFIER*)&_NDR64_RpcTransferSyntax, + 2, + (MIDL_SYNTAX_INFO*)KMSServer_SyntaxInfo + }; +#if _MSC_VER >= 1200 +#pragma warning(pop) +#endif + + +#endif /* defined(_M_AMD64)*/ + diff --git a/vlmcsd/src/Makefile b/vlmcsd/src/Makefile new file mode 100644 index 0000000..fe11e88 --- /dev/null +++ b/vlmcsd/src/Makefile @@ -0,0 +1,35 @@ +SRCDIR := ./ +BINDIR := bin +OBJDIR := build + +TARGETS := $(BINDIR)/vlmcs $(BINDIR)/vlmcsd + +.PHONY: all +all: $(BINDIR) $(TARGETS) + +$(BINDIR)/vlmcs: $(OBJDIR)/vlmcs.o $(OBJDIR)/kmsdata-full.o $(OBJDIR)/crypto.o \ + $(OBJDIR)/kms.o $(OBJDIR)/endian.o $(OBJDIR)/output.o \ + $(OBJDIR)/shared_globals.o $(OBJDIR)/helpers.o \ + $(OBJDIR)/network.o $(OBJDIR)/rpc.o \ + $(OBJDIR)/crypto_internal.o $(OBJDIR)/dns_srv.o + $(CC) $(LDFLAGS) -o $@ $^ + +$(BINDIR)/vlmcsd: $(OBJDIR)/vlmcsd.o $(OBJDIR)/kmsdata.o $(OBJDIR)/crypto.o \ + $(OBJDIR)/kms.o $(OBJDIR)/endian.o $(OBJDIR)/output.o \ + $(OBJDIR)/shared_globals.o $(OBJDIR)/helpers.o \ + $(OBJDIR)/network.o $(OBJDIR)/rpc.o \ + $(OBJDIR)/crypto_internal.o + $(CC) $(LDFLAGS) -o $@ $^ + +$(OBJDIR)/%.o: $(SRCDIR)/%.c | $(OBJDIR) + $(CC) $(CFLAGS) -c $< -o $@ + +$(OBJDIR): + @mkdir -p $(OBJDIR) + +$(BINDIR): + @mkdir -p $(BINDIR) + +.PHONY: clean +clean: + @rm -rf $(OBJDIR) $(BINDIR) diff --git a/vlmcsd/src/config.h b/vlmcsd/src/config.h new file mode 100644 index 0000000..b584ed5 --- /dev/null +++ b/vlmcsd/src/config.h @@ -0,0 +1,674 @@ +#ifndef CONFIG_H_ +#define CONFIG_H_ + +/* Don't change anything ABOVE this line */ + +/* + * As a best practice do not change the original config.h as distributed with vlmcsd. + * Instead make a copy, e.g. myconfig.h, customize it and type 'make CONFIG=myconfig.h' + * to build vlmcsd. This prevents your copy being overwritten when you upgrade to a + * new version. + */ + + + + /* + * ---------------------------------------------------------------------------------------- + * Useful customizations. These options are mandatory. You cannot comment them out. + * Feel free to change them to fit your needs. + * ---------------------------------------------------------------------------------------- + */ + +#ifndef VERSION + /* + * Define your own version identifier here, e.g. '#define VERSION "my vlmcsd based on 1103"' + */ + +#define VERSION "private build" + +#endif // VERSION + + + + + +#ifndef HWID // HwId from the Ratiborus VM +#define HWID 0x3A, 0x1C, 0x04, 0x96, 0x00, 0xB6, 0x00, 0x76 +#endif + + + + + +/* + * Anything below this line is optional. If you want to use any of these options + * uncomment one or more lines starting with "//#define" + */ + + + + /* + * ------------------------------- + * Defaults + * ------------------------------- + */ + + + +#ifndef INI_FILE + /* + * Uncomment and customize the following line if you want vlmcsd to look for an ini file + * at a default location. + */ + + //#define INI_FILE "/etc/vlmcsd.ini" + +#endif // INI_FILE + + + + + +#ifndef DATA_FILE +/* + * Uncomment and customize the following line if you want vlmcsd to look for a KMS data file + * at a custom default location. + */ + + //#define DATA_FILE "/etc/vlmcsd.kmd" + +#endif // DATA_FILE + + +/* + * ---------------------------------------------------------------------------------------- + * Troubleshooting options. Please note that disabling features may also help troubleshooting. + * If you have an old OS that does not support features like pthreads, shared memory or + * semaphores, uncomment "#define NO_LIMIT" and "#define NO_SIGHUP" and leave "#define USE_THREADS" + * commented out. + * ---------------------------------------------------------------------------------------- + */ + + +#ifndef CHILD_HANDLER + /* + * Uncomment the following #define if you are compiling for a platform that does + * not correctly handle the SA_NOCLDWAIT flag when ignoring SIGCHLD, i.e. forked + * processes remain as "zombies" after dying. This option will add a SIGCHLD handler that + * "waits" for a child that has terminated. This is only required for a few + * unixoid OSses. + */ + + //#define CHILD_HANDLER + +#endif // CHILD_HANDLER + + +#ifndef NO_TIMEOUT +/* + * Uncomment the following #define if you are compiling for a platform that does + * not support custom socket send or receive timeouts. + */ + + //#define NO_TIMEOUT + +#endif // NO_TIMEOUT + + +#ifndef NO_DNS +/* + * Uncomment the following #define if you have trouble with accessing routines + * from libresolv. If enabled, vlmcs will be compiled without support for + * detecting KMS servers via DNS. + */ + + //#define NO_DNS + +#endif // NO_DNS + + +#ifndef TERMINAL_FIXED_WIDTH +/* + * Uncomment the following #define and optionally change its value if you are compiling for + * a platform that cannot properly determine the width of a terminal/command prompt. + * This affects the output of "vlmcsd -x" only. It should be rarely necessary to use this. + */ + + //#define TERMINAL_FIXED_WIDTH 80 + +#endif // TERMINAL_FIXED_WIDTH + + + + +#ifndef _PEDANTIC +/* + * Uncomment the following #define if you want to do vlmcs and vlmcsd more checks on the data + * it receives over the network. They are normally not necessary but may provide useful if + * you are testing any KMS server or client emulator that may send malformed KMS packets. + */ + + //#define _PEDANTIC + +#endif // _PEDANTIC + + + + +#ifndef NO_PROCFS +/* + * Cygwin, Linux, Android, NetBSD, DragonflyBSD: + * Do not rely on a properly mounted proc filesystem and use the less reliable + * argv[0] to determine the program's executable name. + * Use only if absolutely necessary (very old versions of these OSses). + * + * Minix, OpenBSD: + * This option has no effect since the OS always must use the less reliable argv[0]. + * + * FreeBSD, Mac OS X, iOS, Solaris, Windows: + * This option is not neccessary (and has no effect) since these OSses provide + * a reliable way to determine the executable name. + * + */ + + //#define NO_PROCFS + +#endif // NO_PROCFS + + + + +#ifndef USE_AUXV +/* + * Linux only: + * Use the process' ELF aux vector to determine the executable name. + * This is actually the best method but is supported only with + * + * * the musl library + * * the glbic library 2.16 or newer + * + * It does NOT work with uclibc (most routers and other small devices) and glibc < 2.16. + * Use it only if your system supports it and you do not plan to use the binary on older systems. + * It won't work on debian 7 or Red Hat 6.x. + * + * It is safe to try this by yourself. vlmcsd won't compile if your system doesn't support it. + */ + + //#define USE_AUXV + +#endif // USE_AUXV + + + + +#ifndef _OPENSSL_NO_HMAC +/* + * If you configured vlmcsd to use OpenSSL (which you shouldn't) you may use this option + * to calculate the KMSv6 HMAC with internal code instead of using OpenSSL. + * + * This may be necessary for some embedded devices that have OpenSSL without HMAC support. + */ + + //#define _OPENSSL_NO_HMAC + +#endif // _OPENSSL_NO_HMAC + + + + +/* + * ---------------------------------------------------------------------------------------- + * Modes of operation + * ---------------------------------------------------------------------------------------- + */ + + +#ifndef USE_THREADS + /* + * Do not use fork() but threads to serve your clients. + * + * Unix-like operarting systems: + * You may use this or not. Entirely your choice. Threads do not require explicitly allocating + * a shared memory segment which might be a problem on some systems. Using fork() is more robust + * although the threaded version of vlmcsd is rock solid too. + * + * Some older unixoid OSses may not have pthreads. Do NOT use USE_THREADS and define NO_SIGHUP + * and NO_LIMIT instead to disable use of the pthreads, shared memory and semaphores. + * + * Cygwin: + * It is recommended to use threads since fork() is extremely slow (no copy on write) and somewhat + * unstable. + * + * Windows: + * This option has no effect since fork() is not supported. + */ + + //#define USE_THREADS + +#endif // USE_THREADS + + + + +#ifndef _CRYPTO_POLARSSL +/* + * Not available on native Windows. Can be used with Cygwin. + * + * Use PolarSSL for crypto routines if possible and if it is safe. There is not much benefit by using this + * options since it can be used for SHA256 and HMAC_SHA256 only. It cannot be used for AES calculations because + * KMSv6 uses a modified algorithm that PolarSSL does not support. KMSv4 CMAC is also unsupported since it uses + * a Rijndael keysize (160 bits) that is not part of the AES standard. + * + * It is strongly recommended not to use an external crypto library. + * + * Do not define both _CRYPTO_OPENSSL and _CRYPTO_POLARSSL + */ + + //#define _CRYPTO_POLARSSL + +#endif // _CRYPTO_POLARSSL + + + + +#ifndef _CRYPTO_OPENSSL +/* + * Not available on native Windows. Can be used with Cygwin. + * + * Use OpenSSL for crypto routines if possible and if it is safe. There is not much benefit by using this + * options since it can be used for SHA256 and HMAC_SHA256 only. It cannot be used for AES calculations because + * KMSv6 uses a modified algorithm that OpenSSL does not support. KMSv4 CMAC is also unsupported since it uses + * a Rijndael keysize (160 bits) that is not part of the AES standard. + * + * It is strongly recommended not to use an external crypto library. + * + * Do not define both _CRYPTO_OPENSSL and _CRYPTO_POLARSSL + */ + + //#define _CRYPTO_OPENSSL + +#endif // _CRYPTO_OPENSSL + + + + +#ifndef _USE_AES_FROM_OPENSSL +/* + * DANGEROUS: Tweak OpenSSL to perform KMSv4 CMAC and KMSv6 modified AES. This option creates the expanded + * AES key by itself and then applies modifications to it. OpenSSL will then perfom modified AES operations. + * + * This options tampers with internal structures of OpenSSL that are subject to change or may have a platform + * specific implementation. In this case your resulting binary can only perform KMSv5 operations. + * + * This option has no effect if _CRYPTO_OPENSSL is not defined. + * + * Don't use this except for your own research on the internals of OpenSSL. + */ + + //#define _USE_AES_FROM_OPENSSL + +#endif // _USE_AES_FROM_OPENSSL + + + + + +#ifndef _OPENSSL_SOFTWARE +/* + * Use this only if you have defined _CRYPTO_OPENSSL and _USE_AES_FROM_OPENSSL. It has no effect otherwise. + * + * This options assumes a different internal AES expanded key in OpenSSL which is used mostly if OpenSSL is + * compiled without support for hardware accelerated AES. It's worth a try if _USE_AES_FROM_OPENSSL doesn't work. + */ + + //#define _OPENSSL_SOFTWARE + +#endif // _OPENSSL_SOFTWARE + + + + +#ifndef FULL_INTERNAL_DATA +/* + * Includes the full database in vlmcsd. + */ + + //#define FULL_INTERNAL_DATA +#endif // FULL_INTERNAL_DATA + + + + +/* + * ---------------------------------------------------------------------------------------- + * Removal of features. Allows you to remove features of vlmcsd you do not need or want. + * Use it to get smaller binaries. This is especially useful on very small embedded devices. + * ---------------------------------------------------------------------------------------- + */ + + +#ifndef NO_FREEBIND + /* + * Do not compile support for FREEBIND (Linux) and IP_BINDANY (FreeBSD). This disables the -F1 command + * line option and you can bind only to (listen on) IP addresses that are currently up and running on + * your system. + */ + +//#define NO_FREEBIND + +#endif // NO_FREEBIND + + + + +#ifndef NO_TAP + /* + * Do not compile support for using a VPN adapter under Windows. Disables -O command line option. + */ + +//#define NO_TAP + +#endif // NO_TAP + + + + +#ifndef NO_VERSION_INFORMATION +/* + * Removes the -V option from vlmcsd and vlmcs that displays the version information + */ + + //#define NO_VERSION_INFORMATION + +#endif // NO_VERSION_INFORMATION + + + + +#ifndef NO_VERBOSE_LOG +/* + * Removes the ability to do verbose logging and disables -v and -q in vlmcsd. It does not remove the -v + * option in the vlmcs client. Disables ini file directive LogVerbose. + */ + + //#define NO_VERBOSE_LOG + +#endif // NO_VERBOSE_LOG + + + + +#ifndef NO_LOG +/* + * Disables logging completely. You can neither log to a file nor to the console. -D and -f will + * start vlmcsd in foreground. -e will not be available. Disables ini file directive LogFile. + * Implies NO_VERBOSE_LOG. + */ + + //#define NO_LOG + +#endif // NO_LOG + + + + +#ifndef NO_STRICT_MODES +/* + * Disables emulator detection protection. Removes -M0, -M1, -E0, -E1, -K0, -K1, -K2 and -K3 from + * vlmcsd command line options and WhitelistingLevel from INI file parameters. vlmcsd always behaves + * as if it was started with -K0, -M0. + */ + + //#define NO_STRICT_MODES + +#endif // NO_STRICT_MODES + + + + + +#ifndef NO_CLIENT_LIST +/* + * Disables the ability to maintain a list of Client Machine IDs (CMIDs). Removes -M0, -M1, -E0 and -E1 + * from vlmcsd command line options. + */ + + //#define NO_CLIENT_LIST + +#endif // !NO_CLIENT_LIST + + + +#ifndef NO_RANDOM_EPID + /* + * Disables the ability to generate random ePIDs. Useful if you managed to grab ePID/HWID from a + * real KMS server and want to use these. Removes -r from the vlmcsd command line and the ini + * file directive RandomizationLevel (The randomization level will be harcoded to 0). + */ + + //#define NO_RANDOM_EPID + +#endif // NO_RANDOM_EPID + + + + +#ifndef NO_INI_FILE +/* + * Disables the ability to use a configuration file (aka ini file). Removes -i from the command line. + */ + + //#define NO_INI_FILE + +#endif // NO_INI_FILE + + + + +#ifndef NO_PID_FILE + /* + * Disables the abilty to write a pid file containing the process id of vlmcsd. If your init system + * does not need this feature, you can safely disables this but it won't save much space. Disables + * the use of -p from the command line and PidFile from the ini file. + */ + + //#define NO_PID_FILE + +#endif // NO_PID_FILE + + + + +#ifndef NO_EXTERNAL_DATA + /* + * Disables the abilty to load external KMS data from a file. Disables command line options -j + * and ini file parameter KmsData. Implies UNSAFE_DATA_LOAD. + */ + + //#define NO_EXTERNAL_DATA + +#endif // NO_EXTERNAL_DATA + + + + +#ifndef NO_INTERNAL_DATA + /* + * Compiles vlmcsd and vlmcs without an internal database. If no database is found at + * either the default location or the file specified with command line option -j., + * the program exits with an error message. + */ + + //#define NO_INTERNAL_DATA + +#endif // NO_INTERNAL_DATA + + + + +#ifndef UNSAFE_DATA_LOAD + /* + * Does not check an external KMS data file for integrity. + * This save some bytes but it dangerous if you load a KMS data file from an unknown source. + */ + + //#define UNSAFE_DATA_LOAD + +#endif // UNSAFE_DATA_LOAD + + + + +#ifndef NO_USER_SWITCH +/* + * Disables switching to another uid and/or gid after starting the program and setting up the sockets. + * You cannot use -u anf -g on the command line as well as User and Group in the ini file. If your init system + * supports starting daemons as another uid/gid (user/group) you can disable this feature in vlmcsd as long as you + * do not need to run vlmcsd on a privileged port ( < 1024 on most systems). + * + * This setting has no effect on native Windows since -u and -g is not available anyway. It may be used with + * Cygwin. + */ + + //#define NO_USER_SWITCH + +#endif // NO_USER_SWITCH + + + + +#ifndef NO_HELP +/* + * Disables display of help in both vlmcsd and vlmcs. Saves some bytes but only makes sense if you have + * access to the man files vlmcsd.8 and vlmcs.1 + */ + + //#define NO_HELP + +#endif // NO_HELP + + + + +#ifndef NO_CUSTOM_INTERVALS +/* + * Disables the ability to specify custom interval for renewing and retrying activation. Newer versions of the Microsoft's + * KMS activation client (as in Win 8.1) do not honor these parameters anyway. Disable them to save some bytes. Removes + * -A and -R from the command line as well as ActivationInterval and RenewalInterval in the ini file. + */ + + //#define NO_CUSTOM_INTERVALS + +#endif // NO_CUSTOM_INTERVALS + + + + +#ifndef NO_PRIVATE_IP_DETECT +/* + * Disables the ability to protect vlmcsd against KMS requests from public IP addresses. + * Removes -o from the command line. + */ + + //#define NO_PRIVATE_IP_DETECT + +#endif // NO_PRIVATE_IP_DETECT + + + + +#ifndef NO_SOCKETS +/* + * Disables standalone startup of vlmcsd. If you use this config directive, you must start vlmcsd from an internet + * superserver like inetd, xinetd, systemd or launchd. Disables -m, -t, -4, -6, -e, -f, -P and -L in the vlmcsd + * command line. Socket setup is the job of your superserver. + */ + + //#define NO_SOCKETS + +#endif // NO_SOCKETS + + + + +#ifndef NO_CL_PIDS +/* + * Disables the ability to specify ePIDs and HWID at the command line. You still may use them in the ini file. + * Removes -0, -3, -w and -H from the vlmcsd command line. + */ + + //#define NO_CL_PIDS + +#endif // NO_CL_PIDS + + + + +#ifndef NO_LIMIT +/* + * Disables the ability to limit the number of worker threads or processes that vlmcsd uses. While you should set a + * limit whenever possible, you may save some bytes by enabling that setting. If you do not use a limit, use vlmcsd + * in a "friendly" environment only, i.e. do not run it without a reasonable limit on the internet. + * + * Removes the ability to use -m in the vlmcsd command line and MaxWorkers in the ini file. + * + * Some older unixoid OSses may not have pthreads. Do NOT use USE_THREADS and define NO_SIGHUP + * and NO_LIMIT instead to disable use of the pthreads, shared memory and semaphores. + */ + + //#define NO_LIMIT + +#endif // NO_LIMIT + + + + +#ifndef NO_SIGHUP +/* + * Disables the ability to signal hangup (SIGHUP) to vlmcsd to restart it (rereading the ini file). The SIGHUP + * handler makes heavy use of OS specific code. It should not cause any trouble on Solaris, Mac OS X and iOS. On Linux + * use "#define USE_AUXV" (see troubleshooting options) if this is supported by your C runtime library. + * + * You may save some bytes by enabling this option. Use it also if the SIGHUP handler causes any trouble on your + * platform. Please note that with no SIGHUP handler at all. vlmcsd will simply terminate (uncleanly) if it receives + * the SIGHUP signal. This is the same behavior as with most other signals. + * + * This option has no effect on native Windows since Posix signaling is not supported. It can be used with Cygwin. + */ + + //#define NO_SIGHUP + +#endif // NO_SIGHUP + + + + +#ifndef SIMPLE_RPC +/* + * Uses a simple version of the RPC protocol which does not support NDR64 and BTFN. + * Supports RPC with the features present in Windows XP and earlier only. Using this creates + * smaller binaries but makes emulator detection easier. + */ + + //#define SIMPLE_RPC +#endif // !SIMPLE_RPC + + + + +#ifndef SIMPLE_SOCKETS +/* + * Disables the ability to choose IP addresses using the -L option in vlmcsd. vlmcsd will listen on all IP addresses. + * It still supports IPv4 and IPv6. + */ + + //#define SIMPLE_SOCKETS + +#endif // SIMPLE_SOCKETS + + + +/* Don't change anything BELOW this line */ + + +#endif /* CONFIG_H_ */ diff --git a/vlmcsd/src/crypto.c b/vlmcsd/src/crypto.c new file mode 100644 index 0000000..e73ffa3 --- /dev/null +++ b/vlmcsd/src/crypto.c @@ -0,0 +1,338 @@ +#ifndef CONFIG +#define CONFIG "config.h" +#endif // CONFIG +#include CONFIG + +#include "crypto.h" +#include "endian.h" +#include + +const BYTE AesKeyV4[] = { + 0x05, 0x3D, 0x83, 0x07, 0xF9, 0xE5, 0xF0, 0x88, 0xEB, 0x5E, 0xA6, 0x68, 0x6C, 0xF0, 0x37, 0xC7, 0xE4, 0xEF, 0xD2, 0xD6}; + +const BYTE AesKeyV5[] = { + 0xCD, 0x7E, 0x79, 0x6F, 0x2A, 0xB2, 0x5D, 0xCB, 0x55, 0xFF, 0xC8, 0xEF, 0x83, 0x64, 0xC4, 0x70 }; + +const BYTE AesKeyV6[] = { + 0xA9, 0x4A, 0x41, 0x95, 0xE2, 0x01, 0x43, 0x2D, 0x9B, 0xCB, 0x46, 0x04, 0x05, 0xD8, 0x4A, 0x21 }; + +static const BYTE SBox[] = { + 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, + 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, + 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, + 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, + 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, + 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, + 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, + 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, + 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, + 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, + 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, + 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, + 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, + 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, + 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, + 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16 +}; + + +void XorBlock(const BYTE *const in, const BYTE *out) // Ensure that this is always 32 bit aligned +{ + /*UAA64( out, 0 ) ^= UAA64( in, 0 ); + UAA64( out, 1 ) ^= UAA64( in, 1 );*/ + + uint_fast8_t i; + + for (i = 0; i < AES_BLOCK_WORDS; i++) + { + ((DWORD*)out)[i] ^= ((DWORD*)in)[i]; + } +} + +#define AddRoundKey(d, rk) XorBlock((const BYTE *)rk, (const BYTE *)d) + +#define Mul2(word) (((word & 0x7f7f7f7f) << 1) ^ (((word & 0x80808080) >> 7) * 0x1b)) +#define Mul3(word) (Mul2(word) ^ word) +#define Mul4(word) (Mul2(Mul2(word))) +#define Mul8(word) (Mul2(Mul2(Mul2(word)))) +#define Mul9(word) (Mul8(word) ^ word) +#define MulB(word) (Mul8(word) ^ Mul3(word)) +#define MulD(word) (Mul8(word) ^ Mul4(word) ^ word) +#define MulE(word) (Mul8(word) ^ Mul4(word) ^ Mul2(word)) + +//32 bit Galois Multiplication (generates bigger code than Macros) +/*static DWORD Mul(DWORD x, DWORD y) +{ + DWORD result = x, yTemp = y, log2; + + if (!y) return 0; + + for (log2 = 0; yTemp >>= 1; log2++ ) + { + result = Mul2(result); + } + + return result ^ Mul(x, y - (1 << log2)); +}*/ + + +void MixColumnsR(BYTE *restrict state) +{ + uint_fast8_t i = 0; + for (; i < AES_BLOCK_WORDS; i++) + { + #if defined(_CRYPTO_OPENSSL) && defined(_OPENSSL_SOFTWARE) && defined(_USE_AES_FROM_OPENSSL) //Always byte swap regardless of endianess + DWORD word = BS32(((DWORD *) state)[i]); + ((DWORD *) state)[i] = BS32(MulE(word) ^ ROR32(MulB(word), 8) ^ ROR32(MulD(word), 16) ^ ROR32(Mul9(word), 24)); + #else + DWORD word = LE32(((DWORD *) state)[i]); + ((DWORD *) state)[i] = LE32(MulE(word) ^ ROR32(MulB(word), 8) ^ ROR32(MulD(word), 16) ^ ROR32(Mul9(word), 24)); + #endif + } +} + + +static DWORD SubDword(DWORD v) +{ + BYTE *b = (BYTE *)&v; + uint_fast8_t i = 0; + + for (; i < sizeof(DWORD); i++) b[i] = SBox[b[i]]; + + return v; +} + + +void AesInitKey(AesCtx *Ctx, const BYTE *Key, int_fast8_t IsV6, int RijndaelKeyBytes) +{ + int RijndaelKeyDwords = RijndaelKeyBytes / sizeof(DWORD); + Ctx->rounds = (uint_fast8_t)(RijndaelKeyDwords + 6); + + static const DWORD RCon[] = { + 0x00000000, 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, + 0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000 }; + + uint_fast8_t i; + DWORD temp; + + memcpy(Ctx->Key, Key, RijndaelKeyBytes); + + for ( i = (uint_fast8_t)RijndaelKeyDwords; i < ( Ctx->rounds + 1 ) << 2; i++ ) + { + temp = Ctx->Key[ i - 1 ]; + + if ( ( i % RijndaelKeyDwords ) == 0 ) + temp = BE32( SubDword( ROR32( BE32(temp), 24) ) ^ RCon[ i / RijndaelKeyDwords ] ); + + Ctx->Key[ i ] = Ctx->Key[ i - RijndaelKeyDwords ] ^ temp; + } + + if ( IsV6 ) + { + BYTE *_p = (BYTE *)Ctx->Key; + + _p[ 4 * 16 ] ^= 0x73; + _p[ 6 * 16 ] ^= 0x09; + _p[ 8 * 16 ] ^= 0xE4; + } +} + + +#if !defined(_CRYPTO_OPENSSL) || !defined(_USE_AES_FROM_OPENSSL) || defined(_OPENSSL_SOFTWARE) +static void SubBytes(BYTE *block) +{ + uint_fast8_t i; + + for (i = 0; i < AES_BLOCK_BYTES; i++) + block[i] = SBox[ block[i] ]; +} + + +static void ShiftRows(BYTE *state) +{ + BYTE bIn[AES_BLOCK_BYTES]; + uint_fast8_t i; + + memcpy(bIn, state, AES_BLOCK_BYTES); + for (i = 0; i < AES_BLOCK_BYTES; i++) + { + state[i] = bIn[(i + ((i & 3) << 2)) & 0xf]; + } +}; + + +static void MixColumns(BYTE *state) +{ + uint_fast8_t i = 0; + for (; i < AES_BLOCK_WORDS; i++) + { + DWORD word = LE32(((DWORD *) state)[i]); + ((DWORD *) state)[i] = LE32(Mul2(word) ^ ROR32(Mul3(word), 8) ^ ROR32(word, 16) ^ ROR32(word, 24)); + } +} + + +void AesEncryptBlock(const AesCtx *const Ctx, BYTE *block) +{ + uint_fast8_t i; + + for ( i = 0 ;; i += 4 ) + { + AddRoundKey(block, &Ctx->Key[ i ]); + SubBytes(block); + ShiftRows(block); + + if ( i >= ( Ctx->rounds - 1 ) << 2 ) break; + + MixColumns(block); + } + + AddRoundKey(block, &Ctx->Key[ Ctx->rounds << 2 ]); +} + + +void AesCmacV4(BYTE *Message, size_t MessageSize, BYTE *MacOut) +{ + size_t i; + BYTE mac[AES_BLOCK_BYTES]; + AesCtx Ctx; + + AesInitKey(&Ctx, AesKeyV4, FALSE, V4_KEY_BYTES); + + memset(mac, 0, sizeof(mac)); + memset(Message + MessageSize, 0, AES_BLOCK_BYTES); + Message[MessageSize] = 0x80; + + for (i = 0; i <= MessageSize; i += AES_BLOCK_BYTES) + { + XorBlock(Message + i, mac); + AesEncryptBlock(&Ctx, mac); + } + + memcpy(MacOut, mac, AES_BLOCK_BYTES); +} +#endif + +#if !defined(_CRYPTO_OPENSSL) || !defined(_USE_AES_FROM_OPENSSL) + +#ifndef SMALL_AES + +static const BYTE SBoxR[] = { + 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB, + 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, + 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, + 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25, + 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, + 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84, + 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06, + 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, + 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, + 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E, + 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, + 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, + 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F, + 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, + 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D +}; + +#define GetSBoxR(x) SBoxR[x] + +#else // SMALL_AES + +static uint8_t SBoxR(uint8_t byte) +{ + uint8_t i; + + for (i = 0; TRUE; i++) + { + if (byte == SBox[i]) return i; + } +} + +#define GetSBoxR(x) SBoxR(x) + +#endif // SMALL_AES + + +static void ShiftRowsR(BYTE *state) +{ + BYTE b[AES_BLOCK_BYTES]; + uint_fast8_t i; + + memcpy(b, state, AES_BLOCK_BYTES); + + for (i = 0; i < AES_BLOCK_BYTES; i++) + state[i] = b[(i - ((i & 0x3) << 2)) & 0xf]; +} + + +static void SubBytesR(BYTE *block) +{ + uint_fast8_t i; + + for (i = 0; i < AES_BLOCK_BYTES; i++) + { + block[i] = GetSBoxR( block[i] ); + } +} + + +void AesEncryptCbc(const AesCtx *const Ctx, BYTE *restrict iv, BYTE *restrict data, size_t *restrict len) +{ + // Pad up to blocksize inclusive + size_t i; + uint_fast8_t pad = (~*len & (AES_BLOCK_BYTES - 1)) + 1; + + #if defined(__GNUC__) && (__GNUC__ == 4 && __GNUC_MINOR__ == 8) // gcc 4.8 memset bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56977 + for (i = 0; i < pad; i++) data[*len + i] = pad; + #else + memset(data + *len, pad, pad); + #endif + *len += pad; + + if ( iv ) XorBlock(iv, data); + AesEncryptBlock(Ctx, data); + + for (i = *len - AES_BLOCK_BYTES; i; i -= AES_BLOCK_BYTES) + { + XorBlock(data, data + AES_BLOCK_BYTES); + data += AES_BLOCK_BYTES; + AesEncryptBlock(Ctx, data); + } +} + + +void AesDecryptBlock(const AesCtx *const Ctx, BYTE *block) +{ + uint_fast8_t i; + + AddRoundKey(block, &Ctx->Key[ Ctx->rounds << 2 ]); + + for ( i = ( Ctx->rounds - 1 ) << 2 ;; i -= 4 ) + { + ShiftRowsR(block); + SubBytesR(block); + AddRoundKey(block, &Ctx->Key[ i ]); + + if ( i == 0 ) break; + + MixColumnsR(block); + } +} + + +void AesDecryptCbc(const AesCtx *const Ctx, BYTE *iv, BYTE *data, size_t len) +{ + BYTE *cc; + + for (cc = data + len - AES_BLOCK_BYTES; cc > data; cc -= AES_BLOCK_BYTES) + { + AesDecryptBlock(Ctx, cc); + XorBlock(cc - AES_BLOCK_BYTES, cc); + } + + AesDecryptBlock(Ctx, cc); + if ( iv ) XorBlock(iv, cc); +} +#endif // _CRYPTO_OPENSSL || OPENSSL_VERSION_NUMBER < 0x10000000L diff --git a/vlmcsd/src/crypto.h b/vlmcsd/src/crypto.h new file mode 100644 index 0000000..0e5f7dc --- /dev/null +++ b/vlmcsd/src/crypto.h @@ -0,0 +1,57 @@ +#ifndef __crypto_h +#define __crypto_h + +#ifndef CONFIG +#define CONFIG "config.h" +#endif // CONFIG +#include CONFIG + +#include "types.h" +#include +#include +#include +#include +#include "endian.h" +#include + +#define AES_KEY_BYTES (16) // 128 Bits +#define AES_BLOCK_BYTES (16) +#define AES_BLOCK_WORDS (AES_BLOCK_BYTES / sizeof(DWORD)) +#define AES_KEY_DWORDS (AES_KEY_BYTES / sizeof(DWORD)) +#define V4_KEY_BYTES (20) // 160 Bits + +#define ROR32(v, n) ( (v) << (32 - n) | (v) >> n ) + +void XorBlock(const BYTE *const in, const BYTE *out); + +void AesCmacV4(BYTE *data, size_t len, BYTE *hash); + +extern const BYTE AesKeyV5[]; +extern const BYTE AesKeyV6[]; + +typedef struct { + DWORD Key[48]; // Supports a maximum of 160 key bits! + uint_fast8_t rounds; +} AesCtx; + +void AesInitKey(AesCtx *Ctx, const BYTE *Key, int_fast8_t IsV6, int AesKeyBytes); +void AesEncryptBlock(const AesCtx *const Ctx, BYTE *block); +void AesDecryptBlock(const AesCtx *const Ctx, BYTE *block); +void AesEncryptCbc(const AesCtx *const Ctx, BYTE *restrict iv, BYTE *restrict data, size_t *restrict len); +void AesDecryptCbc(const AesCtx *const Ctx, BYTE *iv, BYTE *data, size_t len); +void MixColumnsR(BYTE *restrict state); + +#if defined(_CRYPTO_OPENSSL) +#include "crypto_openssl.h" + +#elif defined(_CRYPTO_POLARSSL) +#include "crypto_polarssl.h" + +#elif defined(_CRYPTO_WINDOWS) +#include "crypto_windows.h" + +#else +#include "crypto_internal.h" + +#endif +#endif // __crypto_h diff --git a/vlmcsd/src/crypto_internal.c b/vlmcsd/src/crypto_internal.c new file mode 100644 index 0000000..8733db3 --- /dev/null +++ b/vlmcsd/src/crypto_internal.c @@ -0,0 +1,212 @@ +#ifndef CONFIG +#define CONFIG "config.h" +#endif // CONFIG +#include CONFIG + +#if !defined(_CRYPTO_OPENSSL) && !defined(_CRYPTO_POLARSSL) && !defined(_CRYPTO_WINDOWS) +#include "crypto_internal.h" +#include "endian.h" + +#define F0(x, y, z) ( ((x) & (y)) | (~(x) & (z)) ) +#define F1(x, y, z) ( ((x) & (y)) | ((x) & (z)) | ((y) & (z)) ) + +#define SI1(x) ( ROR32(x, 2 ) ^ ROR32(x, 13) ^ ROR32(x, 22) ) +#define SI2(x) ( ROR32(x, 6 ) ^ ROR32(x, 11) ^ ROR32(x, 25) ) +#define SI3(x) ( ROR32(x, 7 ) ^ ROR32(x, 18) ^ ((x) >> 3 ) ) +#define SI4(x) ( ROR32(x, 17) ^ ROR32(x, 19) ^ ((x) >> 10) ) + +static const DWORD k[] = { + 0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5, 0x3956C25B, 0x59F111F1, + 0x923F82A4, 0xAB1C5ED5, 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3, + 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174, 0xE49B69C1, 0xEFBE4786, + 0x0FC19DC6, 0x240CA1CC, 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA, + 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7, 0xC6E00BF3, 0xD5A79147, + 0x06CA6351, 0x14292967, 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13, + 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85, 0xA2BFE8A1, 0xA81A664B, + 0xC24B8B70, 0xC76C51A3, 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070, + 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5, 0x391C0CB3, 0x4ED8AA4A, + 0x5B9CCA4F, 0x682E6FF3, 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208, + 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2 +}; + + +static void Sha256Init(Sha256Ctx *Ctx) +{ + Ctx->State[0] = 0x6A09E667; + Ctx->State[1] = 0xBB67AE85; + Ctx->State[2] = 0x3C6EF372; + Ctx->State[3] = 0xA54FF53A; + Ctx->State[4] = 0x510E527F; + Ctx->State[5] = 0x9B05688C; + Ctx->State[6] = 0x1F83D9AB; + Ctx->State[7] = 0x5BE0CD19; + Ctx->Len = 0; +} + + +static void Sha256ProcessBlock(Sha256Ctx *Ctx, BYTE *block) +{ + unsigned int i; + DWORD w[64], temp1, temp2; + DWORD a = Ctx->State[0]; + DWORD b = Ctx->State[1]; + DWORD c = Ctx->State[2]; + DWORD d = Ctx->State[3]; + DWORD e = Ctx->State[4]; + DWORD f = Ctx->State[5]; + DWORD g = Ctx->State[6]; + DWORD h = Ctx->State[7]; + + for (i = 0; i < 16; i++) + //w[ i ] = GET_UAA32BE(block, i); + w[i] = BE32(((DWORD*)block)[i]); + + for (i = 16; i < 64; i++) + w[ i ] = SI4(w[ i - 2 ]) + w[ i - 7 ] + SI3(w[ i - 15 ]) + w[ i - 16 ]; + + for (i = 0; i < 64; i++) + { + temp1 = h + SI2(e) + F0(e, f, g) + k[ i ] + w[ i ]; + temp2 = SI1(a) + F1(a, b, c); + + h = g; + g = f; + f = e; + e = d + temp1; + d = c; + c = b; + b = a; + a = temp1 + temp2; + } + + Ctx->State[0] += a; + Ctx->State[1] += b; + Ctx->State[2] += c; + Ctx->State[3] += d; + Ctx->State[4] += e; + Ctx->State[5] += f; + Ctx->State[6] += g; + Ctx->State[7] += h; +} + + +static void Sha256Update(Sha256Ctx *Ctx, BYTE *data, size_t len) +{ + unsigned int b_len = Ctx->Len & 63, + r_len = (b_len ^ 63) + 1; + + Ctx->Len += (unsigned int)len; + + if ( len < r_len ) + { + memcpy(Ctx->Buffer + b_len, data, len); + return; + } + + if ( r_len < 64 ) + { + memcpy(Ctx->Buffer + b_len, data, r_len); + len -= r_len; + data += r_len; + Sha256ProcessBlock(Ctx, Ctx->Buffer); + } + + for (; len >= 64; len -= 64, data += 64) + Sha256ProcessBlock(Ctx, data); + + if ( len ) memcpy(Ctx->Buffer, data, len); +} + + +static void Sha256Finish(Sha256Ctx *Ctx, BYTE *hash) +{ + unsigned int i, b_len = Ctx->Len & 63; + + Ctx->Buffer[ b_len ] = 0x80; + if ( b_len ^ 63 ) memset(Ctx->Buffer + b_len + 1, 0, b_len ^ 63); + + if ( b_len >= 56 ) + { + Sha256ProcessBlock(Ctx, Ctx->Buffer); + memset(Ctx->Buffer, 0, 56); + } + + //PUT_UAA64BE(Ctx->Buffer, (unsigned long long)(Ctx->Len * 8), 7); + ((uint64_t*)Ctx->Buffer)[7] = BE64((uint64_t)Ctx->Len << 3); + Sha256ProcessBlock(Ctx, Ctx->Buffer); + + for (i = 0; i < 8; i++) + //PUT_UAA32BE(hash, Ctx->State[i], i); + ((DWORD*)hash)[i] = BE32(Ctx->State[i]); + +} + + +void Sha256(BYTE *data, size_t len, BYTE *hash) +{ + Sha256Ctx Ctx; + + Sha256Init(&Ctx); + Sha256Update(&Ctx, data, len); + Sha256Finish(&Ctx, hash); +} + + +static void _Sha256HmacInit(Sha256HmacCtx *Ctx, BYTE *key, size_t klen) +{ + BYTE IPad[64]; + unsigned int i; + + memset(IPad, 0x36, sizeof(IPad)); + memset(Ctx->OPad, 0x5C, sizeof(Ctx->OPad)); + + if ( klen > 64 ) + { + BYTE *temp = (BYTE*)alloca(32); + Sha256(key, klen, temp); + klen = 32; + key = temp; + } + + for (i = 0; i < klen; i++) + { + IPad[ i ] ^= key[ i ]; + Ctx->OPad[ i ] ^= key[ i ]; + } + + Sha256Init(&Ctx->ShaCtx); + Sha256Update(&Ctx->ShaCtx, IPad, sizeof(IPad)); +} + + +static void _Sha256HmacUpdate(Sha256HmacCtx *Ctx, BYTE *data, size_t len) +{ + Sha256Update(&Ctx->ShaCtx, data, len); +} + + +static void _Sha256HmacFinish(Sha256HmacCtx *Ctx, BYTE *hmac) +{ + BYTE temp[32]; + + Sha256Finish(&Ctx->ShaCtx, temp); + Sha256Init(&Ctx->ShaCtx); + Sha256Update(&Ctx->ShaCtx, Ctx->OPad, sizeof(Ctx->OPad)); + Sha256Update(&Ctx->ShaCtx, temp, sizeof(temp)); + Sha256Finish(&Ctx->ShaCtx, hmac); +} + + + +int_fast8_t Sha256Hmac(BYTE* key, BYTE* restrict data, DWORD len, BYTE* restrict hmac) +{ + Sha256HmacCtx Ctx; + _Sha256HmacInit(&Ctx, key, 16); + _Sha256HmacUpdate(&Ctx, data, len); + _Sha256HmacFinish(&Ctx, hmac); + return TRUE; +} + + +#endif // No external Crypto + diff --git a/vlmcsd/src/crypto_internal.h b/vlmcsd/src/crypto_internal.h new file mode 100644 index 0000000..f99ca0a --- /dev/null +++ b/vlmcsd/src/crypto_internal.h @@ -0,0 +1,38 @@ +#ifndef __crypto_internal_h +#define __crypto_internal_h + +#if !defined(_CRYPTO_OPENSSL) && !defined(_CRYPTO_POLARSSL) && !defined(_CRYPTO_WINDOWS) + +#ifndef CONFIG +#define CONFIG "config.h" +#endif // CONFIG +#include CONFIG + +#include "crypto.h" + +typedef struct { + DWORD State[8]; + BYTE Buffer[64]; + unsigned int Len; +} Sha256Ctx; + +typedef struct { + Sha256Ctx ShaCtx; + BYTE OPad[64]; +} Sha256HmacCtx; + +void Sha256(BYTE *data, size_t len, BYTE *hash); +int_fast8_t Sha256Hmac(BYTE* key, BYTE* restrict data, DWORD len, BYTE* restrict hmac); + +//void _Sha256HmacInit(Sha256HmacCtx *Ctx, BYTE *key, size_t klen); +//void _Sha256HmacUpdate(Sha256HmacCtx *Ctx, BYTE *data, size_t len); +//void _Sha256HmacFinish(Sha256HmacCtx *Ctx, BYTE *hmac); + +//#define Sha256HmacInit(c, k, l) ( _Sha256HmacInit(c, k, l), !0 ) +//#define Sha256HmacUpdate(c, d, l) ( _Sha256HmacUpdate(c, d, l), !0 ) +//#define Sha256HmacFinish(c, h) ( _Sha256HmacFinish(c, h), !0 ) + + +#endif // !defined(_CRYPTO_OPENSSL) && !defined(_CRYPTO_POLARSSL) && !defined(_CRYPTO_WINDOWS) + +#endif // __crypto_internal_h diff --git a/vlmcsd/src/crypto_openssl.c b/vlmcsd/src/crypto_openssl.c new file mode 100644 index 0000000..f8550c7 --- /dev/null +++ b/vlmcsd/src/crypto_openssl.c @@ -0,0 +1,269 @@ +#ifndef CONFIG +#define CONFIG "config.h" +#endif // CONFIG +#include CONFIG + +#if defined(_CRYPTO_OPENSSL) + +#include "crypto.h" +#include "crypto_openssl.h" // Required for Eclipse only +#include +#include "endian.h" + + +#ifndef _OPENSSL_NO_HMAC + +int Sha256HmacInit_OpenSSL(HMAC_CTX *c, const void *k, int l) +{ + HMAC_CTX_init(c); + #if OPENSSL_VERSION_NUMBER >= 0x10000000L + int result = + #else + int result = TRUE; + #endif + HMAC_Init_ex(c, k, l, EVP_sha256(), NULL); + return result; +} + +int Sha256HmacFinish_OpenSSL(HMAC_CTX *c, unsigned char *h, unsigned int *l) +{ + #if OPENSSL_VERSION_NUMBER >= 0x10000000L + int result = + #else + int result = !0; + #endif + HMAC_Final(c, h, l); + HMAC_CTX_cleanup(c); + return result; +} + +int_fast8_t Sha256Hmac(BYTE* key, BYTE* restrict data, DWORD len, BYTE* restrict hmac) +{ + HMAC_CTX Ctx; + +# if OPENSSL_VERSION_NUMBER >= 0x10000000L + + return + Sha256HmacInit_OpenSSL(&Ctx, key, 16) && + HMAC_Update(&Ctx, data, len) && + Sha256HmacFinish_OpenSSL(&Ctx, hmac, NULL); + +# else // OpenSSL 0.9.x + + Sha256HmacInit_OpenSSL(&Ctx, key, 16); + HMAC_Update(&Ctx, data, len); + Sha256HmacFinish_OpenSSL(&Ctx, hmac, NULL); + return TRUE; + +# endif +} + +#else // _OPENSSL_NO_HMAC (some routers have OpenSSL without support for HMAC) + +int _Sha256HmacInit(Sha256HmacCtx *Ctx, BYTE *key, size_t klen) +{ + BYTE IPad[64]; + unsigned int i; + + memset(IPad, 0x36, sizeof(IPad)); + memset(Ctx->OPad, 0x5C, sizeof(Ctx->OPad)); + + if ( klen > 64 ) + { + BYTE *temp = (BYTE*)alloca(32); + SHA256(key, klen, temp); + klen = 32; + key = temp; + } + + for (i = 0; i < klen; i++) + { + IPad[ i ] ^= key[ i ]; + Ctx->OPad[ i ] ^= key[ i ]; + } + + SHA256_Init(&Ctx->ShaCtx); + return SHA256_Update(&Ctx->ShaCtx, IPad, sizeof(IPad)); +} + +int _Sha256HmacUpdate(Sha256HmacCtx *Ctx, BYTE *data, size_t len) +{ + int rc = SHA256_Update(&Ctx->ShaCtx, data, len); + return rc; +} + +int _Sha256HmacFinish(Sha256HmacCtx *Ctx, BYTE *hmac, void* dummy) +{ + BYTE temp[32]; + + SHA256_Final(temp, &Ctx->ShaCtx); + SHA256_Init(&Ctx->ShaCtx); + SHA256_Update(&Ctx->ShaCtx, Ctx->OPad, sizeof(Ctx->OPad)); + SHA256_Update(&Ctx->ShaCtx, temp, sizeof(temp)); + return SHA256_Final(hmac, &Ctx->ShaCtx); +} + +int_fast8_t Sha256Hmac(BYTE* key, BYTE* restrict data, DWORD len, BYTE* restrict hmac) +{ + Sha256HmacCtx Ctx; + _Sha256HmacInit(&Ctx, key, 16); + _Sha256HmacUpdate(&Ctx, data, len); + _Sha256HmacFinish(&Ctx, hmac, NULL); + return TRUE; +} +#endif + +#if defined(_USE_AES_FROM_OPENSSL) +void TransformOpenSslEncryptKey(AES_KEY *k, const AesCtx *const Ctx) +{ + uint32_t *rk_OpenSSL = k->rd_key, *rk_vlmcsd = (uint32_t*)Ctx->Key; + k->rounds = Ctx->rounds; + + for (; rk_OpenSSL < k->rd_key + ((k->rounds + 1) << 2); rk_OpenSSL++, rk_vlmcsd++) + { + #ifdef _OPENSSL_SOFTWARE + *rk_OpenSSL = BE32(*rk_vlmcsd); + #else + *rk_OpenSSL = LE32(*rk_vlmcsd); + #endif + } +} + +void TransformOpenSslDecryptKey(AES_KEY *k, const AesCtx *const Ctx) +{ + uint_fast8_t i; + + #ifdef _DEBUG_OPENSSL + AES_set_decrypt_key((BYTE*)Ctx->Key, 128, k); + errorout("Correct V5 round key:"); + + for (i = 0; i < (Ctx->rounds + 1) << 4; i++) + { + if (!(i % 16)) errorout("\n"); + if (!(i % 4)) errorout(" "); + errorout("%02X", ((BYTE*)(k->rd_key))[i]); + } + + errorout("\n"); + #endif + + k->rounds = Ctx->rounds; + + /* invert the order of the round keys blockwise (1 Block = AES_BLOCK_SIZE = 16): */ + + for (i = 0; i < (Ctx->rounds + 1) << 2; i++) + { + #ifdef _OPENSSL_SOFTWARE + k->rd_key[((Ctx->rounds-(i >> 2)) << 2) + (i & 3)] = BE32(Ctx->Key[i]); + #else + k->rd_key[((Ctx->rounds-(i >> 2)) << 2) + (i & 3)] = LE32(Ctx->Key[i]); + #endif + } + + /* apply the inverse MixColumn transform to all round keys but the first and the last: */ + + uint32_t *rk = k->rd_key + 4; + + for (i = 0; i < (Ctx->rounds - 1); i++) + { + MixColumnsR((BYTE*)(rk + (i << 2))); + } + + #ifdef _DEBUG_OPENSSL + errorout("Real round key:"); + + for (i = 0; i < (Ctx->rounds + 1) << 4; i++) + { + if (!(i % 16)) errorout("\n"); + if (!(i % 4)) errorout(" "); + errorout("%02X", ((BYTE*)(k->rd_key))[i]); + } + + errorout("\n"); + #endif +} + +static BYTE NullIV[AES_BLOCK_SIZE + 8]; // OpenSSL may overwrite bytes behind IV + +void AesEncryptCbc(const AesCtx *const Ctx, BYTE *iv, BYTE *data, size_t *len) +{ + AES_KEY k; + + // OpenSSL overwrites IV plus 4 bytes + BYTE localIV[24]; // 4 spare bytes for safety + if (iv) memcpy(localIV, iv, AES_BLOCK_SIZE); + + // OpenSSL Low-Level APIs do not pad. Could use EVP API instead but needs more code to access the expanded key + uint_fast8_t pad = (~*len & (AES_BLOCK_SIZE - 1)) + 1; + + #if defined(__GNUC__) && (__GNUC__ == 4 && __GNUC_MINOR__ == 8) // gcc 4.8 memset bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56977 + size_t i; + for (i = 0; i < pad; i++) data[*len + i] = pad; + #else + memset(data + *len, pad, pad); + #endif + *len += pad; + + memset(NullIV, 0, sizeof(NullIV)); + + TransformOpenSslEncryptKey(&k, Ctx); + + AES_cbc_encrypt(data, data, *len, &k, iv ? localIV : NullIV, AES_ENCRYPT); +} + +void AesDecryptBlock(const AesCtx *const Ctx, BYTE *block) +{ + AES_KEY k; + + TransformOpenSslDecryptKey(&k, Ctx); + AES_decrypt(block, block, &k); +} + +#if defined(_CRYPTO_OPENSSL) && defined(_USE_AES_FROM_OPENSSL) && !defined(_OPENSSL_SOFTWARE) +void AesEncryptBlock(const AesCtx *const Ctx, BYTE *block) +{ + AES_KEY k; + + TransformOpenSslEncryptKey(&k, Ctx); + AES_encrypt(block, block, &k); +} +#endif + +void AesDecryptCbc(const AesCtx *const Ctx, BYTE *iv, BYTE *data, size_t len) +{ + AES_KEY k; + + memset(NullIV, 0, sizeof(NullIV)); + + TransformOpenSslDecryptKey(&k, Ctx); + AES_cbc_encrypt(data, data, len, &k, iv ? iv : NullIV, AES_DECRYPT); +} + +#ifndef _OPENSSL_SOFTWARE +void AesCmacV4(BYTE *Message, size_t MessageSize, BYTE *HashOut) +{ + size_t i; + BYTE hash[AES_BLOCK_BYTES]; + AesCtx Ctx; + AES_KEY k; + + AesInitKey(&Ctx, AesKeyV4, FALSE, V4_KEY_BYTES); + TransformOpenSslEncryptKey(&k, &Ctx); + + memset(hash, 0, sizeof(hash)); + memset(Message + MessageSize, 0, AES_BLOCK_BYTES); + Message[MessageSize] = 0x80; + + for (i = 0; i <= MessageSize; i += AES_BLOCK_BYTES) + { + XorBlock(Message + i, hash); + AES_encrypt(hash, hash, &k); + } + + memcpy(HashOut, hash, AES_BLOCK_BYTES); +} +#endif // !_OPENSSL_SOFTWARE + +#endif // defined(_USE_AES_FROM_OPENSSL) + +#endif // _CRYPTO_OPENSSL diff --git a/vlmcsd/src/crypto_openssl.h b/vlmcsd/src/crypto_openssl.h new file mode 100644 index 0000000..d7931f7 --- /dev/null +++ b/vlmcsd/src/crypto_openssl.h @@ -0,0 +1,53 @@ +#ifndef __crypto_openssl_h +#define __crypto_openssl_h + +#ifndef CONFIG +#define CONFIG "config.h" +#endif // CONFIG +#include CONFIG + +#include +#include +#include +#include +#include "crypto.h" + +#define Sha256(d, l, h) SHA256(d, l, h) +int_fast8_t Sha256Hmac(BYTE* key, BYTE* restrict data, DWORD len, BYTE* restrict hmac); + +#ifndef _OPENSSL_NO_HMAC +#define Sha256HmacCtx HMAC_CTX +#else +typedef struct { + SHA256_CTX ShaCtx; + BYTE OPad[64]; +} Sha256HmacCtx; +#endif + +#ifndef _OPENSSL_NO_HMAC + +#define Sha256HmacInit(c, k, l) Sha256HmacInit_OpenSSL(c, k, l) +#define Sha256HmacFinish(c, h) Sha256HmacFinish_OpenSSL(c, h, NULL) + +#if OPENSSL_VERSION_NUMBER >= 0x10000000L +#define Sha256HmacUpdate(c, d, l) HMAC_Update(c, d, l) +#else // OPENSSL_VERSION_NUMBER < 0x10000000L +#define Sha256HmacUpdate(c, d, l) (HMAC_Update(c, d, l), !0) +#endif // OPENSSL_VERSION_NUMBER >= 0x10000000L + +int Sha256HmacInit_OpenSSL(HMAC_CTX *c, const void *k, int l); +int Sha256HmacFinish_OpenSSL(HMAC_CTX *c, unsigned char *h, unsigned int *l); + +#else // _OPENSSL_NO_HMAC + +int _Sha256HmacInit(Sha256HmacCtx *Ctx, BYTE *key, size_t klen); +int _Sha256HmacUpdate(Sha256HmacCtx *Ctx, BYTE *data, size_t len); +int _Sha256HmacFinish(Sha256HmacCtx *Ctx, BYTE *hmac, void* dummy); +#define Sha256HmacInit(c, k, l) _Sha256HmacInit(c, k, l) +#define Sha256HmacFinish(c, h) _Sha256HmacFinish(c, h, NULL) +#define Sha256HmacUpdate(c, d, l) _Sha256HmacUpdate(c, d, l) + +#endif // _OPENSSL_NO_HMAC + +extern const BYTE AesKeyV4[]; +#endif // __crypto_openssl_h diff --git a/vlmcsd/src/crypto_polarssl.h b/vlmcsd/src/crypto_polarssl.h new file mode 100644 index 0000000..0474887 --- /dev/null +++ b/vlmcsd/src/crypto_polarssl.h @@ -0,0 +1,39 @@ +#ifndef __crypto_polarssl_h +#define __crypto_polarssl_h + +#ifndef CONFIG +#define CONFIG "config.h" +#endif // CONFIG +#include CONFIG + +#include +#include "crypto.h" + +#if POLARSSL_VERSION_NUMBER >= 0x01030000 + +#include + +#define Sha256(d, l, h) sha256(d, l, h, 0) + +#define Sha256HmacCtx sha256_context +#define Sha256HmacInit(c, k, l) ( sha256_hmac_starts(c, k, l, 0), !0 ) +#define Sha256HmacUpdate(c, d, l) ( sha256_hmac_update(c, d, l), !0 ) +#define Sha256HmacFinish(c, h) ( sha256_hmac_finish(c, h), !0 ) +#define Sha256Hmac(k, d, l, h) ( sha256_hmac(k, 16, d, l, h, FALSE), !0 ) + +#else // POLARSSL_VERSION_NUMBER + +#include + +#define Sha256(d, l, h) sha2(d, l, h, 0) + +#define Sha256HmacCtx sha2_context +#define Sha256HmacInit(c, k, l) ( sha2_hmac_starts(c, k, l, 0), !0 ) +#define Sha256HmacUpdate(c, d, l) ( sha2_hmac_update(c, d, l), !0 ) +#define Sha256HmacFinish(c, h) ( sha2_hmac_finish(c, h), !0 ) +#define Sha256Hmac(k, d, l, h) ( sha2_hmac(k, 16, d, l, h, FALSE), !0 ) + +#endif // POLARSSL_VERSION_NUMBER +#endif // __crypto_polarssl_h + + diff --git a/vlmcsd/src/crypto_windows.c b/vlmcsd/src/crypto_windows.c new file mode 100644 index 0000000..6a93be5 --- /dev/null +++ b/vlmcsd/src/crypto_windows.c @@ -0,0 +1,170 @@ +/* + * crypto_windows.c + */ +#ifndef CONFIG +#define CONFIG "config.h" +#endif // CONFIG +#include CONFIG + +#ifdef _CRYPTO_WINDOWS + +#if !_WIN32 && !__CYGWIN__ +#error You cannot use Windows CryptoAPI on non-Windows platforms +#else // _WIN32 || __CYGWIN__ + +#include "crypto_windows.h" + + +typedef struct _HMAC_KEYBLOB +{ + BLOBHEADER hdr; + DWORD dwKeySize; + BYTE KeyData[16]; +} HMAC_KEYBLOB; + + +/* + * MingW and Cygwin define NULL as ((void*)0) (Posix standard) which you can't assign to + * non-pointer types without compiler warning. Thus we use the following + */ +#define NULLHANDLE 0 +#define NULLFLAGS 0 + + +static HCRYPTPROV hRsaAesProvider = 0; // Needs to be initialized just once per process + + + +static int_fast8_t AcquireCryptContext() +{ + if (!hRsaAesProvider) + { + return (int_fast8_t)CryptAcquireContextW + ( + &hRsaAesProvider, // Provider handle + NULL, // No key container name + NULL, // Default provider + PROV_RSA_AES, // Provides SHA and AES + CRYPT_VERIFYCONTEXT // We don't need access to persistent keys + ); + } + + return TRUE; +} + + +int_fast8_t Sha256(BYTE* restrict data, DWORD DataSize, BYTE* restrict hash) +{ + HCRYPTHASH hHash = 0; + DWORD HashSize = 32; + + int_fast8_t success = + AcquireCryptContext() && + + CryptCreateHash + ( + hRsaAesProvider,// Provider handle + CALG_SHA_256, // Algorithm + NULLHANDLE, // SHA256 requires no key + NULLFLAGS, // Use default flags + &hHash // Handle for hashing + ) && + + CryptHashData + ( + hHash, // Handle + data, // data to hash + DataSize, // size of data + NULLFLAGS // Use default flags + ) && + + CryptGetHashParam + ( + hHash, // Handle + HP_HASHVAL, // what you actually want to get (the resulting hash) + hash, // data to retrieve + &HashSize, // size of data + NULLFLAGS // currently reserved (as of this writing) + ); + + if (hHash) CryptDestroyHash(hHash); + + return success; +} + + +int_fast8_t Sha256Hmac(const BYTE* key, BYTE* restrict data, DWORD len, BYTE* restrict hmac) +{ +# ifndef USE_THREADS // In fork() mode thread-safety is not required + static +# endif + HMAC_KEYBLOB hmackeyblob = { + // Type, Version, Algorithm + { PLAINTEXTKEYBLOB, CUR_BLOB_VERSION, 0, CALG_RC2 }, + // Key length + 16 + }; + + HCRYPTKEY hKey = NULLHANDLE; + HCRYPTHASH hHmacHash = NULLHANDLE; + HMAC_INFO HmacInfo = { 0 }; + DWORD dwHmacSize = 32; + + HmacInfo.HashAlgid = CALG_SHA_256; + memcpy(hmackeyblob.KeyData, key, sizeof(hmackeyblob.KeyData)); + + BOOL success = + AcquireCryptContext() && + + CryptImportKey + ( + hRsaAesProvider, // provider handle + (PBYTE)&hmackeyblob, // the actual key MS blob format + sizeof(HMAC_KEYBLOB), // size of the entire blob + NULLHANDLE, // password/key for the key store (none required here) + NULLFLAGS, // default flags + &hKey // key handle to retrieve (must be kept until you finish hashing) + ) && + + CryptCreateHash + ( + hRsaAesProvider, // provider handle + CALG_HMAC, // the actual key MS blob format + hKey, // size of the entire blob + NULLFLAGS, // password/key for the key store (none required here) + &hHmacHash // default flags + ) && // key handle to retrieve (must be kept until you finish hashing) + + CryptSetHashParam + ( + hHmacHash, // hash handle + HP_HMAC_INFO, // parameter you want to set + (PBYTE)&HmacInfo, // the HMAC parameters (SHA256 with default ipad and opad) + NULLFLAGS // flags are reserved up to Windows 8.1 + ) && + + CryptHashData + ( + hHmacHash, // hash handle + data, // Pointer to data you want to hash + len, // data length + NULLFLAGS // default flags + ) && + + CryptGetHashParam + ( + hHmacHash, // hash handle + HP_HASHVAL, // what you actually want to get (the resulting HMAC) + hmac, // data to retrieve + &dwHmacSize, // size of data + NULLFLAGS // currently reserved (as of this writing) + ); + + if (hKey) CryptDestroyKey(hKey); + if (hHmacHash) CryptDestroyHash(hHmacHash); + + return (int_fast8_t)success; +} + +#endif // _WIN32 || __CYGWIN__ +#endif // _CRYPTO_WINDOWS diff --git a/vlmcsd/src/crypto_windows.h b/vlmcsd/src/crypto_windows.h new file mode 100644 index 0000000..d26b3f3 --- /dev/null +++ b/vlmcsd/src/crypto_windows.h @@ -0,0 +1,34 @@ +/* + * crypto_windows.h + */ + +#ifdef _CRYPTO_WINDOWS +#ifndef CRYPTO_WINDOWS_H_ +#define CRYPTO_WINDOWS_H_ + +#if !_WIN32 && !__CYGWIN__ +#error You cannot use Windows CryptoAPI on non-Windows platforms +#else // _WIN32 || __CYGWIN__ + +#include "types.h" +#if _MSC_VER +#include "Wincrypt.h" +#endif + +typedef struct _Sha2356HmacCtx +{ + HCRYPTHASH hHmac; + HCRYPTKEY hKey; +} Sha256HmacCtx; + +int_fast8_t Sha256(BYTE* restrict data, DWORD DataSize, BYTE* restrict hash); +int_fast8_t Sha256Hmac(const BYTE* key, BYTE* restrict data, DWORD len, BYTE* restrict hmac); + +/*int_fast8_t Sha256HmacInit(Sha256HmacCtx *Ctx, BYTE *key, uint8_t keySize); +int_fast8_t Sha256HmacUpdate(Sha256HmacCtx *Ctx, BYTE *data, DWORD len); +int_fast8_t Sha256HmacFinish(Sha256HmacCtx *Ctx, BYTE *hmac);*/ + + +#endif // _WIN32 || __CYGWIN__ +#endif /* CRYPTO_WINDOWS_H_ */ +#endif // _CRYPTO_WINDOWS diff --git a/vlmcsd/src/dns_srv.c b/vlmcsd/src/dns_srv.c new file mode 100644 index 0000000..a4e92fe --- /dev/null +++ b/vlmcsd/src/dns_srv.c @@ -0,0 +1,330 @@ +/* + * dns_srv.c + * + * This file contains the code for KMS SRV record lookup in DNS (_vlmcs._tcp.example.com IN SRV 0 0 1688 mykms.example.com) + * + */ + +#ifndef CONFIG +#define CONFIG "config.h" +#endif // CONFIG +#include CONFIG + +#ifndef NO_DNS + +#include "dns_srv.h" + +#include +#include +#ifndef _WIN32 +#include +#include +#include +#include +#include + //#ifndef DNS_PARSER_INTERNAL +#if __ANDROID__ +#include +#include "nameser.h" +#include "resolv.h" +#else // other Unix non-Android +#include +#include +#include +#endif // other Unix non-Android +//#endif // DNS_PARSER_INTERNAL +#else // WIN32 +#include +#endif // WIN32 + +#include "helpers.h" +#include "output.h" +#include "endian.h" + +#if defined(DNS_PARSER_INTERNAL) && !defined(_WIN32) + +#include "ns_name.h" +#include "ns_parse.h" + + // Define macros to redirect DNS parser functions to internal versions + +#undef ns_msg +#undef ns_initparse +#undef ns_parserr +#undef ns_rr +#undef ns_name_uncompress +#undef ns_msg_base +#undef ns_msg_end +#undef ns_rr_rdata +#undef ns_rr_type +#undef ns_msg_count +#undef ns_rr_class +#undef ns_s_an +#define ns_msg ns_msg_vlmcsd +#define ns_initparse ns_initparse_vlmcsd +#define ns_parserr ns_parserr_vlmcsd +#define ns_rr ns_rr_vlmcsd +#define ns_name_uncompress ns_name_uncompress_vlmcsd +#define ns_msg_base ns_msg_base_vlmcsd +#define ns_msg_end ns_msg_end_vlmcsd +#define ns_rr_rdata ns_rr_rdata_vlmcsd +#define ns_rr_type ns_rr_type_vlmcsd +#define ns_msg_count ns_msg_count_vlmcsd +#define ns_rr_class ns_rr_class_vlmcsd +#define ns_s_an ns_s_an_vlmcsd + +#ifndef NS_MAXLABEL +#define NS_MAXLABEL 63 +#endif + +#endif // defined(DNS_PARSER_INTERNAL) && !defined(_WIN32) + + +//TODO: maybe move to helpers.c +static unsigned int isqrt(unsigned int n) +{ + unsigned int c = 0x8000; + unsigned int g = 0x8000; + + for (;;) + { + if (g*g > n) + g ^= c; + + c >>= 1; + + if (c == 0) return g; + + g |= c; + } +} + + +/* + * Compare function for qsort to sort SRV records by priority and weight + * random_weight must be product of weight from SRV record and square root of a random number + */ +static int kmsServerListCompareFunc1(const void* a, const void* b) +{ + if (!a && !b) return 0; + if (a && !b) return -1; + if (!a && b) return 1; + + int priority_order = (int)((*(kms_server_dns_ptr*)a)->priority) - ((int)(*(kms_server_dns_ptr*)b)->priority); + + if (priority_order) return priority_order; + + return (int)((*(kms_server_dns_ptr*)b)->random_weight) - ((int)(*(kms_server_dns_ptr*)a)->random_weight); +} + +/* Sort resulting SRV records */ +void sortSrvRecords(kms_server_dns_ptr* serverlist, const int answers) +{ + int i; + + for (i = 0; i < answers; i++) + { + serverlist[i]->random_weight = (rand32() % 256) * isqrt(serverlist[i]->weight * 1000); + } + + qsort(serverlist, answers, sizeof(kms_server_dns_ptr), kmsServerListCompareFunc1); +} + + +#define RECEIVE_BUFFER_SIZE 2048 +#ifndef _WIN32 // UNIX resolver + +/* + * Retrieves a raw DNS answer (a buffer of what came over the net) + * Result must be parsed + */ +static int getDnsRawAnswer(const char *restrict query, unsigned char** receive_buffer) +{ + if (res_init() < 0) + { + errorout("Cannot initialize resolver: %s", strerror(errno)); + return 0; + } + + //if(!(*receive_buffer = (unsigned char*)malloc(RECEIVE_BUFFER_SIZE))) OutOfMemory(); + *receive_buffer = (unsigned char*)vlmcsd_malloc(RECEIVE_BUFFER_SIZE); + + int bytes_received; + + if (*query == '.') + { +# if __ANDROID__ || __GLIBC__ /* including __UCLIBC__*/ || __APPLE__ || __CYGWIN__ || __FreeBSD__ || __NetBSD__ || __DragonFly__ || __OpenBSD__ || __sun__ + bytes_received = res_querydomain("_vlmcs._tcp", query + 1, ns_c_in, ns_t_srv, *receive_buffer, RECEIVE_BUFFER_SIZE); +# else + char* querystring = (char*)alloca(strlen(query) + 12); + strcpy(querystring, "_vlmcs._tcp"); + strcat(querystring, query); + bytes_received = res_query(querystring, ns_c_in, ns_t_srv, *receive_buffer, RECEIVE_BUFFER_SIZE); +# endif + } + else + { + bytes_received = res_search("_vlmcs._tcp", ns_c_in, ns_t_srv, *receive_buffer, RECEIVE_BUFFER_SIZE); + } + + if (bytes_received < 0) + { + errorout("Fatal: DNS query to %s%s failed: %s\n", "_vlmcs._tcp", *query == '.' ? query : "", hstrerror(h_errno)); + return 0; + } + + return bytes_received; +} + +/* + * Retrieves an unsorted array of SRV records (Unix / Posix) + */ +int getKmsServerList(kms_server_dns_ptr** serverlist, const char *restrict query) +{ + unsigned char* receive_buffer; + *serverlist = NULL; + + int bytes_received = getDnsRawAnswer(query, &receive_buffer); + + if (bytes_received == 0) return 0; + + ns_msg msg; + + if (ns_initparse(receive_buffer, bytes_received, &msg) < 0) + { + errorout("Fatal: Incorrect DNS response: %s\n", strerror(errno)); + free(receive_buffer); + return 0; + } + + uint16_t i, answers = ns_msg_count(msg, ns_s_an); + //if(!(*serverlist = (kms_server_dns_ptr*)malloc(answers * sizeof(kms_server_dns_ptr)))) OutOfMemory(); + *serverlist = (kms_server_dns_ptr*)malloc(answers * sizeof(kms_server_dns_ptr)); + + memset(*serverlist, 0, answers * sizeof(kms_server_dns_ptr)); + + for (i = 0; i < answers; i++) + { + ns_rr rr; + + if (ns_parserr(&msg, ns_s_an, i, &rr) < 0) + { + errorout("Warning: Error in DNS resource record: %s\n", strerror(errno)); + continue; + } + + if (ns_rr_type(rr) != ns_t_srv) + { + errorout("Warning: DNS server returned non-SRV record\n"); + continue; + } + + if (ns_rr_class(rr) != ns_c_in) + { + errorout("Warning: DNS server returned non-IN class record\n"); + continue; + } + + dns_srv_record_ptr srvrecord = (dns_srv_record_ptr)ns_rr_rdata(rr); + kms_server_dns_ptr kms_server = (kms_server_dns_ptr)vlmcsd_malloc(sizeof(kms_server_dns_t)); + + (*serverlist)[i] = kms_server; + + if (ns_name_uncompress(ns_msg_base(msg), ns_msg_end(msg), srvrecord->name, kms_server->serverName, sizeof(kms_server->serverName)) < 0) + { + errorout("Warning: No valid DNS name returned in SRV record: %s\n", strerror(errno)); + continue; + } + + sprintf(kms_server->serverName + strlen(kms_server->serverName), ":%hu", GET_UA16BE(&srvrecord->port)); + kms_server->priority = GET_UA16BE(&srvrecord->priority); + kms_server->weight = GET_UA16BE(&srvrecord->weight); + + } + + free(receive_buffer); + return answers; +} + +#else // WIN32 (Windows Resolver) + +/* + * Retrieves an unsorted array of SRV records (Windows) + */ +int getKmsServerList(kms_server_dns_ptr** serverlist, const char *const restrict query) +{ +# define MAX_DNS_NAME_SIZE 254 + * serverlist = NULL; + PDNS_RECORD receive_buffer; + char dnsDomain[MAX_DNS_NAME_SIZE]; + char FqdnQuery[MAX_DNS_NAME_SIZE]; + DWORD size = MAX_DNS_NAME_SIZE; + DNS_STATUS result; + int answers = 0; + PDNS_RECORD dns_iterator; + + if (*query == '-') + { + if (!GetComputerNameExA(ComputerNamePhysicalDnsDomain, dnsDomain, &size)) + { + errorout("Fatal: Could not determine computer's DNS name: %s\n", vlmcsd_strerror(GetLastError())); + return 0; + } + + strcpy(FqdnQuery, "_vlmcs._tcp."); + strncat(FqdnQuery, dnsDomain, MAX_DNS_NAME_SIZE - 12); + } + else + { + strcpy(FqdnQuery, "_vlmcs._tcp"); + strncat(FqdnQuery, query, MAX_DNS_NAME_SIZE - 11); + } + + if ((result = DnsQuery_UTF8(FqdnQuery, DNS_TYPE_SRV, 0, NULL, &receive_buffer, NULL)) != 0) + { + errorout("Fatal: DNS query to %s failed: %s\n", FqdnQuery, vlmcsd_strerror(result)); + return 0; + } + + for (dns_iterator = receive_buffer; dns_iterator; dns_iterator = dns_iterator->pNext) + { + if (dns_iterator->Flags.S.Section != 1) continue; + + if (dns_iterator->wType != DNS_TYPE_SRV) + { + errorout("Warning: DNS server returned non-SRV record\n"); + continue; + } + + answers++; + } + + *serverlist = (kms_server_dns_ptr*)vlmcsd_malloc(answers * sizeof(kms_server_dns_ptr)); + + for (answers = 0, dns_iterator = receive_buffer; dns_iterator; dns_iterator = dns_iterator->pNext) + { + if (dns_iterator->wType != DNS_TYPE_SRV) continue; + + kms_server_dns_ptr kms_server = (kms_server_dns_ptr)vlmcsd_malloc(sizeof(kms_server_dns_t)); + + memset(kms_server, 0, sizeof(kms_server_dns_t)); + + vlmcsd_snprintf(kms_server->serverName, sizeof(kms_server->serverName), "%s:%hu", dns_iterator->Data.SRV.pNameTarget, dns_iterator->Data.SRV.wPort); + kms_server->priority = dns_iterator->Data.SRV.wPriority; + kms_server->weight = dns_iterator->Data.SRV.wWeight; + + (*serverlist)[answers++] = kms_server; + } + + //sortSrvRecords(*serverlist, answers, NoSrvRecordPriority); + + DnsRecordListFree(receive_buffer, DnsFreeRecordList); + + return answers; +# undef MAX_DNS_NAME_SIZE +} +#endif // _WIN32 +#undef RECEIVE_BUFFER_SIZE +#endif // NO_DNS + + diff --git a/vlmcsd/src/dns_srv.h b/vlmcsd/src/dns_srv.h new file mode 100644 index 0000000..70f5928 --- /dev/null +++ b/vlmcsd/src/dns_srv.h @@ -0,0 +1,103 @@ +/* + * dns_srv.h + * + */ + +#ifndef DNS_SRV_H_ +#define DNS_SRV_H_ +#ifndef NO_DNS + + +#include "types.h" + +typedef struct +{ + uint32_t random_weight; + uint16_t priority; + uint16_t weight; + char serverName[260]; +} kms_server_dns_t, *kms_server_dns_ptr; + +typedef struct +{ + uint16_t priority; + uint16_t weight; + uint16_t port; + unsigned char name[1]; +} dns_srv_record_t, *dns_srv_record_ptr; + +#if __OpenBSD__ +typedef enum __ns_type { + ns_t_invalid = 0, /*%< Cookie. */ + ns_t_a = 1, /*%< Host address. */ + ns_t_ns = 2, /*%< Authoritative server. */ + ns_t_md = 3, /*%< Mail destination. */ + ns_t_mf = 4, /*%< Mail forwarder. */ + ns_t_cname = 5, /*%< Canonical name. */ + ns_t_soa = 6, /*%< Start of authority zone. */ + ns_t_mb = 7, /*%< Mailbox domain name. */ + ns_t_mg = 8, /*%< Mail group member. */ + ns_t_mr = 9, /*%< Mail rename name. */ + ns_t_null = 10, /*%< Null resource record. */ + ns_t_wks = 11, /*%< Well known service. */ + ns_t_ptr = 12, /*%< Domain name pointer. */ + ns_t_hinfo = 13, /*%< Host information. */ + ns_t_minfo = 14, /*%< Mailbox information. */ + ns_t_mx = 15, /*%< Mail routing information. */ + ns_t_txt = 16, /*%< Text strings. */ + ns_t_rp = 17, /*%< Responsible person. */ + ns_t_afsdb = 18, /*%< AFS cell database. */ + ns_t_x25 = 19, /*%< X_25 calling address. */ + ns_t_isdn = 20, /*%< ISDN calling address. */ + ns_t_rt = 21, /*%< Router. */ + ns_t_nsap = 22, /*%< NSAP address. */ + ns_t_nsap_ptr = 23, /*%< Reverse NSAP lookup (deprecated). */ + ns_t_sig = 24, /*%< Security signature. */ + ns_t_key = 25, /*%< Security key. */ + ns_t_px = 26, /*%< X.400 mail mapping. */ + ns_t_gpos = 27, /*%< Geographical position (withdrawn). */ + ns_t_aaaa = 28, /*%< Ip6 Address. */ + ns_t_loc = 29, /*%< Location Information. */ + ns_t_nxt = 30, /*%< Next domain (security). */ + ns_t_eid = 31, /*%< Endpoint identifier. */ + ns_t_nimloc = 32, /*%< Nimrod Locator. */ + ns_t_srv = 33, /*%< Server Selection. */ + ns_t_atma = 34, /*%< ATM Address */ + ns_t_naptr = 35, /*%< Naming Authority PoinTeR */ + ns_t_kx = 36, /*%< Key Exchange */ + ns_t_cert = 37, /*%< Certification record */ + ns_t_a6 = 38, /*%< IPv6 address (deprecated, use ns_t_aaaa) */ + ns_t_dname = 39, /*%< Non-terminal DNAME (for IPv6) */ + ns_t_sink = 40, /*%< Kitchen sink (experimentatl) */ + ns_t_opt = 41, /*%< EDNS0 option (meta-RR) */ + ns_t_apl = 42, /*%< Address prefix list (RFC3123) */ + ns_t_tkey = 249, /*%< Transaction key */ + ns_t_tsig = 250, /*%< Transaction signature. */ + ns_t_ixfr = 251, /*%< Incremental zone transfer. */ + ns_t_axfr = 252, /*%< Transfer zone of authority. */ + ns_t_mailb = 253, /*%< Transfer mailbox records. */ + ns_t_maila = 254, /*%< Transfer mail agent records. */ + ns_t_any = 255, /*%< Wildcard match. */ + ns_t_zxfr = 256, /*%< BIND-specific, nonstandard. */ + ns_t_max = 65536 +} ns_type; + +typedef enum __ns_class { + ns_c_invalid = 0, /*%< Cookie. */ + ns_c_in = 1, /*%< Internet. */ + ns_c_2 = 2, /*%< unallocated/unsupported. */ + ns_c_chaos = 3, /*%< MIT Chaos-net. */ + ns_c_hs = 4, /*%< MIT Hesiod. */ + /* Query class values which do not appear in resource records */ + ns_c_none = 254, /*%< for prereq. sections in update requests */ + ns_c_any = 255, /*%< Wildcard match. */ + ns_c_max = 65536 +} ns_class; + +#endif + +int getKmsServerList(kms_server_dns_ptr** serverlist, const char *const restrict query); +void sortSrvRecords(kms_server_dns_ptr* serverlist, const int answers); + +#endif // NO_DNS +#endif /* DNS_SRV_H_ */ diff --git a/vlmcsd/src/endian.c b/vlmcsd/src/endian.c new file mode 100644 index 0000000..74d4bc8 --- /dev/null +++ b/vlmcsd/src/endian.c @@ -0,0 +1,175 @@ +#ifndef CONFIG +#define CONFIG "config.h" +#endif // CONFIG +#include CONFIG + +#include "endian.h" + +#if defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && defined(__LITTLE_ENDIAN) \ + && defined(BS16) && defined(BS32) && defined(BS64) && !defined(NO_COMPILER_UAA) + +#else // ! defined(__BYTE_ORDER) + +void PUT_UAA64BE(void *p, unsigned long long v, unsigned int i) +{ + unsigned char *_p = (unsigned char *)&((unsigned long long *)p)[i]; + _p[ 0 ] = (unsigned char)(v >> 56); + _p[ 1 ] = (unsigned char)(v >> 48); + _p[ 2 ] = (unsigned char)(v >> 40); + _p[ 3 ] = (unsigned char)(v >> 32); + _p[ 4 ] = (unsigned char)(v >> 24); + _p[ 5 ] = (unsigned char)(v >> 16); + _p[ 6 ] = (unsigned char)(v >> 8); + _p[ 7 ] = (unsigned char)(v); +} + +void PUT_UAA32BE(void *p, unsigned int v, unsigned int i) +{ + unsigned char *_p = (unsigned char *)&((unsigned int *)p)[i]; + _p[ 0 ] = (unsigned char)(v >> 24); + _p[ 1 ] = (unsigned char)(v >> 16); + _p[ 2 ] = (unsigned char)(v >> 8); + _p[ 3 ] = (unsigned char)(v); +} + +void PUT_UAA16BE(void *p, unsigned short v, unsigned int i) +{ + unsigned char *_p = (unsigned char *)&((unsigned short *)p)[i]; + _p[ 0 ] = (unsigned char)(v >> 8); + _p[ 1 ] = (unsigned char)(v); +} + + +void PUT_UAA64LE(void *p, unsigned long long v, unsigned int i) +{ + unsigned char *_p = (unsigned char *)&((unsigned long long *)p)[i]; + _p[ 0 ] = (unsigned char)(v); + _p[ 1 ] = (unsigned char)(v >> 8); + _p[ 2 ] = (unsigned char)(v >> 16); + _p[ 3 ] = (unsigned char)(v >> 24); + _p[ 4 ] = (unsigned char)(v >> 32); + _p[ 5 ] = (unsigned char)(v >> 40); + _p[ 6 ] = (unsigned char)(v >> 48); + _p[ 7 ] = (unsigned char)(v >> 56); +} + +void PUT_UAA32LE(void *p, unsigned int v, unsigned int i) +{ + unsigned char *_p = (unsigned char *)&((unsigned int *)p)[i]; + _p[ 0 ] = (unsigned char)(v); + _p[ 1 ] = (unsigned char)(v >> 8); + _p[ 2 ] = (unsigned char)(v >> 16); + _p[ 3 ] = (unsigned char)(v >> 24); +} + +void PUT_UAA16LE(void *p, unsigned short v, unsigned int i) +{ + unsigned char *_p = (unsigned char *)&((unsigned short *)p)[i]; + _p[ 0 ] = (unsigned char)(v); + _p[ 1 ] = (unsigned char)(v >> 8); +} + + +unsigned long long GET_UAA64BE(void *p, unsigned int i) +{ + unsigned char *_p = (unsigned char *)&((unsigned long long *)p)[i]; + return + (unsigned long long)_p[ 0 ] << 56 | + (unsigned long long)_p[ 1 ] << 48 | + (unsigned long long)_p[ 2 ] << 40 | + (unsigned long long)_p[ 3 ] << 32 | + (unsigned long long)_p[ 4 ] << 24 | + (unsigned long long)_p[ 5 ] << 16 | + (unsigned long long)_p[ 6 ] << 8 | + (unsigned long long)_p[ 7 ]; + +} + +unsigned int GET_UAA32BE(void *p, unsigned int i) +{ + unsigned char *_p = (unsigned char *)&((unsigned int *)p)[i]; + return + (unsigned int)_p[ 0 ] << 24 | + (unsigned int)_p[ 1 ] << 16 | + (unsigned int)_p[ 2 ] << 8 | + (unsigned int)_p[ 3 ]; +} + +unsigned short GET_UAA16BE(void *p, unsigned int i) +{ + unsigned char *_p = (unsigned char *)&((unsigned short *)p)[i]; + return + (unsigned short)_p[ 0 ] << 8 | + (unsigned short)_p[ 1 ]; +} + + +unsigned long long GET_UAA64LE(void *p, unsigned int i) +{ + unsigned char *_p = (unsigned char *)&((unsigned long long *)p)[i]; + return + (unsigned long long)_p[ 0 ] | + (unsigned long long)_p[ 1 ] << 8 | + (unsigned long long)_p[ 2 ] << 16 | + (unsigned long long)_p[ 3 ] << 24 | + (unsigned long long)_p[ 4 ] << 32 | + (unsigned long long)_p[ 5 ] << 40 | + (unsigned long long)_p[ 6 ] << 48 | + (unsigned long long)_p[ 7 ] << 56; + +} + +unsigned int GET_UAA32LE(void *p, unsigned int i) +{ + unsigned char *_p = (unsigned char *)&((unsigned int *)p)[i]; + return + (unsigned int)_p[ 0 ] | + (unsigned int)_p[ 1 ] << 8 | + (unsigned int)_p[ 2 ] << 16 | + (unsigned int)_p[ 3 ] << 24; +} + +unsigned short GET_UAA16LE(void *p, unsigned int i) +{ + unsigned char *_p = (unsigned char *)&((unsigned short *)p)[i]; + return + (unsigned short)_p[ 0 ] | + (unsigned short)_p[ 1 ] << 8; +} +#endif + + +#if defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && defined(__LITTLE_ENDIAN) \ + && defined(BS16) && defined(BS32) && defined(BS64) +#else +unsigned short BE16(unsigned short x) +{ + return GET_UAA16BE(&x, 0); +} + +unsigned short LE16(unsigned short x) +{ + return GET_UAA16LE(&x, 0); +} + +unsigned int BE32(unsigned int x) +{ + return GET_UAA32BE(&x, 0); +} + +unsigned int LE32(unsigned int x) +{ + return GET_UAA32LE(&x, 0); +} + +unsigned long long BE64(unsigned long long x) +{ + return GET_UAA64BE(&x, 0); +} + +unsigned long long LE64(unsigned long long x) +{ + return GET_UAA64LE(&x, 0); +} + +#endif // defined(__BYTE_ORDER) diff --git a/vlmcsd/src/endian.h b/vlmcsd/src/endian.h new file mode 100644 index 0000000..cc52c69 --- /dev/null +++ b/vlmcsd/src/endian.h @@ -0,0 +1,312 @@ +#ifndef __endian_h +#define __endian_h + +#ifndef CONFIG +#define CONFIG "config.h" +#endif // CONFIG +#include CONFIG + +// +// Unaligned access +// + +#if !defined(NO_COMPILER_UAA) +#define UAA16(p, i) (((PACKED16*)p)->val[i]) +#define UAA32(p, i) (((PACKED32*)p)->val[i]) +#define UAA64(p, i) (((PACKED64*)p)->val[i]) +#endif + +// +//Byteswap: Use compiler support if available +// +#ifndef NO_COMPILER_UAA +#ifdef __has_builtin // Clang supports this + +#if __has_builtin(__builtin_bswap16) +#define BS16(x) __builtin_bswap16(x) +#endif + +#if __has_builtin(__builtin_bswap32) +#define BS32(x) __builtin_bswap32(x) +#endif + +#if __has_builtin(__builtin_bswap64) +#define BS64(x) __builtin_bswap64(x) +#endif + +#endif // has_builtin + +#ifdef __GNUC__ // GNU C >= 4.3 has bswap32 and bswap64. GNU C >= 4.8 also has bswap16 +#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ > 2) + +#ifndef BS32 +#define BS32(x) __builtin_bswap32(x) +#endif + +#ifndef BS64 +#define BS64(x) __builtin_bswap64(x) +#endif + +#if (__GNUC__ > 4) || (__GNUC_MINOR__ > 7) + +#ifndef BS16 +#define BS16(x) __builtin_bswap16(x) +#endif + +#endif // GNU C > 4.7 +#endif // __GNUC__ > 4 +#endif // __GNUC__ +#endif // NO_COMPILER_UAA + +// +// Byteorder +// +#if defined(__linux__) || defined(__GLIBC__) || defined(__CYGWIN__) + +#include +#include + +#ifndef BS16 +#define BS16(x) bswap_16(x) +#endif + +#ifndef BS32 +#define BS32(x) bswap_32(x) +#endif + +#ifndef BS64 +#define BS64(x) bswap_64(x) +#endif + +#elif defined(__sun__) + +#include + +#ifndef BS16 +#define BS16(x) BSWAP_16(x) +#endif + +#ifndef BS32 +#define BS32(x) BSWAP_32(x) +#endif + +#ifndef BS64 +#define BS64(x) BSWAP_64(x) +#endif + +#define __LITTLE_ENDIAN 1234 +#define __BIG_ENDIAN 4321 + +#ifdef _LITTLE_ENDIAN +#define __BYTE_ORDER __LITTLE_ENDIAN +#else +#define __BYTE_ORDER __BIG_ENDIAN +#endif + +#elif __minix__ || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) + +#include +#include + +#define __BYTE_ORDER _BYTE_ORDER +#define __LITTLE_ENDIAN _LITTLE_ENDIAN +#define __BIG_ENDIAN _BIG_ENDIAN + +#ifdef __OpenBSD__ + +#ifndef BS16 +#define BS16 swap16 +#endif + +#ifndef BS32 +#define BS32 swap32 +#endif + +#ifndef BS64 +#define BS64 swap64 +#endif + +#else // !__OpenBSD__ + +#ifndef BS16 +#define BS16 bswap16 +#endif + +#ifndef BS32 +#define BS32 bswap32 +#endif + +#ifndef BS64 +#define BS64 bswap64 +#endif + +#endif // !__OpenBSD__ + +#elif defined(__APPLE__) + +#include +#include +#include + +#define __BYTE_ORDER _BYTE_ORDER +#define __LITTLE_ENDIAN _LITTLE_ENDIAN +#define __BIG_ENDIAN _BIG_ENDIAN + +#ifndef BS16 +#define BS16 OSSwapInt16 +#endif + +#ifndef BS32 +#define BS32 OSSwapInt32 +#endif + +#ifndef BS64 +#define BS64 OSSwapInt64 +#endif + +#elif defined(_WIN32) + +#define __LITTLE_ENDIAN 1234 +#define __BIG_ENDIAN 4321 +#define __BYTE_ORDER __LITTLE_ENDIAN + +#include + +#ifndef BS16 +#define BS16 _byteswap_ushort +#endif + +#ifndef BS32 +#define BS32 _byteswap_ulong +#endif + +#ifndef BS64 +#define BS64 _byteswap_uint64 +#endif + +#endif // Byteorder in different OS + + +#if defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && defined(__LITTLE_ENDIAN) \ + && defined(BS16) && defined(BS32) && defined(BS64) + +#if __BYTE_ORDER == __LITTLE_ENDIAN + +#define __BE16(x) BS16(x) +#define __LE16(x) (x) +#define __BE32(x) BS32(x) +#define __LE32(x) (x) +#define __BE64(x) BS64(x) +#define __LE64(x) (x) + +#define PUT_UA16(p, v) PUT_UA16LE(p, v) +#define PUT_UA32(p, v) PUT_UA32LE(p, v) +#define PUT_UA64(p, v) PUT_UA64LE(p, v) + +#else // __BYTE_ORDER == __BIG_ENDIAN + +#define __BE16(x) (x) +#define __LE16(x) BS16(x) +#define __BE32(x) (x) +#define __LE32(x) BS32(x) +#define __BE64(x) (x) +#define __LE64(x) BS64(x) + +#define PUT_UA16(p, v) PUT_UA16BE(p, v) +#define PUT_UA32(p, v) PUT_UA32BE(p, v) +#define PUT_UA64(p, v) PUT_UA64BE(p, v) + +#endif // __BYTE_ORDER + +#define BE16(x) __BE16(x) +#define LE16(x) __LE16(x) +#define BE32(x) __BE32(x) +#define LE32(x) __LE32(x) +#define BE64(x) __BE64(x) +#define LE64(x) __LE64(x) + +#else + +extern unsigned short BE16(unsigned short x); + +extern unsigned short LE16(unsigned short x); + +extern unsigned int BE32(unsigned int x); + +extern unsigned int LE32(unsigned int x); + +extern unsigned long long BE64(unsigned long long x); + +extern unsigned long long LE64(unsigned long long x); + +#endif // defined(__BYTE_ORDER) + +#if defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && defined(__LITTLE_ENDIAN) \ + && defined(BS16) && defined(BS32) && defined(BS64) &&!defined(NO_COMPILER_UAA) + +#define PUT_UAA64BE(p, v, i) ( UAA64(p, i) = __BE64(v) ) +#define PUT_UAA32BE(p, v, i) ( UAA32(p, i) = __BE32(v) ) +#define PUT_UAA16BE(p, v, i) ( UAA16(p, i) = __BE16(v) ) + +#define PUT_UAA64LE(p, v, i) ( UAA64(p, i) = __LE64(v) ) +#define PUT_UAA32LE(p, v, i) ( UAA32(p, i) = __LE32(v) ) +#define PUT_UAA16LE(p, v, i) ( UAA16(p, i) = __LE16(v) ) + +#define GET_UAA64BE(p, i) __BE64(UAA64(p, i)) +#define GET_UAA32BE(p, i) __BE32(UAA32(p, i)) +#define GET_UAA16BE(p, i) __BE16(UAA16(p, i)) + +#define GET_UAA64LE(p, i) __LE64(UAA64(p, i)) +#define GET_UAA32LE(p, i) __LE32(UAA32(p, i)) +#define GET_UAA16LE(p, i) __LE16(UAA16(p, i)) + + +#else // ! defined(__BYTE_ORDER) + +extern void PUT_UAA64BE(void* p, unsigned long long v, unsigned int i); + +extern void PUT_UAA32BE(void* p, unsigned int v, unsigned int i); + +extern void PUT_UAA16BE(void* p, unsigned short v, unsigned int i); + + +extern void PUT_UAA64LE(void* p, unsigned long long v, unsigned int i); + +extern void PUT_UAA32LE(void* p, unsigned int v, unsigned int i); + +extern void PUT_UAA16LE(void* p, unsigned short v, unsigned int i); + + +extern unsigned long long GET_UAA64BE(void* p, unsigned int i); + +extern unsigned int GET_UAA32BE(void* p, unsigned int i); + +extern unsigned short GET_UAA16BE(void* p, unsigned int i); + + +extern unsigned long long GET_UAA64LE(void* p, unsigned int i); + +extern unsigned int GET_UAA32LE(void* p, unsigned int i); + +extern unsigned short GET_UAA16LE(void* p, unsigned int i); +#endif + + + +#define PUT_UA64BE(p, v) PUT_UAA64BE(p, v, 0) +#define PUT_UA32BE(p, v) PUT_UAA32BE(p, v, 0) +#define PUT_UA16BE(p, v) PUT_UAA16BE(p, v, 0) + +#define PUT_UA64LE(p, v) PUT_UAA64LE(p, v, 0) +#define PUT_UA32LE(p, v) PUT_UAA32LE(p, v, 0) +#define PUT_UA16LE(p, v) PUT_UAA16LE(p, v, 0) + +#define GET_UA64BE(p) GET_UAA64BE(p, 0) +#define GET_UA32BE(p) GET_UAA32BE(p, 0) +#define GET_UA16BE(p) GET_UAA16BE(p, 0) + +#define GET_UA64LE(p) GET_UAA64LE(p, 0) +#define GET_UA32LE(p) GET_UAA32LE(p, 0) +#define GET_UA16LE(p) GET_UAA16LE(p, 0) + +#endif // __endian_h diff --git a/vlmcsd/src/getifaddrs-musl.c b/vlmcsd/src/getifaddrs-musl.c new file mode 100644 index 0000000..70f55d0 --- /dev/null +++ b/vlmcsd/src/getifaddrs-musl.c @@ -0,0 +1,263 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include "ifaddrs-musl.h" +//#include +#include +#include +#include "netlink-musl.h" + +#define IFADDRS_HASH_SIZE 64 + +/* getifaddrs() reports hardware addresses with PF_PACKET that implies + * struct sockaddr_ll. But e.g. Infiniband socket address length is + * longer than sockaddr_ll.ssl_addr[8] can hold. Use this hack struct + * to extend ssl_addr - callers should be able to still use it. */ +struct sockaddr_ll_hack { + unsigned short sll_family, sll_protocol; + int sll_ifindex; + unsigned short sll_hatype; + unsigned char sll_pkttype, sll_halen; + unsigned char sll_addr[24]; +}; + +union sockany { + struct sockaddr sa; + struct sockaddr_ll_hack ll; + struct sockaddr_in v4; + struct sockaddr_in6 v6; +}; + +struct ifaddrs_storage { + struct ifaddrs ifa; + struct ifaddrs_storage *hash_next; + union sockany addr, netmask, ifu; + unsigned int index; + char name[IFNAMSIZ+1]; +}; + +struct ifaddrs_ctx { + struct ifaddrs_storage *first; + struct ifaddrs_storage *last; + struct ifaddrs_storage *hash[IFADDRS_HASH_SIZE]; +}; + +void freeifaddrs(struct ifaddrs *ifp) +{ + struct ifaddrs *n; + while (ifp) { + n = ifp->ifa_next; + free(ifp); + ifp = n; + } +} + +static int __netlink_enumerate(int fd, unsigned int seq, int type, int af, + int (*cb)(void *ctx, struct nlmsghdr *h), void *ctx) +{ + struct nlmsghdr *h; + union { + uint8_t buf[8192]; + struct { + struct nlmsghdr nlh; + struct rtgenmsg g; + } req; + struct nlmsghdr reply; + } u; + int r, ret; + + memset(&u.req, 0, sizeof(u.req)); + u.req.nlh.nlmsg_len = sizeof(u.req); + u.req.nlh.nlmsg_type = type; + u.req.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST; + u.req.nlh.nlmsg_seq = seq; + u.req.g.rtgen_family = af; + r = send(fd, &u.req, sizeof(u.req), 0); + if (r < 0) return r; + + while (1) { + r = recv(fd, u.buf, sizeof(u.buf), MSG_DONTWAIT); + if (r <= 0) return -1; + for (h = &u.reply; NLMSG_OK(h, (void*)&u.buf[r]); h = NLMSG_NEXT(h)) { + if (h->nlmsg_type == NLMSG_DONE) return 0; + if (h->nlmsg_type == NLMSG_ERROR) return -1; + ret = cb(ctx, h); + if (ret) return ret; + } + } +} + +int __rtnetlink_enumerate(int link_af, int addr_af, int (*cb)(void *ctx, struct nlmsghdr *h), void *ctx) +{ + int fd, r; + + fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + if (fd < 0) return -1; + r = __netlink_enumerate(fd, 1, RTM_GETLINK, link_af, cb, ctx); + if (!r) r = __netlink_enumerate(fd, 2, RTM_GETADDR, addr_af, cb, ctx); + close(fd); + return r; +} + +static void copy_addr(struct sockaddr **r, int af, union sockany *sa, void *addr, size_t addrlen, int ifindex) +{ + uint8_t *dst; + int len; + + switch (af) { + case AF_INET: + dst = (uint8_t*) &sa->v4.sin_addr; + len = 4; + break; + case AF_INET6: + dst = (uint8_t*) &sa->v6.sin6_addr; + len = 16; + if (IN6_IS_ADDR_LINKLOCAL(addr) || IN6_IS_ADDR_MC_LINKLOCAL(addr)) + sa->v6.sin6_scope_id = ifindex; + break; + default: + return; + } + if (addrlen < len) return; + sa->sa.sa_family = af; + memcpy(dst, addr, len); + *r = &sa->sa; +} + +static void gen_netmask(struct sockaddr **r, int af, union sockany *sa, int prefixlen) +{ + uint8_t addr[16] = {0}; + int i; + + if (prefixlen > 8*sizeof(addr)) prefixlen = 8*sizeof(addr); + i = prefixlen / 8; + memset(addr, 0xff, i); + if (i < sizeof(addr)) addr[i++] = 0xff << (8 - (prefixlen % 8)); + copy_addr(r, af, sa, addr, sizeof(addr), 0); +} + +static void copy_lladdr(struct sockaddr **r, union sockany *sa, void *addr, size_t addrlen, int ifindex, unsigned short hatype) +{ + if (addrlen > sizeof(sa->ll.sll_addr)) return; + sa->ll.sll_family = AF_PACKET; + sa->ll.sll_ifindex = ifindex; + sa->ll.sll_hatype = hatype; + sa->ll.sll_halen = addrlen; + memcpy(sa->ll.sll_addr, addr, addrlen); + *r = &sa->sa; +} + +static int netlink_msg_to_ifaddr(void *pctx, struct nlmsghdr *h) +{ + struct ifaddrs_ctx *ctx = pctx; + struct ifaddrs_storage *ifs, *ifs0 = NULL; + struct ifinfomsg *ifi = NLMSG_DATA(h); + struct ifaddrmsg *ifa = NLMSG_DATA(h); + struct rtattr *rta; + int stats_len = 0; + + if (h->nlmsg_type == RTM_NEWLINK) { + for (rta = NLMSG_RTA(h, sizeof(*ifi)); NLMSG_RTAOK(rta, h); rta = RTA_NEXT(rta)) { + if (rta->rta_type != IFLA_STATS) continue; + stats_len = RTA_DATALEN(rta); + break; + } + } else { + for (ifs0 = ctx->hash[ifa->ifa_index % IFADDRS_HASH_SIZE]; ifs0; ifs0 = ifs0->hash_next) + if (ifs0->index == ifa->ifa_index) + break; + if (!ifs0) return 0; + } + + ifs = calloc(1, sizeof(struct ifaddrs_storage) + stats_len); + if (ifs == 0) return -1; + + if (h->nlmsg_type == RTM_NEWLINK) { + ifs->index = ifi->ifi_index; + ifs->ifa.ifa_flags = ifi->ifi_flags; + + for (rta = NLMSG_RTA(h, sizeof(*ifi)); NLMSG_RTAOK(rta, h); rta = RTA_NEXT(rta)) { + switch (rta->rta_type) { + case IFLA_IFNAME: + if (RTA_DATALEN(rta) < sizeof(ifs->name)) { + memcpy(ifs->name, RTA_DATA(rta), RTA_DATALEN(rta)); + ifs->ifa.ifa_name = ifs->name; + } + break; + case IFLA_ADDRESS: + copy_lladdr(&ifs->ifa.ifa_addr, &ifs->addr, RTA_DATA(rta), RTA_DATALEN(rta), ifi->ifi_index, ifi->ifi_type); + break; + case IFLA_BROADCAST: + copy_lladdr(&ifs->ifa.ifa_broadaddr, &ifs->ifu, RTA_DATA(rta), RTA_DATALEN(rta), ifi->ifi_index, ifi->ifi_type); + break; + case IFLA_STATS: + ifs->ifa.ifa_data = (void*)(ifs+1); + memcpy(ifs->ifa.ifa_data, RTA_DATA(rta), RTA_DATALEN(rta)); + break; + } + } + if (ifs->ifa.ifa_name) { + unsigned int bucket = ifs->index % IFADDRS_HASH_SIZE; + ifs->hash_next = ctx->hash[bucket]; + ctx->hash[bucket] = ifs; + } + } else { + ifs->ifa.ifa_name = ifs0->ifa.ifa_name; + ifs->ifa.ifa_flags = ifs0->ifa.ifa_flags; + for (rta = NLMSG_RTA(h, sizeof(*ifa)); NLMSG_RTAOK(rta, h); rta = RTA_NEXT(rta)) { + switch (rta->rta_type) { + case IFA_ADDRESS: + /* If ifa_addr is already set we, received an IFA_LOCAL before + * so treat this as destination address */ + if (ifs->ifa.ifa_addr) + copy_addr(&ifs->ifa.ifa_dstaddr, ifa->ifa_family, &ifs->ifu, RTA_DATA(rta), RTA_DATALEN(rta), ifa->ifa_index); + else + copy_addr(&ifs->ifa.ifa_addr, ifa->ifa_family, &ifs->addr, RTA_DATA(rta), RTA_DATALEN(rta), ifa->ifa_index); + break; + case IFA_BROADCAST: + copy_addr(&ifs->ifa.ifa_broadaddr, ifa->ifa_family, &ifs->ifu, RTA_DATA(rta), RTA_DATALEN(rta), ifa->ifa_index); + break; + case IFA_LOCAL: + /* If ifa_addr is set and we get IFA_LOCAL, assume we have + * a point-to-point network. Move address to correct field. */ + if (ifs->ifa.ifa_addr) { + ifs->ifu = ifs->addr; + ifs->ifa.ifa_dstaddr = &ifs->ifu.sa; + memset(&ifs->addr, 0, sizeof(ifs->addr)); + } + copy_addr(&ifs->ifa.ifa_addr, ifa->ifa_family, &ifs->addr, RTA_DATA(rta), RTA_DATALEN(rta), ifa->ifa_index); + break; + case IFA_LABEL: + if (RTA_DATALEN(rta) < sizeof(ifs->name)) { + memcpy(ifs->name, RTA_DATA(rta), RTA_DATALEN(rta)); + ifs->ifa.ifa_name = ifs->name; + } + break; + } + } + if (ifs->ifa.ifa_addr) + gen_netmask(&ifs->ifa.ifa_netmask, ifa->ifa_family, &ifs->netmask, ifa->ifa_prefixlen); + } + + if (ifs->ifa.ifa_name) { + if (!ctx->first) ctx->first = ifs; + if (ctx->last) ctx->last->ifa.ifa_next = &ifs->ifa; + ctx->last = ifs; + } else { + free(ifs); + } + return 0; +} + +int getifaddrs(struct ifaddrs **ifap) +{ + struct ifaddrs_ctx _ctx, *ctx = &_ctx; + int r; + memset(ctx, 0, sizeof *ctx); + r = __rtnetlink_enumerate(AF_UNSPEC, AF_UNSPEC, netlink_msg_to_ifaddr, ctx); + if (r == 0) *ifap = &ctx->first->ifa; + else freeifaddrs(&ctx->first->ifa); + return r; +} diff --git a/vlmcsd/src/helpers.c b/vlmcsd/src/helpers.c new file mode 100644 index 0000000..f044842 --- /dev/null +++ b/vlmcsd/src/helpers.c @@ -0,0 +1,734 @@ +/* + * Helper functions used by other modules + */ + + //#ifndef _GNU_SOURCE + //#define _GNU_SOURCE + //#endif + +#ifndef _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#endif + +#ifndef CONFIG +#define CONFIG "config.h" +#endif // CONFIG +#include CONFIG + +#ifndef _WIN32 +#include +#include +#endif // _WIN32 +#ifndef _MSC_VER +#include +#else +#include "wingetopt.h" +#endif +#include +#include +#include +#include "helpers.h" +#include "output.h" +#include "endian.h" +#include "shared_globals.h" + +#ifndef NO_INTERNAL_DATA +#include "kmsdata.h" +#endif // NO_INTERNAL_DATA + +#ifdef _WIN32 +#include +#endif // _WIN32 + +#if __APPLE__ +#include +#endif // __APPLE__ + +#if (__GLIBC__ || __linux__) && defined(USE_AUXV) +#include +#endif + +#if __FreeBSD__ || __FreeBSD_kernel__ +#include +#endif + + /* + * UCS2 <-> UTF-8 functions + * All functions use little endian UCS2 since we only need it to communicate with Windows via RPC + */ + + // Convert one character from UTF-8 to UCS2 + // Returns 0xffff, if utf-8 evaluates to > 0xfffe (outside basic multilingual pane) +WCHAR utf8_to_ucs2_char(const unsigned char *input, const unsigned char **end_ptr) +{ + *end_ptr = input; + if (input[0] == 0) + return (WCHAR)~0; + + if (input[0] < 0x80) { + *end_ptr = input + 1; + return LE16(input[0]); + } + + if ((input[0] & 0xE0) == 0xE0) { + + if (input[1] == 0 || input[2] == 0) + return (WCHAR)~0; + + *end_ptr = input + 3; + + return + LE16((input[0] & 0x0F) << 12 | + (input[1] & 0x3F) << 6 | + (input[2] & 0x3F)); + } + + if ((input[0] & 0xC0) == 0xC0) { + if (input[1] == 0) + return (WCHAR)~0; + + *end_ptr = input + 2; + + return + LE16((input[0] & 0x1F) << 6 | + (input[1] & 0x3F)); + } + return (WCHAR)~0; +} + +// Convert one character from UCS2 to UTF-8 +// Returns length of UTF-8 char (1, 2 or 3) or -1 on error (UTF-16 outside UCS2) +// char *utf8 must be large enough to hold 3 bytes +int ucs2_to_utf8_char(const WCHAR ucs2_le, char *utf8) +{ + const WCHAR ucs2 = LE16(ucs2_le); + + if (ucs2 < 0x80) { + utf8[0] = (char)ucs2; + utf8[1] = '\0'; + return 1; + } + + if (ucs2 >= 0x80 && ucs2 < 0x800) { + utf8[0] = (char)((ucs2 >> 6) | 0xC0); + utf8[1] = (char)((ucs2 & 0x3F) | 0x80); + utf8[2] = '\0'; + return 2; + } + + if (ucs2 >= 0x800 && ucs2 < 0xFFFF) { + + if (ucs2 >= 0xD800 && ucs2 <= 0xDFFF) { + /* Ill-formed (UTF-16 ouside of BMP) */ + return -1; + } + + utf8[0] = ((ucs2 >> 12)) | 0xE0; + utf8[1] = ((ucs2 >> 6) & 0x3F) | 0x80; + utf8[2] = ((ucs2) & 0x3F) | 0x80; + utf8[3] = '\0'; + return 3; + } + + return -1; +} + + +// Converts UTF8 to UCS2. Returns size in bytes of the converted string or -1 on error +size_t utf8_to_ucs2(WCHAR* const ucs2_le, const char* const utf8, const size_t maxucs2, const size_t maxutf8) +{ + const unsigned char* current_utf8 = (unsigned char*)utf8; + WCHAR* current_ucs2_le = ucs2_le; + + for (; *current_utf8; current_ucs2_le++) + { + size_t size = (char*)current_utf8 - utf8; + + if (size >= maxutf8) return (size_t)-1; + if (((*current_utf8 & 0xc0) == 0xc0) && (size >= maxutf8 - 1)) return (size_t)-1; + if (((*current_utf8 & 0xe0) == 0xe0) && (size >= maxutf8 - 2)) return (size_t)-1; + if (current_ucs2_le - ucs2_le >= (intptr_t)maxucs2 - 1) return (size_t)-1; + + *current_ucs2_le = utf8_to_ucs2_char(current_utf8, ¤t_utf8); + current_ucs2_le[1] = 0; + + if (*current_ucs2_le == (WCHAR)-1) return (size_t)-1; + } + return current_ucs2_le - ucs2_le; +} + +// Converts UCS2 to UTF-8. Returns TRUE or FALSE +BOOL ucs2_to_utf8(const WCHAR* const ucs2_le, char* utf8, size_t maxucs2, size_t maxutf8) +{ + char utf8_char[4]; + const WCHAR* current_ucs2 = ucs2_le; + unsigned int index_utf8 = 0; + + for (*utf8 = 0; *current_ucs2; current_ucs2++) + { + if (current_ucs2 - ucs2_le > (intptr_t)maxucs2) return FALSE; + int len = ucs2_to_utf8_char(*current_ucs2, utf8_char); + if (index_utf8 + len > maxutf8) return FALSE; + strncat(utf8, utf8_char, len); + index_utf8 += len; + } + + return TRUE; +} + +/* End of UTF-8 <-> UCS2 conversion */ + + +// Checks, whether a string is a valid integer number between min and max. Returns TRUE or FALSE. Puts int value in *value +BOOL stringToInt(const char *const szValue, const unsigned int min, const unsigned int max, unsigned int *const value) +{ + char *nextchar; + + errno = 0; + long long result = vlmcsd_strtoll(szValue, &nextchar, 10); + + if (errno || result < (long long)min || result >(long long)max || *nextchar) + { + return FALSE; + } + + *value = (unsigned int)result; + return TRUE; +} + + +//Converts a String Guid to a host binary guid in host endianess +int_fast8_t string2UuidLE(const char *const restrict input, GUID *const restrict guid) +{ + int i; + + if (strlen(input) < GUID_STRING_LENGTH) return FALSE; + if (input[8] != '-' || input[13] != '-' || input[18] != '-' || input[23] != '-') return FALSE; + + for (i = 0; i < GUID_STRING_LENGTH; i++) + { + if (i == 8 || i == 13 || i == 18 || i == 23) continue; + + const char c = (char)toupper((int)input[i]); + + if (c < '0' || c > 'F' || (c > '9' && c < 'A')) return FALSE; + } + + char inputCopy[GUID_STRING_LENGTH + 1]; + strncpy(inputCopy, input, GUID_STRING_LENGTH + 1); + inputCopy[8] = inputCopy[13] = inputCopy[18] = 0; + + hex2bin((BYTE*)&guid->Data1, inputCopy, 8); + hex2bin((BYTE*)&guid->Data2, inputCopy + 9, 4); + hex2bin((BYTE*)&guid->Data3, inputCopy + 14, 4); + hex2bin(guid->Data4, input + 19, 16); + + guid->Data1 = BS32(guid->Data1); + guid->Data2 = BS16(guid->Data2); + guid->Data3 = BS16(guid->Data3); + return TRUE; +} + + +__pure DWORD timeSpanString2Seconds(const char *const restrict argument) +{ + char *unitId; + + long long val = vlmcsd_strtoll(argument, &unitId, 10); + + switch (toupper((int)*unitId)) + { + case 'W': + val *= 7; + case 'D': + val *= 24; + case 'H': + val *= 60; + case 0: + case 'M': + val *= 60; + case 'S': + break; + default: + return 0; + } + + if (*unitId && unitId[1]) return 0; + if (val < 1) val = 1; + return (DWORD)(val & UINT_MAX); +} + + +#if !IS_LIBRARY +//Checks a command line argument if it is numeric and between min and max. Returns the numeric value or exits on error +__pure unsigned int getOptionArgumentInt(const char o, const unsigned int min, const unsigned int max) +{ + unsigned int result; + + if (!stringToInt(optarg, min, max, &result)) + { + printerrorf("Fatal: Option \"-%c\" must be numeric between %u and %u.\n", o, min, max); + exit(VLMCSD_EINVAL); + } + + return result; +} + +// Resets getopt() to start parsing from the beginning +void optReset(void) +{ +#if __minix__ || defined(__BSD__) || defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) + optind = 1; + optreset = 1; // Makes newer BSD getopt happy +#elif defined(__UCLIBC__) // uClibc headers also define __GLIBC__ so be careful here + optind = 0; // uClibc seeks compatibility with GLIBC +#elif defined(__GLIBC__) + optind = 0; // Makes GLIBC getopt happy +#else // Standard for most systems + optind = 1; +#endif +} +#endif // !IS_LIBRARY + +#if _WIN32 || __CYGWIN__ + +// Returns a static message buffer containing text for a given Win32 error. Not thread safe (same as strerror) +char* win_strerror(const int message) +{ +#define STRERROR_BUFFER_SIZE 256 + static char buffer[STRERROR_BUFFER_SIZE]; + + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK, NULL, message, 0, buffer, STRERROR_BUFFER_SIZE, NULL); + return buffer; +} + +#endif // _WIN32 || __CYGWIN__ + + +/* + * parses an address in the form host:[port] in addr + * returns host and port in seperate strings + */ +void parseAddress(char *const addr, char** szHost, char** szPort) +{ + *szHost = addr; + +# ifndef NO_SOCKETS + *szPort = (char*)defaultport; +# else // NO_SOCKETS + *szPort = "1688"; +# endif // NO_SOCKETS + + char *lastcolon = strrchr(addr, ':'); + char *firstcolon = strchr(addr, ':'); + char *closingbracket = strrchr(addr, ']'); + + if (*addr == '[' && closingbracket) //Address in brackets + { + *closingbracket = 0; + (*szHost)++; + + if (closingbracket[1] == ':') + *szPort = closingbracket + 2; + } + else if (firstcolon && firstcolon == lastcolon) //IPv4 address or hostname with port + { + *firstcolon = 0; + *szPort = firstcolon + 1; + } +} + + +// Initialize random generator (needs to be done in each thread) +void randomNumberInit() +{ +# if _MSC_VER + srand(GetTickCount()); +# else + struct timeval tv; + gettimeofday(&tv, NULL); + srand((unsigned int)(tv.tv_sec ^ tv.tv_usec)); +# endif +} + + +// We always exit immediately if any OOM condition occurs +__noreturn void OutOfMemory(void) +{ + errorout("Fatal: Out of memory"); + exit(VLMCSD_ENOMEM); +} + + +void* vlmcsd_malloc(size_t len) +{ + void* buf = malloc(len); + if (!buf) OutOfMemory(); + return buf; +} + +char* vlmcsd_strdup(const char* src) +{ +# if _MSC_VER + char* dst = _strdup(src); +# else // !_MSC_VER + char* dst = strdup(src); +# endif + + if (!dst) OutOfMemory(); + return dst; +} + + +/* + * Converts hex digits to bytes in big-endian order. + * Ignores any non-hex characters + */ +void hex2bin(BYTE *const bin, const char *hex, const size_t maxbin) +{ + static const char *const hexdigits = "0123456789ABCDEF"; + char* nextchar; + size_t i; + + for (i = 0; (i < 16) && utf8_to_ucs2_char((const unsigned char*)hex, (const unsigned char**)&nextchar) != (WCHAR)-1; hex = nextchar) + { + const char* pos = strchr(hexdigits, toupper((int)*hex)); + if (!pos) continue; + + if (!(i & 1)) bin[i >> 1] = 0; + bin[i >> 1] |= (char)(pos - hexdigits); + if (!(i & 1)) bin[i >> 1] <<= 4; + i++; + if (i >> 1 > maxbin) break; + } +} + + +__pure BOOL getArgumentBool(int_fast8_t *result, const char *const argument) +{ + if ( + !strncasecmp(argument, "true", 4) || + !strncasecmp(argument, "on", 2) || + !strncasecmp(argument, "yes", 3) || + !strncasecmp(argument, "1", 1) + ) + { + *result = TRUE; + return TRUE; + } + else if ( + !strncasecmp(argument, "false", 5) || + !strncasecmp(argument, "off", 3) || + !strncasecmp(argument, "no", 2) || + !strncasecmp(argument, "0", 1) + ) + { + *result = FALSE; + return TRUE; + } + + return FALSE; +} + +#ifndef IS_LIBRARY +#ifndef NO_EXTERNAL_DATA +__noreturn static void dataFileReadError() +{ + const int error = errno; + errorout("Fatal: Could not read %s: %s\n", fn_data, strerror(error)); + exit(error); +} + +__noreturn static void dataFileFormatError() +{ + errorout("Fatal: %s is not a KMS data file version 2.x\n", fn_data); + exit(VLMCSD_EINVAL); +} +#endif // NO_EXTERNAL_DATA + +#if !defined(DATA_FILE) || !defined(NO_SIGHUP) +void getExeName() +{ + if (fn_exe != NULL) return; + +# if (__GLIBC__ || __linux__) && defined(USE_AUXV) + + fn_exe = (char*)getauxval(AT_EXECFN); + +# elif (__ANDROID__ && __ANDROID_API__ < 16) || (__UCLIBC__ && __UCLIBC_MAJOR__ < 1 && !defined(NO_PROCFS)) // Workaround for older uclibc + + char temp[PATH_MAX + 1]; + + if (realpath("/proc/self/exe", temp) == temp) + { + fn_exe = vlmcsd_strdup(temp); + } + +# elif (__linux__ || __CYGWIN__) && !defined(NO_PROCFS) + + fn_exe = realpath("/proc/self/exe", NULL); + +# elif (__FreeBSD__ || __FreeBSD_kernel__) + + int mib[4]; + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PATHNAME; + mib[3] = -1; + char path[PATH_MAX + 1]; + size_t cb = sizeof(path); + + if (!sysctl(mib, 4, path, &cb, NULL, 0)) + { + fn_exe = vlmcsd_strdup(path); + } + +# elif (__DragonFly__) && !defined(NO_PROCFS) + + fn_exe = realpath("/proc/curproc/file", NULL); + +# elif __NetBSD__ && !defined(NO_PROCFS) + + fn_exe = realpath("/proc/curproc/exe", NULL); + +# elif __sun__ + + fn_exe = getexecname(); + +# elif __APPLE__ + + char path[PATH_MAX + 1]; + uint32_t size = sizeof(path); + + if (_NSGetExecutablePath(path, &size) == 0) + { + fn_exe = vlmcsd_strdup(path); + } + +# elif _WIN32 + + char path[512]; + GetModuleFileName(GetModuleHandle(NULL), path, 512); + path[511] = 0; + fn_exe = vlmcsd_strdup(path); + +# else + // Sorry no exe detection +# endif +} +#endif // defined(DATA_FILE) && defined(NO_SIGHUP) + +#if !defined(DATA_FILE) && !defined(NO_EXTERNAL_DATA) +#ifdef _WIN32 +static void getDefaultDataFile() +{ + char fileName[MAX_PATH]; + getExeName(); + strncpy(fileName, fn_exe, MAX_PATH); + PathRemoveFileSpec(fileName); + strncat(fileName, "\\vlmcsd.kmd", MAX_PATH - 11); + fn_data = vlmcsd_strdup(fileName); +} +#else // !_WIN32 +static void getDefaultDataFile() +{ + char fileName[512]; + getExeName(); + + if (!fn_exe) + { + fn_data = (char*)"/etc/vlmcsd.kmd"; + return; + } + + char* fn_exe_copy = vlmcsd_strdup(fn_exe); + strncpy(fileName, dirname(fn_exe_copy), 512); + free(fn_exe_copy); + strncat(fileName, "/vlmcsd.kmd", 500); + fn_data = vlmcsd_strdup(fileName); +} +#endif // !_WIN32 +#endif // !defined(DATA_FILE) && !defined(NO_EXTERNAL_DATA) + +void loadKmsData() +{ +# ifndef NO_INTERNAL_DATA + KmsData = (PVlmcsdHeader_t)DefaultKmsData; +# endif // NO_INTERNAL_DATA + +# ifndef NO_EXTERNAL_DATA + long size; +# ifndef NO_INTERNAL_DATA + size = (long)getDefaultKmsDataSize(); +# endif // NO_INTERNAL_DATA + +# ifndef DATA_FILE + if (!fn_data) getDefaultDataFile(); +# endif // DATA_FILE + + if (strcmp(fn_data, "-")) + { + FILE *file = fopen(fn_data, "rb"); + + if (!file) + { +# ifndef NO_INTERNAL_DATA + if (ExplicitDataLoad) +# endif // NO_INTERNAL_DATA + { + dataFileReadError(); + } + } + else + { + if (fseek(file, 0, SEEK_END)) dataFileReadError(); + size = ftell(file); + if (size == -1L) dataFileReadError(); + + KmsData = (PVlmcsdHeader_t)vlmcsd_malloc(size); + if (fseek(file, 0, SEEK_SET)) dataFileReadError(); + + const size_t bytesRead = fread(KmsData, 1, size, file); + if ((long)bytesRead != size) dataFileReadError(); + fclose(file); + +# if !defined(NO_LOG) && !defined(NO_SOCKETS) + if (!InetdMode) logger("Read KMS data file version %u.%u %s\n", (unsigned int)LE16(KmsData->MajorVer), (unsigned int)LE16(KmsData->MinorVer), fn_data); +# endif // NO_LOG + } + } + + +# endif // NO_EXTERNAL_DATA + +# ifndef UNSAFE_DATA_LOAD + if (((BYTE*)KmsData)[size - 1] != 0) dataFileFormatError(); +# endif // UNSAFE_DATA_LOAD + + KmsData->MajorVer = LE16(KmsData->MajorVer); + KmsData->MinorVer = LE16(KmsData->MinorVer); + KmsData->AppItemCount = LE32(KmsData->AppItemCount); + KmsData->KmsItemCount = LE32(KmsData->KmsItemCount); + KmsData->SkuItemCount = LE32(KmsData->SkuItemCount); + KmsData->HostBuildCount = LE32(KmsData->HostBuildCount); + + uint32_t i; + + for (i = 0; i < vlmcsd_countof(KmsData->Datapointers); i++) + { + KmsData->Datapointers[i].Pointer = (BYTE*)KmsData + LE64(KmsData->Datapointers[i].Offset); +# ifndef UNSAFE_DATA_LOAD + if ((BYTE*)KmsData->Datapointers[i].Pointer > (BYTE*)KmsData + size) dataFileFormatError(); +# endif // UNSAFE_DATA_LOAD + } + + for (i = 0; i < KmsData->CsvlkCount; i++) + { + PCsvlkData_t csvlkData = &KmsData->CsvlkData[i]; + csvlkData->EPid = (char*)KmsData + LE64(csvlkData->EPidOffset); + csvlkData->ReleaseDate = LE64(csvlkData->ReleaseDate); +# ifndef UNSAFE_DATA_LOAD + if (csvlkData->EPid > (char*)KmsData + size) dataFileFormatError(); +# endif // UNSAFE_DATA_LOAD + +# ifndef NO_RANDOM_EPID + csvlkData->GroupId = LE32(csvlkData->GroupId); + csvlkData->MinKeyId = LE32(csvlkData->MinKeyId); + csvlkData->MaxKeyId = LE32(csvlkData->MaxKeyId); +# endif // NO_RANDOM_EPID + } + + for (i = 0; i < (uint32_t)KmsData->HostBuildCount; i++) + { + PHostBuild_t hostBuild = &KmsData->HostBuildList[i]; + hostBuild->BuildNumber = LE32(hostBuild->BuildNumber); + hostBuild->Flags = LE32(hostBuild->Flags); + hostBuild->PlatformId = LE32(hostBuild->PlatformId); + hostBuild->ReleaseDate = LE64(hostBuild->ReleaseDate); + hostBuild->DisplayName = (char*)KmsData + LE64(hostBuild->DisplayNameOffset); +# ifndef UNSAFE_DATA_LOAD + if (hostBuild->DisplayName > (char*)KmsData + size) dataFileFormatError(); +# endif // UNSAFE_DATA_LOAD + } + + const uint32_t totalItemCount = KmsData->AppItemCount + KmsData->KmsItemCount + KmsData->SkuItemCount; + +# ifndef NO_EXTERNAL_DATA + if ( + memcmp(KmsData->Magic, "KMD", sizeof(KmsData->Magic)) || + KmsData->MajorVer != 2 +# ifndef UNSAFE_DATA_LOAD + || + sizeof(VlmcsdHeader_t) + totalItemCount * sizeof(VlmcsdData_t) >= ((uint64_t)size) +# endif //UNSAFE_DATA_LOAD + ) + { + dataFileFormatError(); + } +# endif // NO_EXTERNAL_DATA + + for (i = 0; i < totalItemCount; i++) + { + PVlmcsdData_t item = &KmsData->AppItemList[i]; + item->Name = (char*)KmsData + LE64(item->NameOffset); + +# ifndef UNSAFE_DATA_LOAD + if ( + item->Name >= (char*)KmsData + (uint64_t)size || + (KmsData->AppItemCount && item->AppIndex >= KmsData->AppItemCount) || + item->KmsIndex >= KmsData->KmsItemCount + ) + { + dataFileFormatError(); + } +# endif // UNSAFE_DATA_LOAD + } +} + +#ifndef NO_SOCKETS +void exitOnWarningLevel(const int_fast8_t level) +{ + if (ExitLevel >= level) + { + printerrorf("Fatal: Exiting on warning level %i or greater\n", (int)ExitLevel); + exit(-1); + } +} +#endif // !NO_SOCKETS + +#endif // IS_LIBRARY + + +#if __ANDROID__ && !defined(USE_THREADS) // Bionic does not wrap these syscalls (intentionally because Google fears, developers don't know how to use it) + +#ifdef __NR_shmget +int shmget(key_t key, size_t size, int shmflg) +{ + return syscall(__NR_shmget, key, size, shmflg); +} +#endif // __NR_shmget + +#ifdef __NR_shmat +void *shmat(int shmid, const void *shmaddr, int shmflg) +{ + return (void *)syscall(__NR_shmat, shmid, shmaddr, shmflg); +} +#endif // __NR_shmat + +#ifdef __NR_shmdt +int shmdt(const void *shmaddr) +{ + return syscall(__NR_shmdt, shmaddr); +} +#endif // __NR_shmdt + +#ifdef __NR_shmctl +int shmctl(int shmid, int cmd, /*struct shmid_ds*/void *buf) +{ + return syscall(__NR_shmctl, shmid, cmd, buf); +} +#endif // __NR_shmctl + +#endif // __ANDROID__ && !defined(USE_THREADS) + + diff --git a/vlmcsd/src/helpers.h b/vlmcsd/src/helpers.h new file mode 100644 index 0000000..d49aefd --- /dev/null +++ b/vlmcsd/src/helpers.h @@ -0,0 +1,57 @@ +#ifndef HELPERS_H +#define HELPERS_H + +#ifndef CONFIG +#define CONFIG "config.h" +#endif // CONFIG +#include CONFIG + +#include +#include "types.h" + +#if __ANDROID__ +#include +#endif // __ANDROID__ + +#define GUID_LE 0 +#define GUID_BE 1 +#define GUID_SWAP 2 + +BOOL stringToInt(const char *const szValue, const unsigned int min, const unsigned int max, unsigned int *const value); +unsigned int getOptionArgumentInt(const char o, const unsigned int min, const unsigned int max); +void optReset(void); +__pure DWORD timeSpanString2Seconds(const char *const restrict argument); +#define timeSpanString2Minutes(x) (timeSpanString2Seconds(x) / 60) +char* win_strerror(const int message); +int ucs2_to_utf8_char (const WCHAR ucs2_le, char *utf8); +size_t utf8_to_ucs2(WCHAR* const ucs2_le, const char* const utf8, const size_t maxucs2, const size_t maxutf8); +WCHAR utf8_to_ucs2_char (const unsigned char * input, const unsigned char ** end_ptr); +BOOL ucs2_to_utf8(const WCHAR* const ucs2_le, char* utf8, size_t maxucs2, size_t maxutf8); +int_fast8_t string2UuidLE(const char *const restrict input, GUID *const restrict guid); +void randomNumberInit(); +void parseAddress(char *const addr, char** szHost, char** szPort); +__noreturn void OutOfMemory(void); +void* vlmcsd_malloc(size_t len); +void hex2bin(BYTE *const bin, const char *hex, const size_t maxbin); +void loadKmsData(); +#if !defined(DATA_FILE) || !defined(NO_SIGHUP) +void getExeName(); +#endif // !defined(DATA_FILE) || !defined(NO_SIGHUP) +__pure BOOL getArgumentBool(int_fast8_t *result, const char *const argument); +char* vlmcsd_strdup(const char* src); + +#if defined(NO_SOCKETS) || IS_LIBRARY +#define exitOnWarningLevel(x) +#else // !NO_SOCKETS +void exitOnWarningLevel(const int_fast8_t level); +#endif // !NO_SOCKETS + + +#if __ANDROID__ && !defined(USE_THREADS) // Bionic does not wrap these syscalls (intentionally because Google fears, developers don't know how to use it) +int shmget(key_t key, size_t size, int shmflg); +void *shmat(int shmid, const void *shmaddr, int shmflg); +int shmdt(const void *shmaddr); +int shmctl(int shmid, int cmd, /*struct shmid_ds*/void *buf); +#endif // __ANDROID__ && !defined(USE_THREADS) + +#endif // HELPERS_H diff --git a/vlmcsd/src/ifaddrs-android.c b/vlmcsd/src/ifaddrs-android.c new file mode 100644 index 0000000..a9683f9 --- /dev/null +++ b/vlmcsd/src/ifaddrs-android.c @@ -0,0 +1,600 @@ +/* +Copyright (c) 2013, Kenneth MacKay +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "ifaddrs-android.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct NetlinkList +{ + struct NetlinkList *m_next; + struct nlmsghdr *m_data; + unsigned int m_size; +} NetlinkList; + +static int netlink_socket(void) +{ + int l_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + if(l_socket < 0) + { + return -1; + } + + struct sockaddr_nl l_addr; + memset(&l_addr, 0, sizeof(l_addr)); + l_addr.nl_family = AF_NETLINK; + if(bind(l_socket, (struct sockaddr *)&l_addr, sizeof(l_addr)) < 0) + { + close(l_socket); + return -1; + } + + return l_socket; +} + +static int netlink_send(int p_socket, int p_request) +{ + char l_buffer[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + NLMSG_ALIGN(sizeof(struct rtgenmsg))]; + memset(l_buffer, 0, sizeof(l_buffer)); + struct nlmsghdr *l_hdr = (struct nlmsghdr *)l_buffer; + struct rtgenmsg *l_msg = (struct rtgenmsg *)NLMSG_DATA(l_hdr); + + l_hdr->nlmsg_len = NLMSG_LENGTH(sizeof(*l_msg)); + l_hdr->nlmsg_type = p_request; + l_hdr->nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST; + l_hdr->nlmsg_pid = 0; + l_hdr->nlmsg_seq = p_socket; + l_msg->rtgen_family = AF_UNSPEC; + + struct sockaddr_nl l_addr; + memset(&l_addr, 0, sizeof(l_addr)); + l_addr.nl_family = AF_NETLINK; + return (sendto(p_socket, l_hdr, l_hdr->nlmsg_len, 0, (struct sockaddr *)&l_addr, sizeof(l_addr))); +} + +static int netlink_recv(int p_socket, void *p_buffer, size_t p_len) +{ + struct msghdr l_msg; + struct iovec l_iov = { p_buffer, p_len }; + struct sockaddr_nl l_addr; + //int l_result; + + for(;;) + { + l_msg.msg_name = (void *)&l_addr; + l_msg.msg_namelen = sizeof(l_addr); + l_msg.msg_iov = &l_iov; + l_msg.msg_iovlen = 1; + l_msg.msg_control = NULL; + l_msg.msg_controllen = 0; + l_msg.msg_flags = 0; + int l_result = recvmsg(p_socket, &l_msg, 0); + + if(l_result < 0) + { + if(errno == EINTR) + { + continue; + } + return -2; + } + + if(l_msg.msg_flags & MSG_TRUNC) + { // buffer was too small + return -1; + } + return l_result; + } +} + +static struct nlmsghdr *getNetlinkResponse(int p_socket, int *p_size, int *p_done) +{ + size_t l_size = 4096; + void *l_buffer = NULL; + + for(;;) + { + free(l_buffer); + l_buffer = malloc(l_size); + + int l_read = netlink_recv(p_socket, l_buffer, l_size); + *p_size = l_read; + if(l_read == -2) + { + free(l_buffer); + return NULL; + } + if(l_read >= 0) + { + pid_t l_pid = getpid(); + struct nlmsghdr *l_hdr; + for(l_hdr = (struct nlmsghdr *)l_buffer; NLMSG_OK(l_hdr, (unsigned int)l_read); l_hdr = (struct nlmsghdr *)NLMSG_NEXT(l_hdr, l_read)) + { + if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket) + { + continue; + } + + if(l_hdr->nlmsg_type == NLMSG_DONE) + { + *p_done = 1; + break; + } + + if(l_hdr->nlmsg_type == NLMSG_ERROR) + { + free(l_buffer); + return NULL; + } + } + return l_buffer; + } + + l_size *= 2; + } +} + +static NetlinkList *newListItem(struct nlmsghdr *p_data, unsigned int p_size) +{ + NetlinkList *l_item = malloc(sizeof(NetlinkList)); + l_item->m_next = NULL; + l_item->m_data = p_data; + l_item->m_size = p_size; + return l_item; +} + +static void freeResultList(NetlinkList *p_list) +{ + NetlinkList *l_cur; + while(p_list) + { + l_cur = p_list; + p_list = p_list->m_next; + free(l_cur->m_data); + free(l_cur); + } +} + +static NetlinkList *getResultList(int p_socket, int p_request) +{ + if(netlink_send(p_socket, p_request) < 0) + { + return NULL; + } + + NetlinkList *l_list = NULL; + NetlinkList *l_end = NULL; + int l_size; + int l_done = 0; + while(!l_done) + { + struct nlmsghdr *l_hdr = getNetlinkResponse(p_socket, &l_size, &l_done); + if(!l_hdr) + { // error + freeResultList(l_list); + return NULL; + } + + NetlinkList *l_item = newListItem(l_hdr, l_size); + if(!l_list) + { + l_list = l_item; + } + else + { + l_end->m_next = l_item; + } + l_end = l_item; + } + return l_list; +} + +static size_t maxSize(size_t a, size_t b) +{ + return (a > b ? a : b); +} + +static size_t calcAddrLen(sa_family_t p_family, int p_dataSize) +{ + switch(p_family) + { + case AF_INET: + return sizeof(struct sockaddr_in); + case AF_INET6: + return sizeof(struct sockaddr_in6); + case AF_PACKET: + return maxSize(sizeof(struct sockaddr_ll), offsetof(struct sockaddr_ll, sll_addr) + p_dataSize); + default: + return maxSize(sizeof(struct sockaddr), offsetof(struct sockaddr, sa_data) + p_dataSize); + } +} + +static void makeSockaddr(sa_family_t p_family, struct sockaddr *p_dest, void *p_data, size_t p_size) +{ + switch(p_family) + { + case AF_INET: + memcpy(&((struct sockaddr_in*)p_dest)->sin_addr, p_data, p_size); + break; + case AF_INET6: + memcpy(&((struct sockaddr_in6*)p_dest)->sin6_addr, p_data, p_size); + break; + case AF_PACKET: + memcpy(((struct sockaddr_ll*)p_dest)->sll_addr, p_data, p_size); + ((struct sockaddr_ll*)p_dest)->sll_halen = p_size; + break; + default: + memcpy(p_dest->sa_data, p_data, p_size); + break; + } + p_dest->sa_family = p_family; +} + +static void addToEnd(struct ifaddrs **p_resultList, struct ifaddrs *p_entry) +{ + if(!*p_resultList) + { + *p_resultList = p_entry; + } + else + { + struct ifaddrs *l_cur = *p_resultList; + while(l_cur->ifa_next) + { + l_cur = l_cur->ifa_next; + } + l_cur->ifa_next = p_entry; + } +} + +static void interpretLink(struct nlmsghdr *p_hdr, struct ifaddrs **p_links, struct ifaddrs **p_resultList) +{ + struct ifinfomsg *l_info = (struct ifinfomsg *)NLMSG_DATA(p_hdr); + + size_t l_nameSize = 0; + size_t l_addrSize = 0; + size_t l_dataSize = 0; + + size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg)); + struct rtattr *l_rta; + for(l_rta = (struct rtattr *)(((char *)l_info) + NLMSG_ALIGN(sizeof(struct ifinfomsg))); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) + { + //void *l_rtaData = RTA_DATA(l_rta); + size_t l_rtaDataSize = RTA_PAYLOAD(l_rta); + switch(l_rta->rta_type) + { + case IFLA_ADDRESS: + case IFLA_BROADCAST: + l_addrSize += NLMSG_ALIGN(calcAddrLen(AF_PACKET, l_rtaDataSize)); + break; + case IFLA_IFNAME: + l_nameSize += NLMSG_ALIGN(l_rtaSize + 1); + break; + case IFLA_STATS: + l_dataSize += NLMSG_ALIGN(l_rtaSize); + break; + default: + break; + } + } + + struct ifaddrs *l_entry = malloc(sizeof(struct ifaddrs) + l_nameSize + l_addrSize + l_dataSize); + memset(l_entry, 0, sizeof(struct ifaddrs)); + l_entry->ifa_name = ""; + + char *l_name = ((char *)l_entry) + sizeof(struct ifaddrs); + char *l_addr = l_name + l_nameSize; + char *l_data = l_addr + l_addrSize; + + l_entry->ifa_flags = l_info->ifi_flags; + + l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg)); + for(l_rta = (struct rtattr *)(((char *)l_info) + NLMSG_ALIGN(sizeof(struct ifinfomsg))); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) + { + void *l_rtaData = RTA_DATA(l_rta); + size_t l_rtaDataSize = RTA_PAYLOAD(l_rta); + switch(l_rta->rta_type) + { + case IFLA_ADDRESS: + case IFLA_BROADCAST: + { + size_t l_addrLen = calcAddrLen(AF_PACKET, l_rtaDataSize); + makeSockaddr(AF_PACKET, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize); + ((struct sockaddr_ll *)l_addr)->sll_ifindex = l_info->ifi_index; + ((struct sockaddr_ll *)l_addr)->sll_hatype = l_info->ifi_type; + if(l_rta->rta_type == IFLA_ADDRESS) + { + l_entry->ifa_addr = (struct sockaddr *)l_addr; + } + else + { + l_entry->ifa_broadaddr = (struct sockaddr *)l_addr; + } + l_addr += NLMSG_ALIGN(l_addrLen); + break; + } + case IFLA_IFNAME: + strncpy(l_name, l_rtaData, l_rtaDataSize); + l_name[l_rtaDataSize] = '\0'; + l_entry->ifa_name = l_name; + break; + case IFLA_STATS: + memcpy(l_data, l_rtaData, l_rtaDataSize); + l_entry->ifa_data = l_data; + break; + default: + break; + } + } + + addToEnd(p_resultList, l_entry); + p_links[l_info->ifi_index - 1] = l_entry; +} + +static void interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_links, struct ifaddrs **p_resultList) +{ + struct ifaddrmsg *l_info = (struct ifaddrmsg *)NLMSG_DATA(p_hdr); + + size_t l_nameSize = 0; + size_t l_addrSize = 0; + + int l_addedNetmask = 0; + + size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg)); + struct rtattr *l_rta; + for(l_rta = (struct rtattr *)(((char *)l_info) + NLMSG_ALIGN(sizeof(struct ifaddrmsg))); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) + { + //void *l_rtaData = RTA_DATA(l_rta); + size_t l_rtaDataSize = RTA_PAYLOAD(l_rta); + if(l_info->ifa_family == AF_PACKET) + { + continue; + } + + switch(l_rta->rta_type) + { + case IFA_ADDRESS: + case IFA_LOCAL: + if((l_info->ifa_family == AF_INET || l_info->ifa_family == AF_INET6) && !l_addedNetmask) + { // make room for netmask + l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize)); + l_addedNetmask = 1; + } + case IFA_BROADCAST: + l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize)); + break; + case IFA_LABEL: + l_nameSize += NLMSG_ALIGN(l_rtaSize + 1); + break; + default: + break; + } + } + + struct ifaddrs *l_entry = malloc(sizeof(struct ifaddrs) + l_nameSize + l_addrSize); + memset(l_entry, 0, sizeof(struct ifaddrs)); + l_entry->ifa_name = p_links[l_info->ifa_index - 1]->ifa_name; + + char *l_name = ((char *)l_entry) + sizeof(struct ifaddrs); + char *l_addr = l_name + l_nameSize; + + l_entry->ifa_flags = l_info->ifa_flags | p_links[l_info->ifa_index - 1]->ifa_flags; + + l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg)); + for(l_rta = (struct rtattr *)(((char *)l_info) + NLMSG_ALIGN(sizeof(struct ifaddrmsg))); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) + { + void *l_rtaData = RTA_DATA(l_rta); + size_t l_rtaDataSize = RTA_PAYLOAD(l_rta); + switch(l_rta->rta_type) + { + case IFA_ADDRESS: + case IFA_BROADCAST: + case IFA_LOCAL: + { + size_t l_addrLen = calcAddrLen(l_info->ifa_family, l_rtaDataSize); + makeSockaddr(l_info->ifa_family, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize); + if(l_info->ifa_family == AF_INET6) + { + if(IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)l_rtaData) || IN6_IS_ADDR_MC_LINKLOCAL((struct in6_addr *)l_rtaData)) + { + ((struct sockaddr_in6 *)l_addr)->sin6_scope_id = l_info->ifa_index; + } + } + + if(l_rta->rta_type == IFA_ADDRESS) + { // apparently in a point-to-point network IFA_ADDRESS contains the dest address and IFA_LOCAL contains the local address + if(l_entry->ifa_addr) + { + l_entry->ifa_dstaddr = (struct sockaddr *)l_addr; + } + else + { + l_entry->ifa_addr = (struct sockaddr *)l_addr; + } + } + else if(l_rta->rta_type == IFA_LOCAL) + { + if(l_entry->ifa_addr) + { + l_entry->ifa_dstaddr = l_entry->ifa_addr; + } + l_entry->ifa_addr = (struct sockaddr *)l_addr; + } + else + { + l_entry->ifa_broadaddr = (struct sockaddr *)l_addr; + } + l_addr += NLMSG_ALIGN(l_addrLen); + break; + } + case IFA_LABEL: + strncpy(l_name, l_rtaData, l_rtaDataSize); + l_name[l_rtaDataSize] = '\0'; + l_entry->ifa_name = l_name; + break; + default: + break; + } + } + + if(l_entry->ifa_addr && (l_entry->ifa_addr->sa_family == AF_INET || l_entry->ifa_addr->sa_family == AF_INET6)) + { + unsigned l_maxPrefix = (l_entry->ifa_addr->sa_family == AF_INET ? 32 : 128); + unsigned l_prefix = (l_info->ifa_prefixlen > l_maxPrefix ? l_maxPrefix : l_info->ifa_prefixlen); + char l_mask[16] = {0}; + unsigned i; + for(i=0; i<(l_prefix/8); ++i) + { + l_mask[i] = 0xff; + } + l_mask[i] = 0xff << (8 - (l_prefix % 8)); + + makeSockaddr(l_entry->ifa_addr->sa_family, (struct sockaddr *)l_addr, l_mask, l_maxPrefix / 8); + l_entry->ifa_netmask = (struct sockaddr *)l_addr; + } + + addToEnd(p_resultList, l_entry); +} + +static void interpret(int p_socket, NetlinkList *p_netlinkList, struct ifaddrs **p_links, struct ifaddrs **p_resultList) +{ + pid_t l_pid = getpid(); + for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next) + { + unsigned int l_nlsize = p_netlinkList->m_size; + struct nlmsghdr *l_hdr; + for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize)) + { + if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket) + { + continue; + } + + if(l_hdr->nlmsg_type == NLMSG_DONE) + { + break; + } + + if(l_hdr->nlmsg_type == RTM_NEWLINK) + { + interpretLink(l_hdr, p_links, p_resultList); + } + else if(l_hdr->nlmsg_type == RTM_NEWADDR) + { + interpretAddr(l_hdr, p_links, p_resultList); + } + } + } +} + +static unsigned countLinks(int p_socket, NetlinkList *p_netlinkList) +{ + unsigned l_links = 0; + pid_t l_pid = getpid(); + for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next) + { + unsigned int l_nlsize = p_netlinkList->m_size; + struct nlmsghdr *l_hdr; + for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize)) + { + if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket) + { + continue; + } + + if(l_hdr->nlmsg_type == NLMSG_DONE) + { + break; + } + + if(l_hdr->nlmsg_type == RTM_NEWLINK) + { + ++l_links; + } + } + } + + return l_links; +} + +int getifaddrs(struct ifaddrs **ifap) +{ + if(!ifap) + { + return -1; + } + *ifap = NULL; + + int l_socket = netlink_socket(); + if(l_socket < 0) + { + return -1; + } + + NetlinkList *l_linkResults = getResultList(l_socket, RTM_GETLINK); + if(!l_linkResults) + { + close(l_socket); + return -1; + } + + NetlinkList *l_addrResults = getResultList(l_socket, RTM_GETADDR); + if(!l_addrResults) + { + close(l_socket); + freeResultList(l_linkResults); + return -1; + } + + unsigned l_numLinks = countLinks(l_socket, l_linkResults) + countLinks(l_socket, l_addrResults); + struct ifaddrs *l_links[l_numLinks]; + memset(l_links, 0, l_numLinks * sizeof(struct ifaddrs *)); + + interpret(l_socket, l_linkResults, l_links, ifap); + interpret(l_socket, l_addrResults, l_links, ifap); + + freeResultList(l_linkResults); + freeResultList(l_addrResults); + close(l_socket); + return 0; +} + +void freeifaddrs(struct ifaddrs *ifa) +{ + struct ifaddrs *l_cur; + while(ifa) + { + l_cur = ifa; + ifa = ifa->ifa_next; + free(l_cur); + } +} diff --git a/vlmcsd/src/ifaddrs-android.h b/vlmcsd/src/ifaddrs-android.h new file mode 100644 index 0000000..0712011 --- /dev/null +++ b/vlmcsd/src/ifaddrs-android.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 1995, 1999 + * Berkeley Software Design, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * BSDI ifaddrs.h,v 2.5 2000/02/23 14:51:59 dab Exp + */ + +#if !__ANDROID__ +#error ifaddrs-android only works with Android +#endif + +#ifndef _IFADDRS_H_ +#define _IFADDRS_H_ + +struct ifaddrs { + struct ifaddrs *ifa_next; + char *ifa_name; + unsigned int ifa_flags; + struct sockaddr *ifa_addr; + struct sockaddr *ifa_netmask; + struct sockaddr *ifa_dstaddr; + void *ifa_data; +}; + +/* + * This may have been defined in . Note that if is + * to be included it must be included before this header file. + */ +#ifndef ifa_broadaddr +#define ifa_broadaddr ifa_dstaddr /* broadcast address interface */ +#endif + +#include + +__BEGIN_DECLS +extern int getifaddrs(struct ifaddrs **ifap); +extern void freeifaddrs(struct ifaddrs *ifa); +__END_DECLS + +#endif diff --git a/vlmcsd/src/ifaddrs-musl.h b/vlmcsd/src/ifaddrs-musl.h new file mode 100644 index 0000000..6e10839 --- /dev/null +++ b/vlmcsd/src/ifaddrs-musl.h @@ -0,0 +1,43 @@ +#ifndef _IFADDRS_H +#define _IFADDRS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#if !__linux__ +#error ifaddrs-musl.h only works with a Linux kernel +#endif + +#if __ANDROID__ +#error ifaddrs-musl.h does not work with Android +#endif + +#include +#include +#include + +struct ifaddrs { + struct ifaddrs *ifa_next; + char *ifa_name; + unsigned ifa_flags; + struct sockaddr *ifa_addr; + struct sockaddr *ifa_netmask; + union { + struct sockaddr *ifu_broadaddr; + struct sockaddr *ifu_dstaddr; + } ifa_ifu; + void *ifa_data; +}; +#define ifa_broadaddr ifa_ifu.ifu_broadaddr +#define ifa_dstaddr ifa_ifu.ifu_dstaddr + +void freeifaddrs(struct ifaddrs *ifp); +int getifaddrs(struct ifaddrs **ifap); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/vlmcsd/src/kms.c b/vlmcsd/src/kms.c new file mode 100644 index 0000000..9e31a72 --- /dev/null +++ b/vlmcsd/src/kms.c @@ -0,0 +1,1202 @@ +#ifndef CONFIG +#define CONFIG "config.h" +#endif // CONFIG +#include CONFIG + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#ifndef _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include +#include +#include +#include +#include +#if !defined(_WIN32) +#if !__ANDROID__ +#include +#endif // !__ANDROID__ +#include +#include +#endif // !defined(_WIN32) + +#include "output.h" +#include "crypto.h" +#include "endian.h" +#include "kms.h" +#include "shared_globals.h" +#include "helpers.h" + +#define FRIENDLY_NAME_WINDOWS "Windows" +#define FRIENDLY_NAME_OFFICE2010 "Office 2010" +#define FRIENDLY_NAME_OFFICE2013 "Office 2013+" + +#ifndef IS_LIBRARY + +#ifdef NO_LOG +#define LOGTEXT(x) "" +#else //!NO_LOG +#define LOGTEXT(x) x +#endif // !NO_LOG + +int32_t getProductIndex(const GUID* guid, const PVlmcsdData_t list, const int32_t count, char** name, char** ePid) +{ + int i; + + for (i = count - 1; i >= 0; i--) + { + if (IsEqualGUID(guid, &list[i].Guid)) + { + if (name) *name = list[i].Name; + if (ePid) *ePid = KmsData->CsvlkData[list[i].EPidIndex].EPid; + return i; + } + } + + if (name) *name = (char*)"Unknown"; + if (ePid) *ePid = KmsData->CsvlkData->EPid; + return i; +} + +#if !defined(NO_INI_FILE)||!defined(NO_VERBOSE_LOG) +const char* getNextString(const char* s) +{ + return s + strlen(s) + 1; +} +#endif //!defined(NO_INI_FILE)||!defined(NO_VERBOSE_LOG) + +#endif // IS_LIBRARY + + +#ifndef NO_RANDOM_EPID +//static const uint16_t HostBuilds[] = { 6002, 7601, 9200, 9600, 14393, 17763 }; + +// Valid language identifiers to be used in the ePID +static const uint16_t LcidList[] = { + 1078, 1052, 1025, 2049, 3073, 4097, 5121, 6145, 7169, 8193, 9217, 10241, 11265, 12289, 13313, 14337, 15361, 16385, + 1067, 1068, 2092, 1069, 1059, 1093, 5146, 1026, 1027, 1028, 2052, 3076, 4100, 5124, 1050, 4122, 1029, 1030, 1125, 1043, 2067, + 1033, 2057, 3081, 4105, 5129, 6153, 7177, 8201, 9225, 10249, 11273, 12297, 13321, 1061, 1080, 1065, 1035, 1036, 2060, + 3084, 4108, 5132, 6156, 1079, 1110, 1031, 2055, 3079, 4103, 5127, 1032, 1095, 1037, 1081, 1038, 1039, 1057, 1040, 2064, 1041, 1099, + 1087, 1111, 1042, 1088, 1062, 1063, 1071, 1086, 2110, 1100, 1082, 1153, 1102, 1104, 1044, 2068, 1045, 1046, 2070, + 1094, 1131, 2155, 3179, 1048, 1049, 9275, 4155, 5179, 3131, 1083, 2107, 8251, 6203, 7227, 1103, 2074, 6170, 3098, + 7194, 1051, 1060, 1034, 2058, 3082, 4106, 5130, 6154, 7178, 8202, 9226, 10250, 11274, 12298, 13322, 14346, 15370, 16394, + 17418, 18442, 19466, 20490, 1089, 1053, 2077, 1114, 1097, 1092, 1098, 1054, 1074, 1058, 1056, 1091, 2115, 1066, 1106, 1076, 1077 +}; + +int32_t getPlatformId(int32_t hostBuild) +{ + int32_t i; + + for (i = 0; i < KmsData->HostBuildCount; i++) + { + if (KmsData->HostBuildList[i].BuildNumber <= hostBuild) + { + return KmsData->HostBuildList[i].PlatformId; + } + } + + return KmsData->HostBuildList[KmsData->HostBuildCount - 1].PlatformId; +} + + +time_t getReleaseDate(int32_t hostBuild) +{ + int32_t i; + + for (i = KmsData->HostBuildCount - 1; i >= 0; i--) + { + if (KmsData->HostBuildList[i].BuildNumber >= hostBuild) + { + return (time_t)KmsData->HostBuildList[i].ReleaseDate; + } + } + + return (time_t)KmsData->HostBuildList->ReleaseDate; +} + + +#ifdef _PEDANTIC +uint16_t IsValidLcid(const uint16_t lcid) +{ + uint16_t i; + + for (i = 0; i < vlmcsd_countof(LcidList); i++) + { + if (lcid == LcidList[i]) return lcid; + } + + return 0; +} + + +uint32_t IsValidHostBuild(const int32_t hostBuild) +{ + PHostBuild_t hostOS; + + for (hostOS = KmsData->HostBuildList; hostOS < KmsData->HostBuildList + KmsData->HostBuildCount; hostOS++) + { + if (hostBuild == hostOS->BuildNumber) return hostBuild; + } + + return 0; +} +#endif // _PEDANTIC +#endif // NO_RANDOM_EPID + + +// Unix time is seconds from 1970-01-01. Should be 64 bits to avoid year 2038 overflow bug. +// FILETIME is 100 nanoseconds from 1601-01-01. Must be 64 bits. +void getUnixTimeAsFileTime(FILETIME* ts) +{ + const int64_t unixtime = (int64_t)time(NULL); + int64_t *filetime = (int64_t*)ts; + + PUT_UA64LE(filetime, (unixtime + 11644473600LL) * 10000000LL); +} + +__pure int64_t fileTimeToUnixTime(FILETIME* ts) +{ + return GET_UA64LE(ts) / 10000000LL - 11644473600LL; +} + + +#ifndef NO_STRICT_MODES +#ifndef NO_CLIENT_LIST + +static PClientList_t ClientLists; +static BYTE ZeroGuid[16] = { 0 }; + +#if !defined(_WIN32) && !defined(__CYGWIN__) +pthread_mutex_t* mutex; +#define mutex_size (((sizeof(pthread_mutex_t)+7)>>3)<<3) +#else +CRITICAL_SECTION* mutex; +#define mutex_size (((sizeof(CRITICAL_SECTION)+7)>>3)<<3) +#endif // _WIN32 + +#ifndef USE_THREADS +static int shmid_clients = -1; +#endif // USE_THREADS + +#if !defined(_WIN32) && !defined(__CYGWIN__) +#define lock_client_lists() pthread_mutex_lock(mutex) +#define unlock_client_lists() pthread_mutex_unlock(mutex) +#define mutex_t pthread_mutex_t +#else +#define lock_client_lists() EnterCriticalSection(mutex) +#define unlock_client_lists() LeaveCriticalSection(mutex) +#define mutex_t CRITICAL_SECTION +#endif + +void CleanUpClientLists() +{ +# ifndef USE_THREADS + shmctl(shmid_clients, IPC_RMID, NULL); +# endif // !USE_THREADS +} + +void InitializeClientLists() +{ + int_fast8_t i; + int_fast16_t j; + +# ifndef USE_THREADS + if ( + (shmid_clients = shmget(IPC_PRIVATE, sizeof(ClientList_t) * KmsData->AppItemCount + mutex_size, IPC_CREAT | 0600)) < 0 || + (mutex = (mutex_t*)shmat(shmid_clients, NULL, 0)) == (mutex_t*)-1 + ) + { + int errno_save = errno; + printerrorf("Warning: CMID lists disabled. Could not create shared memory: %s\n", vlmcsd_strerror(errno_save)); + if (shmid_clients >= 0) shmctl(shmid_clients, IPC_RMID, NULL); + MaintainClients = FALSE; + return; + } + + ClientLists = (PClientList_t)((BYTE*)mutex + mutex_size); + +# if __CYGWIN__ + InitializeCriticalSection(mutex); +# else // !__CYGWIN__ + pthread_mutexattr_t mutex_attr; + pthread_mutexattr_init(&mutex_attr); + pthread_mutexattr_setpshared(&mutex_attr, PTHREAD_PROCESS_SHARED); + pthread_mutex_init(mutex, &mutex_attr); + +# endif // !__CYGWIN__ + +# else // USE_THREADS + + ClientLists = (PClientList_t)vlmcsd_malloc(sizeof(ClientList_t) * KmsData->AppItemCount); + mutex = (mutex_t*)vlmcsd_malloc(sizeof(mutex_t)); + +# if !_WIN32 && !__CYGWIN__ + pthread_mutex_init(mutex, NULL); +# else //_WIN32 || __CYGWIN__ + InitializeCriticalSection(mutex); +# endif //_WIN32 || __CYGWIN__ + +# endif // USE_THREADS + + memset(ClientLists, 0, sizeof(ClientList_t) * KmsData->AppItemCount); + + if (!StartEmpty) + { + for (i = 0; i < KmsData->AppItemCount; i++) + { + const uint8_t maxCount = KmsData->AppItemList[i].NCountPolicy; + ClientLists[i].CurrentCount = (maxCount >> 1) - 1; + ClientLists[i].MaxCount = maxCount; + + for (j = 0; j < (maxCount >> 1) - 1; j++) + { + get16RandomBytes(&ClientLists[i].Guid[j]); + } + } + } +} +#endif // NO_CLIENT_LIST +#endif // !NO_STRICT_MODES + +#ifndef NO_RANDOM_EPID +// formats an int with a fixed number of digits with leading zeros (helper for ePID generation) +static char* itoc(char *const c, const int i, uint_fast8_t digits) +{ + char formatString[8]; + if (digits > 9) digits = 0; + strcpy(formatString, "%"); + + if (digits) + { + formatString[1] = '0'; + formatString[2] = digits | 0x30; + formatString[3] = 0; + } + + strcat(formatString, "u"); + sprintf(c, formatString, i); + return c; +} + +static uint8_t getRandomServerType() +{ +# if defined(USE_MSRPC) || defined(SIMPLE_RPC) + + return rand() % KmsData->HostBuildCount; + +# else // !defined(USE_MSRPC) && !defined(SIMPLE_RPC) + while (TRUE) + { + const uint32_t buildIndex = rand() % KmsData->HostBuildCount; + + if (!(KmsData->HostBuildList[buildIndex].Flags & UseNdr64) == !UseServerRpcNDR64) + { + return (uint8_t)buildIndex; + } + } +# endif // !defined(USE_MSRPC) && !defined(SIMPLE_RPC) +} + + +/* + * Generates a random ePID + */ +static void generateRandomPid(const int index, char *const szPid, int16_t lang, int32_t hostBuild) +{ + char numberBuffer[12]; + + if (!hostBuild) + { + hostBuild = KmsData->HostBuildList[getRandomServerType()].BuildNumber; + } + + + strcpy(szPid, itoc(numberBuffer, getPlatformId(hostBuild), 5)); + strcat(szPid, "-"); + + //if (index > 3) index = 0; + + PCsvlkData_t csvlkData = &KmsData->CsvlkData[index]; + strcat(szPid, itoc(numberBuffer, csvlkData->GroupId, 5)); + strcat(szPid, "-"); + + const int keyId = (rand32() % (csvlkData->MaxKeyId - csvlkData->MinKeyId)) + csvlkData->MinKeyId; + strcat(szPid, itoc(numberBuffer, keyId / 1000000, 3)); + strcat(szPid, "-"); + strcat(szPid, itoc(numberBuffer, keyId % 1000000, 6)); + strcat(szPid, "-03-"); + + if (lang < 1) lang = LcidList[rand() % vlmcsd_countof(LcidList)]; + strcat(szPid, itoc(numberBuffer, lang, 0)); + strcat(szPid, "-"); + + strcat(szPid, itoc(numberBuffer, hostBuild, 0)); + strcat(szPid, ".0000-"); + + const time_t hostBuildReleaseDate = getReleaseDate(hostBuild); + const time_t minTime = csvlkData->ReleaseDate < hostBuildReleaseDate ? hostBuildReleaseDate : csvlkData->ReleaseDate; + + time_t maxTime; + time(&maxTime); + +# ifndef BUILD_TIME +# define BUILD_TIME 1538922811 +# endif + + if (maxTime < (time_t)BUILD_TIME) // Just in case the system time is < 10/17/2013 1:00 pm + maxTime = (time_t)BUILD_TIME; + + time_t kmsTime = (rand32() % (maxTime - minTime)) + minTime; + struct tm *pidTime = gmtime(&kmsTime); + + strcat(szPid, itoc(numberBuffer, pidTime->tm_yday + 1, 3)); + strcat(szPid, itoc(numberBuffer, pidTime->tm_year + 1900, 4)); +} + + +/* + * Generates random ePIDs and stores them if not already read from ini file. + * For use with randomization level 1 + */ +void randomPidInit() +{ + uint32_t i; + + const int16_t lang = Lcid ? Lcid : LcidList[rand() % vlmcsd_countof(LcidList)]; + + for (i = 0; i < KmsData->CsvlkCount; i++) + { + if (KmsResponseParameters[i].Epid) continue; + + char Epid[PID_BUFFER_SIZE]; + + if (!HostBuild) + { + uint8_t index; + +#if defined(USE_MSRPC) || defined(SIMPLE_RPC) + index = getRandomServerType(); +#else // !(defined(USE_MSRPC) || defined(SIMPLE_RPC)) + if (IsNDR64Defined) + { + index = getRandomServerType(); + } + else + { + index = (uint8_t)(rand() % KmsData->HostBuildCount); + UseServerRpcNDR64 = !!(KmsData->HostBuildList[index].Flags & UseNdr64); + } +#endif // !(defined(USE_MSRPC) || defined(SIMPLE_RPC)) + + HostBuild = (uint16_t)KmsData->HostBuildList[index].BuildNumber; + } + + generateRandomPid(i, Epid, lang, HostBuild); + KmsResponseParameters[i].Epid = (const char*)vlmcsd_strdup(Epid); + +#ifndef NO_LOG + KmsResponseParameters[i].EpidSource = "randomized at program start"; + KmsResponseParameters[i].IsRandom = TRUE; +#endif // NO_LOG + } +} + +#endif // NO_RANDOM_EPID + + +#ifndef NO_LOG +static int32_t getProductIndexFromAllLists(const GUID* guid, char** productName) +{ + return getProductIndex(guid, KmsData->AppItemList, KmsData->AppItemCount + KmsData->KmsItemCount + KmsData->SkuItemCount, productName, NULL); +} + +/* + * Logs a Request + */ +static void logRequest(REQUEST* baseRequest) +{ +#ifndef NO_VERBOSE_LOG + if (logverbose) + { + logger("<<< Incoming KMS request\n"); + logRequestVerbose(baseRequest, &logger); + return; + } +#endif // NO_VERBOSE_LOG + + char *productName; + char clientName[64]; + + int32_t index = getProductIndexFromAllLists(&baseRequest->ActID, &productName); + if (index < 0) index = getProductIndexFromAllLists(&baseRequest->KMSID, &productName); + if (index < 0) index = getProductIndexFromAllLists(&baseRequest->AppID, &productName); + + if (index < 0 || !strcasecmp(productName, "Unknown")) + { + productName = (char*)alloca(GUID_STRING_LENGTH + 1); + uuid2StringLE(&baseRequest->ActID, productName); + } + + ucs2_to_utf8(baseRequest->WorkstationName, clientName, 64, 64); + logger("KMS v%i.%i request from %s for %s\n", LE16(baseRequest->MajorVer), LE16(baseRequest->MinorVer), clientName, productName); +} +#endif // NO_LOG + + +/* + * Converts a utf-8 ePID string to UCS-2 and writes it to a RESPONSE struct + */ +#ifndef IS_LIBRARY +static void getEpidFromString(RESPONSE *const Response, const char *const pid) +{ + const size_t length = utf8_to_ucs2(Response->KmsPID, pid, PID_BUFFER_SIZE, PID_BUFFER_SIZE * 3); + Response->PIDSize = LE32(((unsigned int)length + 1) << 1); +} + + +/* + * get ePID from appropriate source + */ +static void getEpid(RESPONSE *const baseResponse, const char** EpidSource, const int32_t index, BYTE *const HwId, const char* defaultEPid) +{ +#if !defined(NO_RANDOM_EPID) || !defined(NO_CL_PIDS) || !defined(NO_INI_FILE) + const char* pid; + if (KmsResponseParameters[index].Epid == NULL) + { +#ifndef NO_RANDOM_EPID + if (RandomizationLevel == 2) + { + char ePid[PID_BUFFER_SIZE]; + generateRandomPid(index, ePid, Lcid, HostBuild); + pid = ePid; + +#ifndef NO_LOG + *EpidSource = "randomized on every request"; +#endif // NO_LOG + } + else +#endif // NO_RANDOM_EPID + { + pid = defaultEPid; +#ifndef NO_LOG + *EpidSource = "vlmcsd default"; +#endif // NO_LOG + } + } + else + { + pid = KmsResponseParameters[index].Epid; + + if (HwId && KmsResponseParameters[index].HwId != NULL) + memcpy(HwId, KmsResponseParameters[index].HwId, sizeof(((RESPONSE_V6 *)0)->HwId)); + +#ifndef NO_LOG + *EpidSource = KmsResponseParameters[index].EpidSource; +#endif // NO_LOG + } + + getEpidFromString(baseResponse, pid); + +#else // defined(NO_RANDOM_EPID) && defined(NO_CL_PIDS) && !defined(NO_INI_FILE) + + getEpidFromString(baseResponse, defaultEPid); + +# ifndef NO_LOG + *EpidSource = "vlmcsd default"; +# endif // NO_LOG + +#endif // defined(NO_RANDOM_EPID) && defined(NO_CL_PIDS) && !defined(NO_INI_FILE) +} +#endif // IS_LIBRARY + + +#if !defined(NO_LOG) && defined(_PEDANTIC) +static BOOL CheckVersion4Uuid(const GUID *const guid, const char *const szGuidName) +{ + if (LE16(guid->Data3) >> 12 != 4 || guid->Data4[0] >> 6 != 2) + { + logger("Warning: %s does not conform to version 4 UUID according to RFC 4122\n", szGuidName); + return FALSE; + } + return TRUE; +} + + +static void CheckRequest(const REQUEST *const Request) +{ + CheckVersion4Uuid(&Request->CMID, "Client machine ID"); + CheckVersion4Uuid(&Request->AppID, "Application ID"); + CheckVersion4Uuid(&Request->KMSID, "Server SKU ID"); + CheckVersion4Uuid(&Request->ActID, "Client SKU ID"); + + if (LE32(Request->IsClientVM) > 1) + logger("Warning: Virtual Machine field in request must be 0 or 1 but is %u\n", LE32(Request->IsClientVM)); + + if (LE32(Request->LicenseStatus) > 6) + logger("Warning: License status must be between 0 and 6 but is %u\n", LE32(Request->LicenseStatus)); +} +#endif // !defined(NO_LOG) && defined(_PEDANTIC) + + +#ifndef NO_LOG +/* + * Logs the Response + */ +static void logResponse(RESPONSE* baseResponse, const BYTE *const hwId, const char *const EpidSource) +{ + char utf8pid[PID_BUFFER_SIZE * 3]; + ucs2_to_utf8(baseResponse->KmsPID, utf8pid, PID_BUFFER_SIZE, PID_BUFFER_SIZE * 3); + +#ifndef NO_VERBOSE_LOG + if (!logverbose) + { +#endif // NO_VERBOSE_LOG + logger("Sending ePID (%s): %s\n", EpidSource, utf8pid); +#ifndef NO_VERBOSE_LOG + } + else + { + logger(">>> Sending response, ePID source = %s\n", EpidSource); + logResponseVerbose(utf8pid, hwId, baseResponse, &logger); + } +#endif // NO_VERBOSE_LOG + +} +#endif + + +#if __UCLIBC__ && !defined(NO_STRICT_MODES) +long long int llabs(long long int j); +#endif + + +/* + * Creates the unencrypted base response + */ +#ifndef IS_LIBRARY +static HRESULT __stdcall CreateResponseBaseCallback(REQUEST* baseRequest, RESPONSE *const baseResponse, BYTE *const hwId, const char* const ipstr_unused) +{ + const char* EpidSource; +#ifndef NO_LOG + logRequest(baseRequest); +#ifdef _PEDANTIC + CheckRequest(baseRequest); +#endif // _PEDANTIC +#endif // NO_LOG + + char* ePid; + const DWORD minClients = LE32(baseRequest->N_Policy); + const DWORD required_clients = minClients < 1 ? 1 : minClients << 1; + + const int32_t index = getProductIndex(&baseRequest->KMSID, KmsData->KmsItemList, KmsData->KmsItemCount, NULL, &ePid); + +# ifndef NO_STRICT_MODES + + if (required_clients > 2000) + { +# ifndef NO_LOG + logger("Rejecting request with more than 1000 minimum clients (0x8007000D)\n"); +# endif + + return 0x8007000D; + } + + if (CheckClientTime) + { + time_t requestTime = (time_t)fileTimeToUnixTime(&baseRequest->ClientTime); + + if (llabs(requestTime - time(NULL)) > 60 * 60 * 4) + { +# ifndef NO_LOG + logger("Client time differs more than 4 hours from system time (0xC004F06C)\n"); +# endif // !NO_LOG + + return 0xC004F06C; + } + } + + if (WhitelistingLevel & 2) + { + if (index >= 0 && (KmsData->KmsItemList[index].IsPreview || KmsData->KmsItemList[index].IsRetail)) + { +# ifndef NO_LOG + logger("Refusing retail or beta product (0xC004F042)\n"); +# endif // !NO_LOG + + return 0xC004F042; + } + } + + if ((WhitelistingLevel & 1) && index < 0) + { +# ifndef NO_LOG + logger("Refusing unknown product (0xC004F042)\n"); +# endif // !NO_LOG + + return 0xC004F042; + } + +# ifndef NO_CLIENT_LIST + const int32_t appIndex = index < 0 ? 0 : KmsData->KmsItemList[index].AppIndex; +# endif // NO_CLIENT_LIST + +# endif // !NO_STRICT_MODES + + const int32_t ePidIndex = index < 0 ? 0 : KmsData->KmsItemList[index].EPidIndex; + +# if !defined(NO_STRICT_MODES) + + if ((WhitelistingLevel & 1) && index >= 0 && !IsEqualGUID(&KmsData->AppItemList[KmsData->KmsItemList[index].AppIndex].Guid, &baseRequest->AppID)) + { +# ifndef NO_LOG + logger("Refusing product with incorrect Application ID (0xC004F042)\n"); +# endif // NO_LOG + return 0xC004F042; + } + +# ifndef NO_CLIENT_LIST + if (MaintainClients) + { + lock_client_lists(); + + int_fast16_t i; + int_fast8_t isKnownClient = FALSE; + + if (required_clients > (DWORD)ClientLists[appIndex].MaxCount) ClientLists[appIndex].MaxCount = required_clients; + + for (i = 0; i < ClientLists[appIndex].MaxCount; i++) + { + if (IsEqualGUID(&ClientLists[appIndex].Guid[i], &baseRequest->CMID)) + { + isKnownClient = TRUE; + break; + } + } + + if (isKnownClient) + { + baseResponse->Count = LE32(ClientLists[appIndex].CurrentCount); + } + else + { + for (i = 0; i < ClientLists[appIndex].MaxCount; i++) + { + if (IsEqualGUID(ZeroGuid, &ClientLists[appIndex].Guid[i])) + { + if (ClientLists[appIndex].CurrentCount >= MAX_CLIENTS) + { +# ifndef NO_LOG + logger("Rejecting more than 671 clients (0xC004D104)\n"); +# endif // !NO_LOG + + unlock_client_lists(); + return 0xC004D104; + } + + baseResponse->Count = LE32(++ClientLists[appIndex].CurrentCount); + memcpy(&ClientLists[appIndex].Guid[i], &baseRequest->CMID, sizeof(GUID)); + break; + } + } + + if (i >= ClientLists[appIndex].MaxCount) + { + memcpy(&ClientLists[appIndex].Guid[ClientLists[appIndex].CurrentPosition], &baseRequest->CMID, sizeof(GUID)); + ClientLists[appIndex].CurrentPosition = (ClientLists[appIndex].CurrentPosition + 1) % (ClientLists[appIndex].MaxCount > MAX_CLIENTS ? MAX_CLIENTS : ClientLists[appIndex].MaxCount); + baseResponse->Count = LE32(ClientLists[appIndex].CurrentCount); + } + } + + unlock_client_lists(); + } + else +# endif // !NO_CLIENT_LIST +# endif // !defined(NO_STRICT_MODES) + { + const uint8_t minimum_answer_clients = (uint8_t)KmsData->CsvlkData[ePidIndex].MinActiveClients; + baseResponse->Count = LE32(required_clients > minimum_answer_clients ? required_clients : minimum_answer_clients); + //if (LE32(baseRequest->N_Policy) > LE32(baseResponse->Count)) baseResponse->Count = LE32(LE32(baseRequest->N_Policy) << 1); + } + + getEpid(baseResponse, &EpidSource, ePidIndex, hwId, ePid); + + baseResponse->Version = baseRequest->Version; + + memcpy(&baseResponse->CMID, &baseRequest->CMID, sizeof(GUID)); + memcpy(&baseResponse->ClientTime, &baseRequest->ClientTime, sizeof(FILETIME)); + + baseResponse->VLActivationInterval = LE32(VLActivationInterval); + baseResponse->VLRenewalInterval = LE32(VLRenewalInterval); + +#ifndef NO_LOG + logResponse(baseResponse, hwId, EpidSource); +#endif // NO_LOG + + return S_OK; +} + +RequestCallback_t CreateResponseBase = &CreateResponseBaseCallback; + +#else // IS_LIBRARY + +RequestCallback_t CreateResponseBase = NULL; + +#endif // IS_LIBRARY + + +////TODO: Move to helpers.c +void get16RandomBytes(void* ptr) +{ + int i; + for (i = 0; i < 4; i++) ((DWORD*)ptr)[i] = rand32(); +} + +/* + * Creates v4 response + */ +size_t CreateResponseV4(REQUEST_V4 *const request_v4, BYTE *const responseBuffer, const char* const ipString) +{ + RESPONSE_V4* response = (RESPONSE_V4*)responseBuffer; + + HRESULT hResult; + if (FAILED(hResult = CreateResponseBase(&request_v4->RequestBase, &response->ResponseBase, NULL, ipString))) return hResult; + + const DWORD pidSize = LE32(response->ResponseBase.PIDSize); + BYTE* postEpidPtr = responseBuffer + V4_PRE_EPID_SIZE + pidSize; + memmove(postEpidPtr, &response->ResponseBase.CMID, V4_POST_EPID_SIZE); + + const size_t encryptSize = V4_PRE_EPID_SIZE + V4_POST_EPID_SIZE + pidSize; + AesCmacV4(responseBuffer, encryptSize, responseBuffer + encryptSize); + + return encryptSize + sizeof(response->MAC); +} + +/* +// Workaround for buggy GCC 4.2/4.3 +#if defined(__GNUC__) && (__GNUC__ == 4 && __GNUC_MINOR__ < 4) +__attribute__((noinline)) +#endif +__pure static uint64_t TimestampInterval(void *ts) +{ + return ( GET_UA64LE(ts) / TIME_C1 ) * TIME_C2 + TIME_C3; +}*/ + + +/* + * Creates the HMAC for v6 + */ +static int_fast8_t CreateV6Hmac(BYTE *const encrypt_start, const size_t encryptSize, const int_fast8_t tolerance) +{ + BYTE hash[32]; + const uint8_t halfHashSize = sizeof(hash) >> 1; + BYTE *responseEnd = encrypt_start + encryptSize; + + // This is the time from the response + FILETIME* ft = (FILETIME*)(responseEnd - V6_POST_EPID_SIZE + sizeof(((RESPONSE*)0)->CMID)); + + // Generate a time slot that changes every 4.11 hours. + // Request and response time must match +/- 1 slot. + // When generating a response tolerance must be 0. + // If verifying the hash, try tolerance -1, 0 and +1. One of them must match. + + uint64_t timeSlot = LE64((GET_UA64LE(ft) / TIME_C1 * TIME_C2 + TIME_C3) + (tolerance * TIME_C1)); + + // The time slot is hashed with SHA256 so it is not so obvious that it is time + Sha256((BYTE*)&timeSlot, sizeof(timeSlot), hash); + + // The last 16 bytes of the hashed time slot are the actual HMAC key + if (!Sha256Hmac + ( + hash + halfHashSize, // Use last 16 bytes of SHA256 as HMAC key + encrypt_start, // hash only the encrypted part of the v6 response + (DWORD)(encryptSize - sizeof(((RESPONSE_V6*)0)->HMAC)), // encryptSize minus the HMAC itself + hash // use same buffer for resulting hash where the key came from + )) + { + return FALSE; + } + + memcpy(responseEnd - sizeof(((RESPONSE_V6*)0)->HMAC), hash + halfHashSize, halfHashSize); + return TRUE; +} + + +/* + * Creates v5 or v6 response + */ +size_t CreateResponseV6(REQUEST_V6 *restrict request_v6, BYTE *const responseBuffer, const char* const ipString) +{ + // The response will be created in a fixed sized struct to + // avoid unaligned access macros and packed structs on RISC systems + // which largely increase code size. + // + // The fixed sized struct with 64 WCHARs for the ePID will be converted + // to a variable sized struct later and requires unaligned access macros. + + RESPONSE_V6* response = (RESPONSE_V6*)responseBuffer; + RESPONSE* baseResponse = &response->ResponseBase; + +#ifdef _DEBUG + // ReSharper disable once CppDeclaratorNeverUsed + RESPONSE_V6_DEBUG* xxx_unused = (RESPONSE_V6_DEBUG*)responseBuffer; +#endif + + static const BYTE DefaultHwId[8] = { HWID }; + const int_fast8_t v6 = LE16(request_v6->MajorVer) > 5; + AesCtx aesCtx; + + AesInitKey(&aesCtx, v6 ? AesKeyV6 : AesKeyV5, v6, AES_KEY_BYTES); + AesDecryptCbc(&aesCtx, NULL, request_v6->IV, V6_DECRYPT_SIZE); + + // get random salt and SHA256 it + get16RandomBytes(response->RandomXoredIVs); + Sha256(response->RandomXoredIVs, sizeof(response->RandomXoredIVs), response->Hash); + + if (v6) // V6 specific stuff + { + // In v6 a random IV is generated + response->Version = request_v6->Version; + get16RandomBytes(response->IV); + + // pre-fill with default HwId (not required for v5) + memcpy(response->HwId, DefaultHwId, sizeof(response->HwId)); + + // Just copy decrypted request IV (using Null IV) here. Note this is identical + // to XORing non-decrypted request and response IVs + memcpy(response->XoredIVs, request_v6->IV, sizeof(response->XoredIVs)); + } + else // V5 specific stuff + { + // In v5 IVs of request and response must be identical (MS client checks this) + // The following memcpy copies Version and IVs at once + memcpy(response, request_v6, V6_UNENCRYPTED_SIZE); + } + + // Xor Random bytes with decrypted request IV + XorBlock(request_v6->IV, response->RandomXoredIVs); + + // Get the base response + HRESULT hResult; + if (FAILED(hResult = CreateResponseBase(&request_v6->RequestBase, baseResponse, response->HwId, ipString))) return hResult; + + // Convert the fixed sized struct into variable sized + const DWORD pidSize = LE32(baseResponse->PIDSize); + BYTE* postEpidPtr = responseBuffer + V6_PRE_EPID_SIZE + pidSize; + const size_t post_epid_size = v6 ? V6_POST_EPID_SIZE : V5_POST_EPID_SIZE; + + memmove(postEpidPtr, &baseResponse->CMID, post_epid_size); + + // number of bytes to encrypt + size_t encryptSize = + V6_PRE_EPID_SIZE + - sizeof(response->Version) + + pidSize + + post_epid_size; + + //AesDecryptBlock(&aesCtx, Response->IV); + if (v6 && !CreateV6Hmac(response->IV, encryptSize, 0)) return 0; + + // Padding auto handled by encryption func + AesEncryptCbc(&aesCtx, NULL, response->IV, &encryptSize); + + return encryptSize + sizeof(response->Version); +} + + +// Create Hashed KMS Client Request Data for KMS Protocol Version 4 +BYTE *CreateRequestV4(size_t *size, const REQUEST* requestBase) +{ + *size = sizeof(REQUEST_V4); + + // Build a proper KMS client request data + BYTE *request = (BYTE *)vlmcsd_malloc(sizeof(REQUEST_V4)); + + // Temporary Pointer for access to REQUEST_V4 structure + REQUEST_V4 *request_v4 = (REQUEST_V4 *)request; + + // Set KMS Client Request Base + memcpy(&request_v4->RequestBase, requestBase, sizeof(REQUEST)); + + // Generate Hash Signature + AesCmacV4(request, sizeof(REQUEST), request_v4->MAC); + + // Return Request Data + return request; +} + + +// Create Encrypted KMS Client Request Data for KMS Protocol Version 6 +BYTE* CreateRequestV6(size_t *size, const REQUEST* requestBase) +{ + *size = sizeof(REQUEST_V6); + + // Temporary Pointer for access to REQUEST_V5 structure + REQUEST_V6 *request = (REQUEST_V6 *)vlmcsd_malloc(sizeof(REQUEST_V6)); + + // KMS Protocol Version + request->Version = requestBase->Version; + + // Initialize the IV + get16RandomBytes(request->IV); + + // Set KMS Client Request Base + memcpy(&request->RequestBase, requestBase, sizeof(REQUEST)); + + // Encrypt KMS Client Request + size_t encryptSize = sizeof(request->RequestBase); + AesCtx ctx; + const int_fast8_t v6 = LE16(request->MajorVer) > 5; + AesInitKey(&ctx, v6 ? AesKeyV6 : AesKeyV5, v6, 16); + AesEncryptCbc(&ctx, request->IV, (BYTE*)(&request->RequestBase), &encryptSize); + + // Return Proper Request Data + return (BYTE*)request; +} + + +/* + * Checks whether Length of ePID is valid + */ +static uint8_t checkPidLength(const RESPONSE *const responseBase) +{ + unsigned int i; + + if (LE32(responseBase->PIDSize) > (PID_BUFFER_SIZE << 1)) return FALSE; + if (responseBase->KmsPID[(LE32(responseBase->PIDSize) >> 1) - 1]) return FALSE; + + for (i = 0; i < (LE32(responseBase->PIDSize) >> 1) - 2; i++) + { + if (!responseBase->KmsPID[i]) return FALSE; + } + + return TRUE; +} + + +/* + * "Decrypts" a KMS v4 response. Actually just copies to a fixed size buffer + */ +RESPONSE_RESULT DecryptResponseV4(RESPONSE_V4* response_v4, const int responseSize, BYTE* const rawResponse, const BYTE* const rawRequest) +{ + const int copySize = + V4_PRE_EPID_SIZE + + (LE32(((RESPONSE_V4*)rawResponse)->ResponseBase.PIDSize) <= PID_BUFFER_SIZE << 1 ? + LE32(((RESPONSE_V4*)rawResponse)->ResponseBase.PIDSize) : + PID_BUFFER_SIZE << 1); + + const int messageSize = copySize + V4_POST_EPID_SIZE; + + memcpy(response_v4, rawResponse, copySize); + memcpy(&response_v4->ResponseBase.CMID, rawResponse + copySize, responseSize - copySize); + + // ensure PID is null terminated + response_v4->ResponseBase.KmsPID[PID_BUFFER_SIZE - 1] = 0; + + uint8_t* mac = rawResponse + messageSize; + AesCmacV4(rawResponse, messageSize, mac); + + REQUEST_V4* request_v4 = (REQUEST_V4*)rawRequest; + RESPONSE_RESULT result; + + result.mask = (DWORD)~0; + result.PidLengthOK = checkPidLength((RESPONSE*)rawResponse); + result.VersionOK = response_v4->ResponseBase.Version == request_v4->RequestBase.Version; + result.HashOK = !memcmp(&response_v4->MAC, mac, sizeof(response_v4->MAC)); + result.TimeStampOK = !memcmp(&response_v4->ResponseBase.ClientTime, &request_v4->RequestBase.ClientTime, sizeof(FILETIME)); + result.ClientMachineIDOK = !memcmp(&response_v4->ResponseBase.CMID, &request_v4->RequestBase.CMID, sizeof(GUID)); + result.effectiveResponseSize = responseSize; + result.correctResponseSize = sizeof(RESPONSE_V4) - sizeof(response_v4->ResponseBase.KmsPID) + LE32(response_v4->ResponseBase.PIDSize); + + return result; +} + + +static RESPONSE_RESULT VerifyResponseV6(RESPONSE_RESULT result, RESPONSE_V6* response_v6, REQUEST_V6* request_v6, BYTE* const rawResponse) +{ + // Check IVs + result.IVsOK = !memcmp // In V6 the XoredIV is actually the request IV + ( + response_v6->XoredIVs, + request_v6->IV, + sizeof(response_v6->XoredIVs) + ); + + result.IVnotSuspicious = !!memcmp // If IVs are identical, it is obviously an emulator + ( + request_v6->IV, + response_v6->IV, + sizeof(request_v6->IV) + ); + + // Check Hmac + int_fast8_t tolerance; + BYTE OldHmac[sizeof(response_v6->HMAC)]; + + result.HmacSha256OK = FALSE; + + memcpy // Save received HMAC to compare with calculated HMAC later + ( + OldHmac, + response_v6->HMAC, + sizeof(response_v6->HMAC) + ); + + //AesEncryptBlock(Ctx, Response_v6->IV); // CreateV6Hmac needs original IV as received over the network + + for (tolerance = -1; tolerance < 2; tolerance++) + { + CreateV6Hmac + ( + rawResponse + sizeof(response_v6->Version), // Pointer to start of the encrypted part of the response + (size_t)result.correctResponseSize - sizeof(response_v6->Version), // size of the encrypted part + tolerance // tolerance -1, 0, or +1 + ); + + result.HmacSha256OK = !memcmp // Compare both HMACs + ( + OldHmac, + rawResponse + (size_t)result.correctResponseSize - sizeof(response_v6->HMAC), + sizeof(OldHmac) + ); + + if (result.HmacSha256OK) break; + } + + return result; +} + + +static RESPONSE_RESULT VerifyResponseV5(RESPONSE_RESULT result, REQUEST_V5* request_v5, RESPONSE_V5* response_v5) +{ + // Check IVs: in V5 (and only v5) request and response IVs must match + result.IVsOK = !memcmp(request_v5->IV, response_v5->IV, sizeof(request_v5->IV)); + + // V5 has no Hmac, always set to TRUE + result.HmacSha256OK = TRUE; + + return result; +} + + +/* + * Decrypts a KMS v5 or v6 response received from a server. + * hwid must supply a valid 16 byte buffer for v6. hwid is ignored in v5 + */ +RESPONSE_RESULT DecryptResponseV6(RESPONSE_V6* response_v6, int responseSize, BYTE* const response, const BYTE* const rawRequest, BYTE* hwid) +{ + RESPONSE_RESULT result; + result.mask = (DWORD)~0; // Set all bits in the results mask to 1. Assume success first. + result.effectiveResponseSize = responseSize; + + int copySize1 = + sizeof(response_v6->Version); + + // Decrypt KMS Server Response (encrypted part starts after RequestIV) + responseSize -= copySize1; + + AesCtx ctx; + const int_fast8_t v6 = LE16(((RESPONSE_V6*)response)->MajorVer) > 5; + + AesInitKey(&ctx, v6 ? AesKeyV6 : AesKeyV5, v6, AES_KEY_BYTES); + AesDecryptCbc(&ctx, NULL, response + copySize1, responseSize); + + // Check padding + BYTE* lastPadByte = response + (size_t)result.effectiveResponseSize - 1; + + // Must be from 1 to 16 + if (!*lastPadByte || *lastPadByte > AES_BLOCK_BYTES) + { + result.DecryptSuccess = FALSE; + return result; + } + + // Check if pad bytes are all the same + BYTE* padByte; + for (padByte = lastPadByte - *lastPadByte + 1; padByte < lastPadByte; padByte++) + { + if (*padByte != *lastPadByte) + { + result.DecryptSuccess = FALSE; + return result; + } + } + + // Add size of Version, KmsPIDLen and variable size PID + const DWORD pidSize = LE32(((RESPONSE_V6*)response)->ResponseBase.PIDSize); + + copySize1 += + V6_UNENCRYPTED_SIZE + + sizeof(response_v6->ResponseBase.PIDSize) + + (pidSize <= PID_BUFFER_SIZE << 1 ? pidSize : PID_BUFFER_SIZE << 1); + + // Copy part 1 of response up to variable sized PID + memcpy(response_v6, response, copySize1); + + // ensure PID is null terminated + response_v6->ResponseBase.KmsPID[PID_BUFFER_SIZE - 1] = 0; + + // Copy part 2 + const size_t copySize2 = v6 ? V6_POST_EPID_SIZE : V5_POST_EPID_SIZE; + memcpy(&response_v6->ResponseBase.CMID, response + copySize1, copySize2); + + // Decrypting the response is finished here. Now we check the results for validity + // A basic client doesn't need the stuff below this comment but we want to use vlmcs + // as a debug tool for KMS emulators. + + REQUEST_V6* request_v6 = (REQUEST_V6*)rawRequest; + const DWORD decryptSize = sizeof(request_v6->IV) + sizeof(request_v6->RequestBase) + sizeof(request_v6->Pad); + + AesDecryptCbc(&ctx, NULL, request_v6->IV, decryptSize); + + // Check that all version information is the same + result.VersionOK = + request_v6->Version == response_v6->ResponseBase.Version && + request_v6->Version == response_v6->Version && + request_v6->Version == request_v6->RequestBase.Version; + + // Check Base Request + result.PidLengthOK = checkPidLength(&((RESPONSE_V6*)response)->ResponseBase); + result.TimeStampOK = !memcmp(&response_v6->ResponseBase.ClientTime, &request_v6->RequestBase.ClientTime, sizeof(FILETIME)); + result.ClientMachineIDOK = IsEqualGUID(&response_v6->ResponseBase.CMID, &request_v6->RequestBase.CMID); + + // Rebuild Random Key and Sha256 Hash + BYTE hashVerify[sizeof(response_v6->Hash)]; + BYTE randomKey[sizeof(response_v6->RandomXoredIVs)]; + + memcpy(randomKey, request_v6->IV, sizeof(randomKey)); + XorBlock(response_v6->RandomXoredIVs, randomKey); + Sha256(randomKey, sizeof(randomKey), hashVerify); + + result.HashOK = !memcmp(response_v6->Hash, hashVerify, sizeof(hashVerify)); + + // size before encryption (padding not included) + result.correctResponseSize = + (v6 ? sizeof(RESPONSE_V6) : sizeof(RESPONSE_V5)) + - sizeof(response_v6->ResponseBase.KmsPID) + + LE32(response_v6->ResponseBase.PIDSize); + + // Version specific stuff + if (v6) + { + // Copy the HwId + memcpy(hwid, response_v6->HwId, sizeof(response_v6->HwId)); + + // Verify the V6 specific part of the response + result = VerifyResponseV6(result, response_v6, request_v6, response); + } + else // V5 + { + // Verify the V5 specific part of the response + result = VerifyResponseV5(result, request_v6, (RESPONSE_V5*)response_v6); + } + + // padded size after encryption + result.correctResponseSize += (~(result.correctResponseSize - sizeof(response_v6->ResponseBase.Version)) & 0xf) + 1; + + return result; +} + diff --git a/vlmcsd/src/kms.h b/vlmcsd/src/kms.h new file mode 100644 index 0000000..d8fb895 --- /dev/null +++ b/vlmcsd/src/kms.h @@ -0,0 +1,410 @@ +#ifndef __kms_h +#define __kms_h + +#ifndef CONFIG +#define CONFIG "config.h" +#endif // CONFIG +#include CONFIG + +#if _MSC_VER +//#include +#else +#include +#endif // _MSC_VER +//#include +#include "types.h" +// +// REQUEST... types are actually fixed size +// RESPONSE... size may vary, defined here is max possible size +// + +#define MAX_RESPONSE_SIZE 384 +#define PID_BUFFER_SIZE 64 +#define MAX_REQUEST_SIZE sizeof(REQUEST_V6) +#define WORKSTATION_NAME_BUFFER 64 + +// Constants for V6 time stamp interval +#define TIME_C1 0x00000022816889BDULL +#define TIME_C2 0x000000208CBAB5EDULL +#define TIME_C3 0x3156CD5AC628477AULL + +#define VERSION_INFO union \ +{ \ + DWORD Version;\ + struct { \ + WORD MinorVer; \ + WORD MajorVer; \ + } /*__packed*/; \ +} /*__packed*/ + +// Aliases for various KMS struct members +#define IsClientVM VMInfo +#define GraceTime BindingExpiration +#define MinutesRemaingInCurrentStatus BindingExpiration +#define ID ActID +#define ApplicationID AppID +#define SkuId ActID +#define KmsId KMSID +#define ClientMachineId CMID +#define MinimumClients N_Policy +#define TimeStamp ClientTime +#define PreviousCLientMachineId CMID_prev +#define Salt IV +#define XorSalt XoredIVs +#define ActivationInterval VLActivationInterval +#define RenewalInterval VLRenewalInterval + +#define MAX_CLIENTS 671 + +typedef struct +{ + GUID Guid[MAX_CLIENTS]; + int_fast16_t CurrentCount; + int_fast16_t MaxCount; + int_fast16_t CurrentPosition; +} ClientList_t, *PClientList_t; + +typedef struct { + VERSION_INFO; + DWORD VMInfo; // 0 = client is bare metal / 1 = client is VM + DWORD LicenseStatus; // 0 = Unlicensed, 1 = Licensed (Activated), 2 = OOB grace, 3 = OOT grace, 4 = NonGenuineGrace, 5 = Notification, 6 = extended grace + DWORD BindingExpiration; // Expiration of the current status in minutes (e.g. when KMS activation or OOB grace expires). + GUID AppID; // Can currently be Windows, Office2010 or Office2013 (see kms.c, table AppList). + GUID ActID; // Most detailed product list. One product key per ActID (see kms.c, table ExtendedProductList). Is ignored by KMS server. + GUID KMSID; // This is actually what the KMS server uses to grant or refuse activation (see kms.c, table BasicProductList). + GUID CMID; // Client machine id. Used by the KMS server for counting minimum clients. + DWORD N_Policy; // Minimum clients required for activation. + FILETIME ClientTime; // Current client time. + GUID CMID_prev; // previous client machine id. All zeros, if it never changed. + WCHAR WorkstationName[64]; // Workstation name. FQDN if available, NetBIOS otherwise. +} /*__packed*/ REQUEST; + +typedef struct { + VERSION_INFO; + DWORD PIDSize; // Size of PIDData in bytes. + WCHAR KmsPID[PID_BUFFER_SIZE]; // ePID (must include terminating zero) + GUID CMID; // Client machine id. Must be the same as in request. + FILETIME ClientTime; // Current client time. Must be the same as in request. + DWORD Count; // Current activated machines. KMS server counts up to N_Policy << 1 then stops + DWORD VLActivationInterval; // Time in minutes when clients should retry activation if it was unsuccessful (default 2 hours) + DWORD VLRenewalInterval; // Time in minutes when clients should renew KMS activation (default 7 days) +} /*__packed*/ RESPONSE; + +#ifdef _DEBUG +typedef struct { + VERSION_INFO; + DWORD PIDSize; + WCHAR KmsPID[49]; // Set this to the ePID length you want to debug + GUID CMID; + FILETIME ClientTime; + DWORD Count; + DWORD VLActivationInterval; + DWORD VLRenewalInterval; +} __packed RESPONSE_DEBUG; +#endif + + +typedef struct { + REQUEST RequestBase; // Base request + BYTE MAC[16]; // Aes 160 bit CMAC +} /*__packed*/ REQUEST_V4; + +typedef struct { + RESPONSE ResponseBase; // Base response + BYTE MAC[16]; // Aes 160 bit CMAC +} /*__packed*/ RESPONSE_V4; + + +typedef struct { + VERSION_INFO; // unencrypted version info + BYTE IV[16]; // IV + REQUEST RequestBase; // Base Request + BYTE Pad[4]; // since this struct is fixed, we use fixed PKCS pad bytes +} /*__packed*/ REQUEST_V5; + +typedef REQUEST_V5 REQUEST_V6; // v5 and v6 requests are identical + +typedef struct { + VERSION_INFO; + BYTE IV[16]; + RESPONSE ResponseBase; + BYTE RandomXoredIVs[16]; // If RequestIV was used for decryption: Random ^ decrypted Request IV ^ ResponseIV. If NULL IV was used for decryption: Random ^ decrypted Request IV + BYTE Hash[32]; // SHA256 of Random used in RandomXoredIVs + BYTE HwId[8]; // HwId from the KMS server + BYTE XoredIVs[16]; // If RequestIV was used for decryption: decrypted Request IV ^ ResponseIV. If NULL IV was used for decryption: decrypted Request IV. + BYTE HMAC[16]; // V6 Hmac (low 16 bytes only), see kms.c CreateV6Hmac + //BYTE Pad[10]; // Pad is variable sized. So do not include in struct +} /*__packed*/ RESPONSE_V6; + +typedef struct { // not used except for sizeof(). Fields are the same as RESPONSE_V6 + VERSION_INFO; + BYTE IV[16]; + RESPONSE ResponseBase; + BYTE RandomXoredIVs[16]; + BYTE Hash[32]; +} /*__packed*/ RESPONSE_V5; + +#ifdef _DEBUG +typedef struct { // Debug structure for direct casting of RPC data in debugger + VERSION_INFO; + BYTE IV[16]; + RESPONSE_DEBUG ResponseBase; + BYTE RandomXoredIVs[16]; + BYTE MAC[32]; + BYTE Unknown[8]; + BYTE XorSalts[16]; + BYTE HMAC[16]; + BYTE Pad[16]; +} __packed RESPONSE_V6_DEBUG; +#endif + +#define V4_PRE_EPID_SIZE ( \ + sizeof(((RESPONSE*)0)->Version) + \ + sizeof(((RESPONSE*)0)->PIDSize) \ + ) + +#define V4_POST_EPID_SIZE ( \ + sizeof(((RESPONSE*)0)->CMID) + \ + sizeof(((RESPONSE*)0)->ClientTime) + \ + sizeof(((RESPONSE*)0)->Count) + \ + sizeof(((RESPONSE*)0)->VLActivationInterval) + \ + sizeof(((RESPONSE*)0)->VLRenewalInterval) \ + ) + +#define V6_DECRYPT_SIZE ( \ + sizeof(((REQUEST_V6*)0)->IV) + \ + sizeof(((REQUEST_V6*)0)->RequestBase) + \ + sizeof(((REQUEST_V6*)0)->Pad) \ + ) + +#define V6_UNENCRYPTED_SIZE ( \ + sizeof(((RESPONSE_V6*)0)->Version) + \ + sizeof(((RESPONSE_V6*)0)->IV) \ + ) + +#define V6_PRE_EPID_SIZE ( \ + V6_UNENCRYPTED_SIZE + \ + sizeof(((RESPONSE*)0)->Version) + \ + sizeof(((RESPONSE*)0)->PIDSize) \ + ) + +#define V5_POST_EPID_SIZE ( \ + V4_POST_EPID_SIZE + \ + sizeof(((RESPONSE_V6*)0)->RandomXoredIVs) + \ + sizeof(((RESPONSE_V6*)0)->Hash) \ + ) + +#define V6_POST_EPID_SIZE ( \ + V5_POST_EPID_SIZE + \ + sizeof(((RESPONSE_V6*)0)->HwId) + \ + sizeof(((RESPONSE_V6*)0)->XoredIVs) + \ + sizeof(((RESPONSE_V6*)0)->HMAC) \ + ) + +#define RESPONSE_RESULT_OK ((1 << 10) - 1) //(9 bits) +typedef union +{ + DWORD mask; + struct + { + BOOL HashOK : 1; + BOOL TimeStampOK : 1; + BOOL ClientMachineIDOK : 1; + BOOL VersionOK : 1; + BOOL IVsOK : 1; + BOOL DecryptSuccess : 1; + BOOL HmacSha256OK : 1; + BOOL PidLengthOK : 1; + BOOL RpcOK : 1; + BOOL IVnotSuspicious : 1; + BOOL reserved3 : 1; + BOOL reserved4 : 1; + BOOL reserved5 : 1; + BOOL reserved6 : 1; + uint32_t effectiveResponseSize : 9; + uint32_t correctResponseSize : 9; + }; +} RESPONSE_RESULT; + +typedef BYTE hwid_t[8]; + +typedef enum +{ + None = 0, + UseNdr64 = 1 << 0, + UseForEpid = 1 << 1, + MayBeServer = 1 << 2, +} HostBuildFlag; + +typedef struct CsvlkData +{ + union + { + uint64_t EPidOffset; + char* EPid; + }; + + int64_t ReleaseDate; + uint32_t GroupId; + uint32_t MinKeyId; + uint32_t MaxKeyId; + uint8_t MinActiveClients; + uint8_t Reserved[3]; + +} CsvlkData_t, *PCsvlkData_t; + +typedef struct VlmcsdData +{ + union + { + GUID Guid; + uint8_t GuidBytes[16]; + }; + + union + { + uint64_t NameOffset; + char* Name; + }; + + uint8_t AppIndex; + uint8_t KmsIndex; + uint8_t ProtocolVersion; + uint8_t NCountPolicy; + uint8_t IsRetail; + uint8_t IsPreview; + uint8_t EPidIndex; + uint8_t reserved; + +} VlmcsdData_t, *PVlmcsdData_t; + +typedef struct +{ + union + { + uint64_t Offset; + void* Pointer; + }; +} DataPointer_t; + +#define KMS_OPTIONS_USENDR64 1 << 0 + +typedef struct HostBuild +{ + union + { + uint64_t DisplayNameOffset; + char* DisplayName; + }; + + int64_t ReleaseDate; + int32_t BuildNumber; + int32_t PlatformId; + HostBuildFlag Flags; + uint8_t reserved[4]; + +} HostBuild_t, *PHostBuild_t; + +typedef struct VlmcsdHeader +{ + BYTE Magic[4]; + VERSION_INFO; + uint8_t CsvlkCount; + uint8_t Flags; + uint8_t Reserved[2]; + + union + { + int32_t Counts[5]; + + struct + { + int32_t AppItemCount; + int32_t KmsItemCount; + int32_t SkuItemCount; + int32_t HostBuildCount; + int32_t reserved2Counts; + }; + }; + + union + { + DataPointer_t Datapointers[5]; + + struct + { + union + { + uint64_t AppItemOffset; + PVlmcsdData_t AppItemList; + }; + + union + { + uint64_t KmsItemOffset; + PVlmcsdData_t KmsItemList; + }; + + union + { + uint64_t SkuItemOffset; + PVlmcsdData_t SkuItemList; + }; + + union + { + uint64_t HostBuildOffset; + PHostBuild_t HostBuildList; + }; + + union + { + uint64_t Reserved2Offset; + void* Reserved2List; + }; + + CsvlkData_t CsvlkData[1]; + }; + }; + +} VlmcsdHeader_t, *PVlmcsdHeader_t; + +//#define EPID_INDEX_WINDOWS 0 +//#define EPID_INDEX_OFFICE2010 1 +//#define EPID_INDEX_OFFICE2013 2 +//#define EPID_INDEX_OFFICE2016 3 +//#define EPID_INDEX_WINCHINAGOV 4 + +typedef HRESULT(__stdcall *RequestCallback_t)(REQUEST* baseRequest, RESPONSE *const baseResponse, BYTE *const hwId, const char* const ipstr); + +size_t CreateResponseV4(REQUEST_V4 *const Request, BYTE *const response_data, const char* const ipstr); +size_t CreateResponseV6(REQUEST_V6 *restrict Request, BYTE *const response_data, const char* const ipstr); +BYTE *CreateRequestV4(size_t *size, const REQUEST* requestBase); +BYTE *CreateRequestV6(size_t *size, const REQUEST* requestBase); +void randomPidInit(); +void get16RandomBytes(void* ptr); +RESPONSE_RESULT DecryptResponseV6(RESPONSE_V6* response_v6, int responseSize, BYTE* const response, const BYTE* const rawRequest, BYTE* hwid); +RESPONSE_RESULT DecryptResponseV4(RESPONSE_V4* response_v4, const int responseSize, BYTE* const rawResponse, const BYTE* const rawRequest); +void getUnixTimeAsFileTime(FILETIME* ts); +__pure int64_t fileTimeToUnixTime(FILETIME* ts); + +#ifndef IS_LIBRARY +int32_t getProductIndex(const GUID* guid, const PVlmcsdData_t list, const int32_t count, char** name, char** ePid); +#if !defined(NO_INI_FILE)||!defined(NO_VERBOSE_LOG) +const char* getNextString(const char* s); +#endif // !defined(NO_INI_FILE)||!defined(NO_VERBOSE_LOG) +#endif // IS_LIBRARY + +#ifndef NO_STRICT_MODES +void InitializeClientLists(); +void CleanUpClientLists(); +#endif // !NO_STRICT_MODES + +extern RequestCallback_t CreateResponseBase; + +#ifdef _PEDANTIC +uint16_t IsValidLcid(const uint16_t lcid); +uint32_t IsValidHostBuild(const int32_t hostBuild); +#endif // _PEDANTIC + +#endif // __kms_h diff --git a/vlmcsd/src/kmsdata-full.c b/vlmcsd/src/kmsdata-full.c new file mode 100644 index 0000000..9f93204 --- /dev/null +++ b/vlmcsd/src/kmsdata-full.c @@ -0,0 +1,963 @@ +#ifndef CONFIG +#define CONFIG "config.h" +#endif // CONFIG +#include CONFIG + +#ifndef NO_INTERNAL_DATA + +#include "kmsdata.h" + +uint8_t DefaultKmsData[] = +{ + /* 0000 */ 0x4B, 0x4D, 0x44, 0x00, 0x00, 0x00, 0x02, 0x00, 0x06, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, // KMD............. + /* 0010 */ 0x1D, 0x00, 0x00, 0x00, 0xCA, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ............... + /* 0020 */ 0x08, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........h....... + /* 0030 */ 0x08, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........H....... + /* 0040 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................ + /* 0050 */ 0x00, 0xB5, 0xB2, 0x5B, 0x00, 0x00, 0x00, 0x00, 0xCE, 0x00, 0x00, 0x00, 0xC0, 0x97, 0xD7, 0x20, // .[........ + /* 0060 */ 0xBF, 0xC4, 0x08, 0x22, 0x00, 0x00, 0x00, 0x00, 0x56, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ."....V....... + /* 0070 */ 0x80, 0x4F, 0x3E, 0x4C, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0xC0, 0x7F, 0xDC, 0x0B, // .O>L....`..... + /* 0080 */ 0x7F, 0x6A, 0xFE, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x9F, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .j............. + /* 0090 */ 0x00, 0x11, 0x07, 0x51, 0x00, 0x00, 0x00, 0x00, 0xCE, 0x00, 0x00, 0x00, 0x80, 0x8E, 0xF2, 0x0D, // ...Q.......... + /* 00A0 */ 0xFF, 0x3F, 0x42, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xE8, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ?B............ + /* 00B0 */ 0x00, 0x9A, 0x00, 0x56, 0x00, 0x00, 0x00, 0x00, 0xCE, 0x00, 0x00, 0x00, 0x40, 0x17, 0x0C, 0x1A, // ...V.......@... + /* 00C0 */ 0xBF, 0xC8, 0x5B, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x31, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // [.....1 ...... + /* 00D0 */ 0x80, 0x33, 0xE4, 0x58, 0x00, 0x00, 0x00, 0x00, 0x12, 0x0F, 0x00, 0x00, 0xC0, 0xE1, 0xE4, 0x00, // .3X......... + /* 00E0 */ 0xFF, 0xC9, 0x9A, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x8B, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .;..... ...... + /* 00F0 */ 0x00, 0x29, 0xA8, 0x5B, 0x00, 0x00, 0x00, 0x00, 0xCE, 0x00, 0x00, 0x00, 0x80, 0x5A, 0xB2, 0x27, // .)[........Z' + /* 0100 */ 0x7F, 0x87, 0xE3, 0x28, 0x00, 0x00, 0x00, 0x00, 0x34, 0x27, 0xC9, 0x55, 0x82, 0xD6, 0x71, 0x4D, // ..(....4'U.qM + /* 0110 */ 0x98, 0x3E, 0xD6, 0xEC, 0x3F, 0x16, 0x05, 0x9F, 0x84, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .>?....!...... + /* 0120 */ 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x81, 0x28, 0xA5, 0x59, 0x89, 0xA9, 0x9D, 0x47, // ...2.....(Y..G + /* 0130 */ 0xAF, 0x46, 0xF2, 0x75, 0xC6, 0x37, 0x06, 0x63, 0x8C, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Fu7.c.!...... + /* 0140 */ 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x01, 0x00, 0x15, 0xCE, 0xF1, 0x0F, 0x89, 0xA9, 0x9D, 0x47, // ............G + /* 0150 */ 0xAF, 0x46, 0xF2, 0x75, 0xC6, 0x37, 0x06, 0x63, 0x97, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Fu7.c.!...... + /* 0160 */ 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x05, 0x00, 0xFB, 0xB1, 0x49, 0x84, 0xEA, 0xF0, 0x7A, 0x49, // ........I.zI + /* 0170 */ 0x99, 0xAB, 0x66, 0xCA, 0x96, 0xE9, 0xA0, 0xF5, 0xA3, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .f..!...... + /* 0180 */ 0x00, 0x00, 0x06, 0x05, 0x00, 0x00, 0x00, 0x00, 0x59, 0x56, 0xB1, 0x11, 0x03, 0xE6, 0xF1, 0x4C, // ........YV..L + /* 0190 */ 0x9C, 0x1F, 0xF0, 0xEC, 0x01, 0xB8, 0x18, 0x88, 0xB7, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .....!...... + /* 01A0 */ 0x00, 0x00, 0x06, 0x19, 0x00, 0x00, 0x00, 0x00, 0x36, 0xD6, 0x7C, 0xD2, 0x62, 0x19, 0xE9, 0x44, // ........6|b.D + /* 01B0 */ 0x8B, 0x4F, 0x27, 0xB6, 0xC2, 0x3E, 0xFB, 0x85, 0xD0, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .O'>.!...... + /* 01C0 */ 0x00, 0x00, 0x06, 0x19, 0x00, 0x00, 0x00, 0x00, 0x23, 0xBF, 0xA0, 0x7B, 0xF5, 0xD0, 0x72, 0x40, // ........#.{r@ + /* 01D0 */ 0x91, 0xD9, 0xD5, 0x5A, 0xF5, 0xA4, 0x81, 0xB6, 0xEC, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .Z.!...... + /* 01E0 */ 0x00, 0x00, 0x06, 0x19, 0x00, 0x00, 0x04, 0x00, 0xC0, 0xE3, 0x9F, 0x96, 0xEC, 0xA3, 0x1A, 0x49, // ...........I + /* 01F0 */ 0x9F, 0x25, 0x42, 0x36, 0x05, 0xDE, 0xB3, 0x65, 0x08, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .%B6.޳e."...... + /* 0200 */ 0x00, 0x00, 0x06, 0x19, 0x00, 0x00, 0x00, 0x00, 0x58, 0x13, 0xC5, 0xE1, 0x3E, 0xFE, 0x03, 0x42, // ........X.>.B + /* 0210 */ 0xA4, 0xA2, 0x3B, 0x6B, 0x20, 0xC9, 0x73, 0x4E, 0x21, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ;k sN!"...... + /* 0220 */ 0x00, 0x00, 0x06, 0x19, 0x01, 0x00, 0x00, 0x00, 0x4F, 0x13, 0xE2, 0x58, 0x11, 0x8E, 0x17, 0x4D, // ........O.X...M + /* 0230 */ 0x9C, 0xB2, 0x91, 0x06, 0x9C, 0x15, 0x11, 0x48, 0x35, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ......H5"...... + /* 0240 */ 0x00, 0x00, 0x06, 0x19, 0x00, 0x00, 0x00, 0x00, 0x19, 0x52, 0xDE, 0x7F, 0xFA, 0xFB, 0x4A, 0x48, // .........R.JH + /* 0250 */ 0x82, 0xC9, 0x34, 0xD1, 0xAD, 0x53, 0xE8, 0x56, 0x4E, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .4ѭSVN"...... + /* 0260 */ 0x00, 0x00, 0x04, 0x19, 0x00, 0x00, 0x00, 0x00, 0x3B, 0x7B, 0xB9, 0xBB, 0xA4, 0x8C, 0x28, 0x4A, // ........;{.(J + /* 0270 */ 0x97, 0x17, 0x89, 0xFA, 0xBD, 0x42, 0xC4, 0xAC, 0x58, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ...BĬX"...... + /* 0280 */ 0x00, 0x00, 0x05, 0x19, 0x01, 0x00, 0x00, 0x00, 0x58, 0xB3, 0x40, 0x3C, 0x48, 0x59, 0xAF, 0x45, // ........X@C + /* 0430 */ 0xB9, 0x0A, 0x39, 0x89, 0x29, 0x23, 0xC6, 0x57, 0xEE, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .9.)#W#...... + /* 0440 */ 0x00, 0x00, 0x06, 0x05, 0x00, 0x01, 0x00, 0x00, 0xDC, 0x64, 0x2A, 0x21, 0xB1, 0x43, 0x3D, 0x4D, // ........d*!C=M + /* 0450 */ 0xA3, 0x0C, 0x2F, 0xC6, 0x9D, 0x20, 0x95, 0xC6, 0x05, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ./. ..$...... + /* 0460 */ 0x00, 0x00, 0x04, 0x19, 0x00, 0x00, 0x00, 0x00, 0x46, 0xF9, 0x5A, 0xE8, 0x25, 0x2E, 0xB7, 0x47, // ........FZ%.G + /* 0470 */ 0x83, 0xE1, 0xBE, 0xBC, 0xEB, 0xEA, 0xC6, 0x11, 0x13, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .ᾼ..$...... + /* 0480 */ 0x01, 0x00, 0x04, 0x05, 0x00, 0x00, 0x01, 0x00, 0xBF, 0xF1, 0xA6, 0xE6, 0x40, 0x9D, 0xC3, 0x40, // ........@.@ + /* 0490 */ 0xAA, 0x9F, 0xC7, 0x7B, 0xA2, 0x15, 0x78, 0xC0, 0x1F, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .{.x.$...... + /* 04A0 */ 0x02, 0x00, 0x05, 0x05, 0x00, 0x00, 0x02, 0x00, 0x68, 0x79, 0x4C, 0xAA, 0xDA, 0xB9, 0x80, 0x46, // ........hyLڹ.F + /* 04B0 */ 0x92, 0xB6, 0xAC, 0xB2, 0x5E, 0x2F, 0x86, 0x6C, 0x2B, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .^/.l+$...... + /* 04C0 */ 0x02, 0x00, 0x05, 0x05, 0x00, 0x01, 0x00, 0x00, 0x1B, 0xF6, 0xB5, 0x85, 0x0B, 0x32, 0xE3, 0x4B, // ...........2K + /* 04D0 */ 0x81, 0x4A, 0xB7, 0x6B, 0x2B, 0xFA, 0xFC, 0x82, 0x45, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .Jk+.E$...... + /* 04E0 */ 0x02, 0x00, 0x06, 0x05, 0x00, 0x00, 0x03, 0x00, 0xB1, 0x9E, 0x7D, 0x61, 0x36, 0xEF, 0x82, 0x4F, // .........}a6.O + /* 04F0 */ 0x86, 0xE0, 0xA6, 0x5A, 0xE0, 0x7B, 0x96, 0xC6, 0x51, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .Z{.Q$...... + /* 0500 */ 0x02, 0x00, 0x06, 0x05, 0x00, 0x00, 0x05, 0x00, 0x62, 0xEB, 0xE8, 0x8D, 0xE0, 0xBB, 0xAC, 0x40, // ........b.໬@ + /* 0510 */ 0xAC, 0x17, 0xF7, 0x55, 0x95, 0x07, 0x1E, 0xA3, 0x5D, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .U...]$...... + /* 0520 */ 0x00, 0x00, 0x06, 0x05, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xC1, 0x9C, 0xA9, 0x19, 0x77, 0x06, 0x43, // ..........w.C + /* 0530 */ 0x96, 0x45, 0x29, 0x41, 0x02, 0xFB, 0xFF, 0x95, 0x77, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .E)A..w$...... + /* 0540 */ 0x00, 0x00, 0x06, 0x05, 0x00, 0x00, 0x00, 0x00, 0x55, 0xAE, 0xE1, 0x34, 0xF8, 0x27, 0x50, 0x49, // ........U4'PI + /* 0550 */ 0x88, 0x77, 0x7A, 0x03, 0xBE, 0x5F, 0xB1, 0x81, 0x96, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .wz._..$...... + /* 0560 */ 0x00, 0x00, 0x06, 0x05, 0x00, 0x00, 0x00, 0x00, 0xBB, 0x3C, 0x4D, 0x03, 0x4B, 0x5D, 0x45, 0x42, // ........`no'...... + /* 0860 */ 0x00, 0x06, 0x06, 0x19, 0x00, 0x00, 0x00, 0x00, 0x8C, 0xB1, 0x00, 0x53, 0x33, 0x2E, 0xC2, 0x4D, // ..........S3.M + /* 0870 */ 0x82, 0x91, 0x47, 0xFF, 0xCE, 0xC7, 0x46, 0xDD, 0x91, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..GF.'...... + /* 0880 */ 0x00, 0x06, 0x06, 0x19, 0x00, 0x00, 0x00, 0x00, 0xBF, 0x5A, 0x0B, 0xA8, 0xAD, 0x76, 0x8B, 0x42, // ........Z.v.B + /* 0890 */ 0xB0, 0x5D, 0xA4, 0x7D, 0x2D, 0xFF, 0xEE, 0xBF, 0xB5, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ]}-'...... + /* 08A0 */ 0x00, 0x06, 0x06, 0x19, 0x00, 0x00, 0x00, 0x00, 0x01, 0x82, 0x80, 0xFF, 0xC6, 0xFE, 0xD4, 0x4F, // ...........O + /* 08B0 */ 0xAE, 0x16, 0xAB, 0xBD, 0xDA, 0xDE, 0x57, 0x06, 0xCF, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .W.'...... + /* 08C0 */ 0x00, 0x06, 0x06, 0x19, 0x00, 0x00, 0x00, 0x00, 0x05, 0xAB, 0xF2, 0x43, 0x87, 0x7C, 0x56, 0x4D, // .........C.|VM + /* 08D0 */ 0xB2, 0x7C, 0x44, 0xD0, 0xF9, 0xA3, 0xDA, 0xBD, 0xEF, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // |Dڽ'...... + /* 08E0 */ 0x00, 0x06, 0x06, 0x19, 0x00, 0x00, 0x00, 0x00, 0x65, 0x8E, 0x86, 0xEC, 0xDF, 0xFA, 0x59, 0x47, // ........e..YG + /* 08F0 */ 0xB2, 0x3E, 0x93, 0xFE, 0x37, 0xF2, 0xCC, 0x29, 0x0D, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // >.7).(...... + /* 0900 */ 0x00, 0x06, 0x06, 0x19, 0x00, 0x00, 0x00, 0x00, 0xEA, 0x50, 0xDB, 0xE4, 0xA1, 0xBD, 0x66, 0x45, // ........P䡽fE + /* 0910 */ 0xB0, 0x47, 0x0C, 0xA5, 0x0A, 0xBC, 0x6F, 0x07, 0x38, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // G..o.8(...... + /* 0920 */ 0x00, 0x06, 0x06, 0x19, 0x00, 0x00, 0x00, 0x00, 0x14, 0xF8, 0xF4, 0x0D, 0x57, 0x3F, 0x8B, 0x4B, // ..........W?.K + /* 0930 */ 0x9A, 0x9D, 0xFD, 0xDA, 0xDC, 0xD6, 0x9F, 0xAC, 0x51, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ...Q(...... + /* 0940 */ 0x00, 0x06, 0x06, 0x19, 0x00, 0x00, 0x00, 0x00, 0x09, 0xE5, 0x2E, 0xAE, 0x34, 0x1B, 0xC0, 0x41, // ..........4.A + /* 0950 */ 0xAC, 0xB7, 0x6D, 0x46, 0x50, 0x16, 0x89, 0x15, 0x65, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mFP...e(...... + /* 0960 */ 0x00, 0x07, 0x04, 0x19, 0x00, 0x00, 0x00, 0x00, 0x08, 0xED, 0xBB, 0x46, 0x7B, 0x9C, 0xFC, 0x48, // .........F{.H + /* 0970 */ 0xA6, 0x14, 0x95, 0x25, 0x05, 0x73, 0xF4, 0xEA, 0x7A, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..%.sz(...... + /* 0980 */ 0x00, 0x07, 0x04, 0x19, 0x00, 0x00, 0x00, 0x00, 0x05, 0xD6, 0xB6, 0x1C, 0xB3, 0x11, 0x14, 0x4E, // .........ֶ...N + /* 0990 */ 0xBB, 0x30, 0xDA, 0x91, 0xC8, 0xE3, 0x98, 0x3A, 0x91, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0..:.(...... + /* 09A0 */ 0x00, 0x07, 0x04, 0x19, 0x00, 0x00, 0x00, 0x00, 0x80, 0x99, 0x2E, 0xB9, 0xD5, 0xB9, 0x21, 0x48, // ...........չ!H + /* 09B0 */ 0x9C, 0x94, 0x14, 0x0F, 0x63, 0x2F, 0x63, 0x12, 0xA8, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ....c/c.(...... + /* 09C0 */ 0x00, 0x07, 0x04, 0x19, 0x00, 0x00, 0x00, 0x00, 0x29, 0x15, 0x04, 0x5A, 0xF8, 0xFE, 0x07, 0x4D, // ........)..Z.M + /* 09D0 */ 0xB0, 0x6F, 0xB5, 0x9B, 0x57, 0x3B, 0x32, 0xD2, 0xBF, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // o.W;2ҿ(...... + /* 09E0 */ 0x00, 0x07, 0x04, 0x19, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x9A, 0xA0, 0x54, 0x7B, 0xD5, 0x10, 0x4C, // ...........T{.L + /* 09F0 */ 0x8B, 0x69, 0xA8, 0x42, 0xD6, 0x59, 0x0A, 0xD5, 0xD8, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .iBY.(...... + /* 0A00 */ 0x00, 0x07, 0x04, 0x19, 0x00, 0x00, 0x00, 0x00, 0x96, 0x78, 0x53, 0xDB, 0x6F, 0x37, 0xAE, 0x48, // .........xSo7H + /* 0A10 */ 0xA4, 0x92, 0x53, 0xD0, 0x54, 0x77, 0x73, 0xD0, 0xF1, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .STws(...... + /* 0A20 */ 0x00, 0x07, 0x04, 0x19, 0x00, 0x00, 0x00, 0x00, 0x6A, 0x29, 0xA8, 0xE1, 0x37, 0xDB, 0xD1, 0x44, // ........j)7D + /* 0A30 */ 0x8C, 0xCE, 0x7B, 0xC9, 0x61, 0xD5, 0x9C, 0x54, 0x0D, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .{a.T.)...... + /* 0A40 */ 0x00, 0x07, 0x04, 0x19, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xD3, 0x6D, 0xAA, 0xB4, 0xC2, 0xE2, 0x40, // ........m@ + /* 0A50 */ 0xA5, 0x44, 0xA6, 0xBB, 0xB3, 0xF5, 0xC3, 0x95, 0x29, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // D.))...... + /* 0A60 */ 0x00, 0x07, 0x04, 0x19, 0x00, 0x00, 0x00, 0x00, 0xBF, 0xD6, 0x4E, 0xC0, 0xC8, 0x55, 0x47, 0x4B, // ........NUGK + /* 0A70 */ 0x9F, 0x8E, 0x5A, 0x1F, 0x31, 0xCE, 0xEE, 0x60, 0x3A, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..Z.1`:)...... + /* 0A80 */ 0x00, 0x08, 0x05, 0x19, 0x01, 0x00, 0x00, 0x00, 0xA2, 0x84, 0x55, 0x9D, 0x85, 0x2D, 0x9A, 0x41, // .........U..-.A + /* 0A90 */ 0x98, 0x2C, 0xA0, 0x08, 0x88, 0xBB, 0x9D, 0xDF, 0x49, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .,....I)...... + /* 0AA0 */ 0x00, 0x08, 0x05, 0x19, 0x01, 0x00, 0x00, 0x00, 0xA0, 0x90, 0x73, 0x19, 0xF6, 0x65, 0x95, 0x4A, // ..........s.e.J + /* 0AB0 */ 0xBD, 0xC4, 0x55, 0xD5, 0x8A, 0x3B, 0x02, 0x53, 0x69, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // U.;.Si)...... + /* 0AC0 */ 0x00, 0x08, 0x05, 0x19, 0x01, 0x00, 0x00, 0x00, 0xD4, 0xFC, 0x60, 0x88, 0x7B, 0xA7, 0x20, 0x4A, // ........`.{ J + /* 0AD0 */ 0x90, 0x45, 0xA1, 0x50, 0xFF, 0x11, 0xD6, 0x09, 0x7A, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .EP..z)...... + /* 0AE0 */ 0x00, 0x08, 0x05, 0x19, 0x01, 0x00, 0x00, 0x00, 0xA3, 0x18, 0x00, 0xA0, 0x0F, 0xF2, 0x32, 0x46, // ............2F + /* 0AF0 */ 0xBF, 0x7C, 0x8D, 0xAA, 0x53, 0x51, 0xC9, 0x14, 0x99, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // |.SQ..)...... + /* 0B00 */ 0x00, 0x08, 0x05, 0x19, 0x01, 0x00, 0x00, 0x00, 0xAF, 0x8B, 0x01, 0x10, 0x21, 0xCE, 0x60, 0x40, // ...........!`@ + /* 0B10 */ 0x80, 0xBD, 0x47, 0xFE, 0x74, 0xED, 0x4D, 0xAB, 0xB4, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .GtM)...... + /* 0B20 */ 0x00, 0x09, 0x05, 0x19, 0x00, 0x00, 0x00, 0x00, 0x48, 0x18, 0xDB, 0x18, 0xE0, 0x12, 0x67, 0x41, // ........H...gA + /* 0B30 */ 0xB9, 0xD7, 0xDA, 0x7F, 0xCD, 0xA5, 0x07, 0xDB, 0xDD, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .ͥ.)...... + /* 0B40 */ 0x00, 0x09, 0x05, 0x19, 0x00, 0x00, 0x00, 0x00, 0xEC, 0x1B, 0x8E, 0x45, 0x7A, 0x83, 0xF6, 0x45, // ..........Ez.E + /* 0B50 */ 0xB9, 0xD5, 0x92, 0x5E, 0xD5, 0xD2, 0x99, 0xDE, 0x04, 0x2A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .^..*...... + /* 0B60 */ 0x00, 0x09, 0x05, 0x19, 0x00, 0x00, 0x00, 0x00, 0xE7, 0x97, 0x49, 0xE1, 0x0A, 0x80, 0xF7, 0x4C, // .........I..L + /* 0B70 */ 0xAD, 0x10, 0xDE, 0x4B, 0x45, 0xB5, 0x78, 0xDB, 0x19, 0x2A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .KEx.*...... + /* 0B80 */ 0x00, 0x09, 0x05, 0x19, 0x00, 0x00, 0x00, 0x00, 0x6D, 0xCD, 0x8B, 0xA9, 0x43, 0x53, 0x03, 0x46, // ........m.CS.F + /* 0B90 */ 0x8A, 0xFE, 0x59, 0x08, 0xE4, 0x61, 0x11, 0x12, 0x30, 0x2A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .Y.a..0*...... + /* 0BA0 */ 0x00, 0x09, 0x05, 0x19, 0x00, 0x00, 0x00, 0x00, 0xC1, 0x45, 0xF2, 0xEB, 0xA8, 0x29, 0xAF, 0x4D, // ........E)M + /* 0BB0 */ 0x9C, 0xB1, 0x38, 0xDF, 0xC6, 0x08, 0xA8, 0xC8, 0x47, 0x2A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .8.G*...... + /* 0BC0 */ 0x00, 0x09, 0x05, 0x19, 0x00, 0x00, 0x00, 0x00, 0x38, 0x32, 0x1C, 0xFE, 0x2A, 0x43, 0xA1, 0x43, // ........82.*CC + /* 0BD0 */ 0x8E, 0x25, 0x97, 0xE7, 0xD1, 0xEF, 0x10, 0xF3, 0x60, 0x2A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .%..`*...... + /* 0BE0 */ 0x00, 0x0A, 0x06, 0x19, 0x01, 0x00, 0x00, 0x00, 0x6A, 0x45, 0xEE, 0xFF, 0x87, 0xCD, 0x90, 0x43, // ........jE..C + /* 0BF0 */ 0x8E, 0x07, 0x16, 0x14, 0x6C, 0x67, 0x2F, 0xD0, 0x71, 0x2A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ....lg/q*...... + /* 0C00 */ 0x00, 0x0A, 0x06, 0x19, 0x01, 0x00, 0x00, 0x00, 0x4F, 0xB7, 0x78, 0xDB, 0x1C, 0xEF, 0x92, 0x48, // ........Ox..H + /* 0C10 */ 0xAB, 0xFE, 0x1E, 0x66, 0xB8, 0x23, 0x1D, 0xF6, 0x86, 0x2A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .f#..*...... + /* 0C20 */ 0x00, 0x0A, 0x06, 0x19, 0x01, 0x00, 0x00, 0x00, 0x64, 0x8A, 0x55, 0x78, 0x19, 0xDC, 0xFE, 0x43, // ........d.Ux.C + /* 0C30 */ 0xA0, 0xD0, 0x80, 0x75, 0xB2, 0xA3, 0x70, 0xA3, 0xA8, 0x2A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..up*...... + /* 0C40 */ 0x00, 0x0A, 0x06, 0x19, 0x01, 0x00, 0x00, 0x00, 0x1D, 0x6A, 0x2C, 0xC7, 0x52, 0xF2, 0x7E, 0x4E, // .........j,R~N + /* 0C50 */ 0xBD, 0xD1, 0x3F, 0xCA, 0x34, 0x2A, 0xCB, 0x35, 0xBB, 0x2A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ?4*5*...... + /* 0C60 */ 0x00, 0x0A, 0x06, 0x19, 0x01, 0x00, 0x00, 0x00, 0xB5, 0x87, 0x8D, 0xE5, 0x26, 0x81, 0x80, 0x45, // ..........&..E + /* 0C70 */ 0x80, 0xFB, 0x86, 0x1B, 0x22, 0xF7, 0x92, 0x96, 0xDC, 0x2A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..."..*...... + /* 0C80 */ 0x00, 0x0A, 0x06, 0x19, 0x01, 0x00, 0x00, 0x00, 0xC7, 0x91, 0xB4, 0xCA, 0x18, 0xA9, 0x60, 0x4F, // ..........`O + /* 0C90 */ 0xB5, 0x02, 0xDA, 0xB7, 0x5E, 0x33, 0x4F, 0x40, 0xFD, 0x2A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .ڷ^3O@*...... + /* 0CA0 */ 0x00, 0x0A, 0x06, 0x19, 0x01, 0x00, 0x00, 0x00, 0x3D, 0xE6, 0x6C, 0x09, 0xAC, 0x4F, 0xA9, 0x48, // ........=l.OH + /* 0CB0 */ 0x82, 0xA9, 0x61, 0xAE, 0x9E, 0x80, 0x0E, 0x5F, 0x20, 0x2B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .a..._ +...... + /* 0CC0 */ 0x00, 0x0A, 0x06, 0x19, 0x01, 0x00, 0x00, 0x00, 0x32, 0x2B, 0x94, 0xE9, 0x55, 0x2E, 0x97, 0x41, // ........2+.U..A + /* 0CD0 */ 0xB0, 0xBD, 0x5F, 0xF5, 0x8C, 0xBA, 0x88, 0x60, 0x3D, 0x2B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // _..`=+...... + /* 0CE0 */ 0x00, 0x0B, 0x06, 0x19, 0x00, 0x00, 0x00, 0x00, 0x12, 0x82, 0x99, 0xBA, 0x0A, 0x46, 0xDB, 0x44, // ............FD + /* 0CF0 */ 0xBF, 0xB5, 0x71, 0xBF, 0x09, 0xD1, 0xC6, 0x8B, 0x58, 0x2B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // q..X+...... + /* 0D00 */ 0x00, 0x0B, 0x06, 0x19, 0x00, 0x00, 0x00, 0x00, 0xD6, 0xEC, 0xDD, 0xC6, 0x54, 0x23, 0x19, 0x4C, // ........T#.L + /* 0D10 */ 0x90, 0x9B, 0x30, 0x6A, 0x30, 0x58, 0x48, 0x4E, 0x84, 0x2B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..0j0XHN.+...... + /* 0D20 */ 0x00, 0x0B, 0x06, 0x19, 0x00, 0x00, 0x00, 0x00, 0xA3, 0xE3, 0xF5, 0xB8, 0x33, 0xED, 0x08, 0x46, // ........3.F + /* 0D30 */ 0x81, 0xE1, 0x37, 0xD6, 0xC9, 0xDC, 0xFD, 0x9C, 0xA1, 0x2B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .7.+...... + /* 0D40 */ 0x00, 0x0B, 0x06, 0x19, 0x00, 0x00, 0x00, 0x00, 0xAF, 0x1A, 0x67, 0x81, 0xD1, 0x79, 0xB1, 0x4E, // .........g.yN + /* 0D50 */ 0xB0, 0x04, 0x8C, 0xBB, 0xE1, 0x73, 0xAF, 0xEA, 0xCC, 0x2B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..s+...... + /* 0D60 */ 0x00, 0x0B, 0x06, 0x19, 0x00, 0x00, 0x00, 0x00, 0x5C, 0x70, 0x3E, 0x11, 0x49, 0xFA, 0xA4, 0x48, // ........\p>.IH + /* 0D70 */ 0xBE, 0xEA, 0x7D, 0xD8, 0x79, 0xB4, 0x6B, 0x14, 0xE3, 0x2B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // }yk.+...... + /* 0D80 */ 0x00, 0x0B, 0x06, 0x19, 0x00, 0x00, 0x00, 0x00, 0x81, 0x69, 0x6B, 0xC0, 0xFD, 0xD7, 0x35, 0x4A, // .........ik5J + /* 0D90 */ 0xB7, 0xB4, 0x05, 0x47, 0x42, 0xB7, 0xAF, 0x67, 0xFC, 0x2B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .GBg+...... + /* 0DA0 */ 0x00, 0x0B, 0x06, 0x19, 0x00, 0x00, 0x00, 0x00, 0x9F, 0xD7, 0x76, 0x74, 0x48, 0x8E, 0xB4, 0x49, // .........vtH.I + /* 0DB0 */ 0xAB, 0x63, 0x4D, 0x0B, 0x81, 0x3A, 0x16, 0xE4, 0x15, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // cM..:..,...... + /* 0DC0 */ 0x00, 0x0B, 0x06, 0x19, 0x00, 0x00, 0x00, 0x00, 0x54, 0x2D, 0xB8, 0x0A, 0xF4, 0x47, 0xCB, 0x4A, // ........T-.GJ + /* 0DD0 */ 0x81, 0x8C, 0xCC, 0x5B, 0xF0, 0xEC, 0xB6, 0x49, 0x30, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..[I0,...... + /* 0DE0 */ 0x00, 0x0B, 0x06, 0x19, 0x00, 0x00, 0x00, 0x00, 0x90, 0x85, 0xE8, 0xF7, 0xC7, 0xDF, 0x78, 0x4C, // ..........xL + /* 0DF0 */ 0xBC, 0xCB, 0x6F, 0x38, 0x65, 0xB9, 0x9D, 0x1A, 0x5B, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // o8e..[,...... + /* 0E00 */ 0x00, 0x0B, 0x06, 0x19, 0x00, 0x00, 0x00, 0x00, 0x9F, 0x2D, 0x4E, 0xCD, 0x59, 0x50, 0x50, 0x4A, // .........-NYPPJ + /* 0E10 */ 0xA9, 0x2D, 0x05, 0xD5, 0xBB, 0x12, 0x67, 0xC7, 0x84, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // -.ջ.g.,...... + /* 0E20 */ 0x00, 0x0B, 0x06, 0x19, 0x00, 0x00, 0x00, 0x00, 0xC7, 0x52, 0xE9, 0xCD, 0x96, 0x2F, 0x9D, 0x4D, // ........R./.M + /* 0E30 */ 0x8F, 0x2B, 0x2D, 0x34, 0x9F, 0x64, 0xFC, 0x51, 0xAD, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .+-4.dQ,...... + /* 0E40 */ 0x00, 0x0C, 0x05, 0x19, 0x00, 0x01, 0x00, 0x00, 0x6B, 0x3E, 0x38, 0xA4, 0xDA, 0xDA, 0x3D, 0x42, // ........k>8=B + /* 0E50 */ 0xA4, 0x3D, 0xF2, 0x56, 0x78, 0x42, 0x96, 0x76, 0xCB, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // =VxB.v,...... + /* 0E60 */ 0x00, 0x0C, 0x05, 0x19, 0x00, 0x01, 0x00, 0x00, 0x7B, 0xA0, 0x59, 0xCF, 0x2A, 0x1A, 0xE0, 0x4B, // ........{.Y*.K + /* 0E70 */ 0xBF, 0xE0, 0x42, 0x3B, 0x58, 0x23, 0xE6, 0x63, 0xEB, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // B;X#c,...... + /* 0E80 */ 0x00, 0x0C, 0x05, 0x19, 0x00, 0x01, 0x00, 0x00, 0x7F, 0x33, 0x9C, 0x2B, 0x1D, 0x7A, 0x71, 0x42, // .........3.+.zqB + /* 0E90 */ 0x90, 0xA3, 0xC6, 0x85, 0x5A, 0x2B, 0x8A, 0x1C, 0x0F, 0x2D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..Z+...-...... + /* 0EA0 */ 0x00, 0x0C, 0x05, 0x19, 0x00, 0x01, 0x00, 0x00, 0x72, 0xAD, 0x1E, 0x63, 0xAB, 0xA8, 0xF8, 0x4D, // ........r.cM + /* 0EB0 */ 0xBB, 0xDF, 0x37, 0x20, 0x29, 0x98, 0x9B, 0xDD, 0x23, 0x2D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 7 )..#-...... + /* 0EC0 */ 0x00, 0x0C, 0x05, 0x19, 0x00, 0x01, 0x00, 0x00, 0x7C, 0x9F, 0xFA, 0xDD, 0x9E, 0xF0, 0xB9, 0x40, // ........|..@ + /* 0ED0 */ 0x8C, 0x1A, 0xBE, 0x87, 0x7A, 0x9A, 0x7F, 0x4B, 0x3B, 0x2D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ...z..K;-...... + /* 0EE0 */ 0x00, 0x0D, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00, 0x56, 0x11, 0xFB, 0x7A, 0x1D, 0x2C, 0xFC, 0x40, // ........V.z.,@ + /* 0EF0 */ 0xB2, 0x60, 0xAA, 0xB7, 0x44, 0x2B, 0x62, 0xFE, 0x53, 0x2D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // `D+bS-...... + /* 0F00 */ 0x00, 0x0D, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00, 0xD4, 0x42, 0x25, 0xAD, 0x54, 0x91, 0x6D, 0x4C, // ........B%T.mL + /* 0F10 */ 0x8A, 0x44, 0x30, 0xF1, 0x1E, 0xE9, 0x69, 0x89, 0x77, 0x2D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .D0.i.w-...... + /* 0F20 */ 0x00, 0x0E, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00, 0xD0, 0xE3, 0x01, 0x24, 0x0A, 0xC5, 0x58, 0x4B, // .........$.XK + /* 0F30 */ 0x87, 0xB2, 0x7E, 0x79, 0x4B, 0x7D, 0x26, 0x07, 0x94, 0x2D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .~yK}&..-...... + /* 0F40 */ 0x00, 0x0E, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00, 0x90, 0x4D, 0xAF, 0xC1, 0xBC, 0xD1, 0xCA, 0x44, // .........MD + /* 0F50 */ 0x85, 0xD4, 0x00, 0x3B, 0xA3, 0x3D, 0xB3, 0xB9, 0xC1, 0x2D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..;=-...... + /* 0F60 */ 0x00, 0x0E, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x49, 0x98, 0x81, 0xD0, 0xAD, 0xB2, 0x47, // .........I..ЭG + /* 0F70 */ 0xB3, 0xBA, 0x31, 0x6B, 0x12, 0xD6, 0x47, 0xB4, 0xE0, 0x2D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 1k.G-...... + /* 0F80 */ 0x00, 0x0E, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xE2, 0xB6, 0x68, 0x09, 0xCF, 0x6B, 0x46, // ........ h.kF + /* 0F90 */ 0x92, 0xD3, 0x45, 0xCD, 0x96, 0x4B, 0x95, 0x09, 0x0F, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .E.K.......... + /* 0FA0 */ 0x00, 0x0F, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00, 0x77, 0xEF, 0x09, 0xFD, 0x47, 0x56, 0xFF, 0x4E, // ........w.GVN + /* 0FB0 */ 0x80, 0x9C, 0xAF, 0x2B, 0x64, 0x65, 0x9A, 0x45, 0x2E, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..+de.E........ + /* 0FC0 */ 0x00, 0x0F, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00, 0x6B, 0x17, 0xEF, 0x01, 0x0D, 0x3E, 0x2A, 0x42, // ........k...>*B + /* 0FD0 */ 0xB4, 0xF8, 0x4E, 0xA8, 0x80, 0x03, 0x5E, 0x8F, 0x5D, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // N..^.]....... + /* 0FE0 */ 0x00, 0x0F, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00, 0x5C, 0x51, 0x72, 0xF7, 0x87, 0x0E, 0xD5, 0x48, // ........\Qr..H + /* 0FF0 */ 0xA6, 0x76, 0xE6, 0x96, 0x2C, 0x3E, 0x11, 0x95, 0x7D, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // v.,>..}....... + /* 1000 */ 0x00, 0x10, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00, 0xD9, 0x8B, 0x8B, 0xA7, 0x17, 0x80, 0xF5, 0x4D, // ............M + /* 1010 */ 0xB8, 0x6A, 0x09, 0xF7, 0x56, 0xAF, 0xFA, 0x7C, 0x9C, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // j.V|........ + /* 1020 */ 0x00, 0x10, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00, 0xF3, 0x8C, 0xA1, 0xCD, 0x96, 0xC1, 0xAD, 0x46, // ..........F + /* 1030 */ 0xB2, 0x89, 0x60, 0xC0, 0x72, 0x86, 0x99, 0x94, 0xB7, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .`r.......... + /* 1040 */ 0x00, 0x10, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00, 0xB9, 0x1F, 0x53, 0x68, 0x11, 0x55, 0x89, 0x49, // .........Sh.U.I + /* 1050 */ 0x97, 0xBE, 0xD1, 0x1A, 0x0F, 0x55, 0x63, 0x3F, 0xDA, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ...Uc?....... + /* 1060 */ 0x00, 0x11, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00, 0x3D, 0x2B, 0x0E, 0x62, 0xE7, 0x09, 0xFD, 0x42, // ........=+.b.B + /* 1070 */ 0x80, 0x2A, 0x17, 0xA1, 0x36, 0x52, 0xFE, 0x7A, 0xFA, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .*.6Rz....... + /* 1080 */ 0x00, 0x11, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00, 0x1B, 0xE6, 0x82, 0x74, 0x89, 0xC5, 0x7F, 0x4B, // ..........t..K + /* 1090 */ 0x8E, 0xCC, 0x46, 0xD4, 0x55, 0xAC, 0x3B, 0x87, 0x1C, 0x2F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .FU;../...... + /* 10A0 */ 0x00, 0x12, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x85, 0x26, 0x8A, 0x7E, 0x1C, 0xD3, 0x48, // ..........&.~.H + /* 10B0 */ 0xA6, 0x87, 0xFB, 0xCA, 0x9B, 0x9A, 0xC1, 0x6B, 0x3E, 0x2F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ...k>/...... + /* 10C0 */ 0x00, 0x12, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00, 0x60, 0x3D, 0x64, 0xD3, 0x42, 0x0C, 0x2D, 0x41, // ........`=dB.-A + /* 10D0 */ 0xA7, 0xD6, 0x52, 0xE6, 0x63, 0x53, 0x27, 0xF6, 0x6C, 0x2F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // RcS'l/...... + /* 10E0 */ 0x00, 0x13, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x83, 0x1C, 0xFD, 0x95, 0xF5, 0x7D, 0x4A, 0x49, // ...........}JI + /* 10F0 */ 0xBE, 0x8B, 0x13, 0x00, 0xE1, 0xC9, 0xD1, 0xCD, 0x8B, 0x2F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..../...... + /* 1100 */ 0x00, 0x13, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0xC7, 0x86, 0x54, 0x7D, 0x20, 0xE1, 0x71, 0x47, // .........T} qG + /* 1110 */ 0xB7, 0xF1, 0x7B, 0x56, 0xC6, 0xD3, 0x17, 0x0C, 0xB2, 0x2F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // {V../...... + /* 1120 */ 0x00, 0x13, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x41, 0xEC, 0xF5, 0xF0, 0x55, 0x0D, 0x32, 0x47, // ........AU.2G + /* 1130 */ 0xAF, 0x02, 0x44, 0x0A, 0x44, 0xA3, 0xCF, 0x0F, 0xDA, 0x2F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .D.D./...... + /* 1140 */ 0x00, 0x13, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0xBE, 0xA2, 0x43, 0xB7, 0xD4, 0x68, 0xD3, 0x4D, // ........ChM + /* 1150 */ 0xAF, 0x32, 0x92, 0x42, 0x5B, 0x7B, 0xB6, 0x23, 0xF7, 0x2F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 2.B[{#/...... + /* 1160 */ 0x00, 0x14, 0x06, 0x05, 0x00, 0x00, 0x00, 0x00, 0x44, 0x13, 0x09, 0x00, 0xA4, 0x1E, 0x37, 0x4F, // ........D....7O + /* 1170 */ 0xB7, 0x89, 0x01, 0x75, 0x0B, 0xA6, 0x98, 0x8C, 0x1C, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..u....0...... + /* 1180 */ 0x00, 0x14, 0x06, 0x05, 0x00, 0x00, 0x00, 0x00, 0xA4, 0x6B, 0xDB, 0x21, 0x7B, 0x9A, 0x14, 0x4A, // ........k!{..J + /* 1190 */ 0x9E, 0x29, 0x64, 0xA6, 0x0C, 0x59, 0x30, 0x1D, 0x3E, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .)d.Y0.>0...... + /* 11A0 */ 0x00, 0x14, 0x06, 0x05, 0x00, 0x00, 0x00, 0x00, 0x4E, 0x04, 0xCA, 0xB3, 0x58, 0xA3, 0x68, 0x4D, // ........N.ʳXhM + /* 11B0 */ 0x98, 0x83, 0xAA, 0xA2, 0x94, 0x1A, 0xCA, 0x99, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .....`0...... + /* 11C0 */ 0x00, 0x14, 0x06, 0x05, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x34, 0xBF, 0x3D, 0x6C, 0x5F, 0xA7, 0x4F, // .........4=l_O + /* 11D0 */ 0xB9, 0x36, 0x69, 0x9D, 0xCE, 0x9E, 0x26, 0x3F, 0x80, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 6i..&?.0...... + /* 11E0 */ 0x00, 0x15, 0x06, 0x05, 0x00, 0x00, 0x00, 0x00, 0xF4, 0x33, 0x44, 0x7B, 0xE7, 0xB1, 0x88, 0x47, // ........3D{.G + /* 11F0 */ 0x89, 0x5A, 0xC4, 0x53, 0x78, 0xD3, 0x82, 0x53, 0x9F, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .ZSx.S.0...... + /* 1200 */ 0x00, 0x15, 0x06, 0x05, 0x00, 0x00, 0x00, 0x00, 0x79, 0x67, 0xC5, 0x21, 0x49, 0xB4, 0x20, 0x4D, // ........yg!I M + /* 1210 */ 0xAD, 0xFC, 0xEE, 0xCE, 0x0E, 0x1A, 0xD7, 0x4B, 0xC1, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..K0...... + /* 1220 */ 0x00, 0x15, 0x06, 0x05, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x1B, 0x5A, 0x2B, 0xAB, 0xA5, 0x54, 0x4C, // ..........Z+TL + /* 1230 */ 0xAC, 0x2F, 0xA6, 0xD9, 0x48, 0x24, 0xA2, 0x83, 0xE0, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // /H$.0...... + /* 1240 */ 0x00, 0x15, 0x06, 0x05, 0x00, 0x00, 0x00, 0x00, 0x10, 0x54, 0x1C, 0x8C, 0x39, 0x9F, 0x05, 0x48, // .........T..9..H + /* 1250 */ 0x8C, 0x9D, 0x63, 0xA0, 0x77, 0x06, 0x35, 0x8F, 0xFF, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..c.w.5.0...... + /* 1260 */ 0x00, 0x15, 0x06, 0x05, 0x00, 0x00, 0x00, 0x00, 0x6E, 0xAF, 0xD9, 0x43, 0x86, 0x5E, 0xE8, 0x4B, // ........nC.^K + /* 1270 */ 0xA7, 0x97, 0xD0, 0x72, 0xA0, 0x46, 0x89, 0x6C, 0x1C, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .r.F.l.1...... + /* 1280 */ 0x00, 0x15, 0x06, 0x05, 0x00, 0x00, 0x00, 0x00, 0xE7, 0x08, 0x9C, 0xE4, 0x82, 0xDA, 0xF8, 0x42, // ...........B + /* 1290 */ 0xBD, 0xE2, 0xB5, 0x70, 0xFB, 0xCA, 0xE7, 0x6C, 0x36, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // pl61...... + /* 12A0 */ 0x00, 0x15, 0x06, 0x05, 0x00, 0x00, 0x00, 0x00, 0x22, 0xEF, 0xC5, 0x61, 0x4F, 0xF1, 0x53, 0x45, // ........"aOSE + /* 12B0 */ 0xA8, 0x24, 0xC4, 0xB3, 0x1E, 0x84, 0xB1, 0x00, 0x6B, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // $ij...k1...... + /* 12C0 */ 0x00, 0x15, 0x06, 0x05, 0x00, 0x00, 0x00, 0x00, 0x44, 0x7C, 0x94, 0xBA, 0x9D, 0xD1, 0x86, 0x47, // ........D|...G + /* 12D0 */ 0xB6, 0xAE, 0x22, 0x77, 0x0B, 0xC9, 0x4C, 0x54, 0x9E, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // "w.LT.1...... + /* 12E0 */ 0x00, 0x16, 0x06, 0x05, 0x00, 0x01, 0x00, 0x00, 0x06, 0x16, 0x3D, 0x4F, 0xEA, 0x3F, 0x01, 0x4C, // ..........=O?.L + /* 12F0 */ 0xBE, 0x3C, 0x8D, 0x67, 0x1C, 0x40, 0x1E, 0x3B, 0xC5, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // <.g.@.;1...... + /* 1300 */ 0x00, 0x17, 0x04, 0x19, 0x00, 0x00, 0x00, 0x00, 0xC2, 0x2D, 0x68, 0x2C, 0x68, 0x8B, 0x63, 0x4F, // ........-h,h.cO + /* 1310 */ 0xA1, 0x65, 0xAE, 0x29, 0x1D, 0x4C, 0xF1, 0x38, 0xDC, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // e).L81...... + /* 1320 */ 0x00, 0x17, 0x04, 0x19, 0x00, 0x00, 0x00, 0x00, 0x08, 0xFF, 0xD8, 0xCF, 0xD7, 0xC0, 0x2B, 0x45, // .........+E + /* 1330 */ 0x9F, 0x60, 0xEF, 0x5C, 0x70, 0xC3, 0x20, 0x94, 0xF5, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .`\p .1...... + /* 1340 */ 0x00, 0x17, 0x04, 0x19, 0x00, 0x00, 0x00, 0x00, 0x50, 0x49, 0xF5, 0xD4, 0xF2, 0x26, 0xB4, 0x4F, // ........PI&O + /* 1350 */ 0xBA, 0x21, 0xFF, 0xAB, 0x16, 0xAF, 0xCA, 0xDE, 0x0E, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // !..2...... + /* 1360 */ 0x00, 0x17, 0x04, 0x19, 0x00, 0x00, 0x00, 0x00, 0x72, 0xE8, 0xE7, 0x8C, 0x8C, 0x18, 0x98, 0x4B, // ........r....K + /* 1370 */ 0x9D, 0x90, 0xF8, 0xF9, 0x0B, 0x7A, 0xAD, 0x02, 0x29, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ...z.)2...... + /* 1380 */ 0x01, 0x18, 0x04, 0x05, 0x00, 0x00, 0x01, 0x00, 0x70, 0xD4, 0xE5, 0xCE, 0x3B, 0x6E, 0xCC, 0x4F, // ........p;nO + /* 1390 */ 0x8C, 0x2B, 0xD1, 0x74, 0x28, 0x56, 0x8A, 0x9F, 0x3C, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .+t(V..<2...... + /* 13A0 */ 0x01, 0x18, 0x04, 0x05, 0x00, 0x00, 0x01, 0x00, 0xB8, 0xD0, 0x47, 0x89, 0x3B, 0xC3, 0xE1, 0x43, // ........G.;C + /* 13B0 */ 0x8C, 0x56, 0x9B, 0x67, 0x4C, 0x05, 0x28, 0x32, 0x4E, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .V.gL.(2N2...... + /* 13C0 */ 0x01, 0x18, 0x04, 0x05, 0x00, 0x00, 0x01, 0x00, 0x39, 0x66, 0x6B, 0xCA, 0xD6, 0x4A, 0xAE, 0x40, // ........9fkJ@ + /* 13D0 */ 0xA5, 0x75, 0x14, 0xDE, 0xE0, 0x7F, 0x64, 0x30, 0x61, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // u..d0a2...... + /* 13E0 */ 0x01, 0x18, 0x04, 0x05, 0x00, 0x00, 0x01, 0x00, 0x40, 0x96, 0xED, 0x09, 0x20, 0xF0, 0x0A, 0x40, // ........@.. .@ + /* 13F0 */ 0xAC, 0xD8, 0xD7, 0xD8, 0x67, 0xDF, 0xD9, 0xC2, 0x76, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // gv2...... + /* 1400 */ 0x01, 0x18, 0x04, 0x05, 0x00, 0x00, 0x01, 0x00, 0x49, 0x4E, 0x3D, 0xEF, 0x3D, 0xA5, 0x81, 0x4D, // ........IN==.M + /* 1410 */ 0xA2, 0xB1, 0x2C, 0xA6, 0xC2, 0x55, 0x6B, 0x2C, 0x8A, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ,Uk,.2...... + /* 1420 */ 0x01, 0x18, 0x04, 0x05, 0x00, 0x00, 0x01, 0x00, 0x5C, 0x6F, 0x58, 0xAB, 0x56, 0x52, 0x32, 0x46, // ........\oXVR2F + /* 1430 */ 0x96, 0x2F, 0xFE, 0xFD, 0x8B, 0x49, 0xE6, 0xF4, 0x9E, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ./.I.2...... + /* 1440 */ 0x01, 0x18, 0x04, 0x05, 0x00, 0x00, 0x01, 0x00, 0x92, 0xC1, 0xB7, 0xEC, 0xAB, 0x73, 0xED, 0x4D, // .........sM + /* 1450 */ 0xAC, 0xF4, 0x23, 0x99, 0xB0, 0x95, 0xD0, 0xCC, 0xB2, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // #..̲2...... + /* 1460 */ 0x01, 0x18, 0x04, 0x05, 0x00, 0x00, 0x01, 0x00, 0x1D, 0x3B, 0x59, 0x45, 0xB1, 0xDF, 0x91, 0x4E, // .........;YE.N + /* 1470 */ 0xBB, 0xFB, 0x2D, 0x5D, 0x0C, 0xE2, 0x22, 0x7A, 0xC6, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // -]."z2...... + /* 1480 */ 0x01, 0x18, 0x04, 0x05, 0x00, 0x00, 0x01, 0x00, 0x60, 0x77, 0x32, 0x6F, 0x5C, 0x8C, 0x7C, 0x41, // ........`w2o\.|A + /* 1490 */ 0x9B, 0x61, 0x83, 0x6A, 0x98, 0x28, 0x7E, 0x0C, 0xDD, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .a.j.(~.2...... + /* 14A0 */ 0x01, 0x18, 0x04, 0x05, 0x00, 0x00, 0x01, 0x00, 0xF7, 0x3F, 0x13, 0xDF, 0x14, 0xBF, 0x95, 0x4F, // ........?...O + /* 14B0 */ 0xAF, 0xE3, 0x7B, 0x48, 0xE7, 0xE3, 0x31, 0xEF, 0xFB, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // {H12...... + /* 14C0 */ 0x01, 0x18, 0x04, 0x05, 0x00, 0x00, 0x01, 0x00, 0x61, 0xBF, 0xC7, 0x5D, 0xC9, 0x5E, 0x96, 0x49, // ........a]^.I + /* 14D0 */ 0x9C, 0xCB, 0xDF, 0x80, 0x6A, 0x2D, 0x0E, 0xFE, 0x13, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..j-..3...... + /* 14E0 */ 0x01, 0x18, 0x04, 0x05, 0x00, 0x00, 0x01, 0x00, 0x75, 0x4F, 0x0C, 0xB5, 0x9B, 0x59, 0xE8, 0x43, // ........uO..YC + /* 14F0 */ 0x8D, 0xCD, 0x10, 0x81, 0xA7, 0x96, 0x72, 0x41, 0x30, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ....rA03...... + /* 1500 */ 0x01, 0x18, 0x04, 0x05, 0x00, 0x00, 0x01, 0x00, 0x87, 0x9E, 0x50, 0xEA, 0xA1, 0x07, 0x45, 0x4A, // ..........P.EJ + /* 1510 */ 0x9E, 0xDC, 0xEB, 0xA5, 0xA3, 0x9F, 0x36, 0xAF, 0x46, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .륣.6F3...... + /* 1520 */ 0x01, 0x18, 0x04, 0x05, 0x00, 0x00, 0x01, 0x00, 0x78, 0xA6, 0xA2, 0x9D, 0x6B, 0xFB, 0x67, 0x4E, // ........x.kgN + /* 1530 */ 0xAB, 0x84, 0x60, 0xDD, 0x6A, 0x9C, 0x81, 0x9A, 0x68, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .`j...h3...... + /* 1540 */ 0x01, 0x18, 0x04, 0x05, 0x00, 0x00, 0x01, 0x00, 0x05, 0x61, 0x23, 0x92, 0x67, 0xBB, 0x4F, 0x49, // .........a#.gOI + /* 1550 */ 0x94, 0xC7, 0x7F, 0x7A, 0x60, 0x79, 0x29, 0xBD, 0x7D, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..z`y)}3...... + /* 1560 */ 0x01, 0x18, 0x04, 0x05, 0x00, 0x00, 0x01, 0x00, 0x9C, 0x38, 0x58, 0xE5, 0xC3, 0x83, 0x29, 0x4B, // .........8X.)K + /* 1570 */ 0xAD, 0xFE, 0x5E, 0x4D, 0x7F, 0x46, 0xC3, 0x58, 0x97, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ^M.FX.3...... + /* 1580 */ 0x01, 0x18, 0x04, 0x05, 0x00, 0x00, 0x01, 0x00, 0xFF, 0x33, 0xD8, 0x9E, 0x92, 0x4F, 0x36, 0x4F, // ........3..O6O + /* 1590 */ 0xB3, 0x70, 0x86, 0x83, 0xA4, 0xF1, 0x32, 0x75, 0xAD, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // p..2u3...... + /* 15A0 */ 0x01, 0x18, 0x04, 0x05, 0x00, 0x00, 0x01, 0x00, 0xE7, 0x82, 0x08, 0x2D, 0xE7, 0xA4, 0x3B, 0x42, // ..........-;B + /* 15B0 */ 0x8C, 0xCC, 0x70, 0xD9, 0x1E, 0x01, 0x58, 0xB1, 0xC8, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .p..X3...... + /* 15C0 */ 0x01, 0x18, 0x04, 0x05, 0x00, 0x00, 0x01, 0x00, 0x2C, 0x62, 0xE7, 0x6E, 0xD8, 0x18, 0x05, 0x40, // ........,bn..@ + /* 15D0 */ 0x9F, 0xB7, 0x92, 0xDB, 0x64, 0x4A, 0x27, 0x9B, 0xD9, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..dJ'.3...... + /* 15E0 */ 0x02, 0x19, 0x05, 0x05, 0x00, 0x00, 0x02, 0x00, 0x52, 0x1D, 0x46, 0xF7, 0x2B, 0x7C, 0xB2, 0x43, // ........R.F+|C + /* 15F0 */ 0x87, 0x44, 0xEA, 0x95, 0x8E, 0x0B, 0xD0, 0x9A, 0xEC, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .D....3...... + /* 1600 */ 0x02, 0x19, 0x05, 0x05, 0x00, 0x00, 0x02, 0x00, 0x40, 0x80, 0x0B, 0xA3, 0x8A, 0xD6, 0x3F, 0x42, // ........@...?B + /* 1610 */ 0xB0, 0xB5, 0x9C, 0xE2, 0x92, 0xEA, 0x5A, 0x8F, 0xFE, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..Z.3...... + /* 1620 */ 0x02, 0x19, 0x05, 0x05, 0x00, 0x00, 0x02, 0x00, 0xE3, 0x11, 0x9F, 0x1B, 0x5C, 0xC8, 0x1B, 0x4E, // ...........\.N + /* 1630 */ 0xBB, 0x29, 0x87, 0x9A, 0xD2, 0xC9, 0x09, 0xE3, 0x13, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // )....4...... + /* 1640 */ 0x02, 0x19, 0x05, 0x05, 0x00, 0x00, 0x02, 0x00, 0x6B, 0x1C, 0x98, 0xDC, 0x8E, 0xFC, 0x0F, 0x42, // ........k....B + /* 1650 */ 0xAA, 0x43, 0xF8, 0xF3, 0x3E, 0x5C, 0x09, 0x23, 0x24, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // C>\.#$4...... + /* 1660 */ 0x02, 0x19, 0x05, 0x05, 0x00, 0x00, 0x02, 0x00, 0xE6, 0xF3, 0xE1, 0xEF, 0xA2, 0xAE, 0x44, 0x41, // ........DA + /* 1670 */ 0xA2, 0x08, 0x32, 0xAA, 0x87, 0x2B, 0x65, 0x45, 0x36, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .2.+eE64...... + /* 1680 */ 0x02, 0x19, 0x05, 0x05, 0x00, 0x00, 0x02, 0x00, 0xFA, 0x3A, 0x1C, 0x77, 0xC5, 0x50, 0x3F, 0x44, // ........:.wP?D + /* 1690 */ 0xB1, 0x51, 0xFF, 0x25, 0x46, 0xD8, 0x63, 0xA0, 0x4A, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Q%Fc.J4...... + /* 16A0 */ 0x02, 0x19, 0x05, 0x05, 0x00, 0x00, 0x02, 0x00, 0x49, 0x26, 0x76, 0x8C, 0xD1, 0x97, 0x53, 0x49, // ........I&v..SI + /* 16B0 */ 0xAD, 0x27, 0xB7, 0xE2, 0xC2, 0x5B, 0x97, 0x2E, 0x5E, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // '[..^4...... + /* 16C0 */ 0x02, 0x19, 0x05, 0x05, 0x00, 0x00, 0x02, 0x00, 0x9C, 0xDA, 0x22, 0xB3, 0xE2, 0xA2, 0x58, 0x40, // ........."X@ + /* 16D0 */ 0x9E, 0x4E, 0xF5, 0x9A, 0x69, 0x70, 0xBD, 0x69, 0x75, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .N.ipiu4...... + /* 16E0 */ 0x02, 0x19, 0x05, 0x05, 0x00, 0x00, 0x02, 0x00, 0x4A, 0x12, 0x5D, 0x4A, 0x20, 0xE6, 0xBA, 0x44, // ........J.]J D + /* 16F0 */ 0xB6, 0xFF, 0x65, 0x89, 0x61, 0xB3, 0x3B, 0x9A, 0x93, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // e.a;..4...... + /* 1700 */ 0x02, 0x19, 0x05, 0x05, 0x00, 0x00, 0x02, 0x00, 0xD1, 0x28, 0x7A, 0x42, 0x7C, 0xD1, 0xBF, 0x4A, // ........(zB|ѿJ + /* 1710 */ 0xB7, 0x17, 0x32, 0xC7, 0x80, 0xBA, 0x6F, 0x07, 0xAB, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .2.o.4...... + /* 1720 */ 0x02, 0x19, 0x05, 0x05, 0x00, 0x00, 0x02, 0x00, 0xF1, 0x9F, 0xC7, 0x00, 0x50, 0x68, 0x3D, 0x44, // ..........Ph=D + /* 1730 */ 0xBF, 0x61, 0x71, 0xCD, 0xE0, 0xDE, 0x30, 0x5F, 0xC8, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // aq0_4...... + /* 1740 */ 0x02, 0x19, 0x05, 0x05, 0x00, 0x00, 0x02, 0x00, 0x38, 0xFB, 0x3A, 0xB1, 0x79, 0xCD, 0xE5, 0x4A, // ........8:yJ + /* 1750 */ 0x9F, 0x7F, 0xEE, 0xD0, 0x58, 0xD7, 0x50, 0xCA, 0xDE, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..XP4...... + /* 1760 */ 0x02, 0x19, 0x05, 0x05, 0x00, 0x00, 0x02, 0x00, 0x0E, 0xC1, 0x3A, 0xE1, 0xD0, 0x75, 0xFF, 0x4A, // .........:uJ + /* 1770 */ 0xA0, 0xCD, 0x76, 0x49, 0x82, 0xCF, 0x54, 0x1C, 0xF3, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .vI.T.4...... + /* 1780 */ 0x02, 0x19, 0x05, 0x05, 0x00, 0x00, 0x02, 0x00, 0xF0, 0xFA, 0x4E, 0xAC, 0x1F, 0xF8, 0x61, 0x4F, // ........N.aO + /* 1790 */ 0xBD, 0xF7, 0xEA, 0x32, 0xB0, 0x2A, 0xB1, 0x17, 0x09, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 2*..5...... + /* 17A0 */ 0x02, 0x19, 0x05, 0x05, 0x00, 0x00, 0x02, 0x00, 0xC6, 0xB1, 0xF5, 0xD9, 0x86, 0x53, 0x5A, 0x49, // ........Ʊ.SZI + /* 17B0 */ 0x88, 0xF9, 0x9A, 0xD6, 0xB4, 0x1A, 0xC9, 0xB3, 0x24, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..ִ.ɳ$5...... + /* 17C0 */ 0x02, 0x19, 0x05, 0x05, 0x00, 0x00, 0x02, 0x00, 0xE2, 0x38, 0xB5, 0x44, 0x34, 0xFB, 0x32, 0x47, // ........8D42G + /* 17D0 */ 0x81, 0xE4, 0x64, 0x4C, 0x17, 0xD2, 0xE7, 0x46, 0x35, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .dL.F55...... + /* 17E0 */ 0x02, 0x1A, 0x05, 0x05, 0x00, 0x01, 0x00, 0x00, 0xA0, 0xBF, 0x73, 0x93, 0xB3, 0x97, 0x87, 0x45, // .........s...E + /* 17F0 */ 0xAB, 0x73, 0x30, 0x93, 0x44, 0x61, 0xD5, 0x5C, 0x56, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // s0.Da\V5...... + /* 1800 */ 0x02, 0x1A, 0x05, 0x05, 0x00, 0x01, 0x00, 0x00, 0xB4, 0x6E, 0x28, 0xAA, 0x6F, 0x55, 0xEB, 0x4E, // ........n(oUN + /* 1810 */ 0x96, 0x7C, 0xC1, 0xB7, 0x71, 0xB7, 0x67, 0x3E, 0x76, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .|qg>v5...... + /* 1820 */ 0x02, 0x1A, 0x05, 0x05, 0x00, 0x01, 0x00, 0x00, 0x56, 0x82, 0xCC, 0x7C, 0xAA, 0xFB, 0xC6, 0x49, // ........V.|I + /* 1830 */ 0xB2, 0xA9, 0xF5, 0xAF, 0xB4, 0x25, 0x7C, 0xD2, 0x97, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // %|.5...... + /* 1840 */ 0x02, 0x1A, 0x05, 0x05, 0x00, 0x01, 0x00, 0x00, 0x17, 0xFE, 0x3D, 0xC5, 0x00, 0xCC, 0x67, 0x49, // .........=.gI + /* 1850 */ 0xB1, 0x88, 0xA0, 0x88, 0xA9, 0x65, 0x49, 0x4D, 0xBA, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ...eIM5...... + /* 1860 */ 0x02, 0x1A, 0x05, 0x05, 0x00, 0x01, 0x00, 0x00, 0x7D, 0xA8, 0x16, 0x28, 0xED, 0xE1, 0x97, 0x40, // ........}.(.@ + /* 1870 */ 0xB3, 0x11, 0xE2, 0x34, 0x1C, 0x57, 0xB1, 0x79, 0xD9, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .4.Wy5...... + /* 1880 */ 0x02, 0x1A, 0x05, 0x05, 0x00, 0x01, 0x00, 0x00, 0x08, 0xF9, 0xC0, 0x67, 0x4F, 0x18, 0x64, 0x4F, // .........gO.dO + /* 1890 */ 0x82, 0x50, 0x12, 0xDB, 0x79, 0x7A, 0xB3, 0xC3, 0xF9, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .P.yz5...... + /* 18A0 */ 0x02, 0x1A, 0x05, 0x05, 0x00, 0x01, 0x00, 0x00, 0x7A, 0x4E, 0xCE, 0x7B, 0x80, 0xDD, 0x82, 0x46, // ........zN{..F + /* 18B0 */ 0x98, 0xFA, 0xF9, 0x93, 0x72, 0x58, 0x03, 0xD2, 0x1B, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..rX..6...... + /* 18C0 */ 0x02, 0x1A, 0x05, 0x05, 0x00, 0x01, 0x00, 0x00, 0x0A, 0x0C, 0xC1, 0x1E, 0xF6, 0x54, 0x3E, 0x45, // ...........T>E + /* 18D0 */ 0xB8, 0x5A, 0x6F, 0xA1, 0xBB, 0xFE, 0xA9, 0xB7, 0x3D, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Zo=6...... + /* 18E0 */ 0x02, 0x1A, 0x05, 0x05, 0x00, 0x01, 0x00, 0x00, 0xBF, 0xB5, 0xD2, 0x87, 0x7B, 0xD4, 0xFB, 0x41, // .........{A + /* 18F0 */ 0xAF, 0x62, 0x71, 0xC3, 0x82, 0xF5, 0xCC, 0x85, 0x62, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // bq..b6...... + /* 1900 */ 0x02, 0x1A, 0x05, 0x05, 0x00, 0x01, 0x00, 0x00, 0xA9, 0x50, 0xFE, 0x3C, 0x03, 0x0E, 0x29, 0x4B, // ........P<..)K + /* 1910 */ 0x97, 0x54, 0x9F, 0x19, 0x3F, 0x07, 0xB7, 0x1F, 0x8E, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .T..?...6...... + /* 1920 */ 0x02, 0x1A, 0x05, 0x05, 0x00, 0x01, 0x00, 0x00, 0x57, 0x9E, 0xE4, 0x39, 0x68, 0xAE, 0xE3, 0x4E, // ........W.9hN + /* 1930 */ 0xB0, 0x98, 0x26, 0x48, 0x0D, 0xF3, 0xDA, 0x96, 0xB4, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .&H..6...... + /* 1940 */ 0x02, 0x1A, 0x05, 0x05, 0x00, 0x01, 0x00, 0x00, 0x17, 0x21, 0xAA, 0x15, 0x79, 0x8F, 0xA8, 0x49, // .........!.y.I + /* 1950 */ 0x83, 0x17, 0x75, 0x30, 0x26, 0xD6, 0xA0, 0x54, 0xDF, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..u0&.T6...... + /* 1960 */ 0x02, 0x1A, 0x05, 0x05, 0x00, 0x01, 0x00, 0x00, 0x0E, 0xD6, 0xBF, 0xCF, 0x5F, 0x0B, 0x7D, 0x42, // .........ֿ_.}B + /* 1970 */ 0x91, 0x7C, 0xA4, 0xDF, 0x42, 0xA8, 0x0E, 0x44, 0x03, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .|B.D.7...... + /* 1980 */ 0x02, 0x1A, 0x05, 0x05, 0x00, 0x01, 0x00, 0x00, 0x81, 0xCC, 0x12, 0x70, 0x87, 0x88, 0xE9, 0x42, // ..........p..B + /* 1990 */ 0xB1, 0x7D, 0x4E, 0x5E, 0x42, 0x76, 0x0F, 0x0D, 0x27, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // }N^Bv..'7...... + /* 19A0 */ 0x02, 0x1A, 0x05, 0x05, 0x00, 0x01, 0x00, 0x00, 0xB6, 0x7E, 0x9C, 0xDE, 0x85, 0x5A, 0x0D, 0x42, // ........~..Z.B + /* 19B0 */ 0x97, 0x03, 0xFF, 0xF1, 0x1B, 0xDD, 0x4D, 0x43, 0x50, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ...MCP7...... + /* 19C0 */ 0x02, 0x1A, 0x05, 0x05, 0x00, 0x01, 0x00, 0x00, 0x0C, 0xFC, 0xC0, 0x67, 0xBA, 0xDE, 0x1B, 0x40, // .........g.@ + /* 19D0 */ 0xBF, 0x8B, 0x9C, 0x8A, 0xD8, 0x39, 0x58, 0x04, 0x6F, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ...9X.o7...... + /* 19E0 */ 0x02, 0x1B, 0x06, 0x05, 0x00, 0x00, 0x03, 0x00, 0x36, 0x5D, 0xE6, 0xC3, 0x1F, 0x14, 0x2F, 0x4D, // ........6]../M + /* 19F0 */ 0xA3, 0x03, 0xA8, 0x42, 0xEE, 0x75, 0x6A, 0x29, 0x82, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .Buj).7...... + /* 1A00 */ 0x02, 0x1B, 0x06, 0x05, 0x00, 0x00, 0x03, 0x00, 0xCB, 0xBC, 0xAA, 0x9C, 0xB1, 0x61, 0x4B, 0x4B, // ........˼.aKK + /* 1A10 */ 0x8B, 0xEC, 0xD1, 0x0A, 0x3C, 0x3A, 0xC2, 0xCE, 0x94, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..<:.7...... + /* 1A20 */ 0x02, 0x1B, 0x06, 0x05, 0x00, 0x00, 0x03, 0x00, 0x6E, 0xEA, 0x14, 0xE9, 0xFA, 0xA5, 0x39, 0x44, // ........n.9D + /* 1A30 */ 0xA3, 0x94, 0xA9, 0xBB, 0x32, 0x93, 0xCA, 0x09, 0xA6, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .2..7...... + /* 1A40 */ 0x02, 0x1B, 0x06, 0x05, 0x00, 0x00, 0x03, 0x00, 0x59, 0xCE, 0xCA, 0xD8, 0xD2, 0x33, 0xC7, 0x4A, // ........Y3J + /* 1A50 */ 0x9B, 0x1B, 0x9B, 0x72, 0x33, 0x9C, 0x51, 0xC8, 0xBA, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ...r3.QȺ7...... + /* 1A60 */ 0x02, 0x1B, 0x06, 0x05, 0x00, 0x00, 0x03, 0x00, 0x65, 0x92, 0x9D, 0xEC, 0x1E, 0x9D, 0xD0, 0x4E, // ........e....N + /* 1A70 */ 0x83, 0x8A, 0xCD, 0xC2, 0x0F, 0x25, 0x51, 0xA1, 0xCE, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ...%Q7...... + /* 1A80 */ 0x02, 0x1B, 0x06, 0x05, 0x00, 0x00, 0x03, 0x00, 0xBA, 0x1B, 0x0B, 0xD7, 0x93, 0xB8, 0x44, 0x45, // ...........DE + /* 1A90 */ 0x96, 0xE2, 0xB7, 0xA3, 0x18, 0x09, 0x1C, 0x33, 0xE2, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .ⷣ...37...... + /* 1AA0 */ 0x02, 0x1B, 0x06, 0x05, 0x00, 0x00, 0x03, 0x00, 0x6F, 0x59, 0x50, 0xD4, 0x4D, 0x89, 0xE0, 0x49, // ........oYPM.I + /* 1AB0 */ 0x96, 0x6A, 0xFD, 0x39, 0xED, 0x4C, 0x4C, 0x64, 0xF9, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .j9LLd7...... + /* 1AC0 */ 0x02, 0x1B, 0x06, 0x05, 0x00, 0x00, 0x03, 0x00, 0x97, 0x41, 0x41, 0x4F, 0xC2, 0x0F, 0x01, 0x4C, // .........AAO..L + /* 1AD0 */ 0xB6, 0x8A, 0x86, 0xCB, 0xB9, 0xAC, 0x25, 0x4C, 0x17, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..˹%L.8...... + /* 1AE0 */ 0x02, 0x1B, 0x06, 0x05, 0x00, 0x00, 0x03, 0x00, 0x10, 0x81, 0x9B, 0x82, 0x6F, 0x0E, 0x49, 0x43, // ............o.IC + /* 1AF0 */ 0xBC, 0xA4, 0x42, 0x80, 0x35, 0x77, 0x78, 0x8D, 0x2F, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // B.5wx./8...... + /* 1B00 */ 0x02, 0x1B, 0x06, 0x05, 0x00, 0x00, 0x03, 0x00, 0xBC, 0xDA, 0x7D, 0xDA, 0xBE, 0x3F, 0x47, 0x44, // ........}ھ?GD + /* 1B10 */ 0x9E, 0x01, 0x6A, 0xB7, 0x44, 0x0B, 0x4C, 0xD4, 0x4B, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..jD.LK8...... + /* 1B20 */ 0x02, 0x1B, 0x06, 0x05, 0x00, 0x00, 0x03, 0x00, 0x45, 0xCA, 0xBA, 0xCB, 0x6A, 0x55, 0x16, 0x44, // ........EʺjU.D + /* 1B30 */ 0xAD, 0x03, 0xBD, 0xA5, 0x98, 0xEA, 0xA7, 0xC8, 0x68, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..h8...... + /* 1B40 */ 0x02, 0x1B, 0x06, 0x05, 0x00, 0x00, 0x03, 0x00, 0xCB, 0x06, 0x1A, 0x04, 0xB8, 0xC5, 0x72, 0x47, // ...........rG + /* 1B50 */ 0x80, 0x9F, 0x41, 0x6D, 0x03, 0xD1, 0x66, 0x54, 0x89, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..Am.fT.8...... + /* 1B60 */ 0x02, 0x1B, 0x06, 0x05, 0x00, 0x00, 0x03, 0x00, 0xE1, 0x4E, 0xE0, 0x83, 0x8D, 0xFA, 0x6D, 0x43, // ........N..mC + /* 1B70 */ 0x89, 0x94, 0xD3, 0x1A, 0x86, 0x2C, 0xAB, 0x77, 0x9F, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ....,w.8...... + /* 1B80 */ 0x02, 0x1B, 0x06, 0x05, 0x00, 0x00, 0x03, 0x00, 0x3D, 0xA2, 0xDF, 0xDE, 0xD1, 0x6E, 0xA6, 0x45, // ........=nE + /* 1B90 */ 0x85, 0xDC, 0x63, 0xCA, 0xE0, 0x54, 0x6D, 0xE6, 0xBE, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .cTm8...... + /* 1BA0 */ 0x02, 0x1B, 0x06, 0x05, 0x00, 0x00, 0x03, 0x00, 0xC1, 0x01, 0xF3, 0x6B, 0x4A, 0xB9, 0xE9, 0x43, // .........kJC + /* 1BB0 */ 0xBA, 0x31, 0xD4, 0x94, 0x59, 0x8C, 0x47, 0xFB, 0xD3, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 1.Y.G8...... + /* 1BC0 */ 0x02, 0x1B, 0x06, 0x05, 0x00, 0x00, 0x03, 0x00, 0xE3, 0xAB, 0x34, 0xB2, 0x57, 0x08, 0x9C, 0x4F, // ........4W..O + /* 1BD0 */ 0xB0, 0x5A, 0x4D, 0xC3, 0x14, 0xF8, 0x55, 0x57, 0xE9, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ZM.UW8...... + /* 1BE0 */ 0x02, 0x1B, 0x06, 0x05, 0x00, 0x00, 0x03, 0x00, 0x21, 0x78, 0x2A, 0xAA, 0x27, 0x18, 0x2C, 0x4C, // ........!x*'.,L + /* 1BF0 */ 0x8F, 0x1D, 0x45, 0x13, 0xA3, 0x4D, 0xDA, 0x97, 0x03, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..E.M..9...... + /* 1C00 */ 0x02, 0x1B, 0x06, 0x05, 0x00, 0x00, 0x03, 0x00, 0x20, 0xE6, 0x1F, 0x36, 0xF4, 0x64, 0xB5, 0x41, // ........ .6dA + /* 1C10 */ 0xBA, 0x77, 0x84, 0xF8, 0xE0, 0x79, 0xB1, 0xF7, 0x1E, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // w.y.9...... + /* 1C20 */ 0x02, 0x1B, 0x06, 0x05, 0x00, 0x00, 0x03, 0x00, 0xDF, 0xBA, 0x11, 0xBB, 0xAA, 0xD8, 0x0E, 0x47, // ........ߺ..G + /* 1C30 */ 0x93, 0x11, 0x20, 0xEA, 0xF8, 0x0F, 0xE5, 0xCC, 0x3D, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .. .=9...... + /* 1C40 */ 0x02, 0x1B, 0x06, 0x05, 0x00, 0x00, 0x03, 0x00, 0x85, 0x88, 0xC8, 0x0B, 0x8C, 0x71, 0x1D, 0x49, // ............q.I + /* 1C50 */ 0x92, 0x1F, 0x6F, 0x21, 0x43, 0x49, 0xE7, 0x9C, 0x4E, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..o!CI.N9...... + /* 1C60 */ 0x02, 0x1B, 0x06, 0x05, 0x00, 0x00, 0x03, 0x00, 0x0C, 0x4D, 0x7C, 0xFC, 0x85, 0x2E, 0xB9, 0x4B, // .........M|..K + /* 1C70 */ 0xAF, 0xD4, 0x01, 0xED, 0x14, 0x76, 0xB5, 0xE9, 0x78, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..vx9...... + /* 1C80 */ 0x02, 0x1B, 0x06, 0x05, 0x00, 0x00, 0x03, 0x00, 0x19, 0x66, 0x0F, 0x50, 0x93, 0xEF, 0x75, 0x4B, // .........f.P.uK + /* 1C90 */ 0xBC, 0xB4, 0x82, 0x81, 0x99, 0x98, 0xA3, 0xCA, 0x9C, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .....9...... + /* 1CA0 */ 0x02, 0x1B, 0x06, 0x05, 0x00, 0x00, 0x03, 0x00, 0xEB, 0xCE, 0x9B, 0x9E, 0x36, 0xE7, 0x26, 0x4F, // ..........6&O + /* 1CB0 */ 0x88, 0xDE, 0x76, 0x3F, 0x87, 0xDC, 0xC4, 0x85, 0xBE, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .v?..9...... + /* 1CC0 */ 0x02, 0x1C, 0x06, 0x05, 0x00, 0x00, 0x05, 0x00, 0xE9, 0x54, 0x78, 0x23, 0xFC, 0x79, 0x97, 0x44, // ........Tx#y.D + /* 1CD0 */ 0xA0, 0xC1, 0xA7, 0x09, 0x69, 0x69, 0x1C, 0x6B, 0xD1, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..ii.k9...... + /* 1CE0 */ 0x02, 0x1C, 0x06, 0x05, 0x00, 0x00, 0x05, 0x00, 0x01, 0xA3, 0xF8, 0xC8, 0xF5, 0x19, 0x32, 0x41, // ..........2A + /* 1CF0 */ 0x96, 0xCE, 0x2D, 0xE9, 0xD4, 0xAD, 0xBD, 0x33, 0xE3, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .-ԭ39...... + /* 1D00 */ 0x02, 0x1C, 0x06, 0x05, 0x00, 0x00, 0x05, 0x00, 0x61, 0xFD, 0x31, 0x31, 0x4F, 0x5E, 0x08, 0x43, // ........a11O^.C + /* 1D10 */ 0x8D, 0x6D, 0x62, 0xBE, 0x19, 0x87, 0xC9, 0x2C, 0xF7, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .mb..,9...... + /* 1D20 */ 0x02, 0x1C, 0x06, 0x05, 0x00, 0x00, 0x05, 0x00, 0x5F, 0x8B, 0xDD, 0x85, 0xA4, 0xEA, 0xF3, 0x4A, // ........_..J + /* 1D30 */ 0xA6, 0x28, 0xCC, 0xE9, 0xE7, 0x7C, 0x9A, 0x03, 0x0E, 0x3A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // (|...:...... + /* 1D40 */ 0x02, 0x1C, 0x06, 0x05, 0x00, 0x00, 0x05, 0x00, 0x3F, 0xBF, 0xA2, 0x2C, 0x9E, 0x94, 0x6A, 0x44, // ........?,..jD + /* 1D50 */ 0x82, 0xC7, 0xE2, 0x5A, 0x15, 0xEC, 0x78, 0xC4, 0x2C, 0x3A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .Z.x,:...... + /* 1D60 */ 0x02, 0x1C, 0x06, 0x05, 0x00, 0x00, 0x05, 0x00, 0xE3, 0xF0, 0x77, 0x17, 0x92, 0x73, 0x98, 0x41, // ........w..s.A + /* 1D70 */ 0x97, 0xEA, 0x8A, 0xE4, 0xDE, 0x6F, 0x63, 0x81, 0x44, 0x3A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..oc.D:...... + /* 1D80 */ 0x02, 0x1C, 0x06, 0x05, 0x00, 0x00, 0x05, 0x00, 0xCA, 0x4C, 0x3E, 0x9D, 0x72, 0xE1, 0xF1, 0x46, // ........L>.rF + /* 1D90 */ 0xA2, 0xF4, 0x1D, 0x21, 0x07, 0x05, 0x14, 0x44, 0x61, 0x3A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .!...Da:...... + /* 1DA0 */ 0x02, 0x1C, 0x06, 0x05, 0x00, 0x00, 0x05, 0x00, 0x6E, 0x6C, 0x4C, 0x73, 0xBA, 0xB0, 0x98, 0x42, // ........nlLs.B + /* 1DB0 */ 0xA8, 0x91, 0x67, 0x17, 0x72, 0xB2, 0xBD, 0x1B, 0x77, 0x3A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .g.r.w:...... + /* 1DC0 */ 0x02, 0x1C, 0x06, 0x05, 0x00, 0x00, 0x05, 0x00, 0x4B, 0xA7, 0x12, 0x69, 0xFB, 0xA5, 0x1A, 0x40, // ........K.i.@ + /* 1DD0 */ 0xBF, 0xDB, 0x2E, 0x3A, 0xB4, 0x6F, 0x4B, 0x02, 0x96, 0x3A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .:oK..:...... + /* 1DE0 */ 0x02, 0x1C, 0x06, 0x05, 0x00, 0x00, 0x05, 0x00, 0x8F, 0xF0, 0x5C, 0x5B, 0x1A, 0xB8, 0x1D, 0x43, // .........\[..C + /* 1DF0 */ 0xB0, 0x80, 0x34, 0x50, 0xD8, 0x62, 0x05, 0x65, 0xAB, 0x3A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .4Pb.e:...... + /* 1E00 */ 0x02, 0x1C, 0x06, 0x05, 0x00, 0x00, 0x05, 0x00, 0xF3, 0x7D, 0x6D, 0xE0, 0xD0, 0xAA, 0x9D, 0x41, // ........}mЪ.A + /* 1E10 */ 0x8D, 0xFB, 0x0A, 0xC3, 0x7E, 0x2B, 0xDF, 0x39, 0xC1, 0x3A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..~+9:...... + /* 1E20 */ 0x02, 0x1C, 0x06, 0x05, 0x00, 0x00, 0x05, 0x00, 0xFE, 0x34, 0x98, 0x05, 0xEA, 0xA8, 0xFF, 0x4B, // ........4..K + /* 1E30 */ 0xB6, 0x7B, 0x4D, 0x00, 0x6B, 0x54, 0x47, 0xD3, 0xDC, 0x3A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // {M.kTG:...... + /* 1E40 */ 0x02, 0x1C, 0x06, 0x05, 0x00, 0x00, 0x05, 0x00, 0xD4, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ ...... + /* 1E50 */ 0x00, 0xB5, 0xB2, 0x5B, 0x00, 0x00, 0x00, 0x00, 0x63, 0x45, 0x00, 0x00, 0x1C, 0x0E, 0x00, 0x00, // .[....cE...... + /* 1E60 */ 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF2, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ ...... + /* 1E70 */ 0x80, 0xE2, 0x9F, 0x57, 0x00, 0x00, 0x00, 0x00, 0x39, 0x38, 0x00, 0x00, 0x1C, 0x0E, 0x00, 0x00, // ..W....98...... + /* 1E80 */ 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .........!...... + /* 1E90 */ 0x00, 0x7A, 0x60, 0x52, 0x00, 0x00, 0x00, 0x00, 0x80, 0x25, 0x00, 0x00, 0x01, 0x19, 0x00, 0x00, // .z`R.....%...... + /* 1EA0 */ 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2D, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........-!...... + /* 1EB0 */ 0x80, 0xD2, 0x89, 0x50, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x23, 0x00, 0x00, 0x32, 0x15, 0x00, 0x00, // ..P....#..2... + /* 1EC0 */ 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........E!...... + /* 1ED0 */ 0x80, 0xFC, 0x62, 0x4D, 0x00, 0x00, 0x00, 0x00, 0xB1, 0x1D, 0x00, 0x00, 0x01, 0xD7, 0x00, 0x00, // .bM.......... + /* 1EE0 */ 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........d!...... + /* 1EF0 */ 0x00, 0x31, 0x1B, 0x4A, 0x00, 0x00, 0x00, 0x00, 0x72, 0x17, 0x00, 0x00, 0x01, 0xD7, 0x00, 0x00, // .1.J....r...... + /* 1F00 */ 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x33, 0x36, 0x31, 0x32, 0x2D, 0x30, 0x30, // ........03612-00 + /* 1F10 */ 0x32, 0x30, 0x36, 0x2D, 0x35, 0x35, 0x36, 0x2D, 0x31, 0x32, 0x33, 0x37, 0x32, 0x37, 0x2D, 0x30, // 206-556-123727-0 + /* 1F20 */ 0x33, 0x2D, 0x31, 0x30, 0x33, 0x33, 0x2D, 0x31, 0x37, 0x37, 0x36, 0x33, 0x2E, 0x30, 0x30, 0x30, // 3-1033-17763.000 + /* 1F30 */ 0x30, 0x2D, 0x32, 0x39, 0x37, 0x32, 0x30, 0x31, 0x38, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, // 0-2972018.Window + /* 1F40 */ 0x73, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, // s.Windows Server + /* 1F50 */ 0x20, 0x32, 0x30, 0x31, 0x39, 0x00, 0x30, 0x33, 0x36, 0x31, 0x32, 0x2D, 0x30, 0x30, 0x30, 0x39, // 2019.03612-0009 + /* 1F60 */ 0x36, 0x2D, 0x31, 0x39, 0x39, 0x2D, 0x37, 0x39, 0x39, 0x31, 0x38, 0x38, 0x2D, 0x30, 0x33, 0x2D, // 6-199-799188-03- + /* 1F70 */ 0x31, 0x30, 0x33, 0x33, 0x2D, 0x31, 0x37, 0x37, 0x36, 0x33, 0x2E, 0x30, 0x30, 0x30, 0x30, 0x2D, // 1033-17763.0000- + /* 1F80 */ 0x32, 0x39, 0x37, 0x32, 0x30, 0x31, 0x38, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x32, 0x30, // 2972018.Office20 + /* 1F90 */ 0x31, 0x30, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x32, 0x30, 0x31, 0x30, 0x00, 0x30, // 10.Office 2010.0 + /* 1FA0 */ 0x33, 0x36, 0x31, 0x32, 0x2D, 0x30, 0x30, 0x32, 0x30, 0x36, 0x2D, 0x32, 0x34, 0x30, 0x2D, 0x37, // 3612-00206-240-7 + /* 1FB0 */ 0x31, 0x39, 0x36, 0x33, 0x39, 0x2D, 0x30, 0x33, 0x2D, 0x31, 0x30, 0x33, 0x33, 0x2D, 0x31, 0x37, // 19639-03-1033-17 + /* 1FC0 */ 0x37, 0x36, 0x33, 0x2E, 0x30, 0x30, 0x30, 0x30, 0x2D, 0x32, 0x39, 0x37, 0x32, 0x30, 0x31, 0x38, // 763.0000-2972018 + /* 1FD0 */ 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x32, 0x30, 0x31, 0x33, 0x00, 0x4F, 0x66, 0x66, 0x69, // .Office2013.Offi + /* 1FE0 */ 0x63, 0x65, 0x20, 0x32, 0x30, 0x31, 0x33, 0x00, 0x30, 0x33, 0x36, 0x31, 0x32, 0x2D, 0x30, 0x30, // ce 2013.03612-00 + /* 1FF0 */ 0x32, 0x30, 0x36, 0x2D, 0x34, 0x33, 0x38, 0x2D, 0x30, 0x30, 0x34, 0x35, 0x33, 0x32, 0x2D, 0x30, // 206-438-004532-0 + /* 2000 */ 0x33, 0x2D, 0x31, 0x30, 0x33, 0x33, 0x2D, 0x31, 0x37, 0x37, 0x36, 0x33, 0x2E, 0x30, 0x30, 0x30, // 3-1033-17763.000 + /* 2010 */ 0x30, 0x2D, 0x32, 0x39, 0x37, 0x32, 0x30, 0x31, 0x38, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, // 0-2972018.Office + /* 2020 */ 0x32, 0x30, 0x31, 0x36, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x32, 0x30, 0x31, 0x36, // 2016.Office 2016 + /* 2030 */ 0x00, 0x30, 0x33, 0x36, 0x31, 0x32, 0x2D, 0x30, 0x33, 0x38, 0x35, 0x38, 0x2D, 0x30, 0x35, 0x33, // .03612-03858-053 + /* 2040 */ 0x2D, 0x30, 0x38, 0x39, 0x35, 0x31, 0x36, 0x2D, 0x30, 0x33, 0x2D, 0x31, 0x30, 0x33, 0x33, 0x2D, // -089516-03-1033- + /* 2050 */ 0x31, 0x37, 0x37, 0x36, 0x33, 0x2E, 0x30, 0x30, 0x30, 0x30, 0x2D, 0x32, 0x39, 0x37, 0x32, 0x30, // 17763.0000-29720 + /* 2060 */ 0x31, 0x38, 0x00, 0x57, 0x69, 0x6E, 0x43, 0x68, 0x69, 0x6E, 0x61, 0x47, 0x6F, 0x76, 0x00, 0x57, // 18.WinChinaGov.W + /* 2070 */ 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, 0x43, 0x68, 0x69, 0x6E, 0x61, 0x20, // indows 10 China + /* 2080 */ 0x47, 0x6F, 0x76, 0x65, 0x72, 0x6E, 0x6D, 0x65, 0x6E, 0x74, 0x00, 0x30, 0x33, 0x36, 0x31, 0x32, // Government.03612 + /* 2090 */ 0x2D, 0x30, 0x30, 0x32, 0x30, 0x36, 0x2D, 0x36, 0x38, 0x34, 0x2D, 0x31, 0x33, 0x37, 0x36, 0x36, // -00206-684-13766 + /* 20A0 */ 0x39, 0x2D, 0x30, 0x33, 0x2D, 0x31, 0x30, 0x33, 0x33, 0x2D, 0x31, 0x37, 0x37, 0x36, 0x33, 0x2E, // 9-03-1033-17763. + /* 20B0 */ 0x30, 0x30, 0x30, 0x30, 0x2D, 0x32, 0x39, 0x37, 0x32, 0x30, 0x31, 0x38, 0x00, 0x4F, 0x66, 0x66, // 0000-2972018.Off + /* 20C0 */ 0x69, 0x63, 0x65, 0x32, 0x30, 0x31, 0x39, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x32, // ice2019.Office 2 + /* 20D0 */ 0x30, 0x31, 0x39, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, 0x31, // 019.Windows 10 1 + /* 20E0 */ 0x38, 0x30, 0x39, 0x20, 0x2F, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x31, // 809 / Server 201 + /* 20F0 */ 0x39, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, 0x31, 0x36, 0x30, // 9.Windows 10 160 + /* 2100 */ 0x37, 0x20, 0x2F, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x31, 0x36, 0x00, // 7 / Server 2016. + /* 2110 */ 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x38, 0x2E, 0x31, 0x20, 0x2F, 0x20, 0x53, 0x65, // Windows 8.1 / Se + /* 2120 */ 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x31, 0x32, 0x20, 0x52, 0x32, 0x00, 0x57, 0x69, 0x6E, // rver 2012 R2.Win + /* 2130 */ 0x64, 0x6F, 0x77, 0x73, 0x20, 0x38, 0x20, 0x2F, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, // dows 8 / Server + /* 2140 */ 0x32, 0x30, 0x31, 0x32, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x37, 0x20, 0x2F, // 2012.Windows 7 / + /* 2150 */ 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x30, 0x38, 0x20, 0x52, 0x32, 0x20, // Server 2008 R2 + /* 2160 */ 0x53, 0x50, 0x31, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x56, 0x69, 0x73, 0x74, // SP1.Windows Vist + /* 2170 */ 0x61, 0x20, 0x2F, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x30, 0x38, 0x20, // a / Server 2008 + /* 2180 */ 0x53, 0x50, 0x32, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x00, 0x4F, 0x66, 0x66, 0x69, // SP2.Windows.Offi + /* 2190 */ 0x63, 0x65, 0x32, 0x30, 0x31, 0x30, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x32, 0x30, 0x31, // ce2010.Office201 + /* 21A0 */ 0x33, 0x2B, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, // 3+.Windows Serve + /* 21B0 */ 0x72, 0x20, 0x32, 0x30, 0x31, 0x39, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x31, // r 2019.Windows 1 + /* 21C0 */ 0x30, 0x20, 0x32, 0x30, 0x31, 0x39, 0x20, 0x28, 0x56, 0x6F, 0x6C, 0x75, 0x6D, 0x65, 0x29, 0x00, // 0 2019 (Volume). + /* 21D0 */ 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, 0x55, 0x6E, 0x6B, 0x6E, 0x6F, // Windows 10 Unkno + /* 21E0 */ 0x77, 0x6E, 0x20, 0x28, 0x56, 0x6F, 0x6C, 0x75, 0x6D, 0x65, 0x29, 0x00, 0x57, 0x69, 0x6E, 0x64, // wn (Volume).Wind + /* 21F0 */ 0x6F, 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, 0x43, 0x68, 0x69, 0x6E, 0x61, 0x20, 0x47, 0x6F, 0x76, // ows 10 China Gov + /* 2200 */ 0x65, 0x72, 0x6E, 0x6D, 0x65, 0x6E, 0x74, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, // ernment.Windows + /* 2210 */ 0x31, 0x30, 0x20, 0x32, 0x30, 0x31, 0x36, 0x20, 0x28, 0x56, 0x6F, 0x6C, 0x75, 0x6D, 0x65, 0x29, // 10 2016 (Volume) + /* 2220 */ 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, 0x28, 0x52, 0x65, 0x74, // .Windows 10 (Ret + /* 2230 */ 0x61, 0x69, 0x6C, 0x29, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, // ail).Windows 10 + /* 2240 */ 0x32, 0x30, 0x31, 0x35, 0x20, 0x28, 0x56, 0x6F, 0x6C, 0x75, 0x6D, 0x65, 0x29, 0x00, 0x57, 0x69, // 2015 (Volume).Wi + /* 2250 */ 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x37, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, // ndows 7.Windows + /* 2260 */ 0x38, 0x20, 0x28, 0x52, 0x65, 0x74, 0x61, 0x69, 0x6C, 0x29, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, // 8 (Retail).Windo + /* 2270 */ 0x77, 0x73, 0x20, 0x38, 0x20, 0x28, 0x56, 0x6F, 0x6C, 0x75, 0x6D, 0x65, 0x29, 0x00, 0x57, 0x69, // ws 8 (Volume).Wi + /* 2280 */ 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x38, 0x2E, 0x31, 0x20, 0x28, 0x52, 0x65, 0x74, 0x61, 0x69, // ndows 8.1 (Retai + /* 2290 */ 0x6C, 0x29, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x38, 0x2E, 0x31, 0x20, 0x28, // l).Windows 8.1 ( + /* 22A0 */ 0x56, 0x6F, 0x6C, 0x75, 0x6D, 0x65, 0x29, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, // Volume).Windows + /* 22B0 */ 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, // Preview.Windows + /* 22C0 */ 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x30, 0x38, 0x20, 0x41, 0x20, 0x28, 0x57, // Server 2008 A (W + /* 22D0 */ 0x65, 0x62, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x48, 0x50, 0x43, 0x29, 0x00, 0x57, 0x69, 0x6E, 0x64, // eb and HPC).Wind + /* 22E0 */ 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x30, 0x38, 0x20, // ows Server 2008 + /* 22F0 */ 0x42, 0x20, 0x28, 0x53, 0x74, 0x61, 0x6E, 0x64, 0x61, 0x72, 0x64, 0x20, 0x61, 0x6E, 0x64, 0x20, // B (Standard and + /* 2300 */ 0x45, 0x6E, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x29, 0x00, 0x57, 0x69, 0x6E, 0x64, // Enterprise).Wind + /* 2310 */ 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x30, 0x38, 0x20, // ows Server 2008 + /* 2320 */ 0x43, 0x20, 0x28, 0x44, 0x61, 0x74, 0x61, 0x63, 0x65, 0x6E, 0x74, 0x65, 0x72, 0x29, 0x00, 0x57, // C (Datacenter).W + /* 2330 */ 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, // indows Server 20 + /* 2340 */ 0x30, 0x38, 0x20, 0x52, 0x32, 0x20, 0x41, 0x20, 0x28, 0x57, 0x65, 0x62, 0x20, 0x61, 0x6E, 0x64, // 08 R2 A (Web and + /* 2350 */ 0x20, 0x48, 0x50, 0x43, 0x29, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, // HPC).Windows Se + /* 2360 */ 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x30, 0x38, 0x20, 0x52, 0x32, 0x20, 0x42, 0x20, 0x28, // rver 2008 R2 B ( + /* 2370 */ 0x53, 0x74, 0x61, 0x6E, 0x64, 0x61, 0x72, 0x64, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x45, 0x6E, 0x74, // Standard and Ent + /* 2380 */ 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x29, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, // erprise).Windows + /* 2390 */ 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x30, 0x38, 0x20, 0x52, 0x32, 0x20, // Server 2008 R2 + /* 23A0 */ 0x43, 0x20, 0x28, 0x44, 0x61, 0x74, 0x61, 0x63, 0x65, 0x6E, 0x74, 0x65, 0x72, 0x29, 0x00, 0x57, // C (Datacenter).W + /* 23B0 */ 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, // indows Server 20 + /* 23C0 */ 0x31, 0x32, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, // 12.Windows Serve + /* 23D0 */ 0x72, 0x20, 0x32, 0x30, 0x31, 0x32, 0x20, 0x52, 0x32, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, // r 2012 R2.Window + /* 23E0 */ 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x31, 0x36, 0x00, 0x57, 0x69, // s Server 2016.Wi + /* 23F0 */ 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x50, 0x72, 0x65, // ndows Server Pre + /* 2400 */ 0x76, 0x69, 0x65, 0x77, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x56, 0x69, 0x73, // view.Windows Vis + /* 2410 */ 0x74, 0x61, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x32, 0x30, 0x31, 0x30, 0x00, 0x4F, // ta.Office 2010.O + /* 2420 */ 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x32, 0x30, 0x31, 0x33, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, // ffice 2013.Offic + /* 2430 */ 0x65, 0x20, 0x32, 0x30, 0x31, 0x33, 0x20, 0x28, 0x50, 0x72, 0x65, 0x2D, 0x52, 0x65, 0x6C, 0x65, // e 2013 (Pre-Rele + /* 2440 */ 0x61, 0x73, 0x65, 0x29, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x32, 0x30, 0x31, 0x36, // ase).Office 2016 + /* 2450 */ 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x32, 0x30, 0x31, 0x39, 0x00, 0x57, 0x69, 0x6E, // .Office 2019.Win + /* 2460 */ 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x31, 0x39, // dows Server 2019 + /* 2470 */ 0x20, 0x41, 0x52, 0x4D, 0x36, 0x34, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, // ARM64.Windows S + /* 2480 */ 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x31, 0x39, 0x20, 0x41, 0x7A, 0x75, 0x72, 0x65, // erver 2019 Azure + /* 2490 */ 0x20, 0x43, 0x6F, 0x72, 0x65, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, // Core.Windows Se + /* 24A0 */ 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x31, 0x39, 0x20, 0x44, 0x61, 0x74, 0x61, 0x63, 0x65, // rver 2019 Datace + /* 24B0 */ 0x6E, 0x74, 0x65, 0x72, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, // nter.Windows Ser + /* 24C0 */ 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x31, 0x39, 0x20, 0x45, 0x73, 0x73, 0x65, 0x6E, 0x74, 0x69, // ver 2019 Essenti + /* 24D0 */ 0x61, 0x6C, 0x73, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, // als.Windows Serv + /* 24E0 */ 0x65, 0x72, 0x20, 0x32, 0x30, 0x31, 0x39, 0x20, 0x53, 0x74, 0x61, 0x6E, 0x64, 0x61, 0x72, 0x64, // er 2019 Standard + /* 24F0 */ 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, // .Windows Server + /* 2500 */ 0x32, 0x30, 0x31, 0x39, 0x20, 0x44, 0x61, 0x74, 0x61, 0x63, 0x65, 0x6E, 0x74, 0x65, 0x72, 0x20, // 2019 Datacenter + /* 2510 */ 0x28, 0x53, 0x65, 0x6D, 0x69, 0x2D, 0x41, 0x6E, 0x6E, 0x75, 0x61, 0x6C, 0x20, 0x43, 0x68, 0x61, // (Semi-Annual Cha + /* 2520 */ 0x6E, 0x6E, 0x65, 0x6C, 0x29, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, // nnel).Windows Se + /* 2530 */ 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x31, 0x39, 0x20, 0x53, 0x74, 0x61, 0x6E, 0x64, 0x61, // rver 2019 Standa + /* 2540 */ 0x72, 0x64, 0x20, 0x28, 0x53, 0x65, 0x6D, 0x69, 0x2D, 0x41, 0x6E, 0x6E, 0x75, 0x61, 0x6C, 0x20, // rd (Semi-Annual + /* 2550 */ 0x43, 0x68, 0x61, 0x6E, 0x6E, 0x65, 0x6C, 0x29, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, // Channel).Windows + /* 2560 */ 0x20, 0x31, 0x30, 0x20, 0x45, 0x6E, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x20, 0x4C, // 10 Enterprise L + /* 2570 */ 0x54, 0x53, 0x43, 0x20, 0x32, 0x30, 0x31, 0x39, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, // TSC 2019.Windows + /* 2580 */ 0x20, 0x31, 0x30, 0x20, 0x45, 0x6E, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x20, 0x4C, // 10 Enterprise L + /* 2590 */ 0x54, 0x53, 0x43, 0x20, 0x32, 0x30, 0x31, 0x39, 0x20, 0x4E, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, // TSC 2019 N.Windo + /* 25A0 */ 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, 0x45, 0x6E, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, // ws 10 Enterprise + /* 25B0 */ 0x20, 0x47, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, 0x45, 0x6E, // G.Windows 10 En + /* 25C0 */ 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x20, 0x47, 0x4E, 0x00, 0x57, 0x69, 0x6E, 0x64, // terprise GN.Wind + /* 25D0 */ 0x6F, 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, 0x45, 0x6E, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, // ows 10 Enterpris + /* 25E0 */ 0x65, 0x20, 0x32, 0x30, 0x31, 0x36, 0x20, 0x4C, 0x54, 0x53, 0x42, 0x00, 0x57, 0x69, 0x6E, 0x64, // e 2016 LTSB.Wind + /* 25F0 */ 0x6F, 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, 0x45, 0x6E, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, // ows 10 Enterpris + /* 2600 */ 0x65, 0x20, 0x32, 0x30, 0x31, 0x36, 0x20, 0x4C, 0x54, 0x53, 0x42, 0x20, 0x4E, 0x00, 0x57, 0x69, // e 2016 LTSB N.Wi + /* 2610 */ 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, 0x48, 0x6F, 0x6D, 0x65, 0x00, 0x57, 0x69, // ndows 10 Home.Wi + /* 2620 */ 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, 0x48, 0x6F, 0x6D, 0x65, 0x20, 0x43, 0x6F, // ndows 10 Home Co + /* 2630 */ 0x75, 0x6E, 0x74, 0x72, 0x79, 0x20, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x00, 0x57, // untry Specific.W + /* 2640 */ 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, 0x48, 0x6F, 0x6D, 0x65, 0x20, 0x4E, // indows 10 Home N + /* 2650 */ 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, 0x48, 0x6F, 0x6D, 0x65, // .Windows 10 Home + /* 2660 */ 0x20, 0x53, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20, 0x4C, 0x61, 0x6E, 0x67, 0x75, 0x61, 0x67, 0x65, // Single Language + /* 2670 */ 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, 0x45, 0x64, 0x75, 0x63, // .Windows 10 Educ + /* 2680 */ 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x31, 0x30, // ation.Windows 10 + /* 2690 */ 0x20, 0x45, 0x64, 0x75, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x4E, 0x00, 0x57, 0x69, 0x6E, // Education N.Win + /* 26A0 */ 0x64, 0x6F, 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, 0x45, 0x6E, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, // dows 10 Enterpri + /* 26B0 */ 0x73, 0x65, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, 0x45, 0x6E, // se.Windows 10 En + /* 26C0 */ 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x20, 0x32, 0x30, 0x31, 0x35, 0x20, 0x4C, 0x54, // terprise 2015 LT + /* 26D0 */ 0x53, 0x42, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, 0x45, 0x6E, // SB.Windows 10 En + /* 26E0 */ 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x20, 0x32, 0x30, 0x31, 0x35, 0x20, 0x4C, 0x54, // terprise 2015 LT + /* 26F0 */ 0x53, 0x42, 0x20, 0x4E, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, // SB N.Windows 10 + /* 2700 */ 0x45, 0x6E, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x20, 0x4E, 0x00, 0x57, 0x69, 0x6E, // Enterprise N.Win + /* 2710 */ 0x64, 0x6F, 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, 0x50, 0x72, 0x6F, 0x66, 0x65, 0x73, 0x73, 0x69, // dows 10 Professi + /* 2720 */ 0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x57, 0x6F, 0x72, 0x6B, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6F, 0x6E, // onal Workstation + /* 2730 */ 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, 0x50, 0x72, 0x6F, 0x66, // .Windows 10 Prof + /* 2740 */ 0x65, 0x73, 0x73, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x57, 0x6F, 0x72, 0x6B, 0x73, 0x74, 0x61, // essional Worksta + /* 2750 */ 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x4E, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x31, // tion N.Windows 1 + /* 2760 */ 0x30, 0x20, 0x50, 0x72, 0x6F, 0x66, 0x65, 0x73, 0x73, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x00, 0x57, // 0 Professional.W + /* 2770 */ 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, 0x50, 0x72, 0x6F, 0x66, 0x65, 0x73, // indows 10 Profes + /* 2780 */ 0x73, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x45, 0x64, 0x75, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, // sional Education + /* 2790 */ 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, 0x50, 0x72, 0x6F, 0x66, // .Windows 10 Prof + /* 27A0 */ 0x65, 0x73, 0x73, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x45, 0x64, 0x75, 0x63, 0x61, 0x74, 0x69, // essional Educati + /* 27B0 */ 0x6F, 0x6E, 0x20, 0x4E, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, // on N.Windows 10 + /* 27C0 */ 0x50, 0x72, 0x6F, 0x66, 0x65, 0x73, 0x73, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x4E, 0x00, 0x57, // Professional N.W + /* 27D0 */ 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, 0x50, 0x72, 0x6F, 0x66, 0x65, 0x73, // indows 10 Profes + /* 27E0 */ 0x73, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x00, 0x57, // sional Preview.W + /* 27F0 */ 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, 0x45, 0x6E, 0x74, 0x65, 0x72, 0x70, // indows 10 Enterp + /* 2800 */ 0x72, 0x69, 0x73, 0x65, 0x20, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x00, 0x57, 0x69, 0x6E, // rise Preview.Win + /* 2810 */ 0x64, 0x6F, 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, 0x45, 0x6E, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, // dows 10 Enterpri + /* 2820 */ 0x73, 0x65, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6C, 0x20, 0x44, // se for Virtual D + /* 2830 */ 0x65, 0x73, 0x6B, 0x74, 0x6F, 0x70, 0x73, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, // esktops.Windows + /* 2840 */ 0x31, 0x30, 0x20, 0x52, 0x65, 0x6D, 0x6F, 0x74, 0x65, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, // 10 Remote Server + /* 2850 */ 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, 0x53, 0x20, 0x28, 0x4C, // .Windows 10 S (L + /* 2860 */ 0x65, 0x61, 0x6E, 0x29, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x37, 0x20, 0x45, // ean).Windows 7 E + /* 2870 */ 0x6E, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, // nterprise.Window + /* 2880 */ 0x73, 0x20, 0x37, 0x20, 0x45, 0x6E, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x20, 0x45, // s 7 Enterprise E + /* 2890 */ 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x37, 0x20, 0x45, 0x6E, 0x74, 0x65, 0x72, // .Windows 7 Enter + /* 28A0 */ 0x70, 0x72, 0x69, 0x73, 0x65, 0x20, 0x4E, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, // prise N.Windows + /* 28B0 */ 0x37, 0x20, 0x50, 0x72, 0x6F, 0x66, 0x65, 0x73, 0x73, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x00, 0x57, // 7 Professional.W + /* 28C0 */ 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x37, 0x20, 0x50, 0x72, 0x6F, 0x66, 0x65, 0x73, 0x73, // indows 7 Profess + /* 28D0 */ 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x45, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, // ional E.Windows + /* 28E0 */ 0x37, 0x20, 0x50, 0x72, 0x6F, 0x66, 0x65, 0x73, 0x73, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x4E, // 7 Professional N + /* 28F0 */ 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x37, 0x20, 0x45, 0x6D, 0x62, 0x65, 0x64, // .Windows 7 Embed + /* 2900 */ 0x64, 0x65, 0x64, 0x20, 0x50, 0x4F, 0x53, 0x52, 0x65, 0x61, 0x64, 0x79, 0x00, 0x57, 0x69, 0x6E, // ded POSReady.Win + /* 2910 */ 0x64, 0x6F, 0x77, 0x73, 0x20, 0x37, 0x20, 0x45, 0x6D, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x20, // dows 7 Embedded + /* 2920 */ 0x53, 0x74, 0x61, 0x6E, 0x64, 0x61, 0x72, 0x64, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, // Standard.Windows + /* 2930 */ 0x20, 0x37, 0x20, 0x54, 0x68, 0x69, 0x6E, 0x50, 0x43, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, // 7 ThinPC.Window + /* 2940 */ 0x73, 0x20, 0x38, 0x20, 0x43, 0x6F, 0x72, 0x65, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, // s 8 Core.Windows + /* 2950 */ 0x20, 0x38, 0x20, 0x43, 0x6F, 0x72, 0x65, 0x20, 0x43, 0x6F, 0x75, 0x6E, 0x74, 0x72, 0x79, 0x20, // 8 Core Country + /* 2960 */ 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, // Specific.Windows + /* 2970 */ 0x20, 0x38, 0x20, 0x43, 0x6F, 0x72, 0x65, 0x20, 0x4E, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, // 8 Core N.Window + /* 2980 */ 0x73, 0x20, 0x38, 0x20, 0x43, 0x6F, 0x72, 0x65, 0x20, 0x53, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20, // s 8 Core Single + /* 2990 */ 0x4C, 0x61, 0x6E, 0x67, 0x75, 0x61, 0x67, 0x65, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, // Language.Windows + /* 29A0 */ 0x20, 0x38, 0x20, 0x50, 0x72, 0x6F, 0x66, 0x65, 0x73, 0x73, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x20, // 8 Professional + /* 29B0 */ 0x57, 0x4D, 0x43, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x38, 0x20, 0x45, 0x6D, // WMC.Windows 8 Em + /* 29C0 */ 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x20, 0x49, 0x6E, 0x64, 0x75, 0x73, 0x74, 0x72, 0x79, 0x20, // bedded Industry + /* 29D0 */ 0x50, 0x72, 0x6F, 0x66, 0x65, 0x73, 0x73, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x00, 0x57, 0x69, 0x6E, // Professional.Win + /* 29E0 */ 0x64, 0x6F, 0x77, 0x73, 0x20, 0x38, 0x20, 0x45, 0x6D, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x20, // dows 8 Embedded + /* 29F0 */ 0x49, 0x6E, 0x64, 0x75, 0x73, 0x74, 0x72, 0x79, 0x20, 0x45, 0x6E, 0x74, 0x65, 0x72, 0x70, 0x72, // Industry Enterpr + /* 2A00 */ 0x69, 0x73, 0x65, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x38, 0x20, 0x45, 0x6E, // ise.Windows 8 En + /* 2A10 */ 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, // terprise.Windows + /* 2A20 */ 0x20, 0x38, 0x20, 0x45, 0x6E, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x20, 0x4E, 0x00, // 8 Enterprise N. + /* 2A30 */ 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x38, 0x20, 0x50, 0x72, 0x6F, 0x66, 0x65, 0x73, // Windows 8 Profes + /* 2A40 */ 0x73, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x38, // sional.Windows 8 + /* 2A50 */ 0x20, 0x50, 0x72, 0x6F, 0x66, 0x65, 0x73, 0x73, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x4E, 0x00, // Professional N. + /* 2A60 */ 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x38, 0x2E, 0x31, 0x20, 0x43, 0x6F, 0x72, 0x65, // Windows 8.1 Core + /* 2A70 */ 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x38, 0x2E, 0x31, 0x20, 0x43, 0x6F, 0x72, // .Windows 8.1 Cor + /* 2A80 */ 0x65, 0x20, 0x41, 0x52, 0x4D, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x38, 0x2E, // e ARM.Windows 8. + /* 2A90 */ 0x31, 0x20, 0x43, 0x6F, 0x72, 0x65, 0x20, 0x43, 0x6F, 0x75, 0x6E, 0x74, 0x72, 0x79, 0x20, 0x53, // 1 Core Country S + /* 2AA0 */ 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, // pecific.Windows + /* 2AB0 */ 0x38, 0x2E, 0x31, 0x20, 0x43, 0x6F, 0x72, 0x65, 0x20, 0x4E, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, // 8.1 Core N.Windo + /* 2AC0 */ 0x77, 0x73, 0x20, 0x38, 0x2E, 0x31, 0x20, 0x43, 0x6F, 0x72, 0x65, 0x20, 0x53, 0x69, 0x6E, 0x67, // ws 8.1 Core Sing + /* 2AD0 */ 0x6C, 0x65, 0x20, 0x4C, 0x61, 0x6E, 0x67, 0x75, 0x61, 0x67, 0x65, 0x00, 0x57, 0x69, 0x6E, 0x64, // le Language.Wind + /* 2AE0 */ 0x6F, 0x77, 0x73, 0x20, 0x38, 0x2E, 0x31, 0x20, 0x50, 0x72, 0x6F, 0x66, 0x65, 0x73, 0x73, 0x69, // ows 8.1 Professi + /* 2AF0 */ 0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x53, 0x74, 0x75, 0x64, 0x65, 0x6E, 0x74, 0x00, 0x57, 0x69, 0x6E, // onal Student.Win + /* 2B00 */ 0x64, 0x6F, 0x77, 0x73, 0x20, 0x38, 0x2E, 0x31, 0x20, 0x50, 0x72, 0x6F, 0x66, 0x65, 0x73, 0x73, // dows 8.1 Profess + /* 2B10 */ 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x53, 0x74, 0x75, 0x64, 0x65, 0x6E, 0x74, 0x20, 0x4E, 0x00, // ional Student N. + /* 2B20 */ 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x38, 0x2E, 0x31, 0x20, 0x50, 0x72, 0x6F, 0x66, // Windows 8.1 Prof + /* 2B30 */ 0x65, 0x73, 0x73, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x57, 0x4D, 0x43, 0x00, 0x57, 0x69, 0x6E, // essional WMC.Win + /* 2B40 */ 0x64, 0x6F, 0x77, 0x73, 0x20, 0x38, 0x2E, 0x31, 0x20, 0x43, 0x6F, 0x72, 0x65, 0x20, 0x43, 0x6F, // dows 8.1 Core Co + /* 2B50 */ 0x6E, 0x6E, 0x65, 0x63, 0x74, 0x65, 0x64, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, // nnected.Windows + /* 2B60 */ 0x38, 0x2E, 0x31, 0x20, 0x43, 0x6F, 0x72, 0x65, 0x20, 0x43, 0x6F, 0x6E, 0x6E, 0x65, 0x63, 0x74, // 8.1 Core Connect + /* 2B70 */ 0x65, 0x64, 0x20, 0x43, 0x6F, 0x75, 0x6E, 0x74, 0x72, 0x79, 0x20, 0x53, 0x70, 0x65, 0x63, 0x69, // ed Country Speci + /* 2B80 */ 0x66, 0x69, 0x63, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x38, 0x2E, 0x31, 0x20, // fic.Windows 8.1 + /* 2B90 */ 0x43, 0x6F, 0x72, 0x65, 0x20, 0x43, 0x6F, 0x6E, 0x6E, 0x65, 0x63, 0x74, 0x65, 0x64, 0x20, 0x4E, // Core Connected N + /* 2BA0 */ 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x38, 0x2E, 0x31, 0x20, 0x43, 0x6F, 0x72, // .Windows 8.1 Cor + /* 2BB0 */ 0x65, 0x20, 0x43, 0x6F, 0x6E, 0x6E, 0x65, 0x63, 0x74, 0x65, 0x64, 0x20, 0x53, 0x69, 0x6E, 0x67, // e Connected Sing + /* 2BC0 */ 0x6C, 0x65, 0x20, 0x4C, 0x61, 0x6E, 0x67, 0x75, 0x61, 0x67, 0x65, 0x00, 0x57, 0x69, 0x6E, 0x64, // le Language.Wind + /* 2BD0 */ 0x6F, 0x77, 0x73, 0x20, 0x38, 0x2E, 0x31, 0x20, 0x45, 0x6E, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, // ows 8.1 Enterpri + /* 2BE0 */ 0x73, 0x65, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x38, 0x2E, 0x31, 0x20, 0x45, // se.Windows 8.1 E + /* 2BF0 */ 0x6E, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x20, 0x4E, 0x00, 0x57, 0x69, 0x6E, 0x64, // nterprise N.Wind + /* 2C00 */ 0x6F, 0x77, 0x73, 0x20, 0x38, 0x2E, 0x31, 0x20, 0x50, 0x72, 0x6F, 0x66, 0x65, 0x73, 0x73, 0x69, // ows 8.1 Professi + /* 2C10 */ 0x6F, 0x6E, 0x61, 0x6C, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x38, 0x2E, 0x31, // onal.Windows 8.1 + /* 2C20 */ 0x20, 0x50, 0x72, 0x6F, 0x66, 0x65, 0x73, 0x73, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x4E, 0x00, // Professional N. + /* 2C30 */ 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x38, 0x2E, 0x31, 0x20, 0x45, 0x6D, 0x62, 0x65, // Windows 8.1 Embe + /* 2C40 */ 0x64, 0x64, 0x65, 0x64, 0x20, 0x49, 0x6E, 0x64, 0x75, 0x73, 0x74, 0x72, 0x79, 0x20, 0x50, 0x72, // dded Industry Pr + /* 2C50 */ 0x6F, 0x66, 0x65, 0x73, 0x73, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, // ofessional.Windo + /* 2C60 */ 0x77, 0x73, 0x20, 0x38, 0x2E, 0x31, 0x20, 0x45, 0x6D, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x20, // ws 8.1 Embedded + /* 2C70 */ 0x49, 0x6E, 0x64, 0x75, 0x73, 0x74, 0x72, 0x79, 0x20, 0x41, 0x75, 0x74, 0x6F, 0x6D, 0x6F, 0x74, // Industry Automot + /* 2C80 */ 0x69, 0x76, 0x65, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x38, 0x2E, 0x31, 0x20, // ive.Windows 8.1 + /* 2C90 */ 0x45, 0x6D, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x20, 0x49, 0x6E, 0x64, 0x75, 0x73, 0x74, 0x72, // Embedded Industr + /* 2CA0 */ 0x79, 0x20, 0x45, 0x6E, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x00, 0x57, 0x69, 0x6E, // y Enterprise.Win + /* 2CB0 */ 0x64, 0x6F, 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, 0x45, 0x6E, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, // dows 10 Enterpri + /* 2CC0 */ 0x73, 0x65, 0x20, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, // se Preview.Windo + /* 2CD0 */ 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, 0x50, 0x72, 0x6F, 0x66, 0x65, 0x73, 0x73, 0x69, 0x6F, 0x6E, // ws 10 Profession + /* 2CE0 */ 0x61, 0x6C, 0x20, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, // al Preview.Windo + /* 2CF0 */ 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, 0x50, 0x72, 0x6F, 0x66, 0x65, 0x73, 0x73, 0x69, 0x6F, 0x6E, // ws 10 Profession + /* 2D00 */ 0x61, 0x6C, 0x20, 0x57, 0x4D, 0x43, 0x20, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x00, 0x57, // al WMC Preview.W + /* 2D10 */ 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x38, 0x2E, 0x78, 0x20, 0x50, 0x72, 0x65, 0x76, 0x69, // indows 8.x Previ + /* 2D20 */ 0x65, 0x77, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x38, 0x2E, 0x78, 0x20, 0x50, // ew.Windows 8.x P + /* 2D30 */ 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x20, 0x41, 0x52, 0x4D, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, // review ARM.Windo + /* 2D40 */ 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x30, 0x38, 0x20, 0x57, // ws Server 2008 W + /* 2D50 */ 0x65, 0x62, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, // eb.Windows Serve + /* 2D60 */ 0x72, 0x20, 0x32, 0x30, 0x30, 0x38, 0x20, 0x43, 0x6F, 0x6D, 0x70, 0x75, 0x74, 0x65, 0x20, 0x43, // r 2008 Compute C + /* 2D70 */ 0x6C, 0x75, 0x73, 0x74, 0x65, 0x72, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, // luster.Windows S + /* 2D80 */ 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x30, 0x38, 0x20, 0x53, 0x74, 0x61, 0x6E, 0x64, // erver 2008 Stand + /* 2D90 */ 0x61, 0x72, 0x64, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, // ard.Windows Serv + /* 2DA0 */ 0x65, 0x72, 0x20, 0x32, 0x30, 0x30, 0x38, 0x20, 0x53, 0x74, 0x61, 0x6E, 0x64, 0x61, 0x72, 0x64, // er 2008 Standard + /* 2DB0 */ 0x20, 0x77, 0x69, 0x74, 0x68, 0x6F, 0x75, 0x74, 0x20, 0x48, 0x79, 0x70, 0x65, 0x72, 0x2D, 0x56, // without Hyper-V + /* 2DC0 */ 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, // .Windows Server + /* 2DD0 */ 0x32, 0x30, 0x30, 0x38, 0x20, 0x45, 0x6E, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x00, // 2008 Enterprise. + /* 2DE0 */ 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, // Windows Server 2 + /* 2DF0 */ 0x30, 0x30, 0x38, 0x20, 0x45, 0x6E, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x20, 0x77, // 008 Enterprise w + /* 2E00 */ 0x69, 0x74, 0x68, 0x6F, 0x75, 0x74, 0x20, 0x48, 0x79, 0x70, 0x65, 0x72, 0x2D, 0x56, 0x00, 0x57, // ithout Hyper-V.W + /* 2E10 */ 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, // indows Server 20 + /* 2E20 */ 0x30, 0x38, 0x20, 0x44, 0x61, 0x74, 0x61, 0x63, 0x65, 0x6E, 0x74, 0x65, 0x72, 0x00, 0x57, 0x69, // 08 Datacenter.Wi + /* 2E30 */ 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x30, // ndows Server 200 + /* 2E40 */ 0x38, 0x20, 0x44, 0x61, 0x74, 0x61, 0x63, 0x65, 0x6E, 0x74, 0x65, 0x72, 0x20, 0x77, 0x69, 0x74, // 8 Datacenter wit + /* 2E50 */ 0x68, 0x6F, 0x75, 0x74, 0x20, 0x48, 0x79, 0x70, 0x65, 0x72, 0x2D, 0x56, 0x00, 0x57, 0x69, 0x6E, // hout Hyper-V.Win + /* 2E60 */ 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x30, 0x38, // dows Server 2008 + /* 2E70 */ 0x20, 0x66, 0x6F, 0x72, 0x20, 0x49, 0x74, 0x61, 0x6E, 0x69, 0x75, 0x6D, 0x00, 0x57, 0x69, 0x6E, // for Itanium.Win + /* 2E80 */ 0x64, 0x6F, 0x77, 0x73, 0x20, 0x4D, 0x75, 0x6C, 0x74, 0x69, 0x50, 0x6F, 0x69, 0x6E, 0x74, 0x20, // dows MultiPoint + /* 2E90 */ 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x31, 0x30, 0x00, 0x57, 0x69, 0x6E, 0x64, // Server 2010.Wind + /* 2EA0 */ 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x30, 0x38, 0x20, // ows Server 2008 + /* 2EB0 */ 0x52, 0x32, 0x20, 0x57, 0x65, 0x62, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, // R2 Web.Windows S + /* 2EC0 */ 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x30, 0x38, 0x20, 0x52, 0x32, 0x20, 0x48, 0x50, // erver 2008 R2 HP + /* 2ED0 */ 0x43, 0x20, 0x45, 0x64, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, // C Edition.Window + /* 2EE0 */ 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x30, 0x38, 0x20, 0x52, 0x32, // s Server 2008 R2 + /* 2EF0 */ 0x20, 0x53, 0x74, 0x61, 0x6E, 0x64, 0x61, 0x72, 0x64, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, // Standard.Window + /* 2F00 */ 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x30, 0x38, 0x20, 0x52, 0x32, // s Server 2008 R2 + /* 2F10 */ 0x20, 0x45, 0x6E, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x00, 0x57, 0x69, 0x6E, 0x64, // Enterprise.Wind + /* 2F20 */ 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x30, 0x38, 0x20, // ows Server 2008 + /* 2F30 */ 0x52, 0x32, 0x20, 0x44, 0x61, 0x74, 0x61, 0x63, 0x65, 0x6E, 0x74, 0x65, 0x72, 0x00, 0x57, 0x69, // R2 Datacenter.Wi + /* 2F40 */ 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x30, // ndows Server 200 + /* 2F50 */ 0x38, 0x20, 0x52, 0x32, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x49, 0x74, 0x61, 0x6E, 0x69, 0x75, 0x6D, // 8 R2 for Itanium + /* 2F60 */ 0x20, 0x45, 0x6E, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x00, 0x57, 0x69, 0x6E, 0x64, // Enterprise.Wind + /* 2F70 */ 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x31, 0x32, 0x20, // ows Server 2012 + /* 2F80 */ 0x44, 0x61, 0x74, 0x61, 0x63, 0x65, 0x6E, 0x74, 0x65, 0x72, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, // Datacenter.Windo + /* 2F90 */ 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x31, 0x32, 0x20, 0x4D, // ws Server 2012 M + /* 2FA0 */ 0x75, 0x6C, 0x74, 0x69, 0x50, 0x6F, 0x69, 0x6E, 0x74, 0x20, 0x50, 0x72, 0x65, 0x6D, 0x69, 0x75, // ultiPoint Premiu + /* 2FB0 */ 0x6D, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, // m.Windows Server + /* 2FC0 */ 0x20, 0x32, 0x30, 0x31, 0x32, 0x20, 0x4D, 0x75, 0x6C, 0x74, 0x69, 0x50, 0x6F, 0x69, 0x6E, 0x74, // 2012 MultiPoint + /* 2FD0 */ 0x20, 0x53, 0x74, 0x61, 0x6E, 0x64, 0x61, 0x72, 0x64, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, // Standard.Window + /* 2FE0 */ 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x31, 0x32, 0x20, 0x53, 0x74, // s Server 2012 St + /* 2FF0 */ 0x61, 0x6E, 0x64, 0x61, 0x72, 0x64, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, // andard.Windows S + /* 3000 */ 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x31, 0x32, 0x20, 0x52, 0x32, 0x20, 0x43, 0x6C, // erver 2012 R2 Cl + /* 3010 */ 0x6F, 0x75, 0x64, 0x20, 0x53, 0x74, 0x6F, 0x72, 0x61, 0x67, 0x65, 0x00, 0x57, 0x69, 0x6E, 0x64, // oud Storage.Wind + /* 3020 */ 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x31, 0x32, 0x20, // ows Server 2012 + /* 3030 */ 0x52, 0x32, 0x20, 0x44, 0x61, 0x74, 0x61, 0x63, 0x65, 0x6E, 0x74, 0x65, 0x72, 0x00, 0x57, 0x69, // R2 Datacenter.Wi + /* 3040 */ 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x31, // ndows Server 201 + /* 3050 */ 0x32, 0x20, 0x52, 0x32, 0x20, 0x45, 0x73, 0x73, 0x65, 0x6E, 0x74, 0x69, 0x61, 0x6C, 0x73, 0x00, // 2 R2 Essentials. + /* 3060 */ 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, // Windows Server 2 + /* 3070 */ 0x30, 0x31, 0x32, 0x20, 0x52, 0x32, 0x20, 0x53, 0x74, 0x61, 0x6E, 0x64, 0x61, 0x72, 0x64, 0x00, // 012 R2 Standard. + /* 3080 */ 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, // Windows Server 2 + /* 3090 */ 0x30, 0x31, 0x36, 0x20, 0x41, 0x7A, 0x75, 0x72, 0x65, 0x20, 0x43, 0x6F, 0x72, 0x65, 0x00, 0x57, // 016 Azure Core.W + /* 30A0 */ 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, // indows Server 20 + /* 30B0 */ 0x31, 0x36, 0x20, 0x43, 0x6C, 0x6F, 0x75, 0x64, 0x20, 0x53, 0x74, 0x6F, 0x72, 0x61, 0x67, 0x65, // 16 Cloud Storage + /* 30C0 */ 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, // .Windows Server + /* 30D0 */ 0x32, 0x30, 0x31, 0x36, 0x20, 0x44, 0x61, 0x74, 0x61, 0x63, 0x65, 0x6E, 0x74, 0x65, 0x72, 0x00, // 2016 Datacenter. + /* 30E0 */ 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, // Windows Server 2 + /* 30F0 */ 0x30, 0x31, 0x36, 0x20, 0x45, 0x73, 0x73, 0x65, 0x6E, 0x74, 0x69, 0x61, 0x6C, 0x73, 0x00, 0x57, // 016 Essentials.W + /* 3100 */ 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, // indows Server 20 + /* 3110 */ 0x31, 0x36, 0x20, 0x53, 0x74, 0x61, 0x6E, 0x64, 0x61, 0x72, 0x64, 0x00, 0x57, 0x69, 0x6E, 0x64, // 16 Standard.Wind + /* 3120 */ 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x31, 0x36, 0x20, // ows Server 2016 + /* 3130 */ 0x41, 0x52, 0x4D, 0x36, 0x34, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, // ARM64.Windows Se + /* 3140 */ 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x31, 0x36, 0x20, 0x44, 0x61, 0x74, 0x61, 0x63, 0x65, // rver 2016 Datace + /* 3150 */ 0x6E, 0x74, 0x65, 0x72, 0x20, 0x28, 0x53, 0x65, 0x6D, 0x69, 0x2D, 0x41, 0x6E, 0x6E, 0x75, 0x61, // nter (Semi-Annua + /* 3160 */ 0x6C, 0x20, 0x43, 0x68, 0x61, 0x6E, 0x6E, 0x65, 0x6C, 0x29, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, // l Channel).Windo + /* 3170 */ 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x31, 0x36, 0x20, 0x53, // ws Server 2016 S + /* 3180 */ 0x74, 0x61, 0x6E, 0x64, 0x61, 0x72, 0x64, 0x20, 0x28, 0x53, 0x65, 0x6D, 0x69, 0x2D, 0x41, 0x6E, // tandard (Semi-An + /* 3190 */ 0x6E, 0x75, 0x61, 0x6C, 0x20, 0x43, 0x68, 0x61, 0x6E, 0x6E, 0x65, 0x6C, 0x29, 0x00, 0x57, 0x69, // nual Channel).Wi + /* 31A0 */ 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x31, // ndows Server 201 + /* 31B0 */ 0x36, 0x20, 0x44, 0x61, 0x74, 0x61, 0x63, 0x65, 0x6E, 0x74, 0x65, 0x72, 0x20, 0x50, 0x72, 0x65, // 6 Datacenter Pre + /* 31C0 */ 0x76, 0x69, 0x65, 0x77, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x56, 0x69, 0x73, // view.Windows Vis + /* 31D0 */ 0x74, 0x61, 0x20, 0x42, 0x75, 0x73, 0x69, 0x6E, 0x65, 0x73, 0x73, 0x00, 0x57, 0x69, 0x6E, 0x64, // ta Business.Wind + /* 31E0 */ 0x6F, 0x77, 0x73, 0x20, 0x56, 0x69, 0x73, 0x74, 0x61, 0x20, 0x42, 0x75, 0x73, 0x69, 0x6E, 0x65, // ows Vista Busine + /* 31F0 */ 0x73, 0x73, 0x20, 0x4E, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x56, 0x69, 0x73, // ss N.Windows Vis + /* 3200 */ 0x74, 0x61, 0x20, 0x45, 0x6E, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x00, 0x57, 0x69, // ta Enterprise.Wi + /* 3210 */ 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x56, 0x69, 0x73, 0x74, 0x61, 0x20, 0x45, 0x6E, 0x74, 0x65, // ndows Vista Ente + /* 3220 */ 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x20, 0x4E, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, // rprise N.Office + /* 3230 */ 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x20, 0x32, 0x30, 0x31, 0x30, 0x00, 0x4F, 0x66, 0x66, 0x69, // Access 2010.Offi + /* 3240 */ 0x63, 0x65, 0x20, 0x45, 0x78, 0x63, 0x65, 0x6C, 0x20, 0x32, 0x30, 0x31, 0x30, 0x00, 0x4F, 0x66, // ce Excel 2010.Of + /* 3250 */ 0x66, 0x69, 0x63, 0x65, 0x20, 0x47, 0x72, 0x6F, 0x6F, 0x76, 0x65, 0x20, 0x32, 0x30, 0x31, 0x30, // fice Groove 2010 + /* 3260 */ 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x49, 0x6E, 0x66, 0x6F, 0x50, 0x61, 0x74, 0x68, // .Office InfoPath + /* 3270 */ 0x20, 0x32, 0x30, 0x31, 0x30, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x4D, 0x6F, 0x6E, // 2010.Office Mon + /* 3280 */ 0x64, 0x6F, 0x20, 0x31, 0x20, 0x32, 0x30, 0x31, 0x30, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, // do 1 2010.Office + /* 3290 */ 0x20, 0x4D, 0x6F, 0x6E, 0x64, 0x6F, 0x20, 0x32, 0x20, 0x32, 0x30, 0x31, 0x30, 0x00, 0x4F, 0x66, // Mondo 2 2010.Of + /* 32A0 */ 0x66, 0x69, 0x63, 0x65, 0x20, 0x4F, 0x6E, 0x65, 0x4E, 0x6F, 0x74, 0x65, 0x20, 0x32, 0x30, 0x31, // fice OneNote 201 + /* 32B0 */ 0x30, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x4F, 0x75, 0x74, 0x4C, 0x6F, 0x6F, 0x6B, // 0.Office OutLook + /* 32C0 */ 0x20, 0x32, 0x30, 0x31, 0x30, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x50, 0x6F, 0x77, // 2010.Office Pow + /* 32D0 */ 0x65, 0x72, 0x50, 0x6F, 0x69, 0x6E, 0x74, 0x20, 0x32, 0x30, 0x31, 0x30, 0x00, 0x4F, 0x66, 0x66, // erPoint 2010.Off + /* 32E0 */ 0x69, 0x63, 0x65, 0x20, 0x50, 0x72, 0x6F, 0x66, 0x65, 0x73, 0x73, 0x69, 0x6F, 0x6E, 0x61, 0x6C, // ice Professional + /* 32F0 */ 0x20, 0x50, 0x6C, 0x75, 0x73, 0x20, 0x32, 0x30, 0x31, 0x30, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, // Plus 2010.Offic + /* 3300 */ 0x65, 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, 0x63, 0x74, 0x20, 0x50, 0x72, 0x6F, 0x20, 0x32, 0x30, // e Project Pro 20 + /* 3310 */ 0x31, 0x30, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, 0x63, // 10.Office Projec + /* 3320 */ 0x74, 0x20, 0x53, 0x74, 0x61, 0x6E, 0x64, 0x61, 0x72, 0x64, 0x20, 0x32, 0x30, 0x31, 0x30, 0x00, // t Standard 2010. + /* 3330 */ 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x50, 0x75, 0x62, 0x6C, 0x69, 0x73, 0x68, 0x65, 0x72, // Office Publisher + /* 3340 */ 0x20, 0x32, 0x30, 0x31, 0x30, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x53, 0x6D, 0x61, // 2010.Office Sma + /* 3350 */ 0x6C, 0x6C, 0x20, 0x42, 0x75, 0x73, 0x69, 0x6E, 0x65, 0x73, 0x73, 0x20, 0x42, 0x61, 0x73, 0x69, // ll Business Basi + /* 3360 */ 0x63, 0x73, 0x20, 0x32, 0x30, 0x31, 0x30, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x53, // cs 2010.Office S + /* 3370 */ 0x74, 0x61, 0x6E, 0x64, 0x61, 0x72, 0x64, 0x20, 0x32, 0x30, 0x31, 0x30, 0x00, 0x4F, 0x66, 0x66, // tandard 2010.Off + /* 3380 */ 0x69, 0x63, 0x65, 0x20, 0x56, 0x69, 0x73, 0x69, 0x6F, 0x20, 0x50, 0x72, 0x65, 0x6D, 0x69, 0x75, // ice Visio Premiu + /* 3390 */ 0x6D, 0x20, 0x32, 0x30, 0x31, 0x30, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x56, 0x69, // m 2010.Office Vi + /* 33A0 */ 0x73, 0x69, 0x6F, 0x20, 0x50, 0x72, 0x6F, 0x20, 0x32, 0x30, 0x31, 0x30, 0x00, 0x4F, 0x66, 0x66, // sio Pro 2010.Off + /* 33B0 */ 0x69, 0x63, 0x65, 0x20, 0x56, 0x69, 0x73, 0x69, 0x6F, 0x20, 0x53, 0x74, 0x61, 0x6E, 0x64, 0x61, // ice Visio Standa + /* 33C0 */ 0x72, 0x64, 0x20, 0x32, 0x30, 0x31, 0x30, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x57, // rd 2010.Office W + /* 33D0 */ 0x6F, 0x72, 0x64, 0x20, 0x32, 0x30, 0x31, 0x30, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, // ord 2010.Office + /* 33E0 */ 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x20, 0x32, 0x30, 0x31, 0x33, 0x00, 0x4F, 0x66, 0x66, 0x69, // Access 2013.Offi + /* 33F0 */ 0x63, 0x65, 0x20, 0x45, 0x78, 0x63, 0x65, 0x6C, 0x20, 0x32, 0x30, 0x31, 0x33, 0x00, 0x4F, 0x66, // ce Excel 2013.Of + /* 3400 */ 0x66, 0x69, 0x63, 0x65, 0x20, 0x49, 0x6E, 0x66, 0x6F, 0x50, 0x61, 0x74, 0x68, 0x20, 0x32, 0x30, // fice InfoPath 20 + /* 3410 */ 0x31, 0x33, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x4C, 0x79, 0x6E, 0x63, 0x20, 0x32, // 13.Office Lync 2 + /* 3420 */ 0x30, 0x31, 0x33, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x4D, 0x6F, 0x6E, 0x64, 0x6F, // 013.Office Mondo + /* 3430 */ 0x20, 0x32, 0x30, 0x31, 0x33, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x4F, 0x6E, 0x65, // 2013.Office One + /* 3440 */ 0x4E, 0x6F, 0x74, 0x65, 0x20, 0x32, 0x30, 0x31, 0x33, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, // Note 2013.Office + /* 3450 */ 0x20, 0x4F, 0x75, 0x74, 0x4C, 0x6F, 0x6F, 0x6B, 0x20, 0x32, 0x30, 0x31, 0x33, 0x00, 0x4F, 0x66, // OutLook 2013.Of + /* 3460 */ 0x66, 0x69, 0x63, 0x65, 0x20, 0x50, 0x6F, 0x77, 0x65, 0x72, 0x50, 0x6F, 0x69, 0x6E, 0x74, 0x20, // fice PowerPoint + /* 3470 */ 0x32, 0x30, 0x31, 0x33, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x50, 0x72, 0x6F, 0x66, // 2013.Office Prof + /* 3480 */ 0x65, 0x73, 0x73, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x50, 0x6C, 0x75, 0x73, 0x20, 0x32, 0x30, // essional Plus 20 + /* 3490 */ 0x31, 0x33, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, 0x63, // 13.Office Projec + /* 34A0 */ 0x74, 0x20, 0x50, 0x72, 0x6F, 0x20, 0x32, 0x30, 0x31, 0x33, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, // t Pro 2013.Offic + /* 34B0 */ 0x65, 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, 0x63, 0x74, 0x20, 0x53, 0x74, 0x61, 0x6E, 0x64, 0x61, // e Project Standa + /* 34C0 */ 0x72, 0x64, 0x20, 0x32, 0x30, 0x31, 0x33, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x50, // rd 2013.Office P + /* 34D0 */ 0x75, 0x62, 0x6C, 0x69, 0x73, 0x68, 0x65, 0x72, 0x20, 0x32, 0x30, 0x31, 0x33, 0x00, 0x4F, 0x66, // ublisher 2013.Of + /* 34E0 */ 0x66, 0x69, 0x63, 0x65, 0x20, 0x53, 0x74, 0x61, 0x6E, 0x64, 0x61, 0x72, 0x64, 0x20, 0x32, 0x30, // fice Standard 20 + /* 34F0 */ 0x31, 0x33, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x56, 0x69, 0x73, 0x69, 0x6F, 0x20, // 13.Office Visio + /* 3500 */ 0x50, 0x72, 0x6F, 0x20, 0x32, 0x30, 0x31, 0x33, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, // Pro 2013.Office + /* 3510 */ 0x56, 0x69, 0x73, 0x69, 0x6F, 0x20, 0x53, 0x74, 0x61, 0x6E, 0x64, 0x61, 0x72, 0x64, 0x20, 0x32, // Visio Standard 2 + /* 3520 */ 0x30, 0x31, 0x33, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x57, 0x6F, 0x72, 0x64, 0x20, // 013.Office Word + /* 3530 */ 0x32, 0x30, 0x31, 0x33, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x41, 0x63, 0x63, 0x65, // 2013.Office Acce + /* 3540 */ 0x73, 0x73, 0x20, 0x32, 0x30, 0x31, 0x33, 0x20, 0x28, 0x50, 0x72, 0x65, 0x2D, 0x52, 0x65, 0x6C, // ss 2013 (Pre-Rel + /* 3550 */ 0x65, 0x61, 0x73, 0x65, 0x29, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x45, 0x78, 0x63, // ease).Office Exc + /* 3560 */ 0x65, 0x6C, 0x20, 0x32, 0x30, 0x31, 0x33, 0x20, 0x28, 0x50, 0x72, 0x65, 0x2D, 0x52, 0x65, 0x6C, // el 2013 (Pre-Rel + /* 3570 */ 0x65, 0x61, 0x73, 0x65, 0x29, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x47, 0x72, 0x6F, // ease).Office Gro + /* 3580 */ 0x6F, 0x76, 0x65, 0x20, 0x32, 0x30, 0x31, 0x33, 0x20, 0x28, 0x50, 0x72, 0x65, 0x2D, 0x52, 0x65, // ove 2013 (Pre-Re + /* 3590 */ 0x6C, 0x65, 0x61, 0x73, 0x65, 0x29, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x49, 0x6E, // lease).Office In + /* 35A0 */ 0x66, 0x6F, 0x50, 0x61, 0x74, 0x68, 0x20, 0x32, 0x30, 0x31, 0x33, 0x20, 0x28, 0x50, 0x72, 0x65, // foPath 2013 (Pre + /* 35B0 */ 0x2D, 0x52, 0x65, 0x6C, 0x65, 0x61, 0x73, 0x65, 0x29, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, // -Release).Office + /* 35C0 */ 0x20, 0x4C, 0x79, 0x6E, 0x63, 0x20, 0x32, 0x30, 0x31, 0x33, 0x20, 0x28, 0x50, 0x72, 0x65, 0x2D, // Lync 2013 (Pre- + /* 35D0 */ 0x52, 0x65, 0x6C, 0x65, 0x61, 0x73, 0x65, 0x29, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, // Release).Office + /* 35E0 */ 0x4D, 0x6F, 0x6E, 0x64, 0x6F, 0x20, 0x32, 0x30, 0x31, 0x33, 0x20, 0x28, 0x50, 0x72, 0x65, 0x2D, // Mondo 2013 (Pre- + /* 35F0 */ 0x52, 0x65, 0x6C, 0x65, 0x61, 0x73, 0x65, 0x29, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, // Release).Office + /* 3600 */ 0x4F, 0x6E, 0x65, 0x4E, 0x6F, 0x74, 0x65, 0x20, 0x32, 0x30, 0x31, 0x33, 0x20, 0x28, 0x50, 0x72, // OneNote 2013 (Pr + /* 3610 */ 0x65, 0x2D, 0x52, 0x65, 0x6C, 0x65, 0x61, 0x73, 0x65, 0x29, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, // e-Release).Offic + /* 3620 */ 0x65, 0x20, 0x4F, 0x75, 0x74, 0x6C, 0x6F, 0x6F, 0x6B, 0x20, 0x32, 0x30, 0x31, 0x33, 0x20, 0x28, // e Outlook 2013 ( + /* 3630 */ 0x50, 0x72, 0x65, 0x2D, 0x52, 0x65, 0x6C, 0x65, 0x61, 0x73, 0x65, 0x29, 0x00, 0x4F, 0x66, 0x66, // Pre-Release).Off + /* 3640 */ 0x69, 0x63, 0x65, 0x20, 0x50, 0x6F, 0x77, 0x65, 0x72, 0x50, 0x6F, 0x69, 0x6E, 0x74, 0x20, 0x32, // ice PowerPoint 2 + /* 3650 */ 0x30, 0x31, 0x33, 0x20, 0x28, 0x50, 0x72, 0x65, 0x2D, 0x52, 0x65, 0x6C, 0x65, 0x61, 0x73, 0x65, // 013 (Pre-Release + /* 3660 */ 0x29, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x50, 0x72, 0x6F, 0x66, 0x65, 0x73, 0x73, // ).Office Profess + /* 3670 */ 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x50, 0x6C, 0x75, 0x73, 0x20, 0x32, 0x30, 0x31, 0x33, 0x20, // ional Plus 2013 + /* 3680 */ 0x28, 0x50, 0x72, 0x65, 0x2D, 0x52, 0x65, 0x6C, 0x65, 0x61, 0x73, 0x65, 0x29, 0x00, 0x4F, 0x66, // (Pre-Release).Of + /* 3690 */ 0x66, 0x69, 0x63, 0x65, 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, 0x63, 0x74, 0x20, 0x50, 0x72, 0x6F, // fice Project Pro + /* 36A0 */ 0x20, 0x32, 0x30, 0x31, 0x33, 0x20, 0x28, 0x50, 0x72, 0x65, 0x2D, 0x52, 0x65, 0x6C, 0x65, 0x61, // 2013 (Pre-Relea + /* 36B0 */ 0x73, 0x65, 0x29, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, // se).Office Proje + /* 36C0 */ 0x63, 0x74, 0x20, 0x53, 0x74, 0x61, 0x6E, 0x64, 0x61, 0x72, 0x64, 0x20, 0x32, 0x30, 0x31, 0x33, // ct Standard 2013 + /* 36D0 */ 0x20, 0x28, 0x50, 0x72, 0x65, 0x2D, 0x52, 0x65, 0x6C, 0x65, 0x61, 0x73, 0x65, 0x29, 0x00, 0x4F, // (Pre-Release).O + /* 36E0 */ 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x50, 0x75, 0x62, 0x6C, 0x69, 0x73, 0x68, 0x65, 0x72, 0x20, // ffice Publisher + /* 36F0 */ 0x32, 0x30, 0x31, 0x33, 0x20, 0x28, 0x50, 0x72, 0x65, 0x2D, 0x52, 0x65, 0x6C, 0x65, 0x61, 0x73, // 2013 (Pre-Releas + /* 3700 */ 0x65, 0x29, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x56, 0x69, 0x73, 0x69, 0x6F, 0x20, // e).Office Visio + /* 3710 */ 0x50, 0x72, 0x6F, 0x20, 0x32, 0x30, 0x31, 0x33, 0x20, 0x28, 0x50, 0x72, 0x65, 0x2D, 0x52, 0x65, // Pro 2013 (Pre-Re + /* 3720 */ 0x6C, 0x65, 0x61, 0x73, 0x65, 0x29, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x56, 0x69, // lease).Office Vi + /* 3730 */ 0x73, 0x69, 0x6F, 0x20, 0x53, 0x74, 0x61, 0x6E, 0x64, 0x61, 0x72, 0x64, 0x20, 0x32, 0x30, 0x31, // sio Standard 201 + /* 3740 */ 0x33, 0x20, 0x28, 0x50, 0x72, 0x65, 0x2D, 0x52, 0x65, 0x6C, 0x65, 0x61, 0x73, 0x65, 0x29, 0x00, // 3 (Pre-Release). + /* 3750 */ 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x57, 0x6F, 0x72, 0x64, 0x20, 0x32, 0x30, 0x31, 0x33, // Office Word 2013 + /* 3760 */ 0x20, 0x28, 0x50, 0x72, 0x65, 0x2D, 0x52, 0x65, 0x6C, 0x65, 0x61, 0x73, 0x65, 0x29, 0x00, 0x4F, // (Pre-Release).O + /* 3770 */ 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x20, 0x32, 0x30, 0x31, // ffice Access 201 + /* 3780 */ 0x36, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x45, 0x78, 0x63, 0x65, 0x6C, 0x20, 0x32, // 6.Office Excel 2 + /* 3790 */ 0x30, 0x31, 0x36, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x4D, 0x6F, 0x6E, 0x64, 0x6F, // 016.Office Mondo + /* 37A0 */ 0x20, 0x32, 0x30, 0x31, 0x36, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x4D, 0x6F, 0x6E, // 2016.Office Mon + /* 37B0 */ 0x64, 0x6F, 0x20, 0x52, 0x20, 0x32, 0x30, 0x31, 0x36, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, // do R 2016.Office + /* 37C0 */ 0x20, 0x4F, 0x6E, 0x65, 0x4E, 0x6F, 0x74, 0x65, 0x20, 0x32, 0x30, 0x31, 0x36, 0x00, 0x4F, 0x66, // OneNote 2016.Of + /* 37D0 */ 0x66, 0x69, 0x63, 0x65, 0x20, 0x4F, 0x75, 0x74, 0x6C, 0x6F, 0x6F, 0x6B, 0x20, 0x32, 0x30, 0x31, // fice Outlook 201 + /* 37E0 */ 0x36, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x50, 0x6F, 0x77, 0x65, 0x72, 0x70, 0x6F, // 6.Office Powerpo + /* 37F0 */ 0x69, 0x6E, 0x74, 0x20, 0x32, 0x30, 0x31, 0x36, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, // int 2016.Office + /* 3800 */ 0x50, 0x72, 0x6F, 0x66, 0x65, 0x73, 0x73, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x50, 0x6C, 0x75, // Professional Plu + /* 3810 */ 0x73, 0x20, 0x32, 0x30, 0x31, 0x36, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x50, 0x72, // s 2016.Office Pr + /* 3820 */ 0x6F, 0x6A, 0x65, 0x63, 0x74, 0x20, 0x50, 0x72, 0x6F, 0x20, 0x32, 0x30, 0x31, 0x36, 0x00, 0x4F, // oject Pro 2016.O + /* 3830 */ 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, 0x63, 0x74, 0x20, 0x50, 0x72, // ffice Project Pr + /* 3840 */ 0x6F, 0x20, 0x32, 0x30, 0x31, 0x36, 0x20, 0x43, 0x32, 0x52, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, // o 2016 C2R.Offic + /* 3850 */ 0x65, 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, 0x63, 0x74, 0x20, 0x53, 0x74, 0x61, 0x6E, 0x64, 0x61, // e Project Standa + /* 3860 */ 0x72, 0x64, 0x20, 0x32, 0x30, 0x31, 0x36, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x50, // rd 2016.Office P + /* 3870 */ 0x72, 0x6F, 0x6A, 0x65, 0x63, 0x74, 0x20, 0x53, 0x74, 0x61, 0x6E, 0x64, 0x61, 0x72, 0x64, 0x20, // roject Standard + /* 3880 */ 0x32, 0x30, 0x31, 0x36, 0x20, 0x43, 0x32, 0x52, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, // 2016 C2R.Office + /* 3890 */ 0x50, 0x75, 0x62, 0x6C, 0x69, 0x73, 0x68, 0x65, 0x72, 0x20, 0x32, 0x30, 0x31, 0x36, 0x00, 0x4F, // Publisher 2016.O + /* 38A0 */ 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x53, 0x6B, 0x79, 0x70, 0x65, 0x20, 0x66, 0x6F, 0x72, 0x20, // ffice Skype for + /* 38B0 */ 0x42, 0x75, 0x73, 0x69, 0x6E, 0x65, 0x73, 0x73, 0x20, 0x32, 0x30, 0x31, 0x36, 0x00, 0x4F, 0x66, // Business 2016.Of + /* 38C0 */ 0x66, 0x69, 0x63, 0x65, 0x20, 0x53, 0x74, 0x61, 0x6E, 0x64, 0x61, 0x72, 0x64, 0x20, 0x32, 0x30, // fice Standard 20 + /* 38D0 */ 0x31, 0x36, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x56, 0x69, 0x73, 0x69, 0x6F, 0x20, // 16.Office Visio + /* 38E0 */ 0x50, 0x72, 0x6F, 0x20, 0x32, 0x30, 0x31, 0x36, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, // Pro 2016.Office + /* 38F0 */ 0x56, 0x69, 0x73, 0x69, 0x6F, 0x20, 0x50, 0x72, 0x6F, 0x20, 0x32, 0x30, 0x31, 0x36, 0x20, 0x43, // Visio Pro 2016 C + /* 3900 */ 0x32, 0x52, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x56, 0x69, 0x73, 0x69, 0x6F, 0x20, // 2R.Office Visio + /* 3910 */ 0x53, 0x74, 0x61, 0x6E, 0x64, 0x61, 0x72, 0x64, 0x20, 0x32, 0x30, 0x31, 0x36, 0x00, 0x4F, 0x66, // Standard 2016.Of + /* 3920 */ 0x66, 0x69, 0x63, 0x65, 0x20, 0x56, 0x69, 0x73, 0x69, 0x6F, 0x20, 0x53, 0x74, 0x61, 0x6E, 0x64, // fice Visio Stand + /* 3930 */ 0x61, 0x72, 0x64, 0x20, 0x32, 0x30, 0x31, 0x36, 0x20, 0x43, 0x32, 0x52, 0x00, 0x4F, 0x66, 0x66, // ard 2016 C2R.Off + /* 3940 */ 0x69, 0x63, 0x65, 0x20, 0x57, 0x6F, 0x72, 0x64, 0x20, 0x32, 0x30, 0x31, 0x36, 0x00, 0x4F, 0x66, // ice Word 2016.Of + /* 3950 */ 0x66, 0x69, 0x63, 0x65, 0x20, 0x50, 0x72, 0x6F, 0x66, 0x65, 0x73, 0x73, 0x69, 0x6F, 0x6E, 0x61, // fice Professiona + /* 3960 */ 0x6C, 0x20, 0x50, 0x6C, 0x75, 0x73, 0x20, 0x32, 0x30, 0x31, 0x39, 0x20, 0x43, 0x32, 0x52, 0x20, // l Plus 2019 C2R + /* 3970 */ 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x50, // Preview.Office P + /* 3980 */ 0x72, 0x6F, 0x6A, 0x65, 0x63, 0x74, 0x20, 0x50, 0x72, 0x6F, 0x20, 0x32, 0x30, 0x31, 0x39, 0x20, // roject Pro 2019 + /* 3990 */ 0x43, 0x32, 0x52, 0x20, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x00, 0x4F, 0x66, 0x66, 0x69, // C2R Preview.Offi + /* 39A0 */ 0x63, 0x65, 0x20, 0x56, 0x69, 0x73, 0x69, 0x6F, 0x20, 0x50, 0x72, 0x6F, 0x20, 0x32, 0x30, 0x31, // ce Visio Pro 201 + /* 39B0 */ 0x39, 0x20, 0x43, 0x32, 0x52, 0x20, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x00, 0x4F, 0x66, // 9 C2R Preview.Of + /* 39C0 */ 0x66, 0x69, 0x63, 0x65, 0x20, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x20, 0x32, 0x30, 0x31, 0x39, // fice Access 2019 + /* 39D0 */ 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x45, 0x78, 0x63, 0x65, 0x6C, 0x20, 0x32, 0x30, // .Office Excel 20 + /* 39E0 */ 0x31, 0x39, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x4F, 0x75, 0x74, 0x6C, 0x6F, 0x6F, // 19.Office Outloo + /* 39F0 */ 0x6B, 0x20, 0x32, 0x30, 0x31, 0x39, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x50, 0x6F, // k 2019.Office Po + /* 3A00 */ 0x77, 0x65, 0x72, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x20, 0x32, 0x30, 0x31, 0x39, 0x00, 0x4F, 0x66, // werpoint 2019.Of + /* 3A10 */ 0x66, 0x69, 0x63, 0x65, 0x20, 0x50, 0x72, 0x6F, 0x66, 0x65, 0x73, 0x73, 0x69, 0x6F, 0x6E, 0x61, // fice Professiona + /* 3A20 */ 0x6C, 0x20, 0x50, 0x6C, 0x75, 0x73, 0x20, 0x32, 0x30, 0x31, 0x39, 0x00, 0x4F, 0x66, 0x66, 0x69, // l Plus 2019.Offi + /* 3A30 */ 0x63, 0x65, 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, 0x63, 0x74, 0x20, 0x50, 0x72, 0x6F, 0x20, 0x32, // ce Project Pro 2 + /* 3A40 */ 0x30, 0x31, 0x39, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, // 019.Office Proje + /* 3A50 */ 0x63, 0x74, 0x20, 0x53, 0x74, 0x61, 0x6E, 0x64, 0x61, 0x72, 0x64, 0x20, 0x32, 0x30, 0x31, 0x39, // ct Standard 2019 + /* 3A60 */ 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x50, 0x75, 0x62, 0x6C, 0x69, 0x73, 0x68, 0x65, // .Office Publishe + /* 3A70 */ 0x72, 0x20, 0x32, 0x30, 0x31, 0x39, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x53, 0x6B, // r 2019.Office Sk + /* 3A80 */ 0x79, 0x70, 0x65, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x42, 0x75, 0x73, 0x69, 0x6E, 0x65, 0x73, 0x73, // ype for Business + /* 3A90 */ 0x20, 0x32, 0x30, 0x31, 0x39, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x53, 0x74, 0x61, // 2019.Office Sta + /* 3AA0 */ 0x6E, 0x64, 0x61, 0x72, 0x64, 0x20, 0x32, 0x30, 0x31, 0x39, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, // ndard 2019.Offic + /* 3AB0 */ 0x65, 0x20, 0x56, 0x69, 0x73, 0x69, 0x6F, 0x20, 0x50, 0x72, 0x6F, 0x20, 0x32, 0x30, 0x31, 0x39, // e Visio Pro 2019 + /* 3AC0 */ 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x56, 0x69, 0x73, 0x69, 0x6F, 0x20, 0x53, 0x74, // .Office Visio St + /* 3AD0 */ 0x61, 0x6E, 0x64, 0x61, 0x72, 0x64, 0x20, 0x32, 0x30, 0x31, 0x39, 0x00, 0x4F, 0x66, 0x66, 0x69, // andard 2019.Offi + /* 3AE0 */ 0x63, 0x65, 0x20, 0x57, 0x6F, 0x72, 0x64, 0x20, 0x32, 0x30, 0x31, 0x39, 0x00, // ce Word 2019. +}; + +__pure size_t getDefaultKmsDataSize() +{ + return sizeof(DefaultKmsData); +} + +#endif // NO_INTERNAL_DATA + diff --git a/vlmcsd/src/kmsdata.c b/vlmcsd/src/kmsdata.c new file mode 100644 index 0000000..c8759a9 --- /dev/null +++ b/vlmcsd/src/kmsdata.c @@ -0,0 +1,1167 @@ +#ifndef CONFIG +#define CONFIG "config.h" +#endif // CONFIG +#include CONFIG + +#ifndef NO_INTERNAL_DATA + +#include "kmsdata.h" + +#if defined(FULL_INTERNAL_DATA) + +uint8_t DefaultKmsData[] = +{ + /* 0000 */ 0x4B, 0x4D, 0x44, 0x00, 0x00, 0x00, 0x02, 0x00, 0x06, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, // KMD............. + /* 0010 */ 0x1D, 0x00, 0x00, 0x00, 0xCA, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ............... + /* 0020 */ 0x08, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........h....... + /* 0030 */ 0x08, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........H....... + /* 0040 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................ + /* 0050 */ 0x00, 0xB5, 0xB2, 0x5B, 0x00, 0x00, 0x00, 0x00, 0xCE, 0x00, 0x00, 0x00, 0xC0, 0x97, 0xD7, 0x20, // .[........ + /* 0060 */ 0xBF, 0xC4, 0x08, 0x22, 0x00, 0x00, 0x00, 0x00, 0x56, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ."....V....... + /* 0070 */ 0x80, 0x4F, 0x3E, 0x4C, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0xC0, 0x7F, 0xDC, 0x0B, // .O>L....`..... + /* 0080 */ 0x7F, 0x6A, 0xFE, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x9F, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .j............. + /* 0090 */ 0x00, 0x11, 0x07, 0x51, 0x00, 0x00, 0x00, 0x00, 0xCE, 0x00, 0x00, 0x00, 0x80, 0x8E, 0xF2, 0x0D, // ...Q.......... + /* 00A0 */ 0xFF, 0x3F, 0x42, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xE8, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ?B............ + /* 00B0 */ 0x00, 0x9A, 0x00, 0x56, 0x00, 0x00, 0x00, 0x00, 0xCE, 0x00, 0x00, 0x00, 0x40, 0x17, 0x0C, 0x1A, // ...V.......@... + /* 00C0 */ 0xBF, 0xC8, 0x5B, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x31, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // [.....1 ...... + /* 00D0 */ 0x80, 0x33, 0xE4, 0x58, 0x00, 0x00, 0x00, 0x00, 0x12, 0x0F, 0x00, 0x00, 0xC0, 0xE1, 0xE4, 0x00, // .3X......... + /* 00E0 */ 0xFF, 0xC9, 0x9A, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x8B, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .;..... ...... + /* 00F0 */ 0x00, 0x29, 0xA8, 0x5B, 0x00, 0x00, 0x00, 0x00, 0xCE, 0x00, 0x00, 0x00, 0x80, 0x5A, 0xB2, 0x27, // .)[........Z' + /* 0100 */ 0x7F, 0x87, 0xE3, 0x28, 0x00, 0x00, 0x00, 0x00, 0x34, 0x27, 0xC9, 0x55, 0x82, 0xD6, 0x71, 0x4D, // ..(....4'U.qM + /* 0110 */ 0x98, 0x3E, 0xD6, 0xEC, 0x3F, 0x16, 0x05, 0x9F, 0x84, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .>?....!...... + /* 0120 */ 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x81, 0x28, 0xA5, 0x59, 0x89, 0xA9, 0x9D, 0x47, // ...2.....(Y..G + /* 0130 */ 0xAF, 0x46, 0xF2, 0x75, 0xC6, 0x37, 0x06, 0x63, 0x8C, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Fu7.c.!...... + /* 0140 */ 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x01, 0x00, 0x15, 0xCE, 0xF1, 0x0F, 0x89, 0xA9, 0x9D, 0x47, // ............G + /* 0150 */ 0xAF, 0x46, 0xF2, 0x75, 0xC6, 0x37, 0x06, 0x63, 0x97, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Fu7.c.!...... + /* 0160 */ 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x05, 0x00, 0xFB, 0xB1, 0x49, 0x84, 0xEA, 0xF0, 0x7A, 0x49, // ........I.zI + /* 0170 */ 0x99, 0xAB, 0x66, 0xCA, 0x96, 0xE9, 0xA0, 0xF5, 0xA3, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .f..!...... + /* 0180 */ 0x00, 0x00, 0x06, 0x05, 0x00, 0x00, 0x00, 0x00, 0x59, 0x56, 0xB1, 0x11, 0x03, 0xE6, 0xF1, 0x4C, // ........YV..L + /* 0190 */ 0x9C, 0x1F, 0xF0, 0xEC, 0x01, 0xB8, 0x18, 0x88, 0xB7, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .....!...... + /* 01A0 */ 0x00, 0x00, 0x06, 0x19, 0x00, 0x00, 0x00, 0x00, 0x36, 0xD6, 0x7C, 0xD2, 0x62, 0x19, 0xE9, 0x44, // ........6|b.D + /* 01B0 */ 0x8B, 0x4F, 0x27, 0xB6, 0xC2, 0x3E, 0xFB, 0x85, 0xD0, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .O'>.!...... + /* 01C0 */ 0x00, 0x00, 0x06, 0x19, 0x00, 0x00, 0x00, 0x00, 0x23, 0xBF, 0xA0, 0x7B, 0xF5, 0xD0, 0x72, 0x40, // ........#.{r@ + /* 01D0 */ 0x91, 0xD9, 0xD5, 0x5A, 0xF5, 0xA4, 0x81, 0xB6, 0xEC, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .Z.!...... + /* 01E0 */ 0x00, 0x00, 0x06, 0x19, 0x00, 0x00, 0x04, 0x00, 0xC0, 0xE3, 0x9F, 0x96, 0xEC, 0xA3, 0x1A, 0x49, // ...........I + /* 01F0 */ 0x9F, 0x25, 0x42, 0x36, 0x05, 0xDE, 0xB3, 0x65, 0x08, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .%B6.޳e."...... + /* 0200 */ 0x00, 0x00, 0x06, 0x19, 0x00, 0x00, 0x00, 0x00, 0x58, 0x13, 0xC5, 0xE1, 0x3E, 0xFE, 0x03, 0x42, // ........X.>.B + /* 0210 */ 0xA4, 0xA2, 0x3B, 0x6B, 0x20, 0xC9, 0x73, 0x4E, 0x21, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ;k sN!"...... + /* 0220 */ 0x00, 0x00, 0x06, 0x19, 0x01, 0x00, 0x00, 0x00, 0x4F, 0x13, 0xE2, 0x58, 0x11, 0x8E, 0x17, 0x4D, // ........O.X...M + /* 0230 */ 0x9C, 0xB2, 0x91, 0x06, 0x9C, 0x15, 0x11, 0x48, 0x35, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ......H5"...... + /* 0240 */ 0x00, 0x00, 0x06, 0x19, 0x00, 0x00, 0x00, 0x00, 0x19, 0x52, 0xDE, 0x7F, 0xFA, 0xFB, 0x4A, 0x48, // .........R.JH + /* 0250 */ 0x82, 0xC9, 0x34, 0xD1, 0xAD, 0x53, 0xE8, 0x56, 0x4E, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .4ѭSVN"...... + /* 0260 */ 0x00, 0x00, 0x04, 0x19, 0x00, 0x00, 0x00, 0x00, 0x3B, 0x7B, 0xB9, 0xBB, 0xA4, 0x8C, 0x28, 0x4A, // ........;{.(J + /* 0270 */ 0x97, 0x17, 0x89, 0xFA, 0xBD, 0x42, 0xC4, 0xAC, 0x58, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ...BĬX"...... + /* 0280 */ 0x00, 0x00, 0x05, 0x19, 0x01, 0x00, 0x00, 0x00, 0x58, 0xB3, 0x40, 0x3C, 0x48, 0x59, 0xAF, 0x45, // ........X@C + /* 0430 */ 0xB9, 0x0A, 0x39, 0x89, 0x29, 0x23, 0xC6, 0x57, 0xEE, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .9.)#W#...... + /* 0440 */ 0x00, 0x00, 0x06, 0x05, 0x00, 0x01, 0x00, 0x00, 0xDC, 0x64, 0x2A, 0x21, 0xB1, 0x43, 0x3D, 0x4D, // ........d*!C=M + /* 0450 */ 0xA3, 0x0C, 0x2F, 0xC6, 0x9D, 0x20, 0x95, 0xC6, 0x05, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ./. ..$...... + /* 0460 */ 0x00, 0x00, 0x04, 0x19, 0x00, 0x00, 0x00, 0x00, 0x46, 0xF9, 0x5A, 0xE8, 0x25, 0x2E, 0xB7, 0x47, // ........FZ%.G + /* 0470 */ 0x83, 0xE1, 0xBE, 0xBC, 0xEB, 0xEA, 0xC6, 0x11, 0x13, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .ᾼ..$...... + /* 0480 */ 0x01, 0x00, 0x04, 0x05, 0x00, 0x00, 0x01, 0x00, 0xBF, 0xF1, 0xA6, 0xE6, 0x40, 0x9D, 0xC3, 0x40, // ........@.@ + /* 0490 */ 0xAA, 0x9F, 0xC7, 0x7B, 0xA2, 0x15, 0x78, 0xC0, 0x1F, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .{.x.$...... + /* 04A0 */ 0x02, 0x00, 0x05, 0x05, 0x00, 0x00, 0x02, 0x00, 0x68, 0x79, 0x4C, 0xAA, 0xDA, 0xB9, 0x80, 0x46, // ........hyLڹ.F + /* 04B0 */ 0x92, 0xB6, 0xAC, 0xB2, 0x5E, 0x2F, 0x86, 0x6C, 0x2B, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .^/.l+$...... + /* 04C0 */ 0x02, 0x00, 0x05, 0x05, 0x00, 0x01, 0x00, 0x00, 0x1B, 0xF6, 0xB5, 0x85, 0x0B, 0x32, 0xE3, 0x4B, // ...........2K + /* 04D0 */ 0x81, 0x4A, 0xB7, 0x6B, 0x2B, 0xFA, 0xFC, 0x82, 0x45, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .Jk+.E$...... + /* 04E0 */ 0x02, 0x00, 0x06, 0x05, 0x00, 0x00, 0x03, 0x00, 0xB1, 0x9E, 0x7D, 0x61, 0x36, 0xEF, 0x82, 0x4F, // .........}a6.O + /* 04F0 */ 0x86, 0xE0, 0xA6, 0x5A, 0xE0, 0x7B, 0x96, 0xC6, 0x51, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .Z{.Q$...... + /* 0500 */ 0x02, 0x00, 0x06, 0x05, 0x00, 0x00, 0x05, 0x00, 0x62, 0xEB, 0xE8, 0x8D, 0xE0, 0xBB, 0xAC, 0x40, // ........b.໬@ + /* 0510 */ 0xAC, 0x17, 0xF7, 0x55, 0x95, 0x07, 0x1E, 0xA3, 0x5D, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .U...]$...... + /* 0520 */ 0x00, 0x00, 0x06, 0x05, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xC1, 0x9C, 0xA9, 0x19, 0x77, 0x06, 0x43, // ..........w.C + /* 0530 */ 0x96, 0x45, 0x29, 0x41, 0x02, 0xFB, 0xFF, 0x95, 0x77, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .E)A..w$...... + /* 0540 */ 0x00, 0x00, 0x06, 0x05, 0x00, 0x00, 0x00, 0x00, 0x55, 0xAE, 0xE1, 0x34, 0xF8, 0x27, 0x50, 0x49, // ........U4'PI + /* 0550 */ 0x88, 0x77, 0x7A, 0x03, 0xBE, 0x5F, 0xB1, 0x81, 0x96, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .wz._..$...... + /* 0560 */ 0x00, 0x00, 0x06, 0x05, 0x00, 0x00, 0x00, 0x00, 0xBB, 0x3C, 0x4D, 0x03, 0x4B, 0x5D, 0x45, 0x42, // ........`no'...... + /* 0860 */ 0x00, 0x06, 0x06, 0x19, 0x00, 0x00, 0x00, 0x00, 0x8C, 0xB1, 0x00, 0x53, 0x33, 0x2E, 0xC2, 0x4D, // ..........S3.M + /* 0870 */ 0x82, 0x91, 0x47, 0xFF, 0xCE, 0xC7, 0x46, 0xDD, 0x91, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..GF.'...... + /* 0880 */ 0x00, 0x06, 0x06, 0x19, 0x00, 0x00, 0x00, 0x00, 0xBF, 0x5A, 0x0B, 0xA8, 0xAD, 0x76, 0x8B, 0x42, // ........Z.v.B + /* 0890 */ 0xB0, 0x5D, 0xA4, 0x7D, 0x2D, 0xFF, 0xEE, 0xBF, 0xB5, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ]}-'...... + /* 08A0 */ 0x00, 0x06, 0x06, 0x19, 0x00, 0x00, 0x00, 0x00, 0x01, 0x82, 0x80, 0xFF, 0xC6, 0xFE, 0xD4, 0x4F, // ...........O + /* 08B0 */ 0xAE, 0x16, 0xAB, 0xBD, 0xDA, 0xDE, 0x57, 0x06, 0xCF, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .W.'...... + /* 08C0 */ 0x00, 0x06, 0x06, 0x19, 0x00, 0x00, 0x00, 0x00, 0x05, 0xAB, 0xF2, 0x43, 0x87, 0x7C, 0x56, 0x4D, // .........C.|VM + /* 08D0 */ 0xB2, 0x7C, 0x44, 0xD0, 0xF9, 0xA3, 0xDA, 0xBD, 0xEF, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // |Dڽ'...... + /* 08E0 */ 0x00, 0x06, 0x06, 0x19, 0x00, 0x00, 0x00, 0x00, 0x65, 0x8E, 0x86, 0xEC, 0xDF, 0xFA, 0x59, 0x47, // ........e..YG + /* 08F0 */ 0xB2, 0x3E, 0x93, 0xFE, 0x37, 0xF2, 0xCC, 0x29, 0x0D, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // >.7).(...... + /* 0900 */ 0x00, 0x06, 0x06, 0x19, 0x00, 0x00, 0x00, 0x00, 0xEA, 0x50, 0xDB, 0xE4, 0xA1, 0xBD, 0x66, 0x45, // ........P䡽fE + /* 0910 */ 0xB0, 0x47, 0x0C, 0xA5, 0x0A, 0xBC, 0x6F, 0x07, 0x38, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // G..o.8(...... + /* 0920 */ 0x00, 0x06, 0x06, 0x19, 0x00, 0x00, 0x00, 0x00, 0x14, 0xF8, 0xF4, 0x0D, 0x57, 0x3F, 0x8B, 0x4B, // ..........W?.K + /* 0930 */ 0x9A, 0x9D, 0xFD, 0xDA, 0xDC, 0xD6, 0x9F, 0xAC, 0x51, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ...Q(...... + /* 0940 */ 0x00, 0x06, 0x06, 0x19, 0x00, 0x00, 0x00, 0x00, 0x09, 0xE5, 0x2E, 0xAE, 0x34, 0x1B, 0xC0, 0x41, // ..........4.A + /* 0950 */ 0xAC, 0xB7, 0x6D, 0x46, 0x50, 0x16, 0x89, 0x15, 0x65, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mFP...e(...... + /* 0960 */ 0x00, 0x07, 0x04, 0x19, 0x00, 0x00, 0x00, 0x00, 0x08, 0xED, 0xBB, 0x46, 0x7B, 0x9C, 0xFC, 0x48, // .........F{.H + /* 0970 */ 0xA6, 0x14, 0x95, 0x25, 0x05, 0x73, 0xF4, 0xEA, 0x7A, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..%.sz(...... + /* 0980 */ 0x00, 0x07, 0x04, 0x19, 0x00, 0x00, 0x00, 0x00, 0x05, 0xD6, 0xB6, 0x1C, 0xB3, 0x11, 0x14, 0x4E, // .........ֶ...N + /* 0990 */ 0xBB, 0x30, 0xDA, 0x91, 0xC8, 0xE3, 0x98, 0x3A, 0x91, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0..:.(...... + /* 09A0 */ 0x00, 0x07, 0x04, 0x19, 0x00, 0x00, 0x00, 0x00, 0x80, 0x99, 0x2E, 0xB9, 0xD5, 0xB9, 0x21, 0x48, // ...........չ!H + /* 09B0 */ 0x9C, 0x94, 0x14, 0x0F, 0x63, 0x2F, 0x63, 0x12, 0xA8, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ....c/c.(...... + /* 09C0 */ 0x00, 0x07, 0x04, 0x19, 0x00, 0x00, 0x00, 0x00, 0x29, 0x15, 0x04, 0x5A, 0xF8, 0xFE, 0x07, 0x4D, // ........)..Z.M + /* 09D0 */ 0xB0, 0x6F, 0xB5, 0x9B, 0x57, 0x3B, 0x32, 0xD2, 0xBF, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // o.W;2ҿ(...... + /* 09E0 */ 0x00, 0x07, 0x04, 0x19, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x9A, 0xA0, 0x54, 0x7B, 0xD5, 0x10, 0x4C, // ...........T{.L + /* 09F0 */ 0x8B, 0x69, 0xA8, 0x42, 0xD6, 0x59, 0x0A, 0xD5, 0xD8, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .iBY.(...... + /* 0A00 */ 0x00, 0x07, 0x04, 0x19, 0x00, 0x00, 0x00, 0x00, 0x96, 0x78, 0x53, 0xDB, 0x6F, 0x37, 0xAE, 0x48, // .........xSo7H + /* 0A10 */ 0xA4, 0x92, 0x53, 0xD0, 0x54, 0x77, 0x73, 0xD0, 0xF1, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .STws(...... + /* 0A20 */ 0x00, 0x07, 0x04, 0x19, 0x00, 0x00, 0x00, 0x00, 0x6A, 0x29, 0xA8, 0xE1, 0x37, 0xDB, 0xD1, 0x44, // ........j)7D + /* 0A30 */ 0x8C, 0xCE, 0x7B, 0xC9, 0x61, 0xD5, 0x9C, 0x54, 0x0D, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .{a.T.)...... + /* 0A40 */ 0x00, 0x07, 0x04, 0x19, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xD3, 0x6D, 0xAA, 0xB4, 0xC2, 0xE2, 0x40, // ........m@ + /* 0A50 */ 0xA5, 0x44, 0xA6, 0xBB, 0xB3, 0xF5, 0xC3, 0x95, 0x29, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // D.))...... + /* 0A60 */ 0x00, 0x07, 0x04, 0x19, 0x00, 0x00, 0x00, 0x00, 0xBF, 0xD6, 0x4E, 0xC0, 0xC8, 0x55, 0x47, 0x4B, // ........NUGK + /* 0A70 */ 0x9F, 0x8E, 0x5A, 0x1F, 0x31, 0xCE, 0xEE, 0x60, 0x3A, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..Z.1`:)...... + /* 0A80 */ 0x00, 0x08, 0x05, 0x19, 0x01, 0x00, 0x00, 0x00, 0xA2, 0x84, 0x55, 0x9D, 0x85, 0x2D, 0x9A, 0x41, // .........U..-.A + /* 0A90 */ 0x98, 0x2C, 0xA0, 0x08, 0x88, 0xBB, 0x9D, 0xDF, 0x49, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .,....I)...... + /* 0AA0 */ 0x00, 0x08, 0x05, 0x19, 0x01, 0x00, 0x00, 0x00, 0xA0, 0x90, 0x73, 0x19, 0xF6, 0x65, 0x95, 0x4A, // ..........s.e.J + /* 0AB0 */ 0xBD, 0xC4, 0x55, 0xD5, 0x8A, 0x3B, 0x02, 0x53, 0x69, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // U.;.Si)...... + /* 0AC0 */ 0x00, 0x08, 0x05, 0x19, 0x01, 0x00, 0x00, 0x00, 0xD4, 0xFC, 0x60, 0x88, 0x7B, 0xA7, 0x20, 0x4A, // ........`.{ J + /* 0AD0 */ 0x90, 0x45, 0xA1, 0x50, 0xFF, 0x11, 0xD6, 0x09, 0x7A, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .EP..z)...... + /* 0AE0 */ 0x00, 0x08, 0x05, 0x19, 0x01, 0x00, 0x00, 0x00, 0xA3, 0x18, 0x00, 0xA0, 0x0F, 0xF2, 0x32, 0x46, // ............2F + /* 0AF0 */ 0xBF, 0x7C, 0x8D, 0xAA, 0x53, 0x51, 0xC9, 0x14, 0x99, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // |.SQ..)...... + /* 0B00 */ 0x00, 0x08, 0x05, 0x19, 0x01, 0x00, 0x00, 0x00, 0xAF, 0x8B, 0x01, 0x10, 0x21, 0xCE, 0x60, 0x40, // ...........!`@ + /* 0B10 */ 0x80, 0xBD, 0x47, 0xFE, 0x74, 0xED, 0x4D, 0xAB, 0xB4, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .GtM)...... + /* 0B20 */ 0x00, 0x09, 0x05, 0x19, 0x00, 0x00, 0x00, 0x00, 0x48, 0x18, 0xDB, 0x18, 0xE0, 0x12, 0x67, 0x41, // ........H...gA + /* 0B30 */ 0xB9, 0xD7, 0xDA, 0x7F, 0xCD, 0xA5, 0x07, 0xDB, 0xDD, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .ͥ.)...... + /* 0B40 */ 0x00, 0x09, 0x05, 0x19, 0x00, 0x00, 0x00, 0x00, 0xEC, 0x1B, 0x8E, 0x45, 0x7A, 0x83, 0xF6, 0x45, // ..........Ez.E + /* 0B50 */ 0xB9, 0xD5, 0x92, 0x5E, 0xD5, 0xD2, 0x99, 0xDE, 0x04, 0x2A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .^..*...... + /* 0B60 */ 0x00, 0x09, 0x05, 0x19, 0x00, 0x00, 0x00, 0x00, 0xE7, 0x97, 0x49, 0xE1, 0x0A, 0x80, 0xF7, 0x4C, // .........I..L + /* 0B70 */ 0xAD, 0x10, 0xDE, 0x4B, 0x45, 0xB5, 0x78, 0xDB, 0x19, 0x2A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .KEx.*...... + /* 0B80 */ 0x00, 0x09, 0x05, 0x19, 0x00, 0x00, 0x00, 0x00, 0x6D, 0xCD, 0x8B, 0xA9, 0x43, 0x53, 0x03, 0x46, // ........m.CS.F + /* 0B90 */ 0x8A, 0xFE, 0x59, 0x08, 0xE4, 0x61, 0x11, 0x12, 0x30, 0x2A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .Y.a..0*...... + /* 0BA0 */ 0x00, 0x09, 0x05, 0x19, 0x00, 0x00, 0x00, 0x00, 0xC1, 0x45, 0xF2, 0xEB, 0xA8, 0x29, 0xAF, 0x4D, // ........E)M + /* 0BB0 */ 0x9C, 0xB1, 0x38, 0xDF, 0xC6, 0x08, 0xA8, 0xC8, 0x47, 0x2A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .8.G*...... + /* 0BC0 */ 0x00, 0x09, 0x05, 0x19, 0x00, 0x00, 0x00, 0x00, 0x38, 0x32, 0x1C, 0xFE, 0x2A, 0x43, 0xA1, 0x43, // ........82.*CC + /* 0BD0 */ 0x8E, 0x25, 0x97, 0xE7, 0xD1, 0xEF, 0x10, 0xF3, 0x60, 0x2A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .%..`*...... + /* 0BE0 */ 0x00, 0x0A, 0x06, 0x19, 0x01, 0x00, 0x00, 0x00, 0x6A, 0x45, 0xEE, 0xFF, 0x87, 0xCD, 0x90, 0x43, // ........jE..C + /* 0BF0 */ 0x8E, 0x07, 0x16, 0x14, 0x6C, 0x67, 0x2F, 0xD0, 0x71, 0x2A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ....lg/q*...... + /* 0C00 */ 0x00, 0x0A, 0x06, 0x19, 0x01, 0x00, 0x00, 0x00, 0x4F, 0xB7, 0x78, 0xDB, 0x1C, 0xEF, 0x92, 0x48, // ........Ox..H + /* 0C10 */ 0xAB, 0xFE, 0x1E, 0x66, 0xB8, 0x23, 0x1D, 0xF6, 0x86, 0x2A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .f#..*...... + /* 0C20 */ 0x00, 0x0A, 0x06, 0x19, 0x01, 0x00, 0x00, 0x00, 0x64, 0x8A, 0x55, 0x78, 0x19, 0xDC, 0xFE, 0x43, // ........d.Ux.C + /* 0C30 */ 0xA0, 0xD0, 0x80, 0x75, 0xB2, 0xA3, 0x70, 0xA3, 0xA8, 0x2A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..up*...... + /* 0C40 */ 0x00, 0x0A, 0x06, 0x19, 0x01, 0x00, 0x00, 0x00, 0x1D, 0x6A, 0x2C, 0xC7, 0x52, 0xF2, 0x7E, 0x4E, // .........j,R~N + /* 0C50 */ 0xBD, 0xD1, 0x3F, 0xCA, 0x34, 0x2A, 0xCB, 0x35, 0xBB, 0x2A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ?4*5*...... + /* 0C60 */ 0x00, 0x0A, 0x06, 0x19, 0x01, 0x00, 0x00, 0x00, 0xB5, 0x87, 0x8D, 0xE5, 0x26, 0x81, 0x80, 0x45, // ..........&..E + /* 0C70 */ 0x80, 0xFB, 0x86, 0x1B, 0x22, 0xF7, 0x92, 0x96, 0xDC, 0x2A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..."..*...... + /* 0C80 */ 0x00, 0x0A, 0x06, 0x19, 0x01, 0x00, 0x00, 0x00, 0xC7, 0x91, 0xB4, 0xCA, 0x18, 0xA9, 0x60, 0x4F, // ..........`O + /* 0C90 */ 0xB5, 0x02, 0xDA, 0xB7, 0x5E, 0x33, 0x4F, 0x40, 0xFD, 0x2A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .ڷ^3O@*...... + /* 0CA0 */ 0x00, 0x0A, 0x06, 0x19, 0x01, 0x00, 0x00, 0x00, 0x3D, 0xE6, 0x6C, 0x09, 0xAC, 0x4F, 0xA9, 0x48, // ........=l.OH + /* 0CB0 */ 0x82, 0xA9, 0x61, 0xAE, 0x9E, 0x80, 0x0E, 0x5F, 0x20, 0x2B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .a..._ +...... + /* 0CC0 */ 0x00, 0x0A, 0x06, 0x19, 0x01, 0x00, 0x00, 0x00, 0x32, 0x2B, 0x94, 0xE9, 0x55, 0x2E, 0x97, 0x41, // ........2+.U..A + /* 0CD0 */ 0xB0, 0xBD, 0x5F, 0xF5, 0x8C, 0xBA, 0x88, 0x60, 0x3D, 0x2B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // _..`=+...... + /* 0CE0 */ 0x00, 0x0B, 0x06, 0x19, 0x00, 0x00, 0x00, 0x00, 0x12, 0x82, 0x99, 0xBA, 0x0A, 0x46, 0xDB, 0x44, // ............FD + /* 0CF0 */ 0xBF, 0xB5, 0x71, 0xBF, 0x09, 0xD1, 0xC6, 0x8B, 0x58, 0x2B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // q..X+...... + /* 0D00 */ 0x00, 0x0B, 0x06, 0x19, 0x00, 0x00, 0x00, 0x00, 0xD6, 0xEC, 0xDD, 0xC6, 0x54, 0x23, 0x19, 0x4C, // ........T#.L + /* 0D10 */ 0x90, 0x9B, 0x30, 0x6A, 0x30, 0x58, 0x48, 0x4E, 0x84, 0x2B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..0j0XHN.+...... + /* 0D20 */ 0x00, 0x0B, 0x06, 0x19, 0x00, 0x00, 0x00, 0x00, 0xA3, 0xE3, 0xF5, 0xB8, 0x33, 0xED, 0x08, 0x46, // ........3.F + /* 0D30 */ 0x81, 0xE1, 0x37, 0xD6, 0xC9, 0xDC, 0xFD, 0x9C, 0xA1, 0x2B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .7.+...... + /* 0D40 */ 0x00, 0x0B, 0x06, 0x19, 0x00, 0x00, 0x00, 0x00, 0xAF, 0x1A, 0x67, 0x81, 0xD1, 0x79, 0xB1, 0x4E, // .........g.yN + /* 0D50 */ 0xB0, 0x04, 0x8C, 0xBB, 0xE1, 0x73, 0xAF, 0xEA, 0xCC, 0x2B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..s+...... + /* 0D60 */ 0x00, 0x0B, 0x06, 0x19, 0x00, 0x00, 0x00, 0x00, 0x5C, 0x70, 0x3E, 0x11, 0x49, 0xFA, 0xA4, 0x48, // ........\p>.IH + /* 0D70 */ 0xBE, 0xEA, 0x7D, 0xD8, 0x79, 0xB4, 0x6B, 0x14, 0xE3, 0x2B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // }yk.+...... + /* 0D80 */ 0x00, 0x0B, 0x06, 0x19, 0x00, 0x00, 0x00, 0x00, 0x81, 0x69, 0x6B, 0xC0, 0xFD, 0xD7, 0x35, 0x4A, // .........ik5J + /* 0D90 */ 0xB7, 0xB4, 0x05, 0x47, 0x42, 0xB7, 0xAF, 0x67, 0xFC, 0x2B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .GBg+...... + /* 0DA0 */ 0x00, 0x0B, 0x06, 0x19, 0x00, 0x00, 0x00, 0x00, 0x9F, 0xD7, 0x76, 0x74, 0x48, 0x8E, 0xB4, 0x49, // .........vtH.I + /* 0DB0 */ 0xAB, 0x63, 0x4D, 0x0B, 0x81, 0x3A, 0x16, 0xE4, 0x15, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // cM..:..,...... + /* 0DC0 */ 0x00, 0x0B, 0x06, 0x19, 0x00, 0x00, 0x00, 0x00, 0x54, 0x2D, 0xB8, 0x0A, 0xF4, 0x47, 0xCB, 0x4A, // ........T-.GJ + /* 0DD0 */ 0x81, 0x8C, 0xCC, 0x5B, 0xF0, 0xEC, 0xB6, 0x49, 0x30, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..[I0,...... + /* 0DE0 */ 0x00, 0x0B, 0x06, 0x19, 0x00, 0x00, 0x00, 0x00, 0x90, 0x85, 0xE8, 0xF7, 0xC7, 0xDF, 0x78, 0x4C, // ..........xL + /* 0DF0 */ 0xBC, 0xCB, 0x6F, 0x38, 0x65, 0xB9, 0x9D, 0x1A, 0x5B, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // o8e..[,...... + /* 0E00 */ 0x00, 0x0B, 0x06, 0x19, 0x00, 0x00, 0x00, 0x00, 0x9F, 0x2D, 0x4E, 0xCD, 0x59, 0x50, 0x50, 0x4A, // .........-NYPPJ + /* 0E10 */ 0xA9, 0x2D, 0x05, 0xD5, 0xBB, 0x12, 0x67, 0xC7, 0x84, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // -.ջ.g.,...... + /* 0E20 */ 0x00, 0x0B, 0x06, 0x19, 0x00, 0x00, 0x00, 0x00, 0xC7, 0x52, 0xE9, 0xCD, 0x96, 0x2F, 0x9D, 0x4D, // ........R./.M + /* 0E30 */ 0x8F, 0x2B, 0x2D, 0x34, 0x9F, 0x64, 0xFC, 0x51, 0xAD, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .+-4.dQ,...... + /* 0E40 */ 0x00, 0x0C, 0x05, 0x19, 0x00, 0x01, 0x00, 0x00, 0x6B, 0x3E, 0x38, 0xA4, 0xDA, 0xDA, 0x3D, 0x42, // ........k>8=B + /* 0E50 */ 0xA4, 0x3D, 0xF2, 0x56, 0x78, 0x42, 0x96, 0x76, 0xCB, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // =VxB.v,...... + /* 0E60 */ 0x00, 0x0C, 0x05, 0x19, 0x00, 0x01, 0x00, 0x00, 0x7B, 0xA0, 0x59, 0xCF, 0x2A, 0x1A, 0xE0, 0x4B, // ........{.Y*.K + /* 0E70 */ 0xBF, 0xE0, 0x42, 0x3B, 0x58, 0x23, 0xE6, 0x63, 0xEB, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // B;X#c,...... + /* 0E80 */ 0x00, 0x0C, 0x05, 0x19, 0x00, 0x01, 0x00, 0x00, 0x7F, 0x33, 0x9C, 0x2B, 0x1D, 0x7A, 0x71, 0x42, // .........3.+.zqB + /* 0E90 */ 0x90, 0xA3, 0xC6, 0x85, 0x5A, 0x2B, 0x8A, 0x1C, 0x0F, 0x2D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..Z+...-...... + /* 0EA0 */ 0x00, 0x0C, 0x05, 0x19, 0x00, 0x01, 0x00, 0x00, 0x72, 0xAD, 0x1E, 0x63, 0xAB, 0xA8, 0xF8, 0x4D, // ........r.cM + /* 0EB0 */ 0xBB, 0xDF, 0x37, 0x20, 0x29, 0x98, 0x9B, 0xDD, 0x23, 0x2D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 7 )..#-...... + /* 0EC0 */ 0x00, 0x0C, 0x05, 0x19, 0x00, 0x01, 0x00, 0x00, 0x7C, 0x9F, 0xFA, 0xDD, 0x9E, 0xF0, 0xB9, 0x40, // ........|..@ + /* 0ED0 */ 0x8C, 0x1A, 0xBE, 0x87, 0x7A, 0x9A, 0x7F, 0x4B, 0x3B, 0x2D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ...z..K;-...... + /* 0EE0 */ 0x00, 0x0D, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00, 0x56, 0x11, 0xFB, 0x7A, 0x1D, 0x2C, 0xFC, 0x40, // ........V.z.,@ + /* 0EF0 */ 0xB2, 0x60, 0xAA, 0xB7, 0x44, 0x2B, 0x62, 0xFE, 0x53, 0x2D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // `D+bS-...... + /* 0F00 */ 0x00, 0x0D, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00, 0xD4, 0x42, 0x25, 0xAD, 0x54, 0x91, 0x6D, 0x4C, // ........B%T.mL + /* 0F10 */ 0x8A, 0x44, 0x30, 0xF1, 0x1E, 0xE9, 0x69, 0x89, 0x77, 0x2D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .D0.i.w-...... + /* 0F20 */ 0x00, 0x0E, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00, 0xD0, 0xE3, 0x01, 0x24, 0x0A, 0xC5, 0x58, 0x4B, // .........$.XK + /* 0F30 */ 0x87, 0xB2, 0x7E, 0x79, 0x4B, 0x7D, 0x26, 0x07, 0x94, 0x2D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .~yK}&..-...... + /* 0F40 */ 0x00, 0x0E, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00, 0x90, 0x4D, 0xAF, 0xC1, 0xBC, 0xD1, 0xCA, 0x44, // .........MD + /* 0F50 */ 0x85, 0xD4, 0x00, 0x3B, 0xA3, 0x3D, 0xB3, 0xB9, 0xC1, 0x2D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..;=-...... + /* 0F60 */ 0x00, 0x0E, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x49, 0x98, 0x81, 0xD0, 0xAD, 0xB2, 0x47, // .........I..ЭG + /* 0F70 */ 0xB3, 0xBA, 0x31, 0x6B, 0x12, 0xD6, 0x47, 0xB4, 0xE0, 0x2D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 1k.G-...... + /* 0F80 */ 0x00, 0x0E, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00, 0x20, 0xE2, 0xB6, 0x68, 0x09, 0xCF, 0x6B, 0x46, // ........ h.kF + /* 0F90 */ 0x92, 0xD3, 0x45, 0xCD, 0x96, 0x4B, 0x95, 0x09, 0x0F, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .E.K.......... + /* 0FA0 */ 0x00, 0x0F, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00, 0x77, 0xEF, 0x09, 0xFD, 0x47, 0x56, 0xFF, 0x4E, // ........w.GVN + /* 0FB0 */ 0x80, 0x9C, 0xAF, 0x2B, 0x64, 0x65, 0x9A, 0x45, 0x2E, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..+de.E........ + /* 0FC0 */ 0x00, 0x0F, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00, 0x6B, 0x17, 0xEF, 0x01, 0x0D, 0x3E, 0x2A, 0x42, // ........k...>*B + /* 0FD0 */ 0xB4, 0xF8, 0x4E, 0xA8, 0x80, 0x03, 0x5E, 0x8F, 0x5D, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // N..^.]....... + /* 0FE0 */ 0x00, 0x0F, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00, 0x5C, 0x51, 0x72, 0xF7, 0x87, 0x0E, 0xD5, 0x48, // ........\Qr..H + /* 0FF0 */ 0xA6, 0x76, 0xE6, 0x96, 0x2C, 0x3E, 0x11, 0x95, 0x7D, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // v.,>..}....... + /* 1000 */ 0x00, 0x10, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00, 0xD9, 0x8B, 0x8B, 0xA7, 0x17, 0x80, 0xF5, 0x4D, // ............M + /* 1010 */ 0xB8, 0x6A, 0x09, 0xF7, 0x56, 0xAF, 0xFA, 0x7C, 0x9C, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // j.V|........ + /* 1020 */ 0x00, 0x10, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00, 0xF3, 0x8C, 0xA1, 0xCD, 0x96, 0xC1, 0xAD, 0x46, // ..........F + /* 1030 */ 0xB2, 0x89, 0x60, 0xC0, 0x72, 0x86, 0x99, 0x94, 0xB7, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .`r.......... + /* 1040 */ 0x00, 0x10, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00, 0xB9, 0x1F, 0x53, 0x68, 0x11, 0x55, 0x89, 0x49, // .........Sh.U.I + /* 1050 */ 0x97, 0xBE, 0xD1, 0x1A, 0x0F, 0x55, 0x63, 0x3F, 0xDA, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ...Uc?....... + /* 1060 */ 0x00, 0x11, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00, 0x3D, 0x2B, 0x0E, 0x62, 0xE7, 0x09, 0xFD, 0x42, // ........=+.b.B + /* 1070 */ 0x80, 0x2A, 0x17, 0xA1, 0x36, 0x52, 0xFE, 0x7A, 0xFA, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .*.6Rz....... + /* 1080 */ 0x00, 0x11, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00, 0x1B, 0xE6, 0x82, 0x74, 0x89, 0xC5, 0x7F, 0x4B, // ..........t..K + /* 1090 */ 0x8E, 0xCC, 0x46, 0xD4, 0x55, 0xAC, 0x3B, 0x87, 0x1C, 0x2F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .FU;../...... + /* 10A0 */ 0x00, 0x12, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x85, 0x26, 0x8A, 0x7E, 0x1C, 0xD3, 0x48, // ..........&.~.H + /* 10B0 */ 0xA6, 0x87, 0xFB, 0xCA, 0x9B, 0x9A, 0xC1, 0x6B, 0x3E, 0x2F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ...k>/...... + /* 10C0 */ 0x00, 0x12, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00, 0x60, 0x3D, 0x64, 0xD3, 0x42, 0x0C, 0x2D, 0x41, // ........`=dB.-A + /* 10D0 */ 0xA7, 0xD6, 0x52, 0xE6, 0x63, 0x53, 0x27, 0xF6, 0x6C, 0x2F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // RcS'l/...... + /* 10E0 */ 0x00, 0x13, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x83, 0x1C, 0xFD, 0x95, 0xF5, 0x7D, 0x4A, 0x49, // ...........}JI + /* 10F0 */ 0xBE, 0x8B, 0x13, 0x00, 0xE1, 0xC9, 0xD1, 0xCD, 0x8B, 0x2F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..../...... + /* 1100 */ 0x00, 0x13, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0xC7, 0x86, 0x54, 0x7D, 0x20, 0xE1, 0x71, 0x47, // .........T} qG + /* 1110 */ 0xB7, 0xF1, 0x7B, 0x56, 0xC6, 0xD3, 0x17, 0x0C, 0xB2, 0x2F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // {V../...... + /* 1120 */ 0x00, 0x13, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x41, 0xEC, 0xF5, 0xF0, 0x55, 0x0D, 0x32, 0x47, // ........AU.2G + /* 1130 */ 0xAF, 0x02, 0x44, 0x0A, 0x44, 0xA3, 0xCF, 0x0F, 0xDA, 0x2F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .D.D./...... + /* 1140 */ 0x00, 0x13, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0xBE, 0xA2, 0x43, 0xB7, 0xD4, 0x68, 0xD3, 0x4D, // ........ChM + /* 1150 */ 0xAF, 0x32, 0x92, 0x42, 0x5B, 0x7B, 0xB6, 0x23, 0xF7, 0x2F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 2.B[{#/...... + /* 1160 */ 0x00, 0x14, 0x06, 0x05, 0x00, 0x00, 0x00, 0x00, 0x44, 0x13, 0x09, 0x00, 0xA4, 0x1E, 0x37, 0x4F, // ........D....7O + /* 1170 */ 0xB7, 0x89, 0x01, 0x75, 0x0B, 0xA6, 0x98, 0x8C, 0x1C, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..u....0...... + /* 1180 */ 0x00, 0x14, 0x06, 0x05, 0x00, 0x00, 0x00, 0x00, 0xA4, 0x6B, 0xDB, 0x21, 0x7B, 0x9A, 0x14, 0x4A, // ........k!{..J + /* 1190 */ 0x9E, 0x29, 0x64, 0xA6, 0x0C, 0x59, 0x30, 0x1D, 0x3E, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .)d.Y0.>0...... + /* 11A0 */ 0x00, 0x14, 0x06, 0x05, 0x00, 0x00, 0x00, 0x00, 0x4E, 0x04, 0xCA, 0xB3, 0x58, 0xA3, 0x68, 0x4D, // ........N.ʳXhM + /* 11B0 */ 0x98, 0x83, 0xAA, 0xA2, 0x94, 0x1A, 0xCA, 0x99, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .....`0...... + /* 11C0 */ 0x00, 0x14, 0x06, 0x05, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x34, 0xBF, 0x3D, 0x6C, 0x5F, 0xA7, 0x4F, // .........4=l_O + /* 11D0 */ 0xB9, 0x36, 0x69, 0x9D, 0xCE, 0x9E, 0x26, 0x3F, 0x80, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 6i..&?.0...... + /* 11E0 */ 0x00, 0x15, 0x06, 0x05, 0x00, 0x00, 0x00, 0x00, 0xF4, 0x33, 0x44, 0x7B, 0xE7, 0xB1, 0x88, 0x47, // ........3D{.G + /* 11F0 */ 0x89, 0x5A, 0xC4, 0x53, 0x78, 0xD3, 0x82, 0x53, 0x9F, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .ZSx.S.0...... + /* 1200 */ 0x00, 0x15, 0x06, 0x05, 0x00, 0x00, 0x00, 0x00, 0x79, 0x67, 0xC5, 0x21, 0x49, 0xB4, 0x20, 0x4D, // ........yg!I M + /* 1210 */ 0xAD, 0xFC, 0xEE, 0xCE, 0x0E, 0x1A, 0xD7, 0x4B, 0xC1, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..K0...... + /* 1220 */ 0x00, 0x15, 0x06, 0x05, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x1B, 0x5A, 0x2B, 0xAB, 0xA5, 0x54, 0x4C, // ..........Z+TL + /* 1230 */ 0xAC, 0x2F, 0xA6, 0xD9, 0x48, 0x24, 0xA2, 0x83, 0xE0, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // /H$.0...... + /* 1240 */ 0x00, 0x15, 0x06, 0x05, 0x00, 0x00, 0x00, 0x00, 0x10, 0x54, 0x1C, 0x8C, 0x39, 0x9F, 0x05, 0x48, // .........T..9..H + /* 1250 */ 0x8C, 0x9D, 0x63, 0xA0, 0x77, 0x06, 0x35, 0x8F, 0xFF, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..c.w.5.0...... + /* 1260 */ 0x00, 0x15, 0x06, 0x05, 0x00, 0x00, 0x00, 0x00, 0x6E, 0xAF, 0xD9, 0x43, 0x86, 0x5E, 0xE8, 0x4B, // ........nC.^K + /* 1270 */ 0xA7, 0x97, 0xD0, 0x72, 0xA0, 0x46, 0x89, 0x6C, 0x1C, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .r.F.l.1...... + /* 1280 */ 0x00, 0x15, 0x06, 0x05, 0x00, 0x00, 0x00, 0x00, 0xE7, 0x08, 0x9C, 0xE4, 0x82, 0xDA, 0xF8, 0x42, // ...........B + /* 1290 */ 0xBD, 0xE2, 0xB5, 0x70, 0xFB, 0xCA, 0xE7, 0x6C, 0x36, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // pl61...... + /* 12A0 */ 0x00, 0x15, 0x06, 0x05, 0x00, 0x00, 0x00, 0x00, 0x22, 0xEF, 0xC5, 0x61, 0x4F, 0xF1, 0x53, 0x45, // ........"aOSE + /* 12B0 */ 0xA8, 0x24, 0xC4, 0xB3, 0x1E, 0x84, 0xB1, 0x00, 0x6B, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // $ij...k1...... + /* 12C0 */ 0x00, 0x15, 0x06, 0x05, 0x00, 0x00, 0x00, 0x00, 0x44, 0x7C, 0x94, 0xBA, 0x9D, 0xD1, 0x86, 0x47, // ........D|...G + /* 12D0 */ 0xB6, 0xAE, 0x22, 0x77, 0x0B, 0xC9, 0x4C, 0x54, 0x9E, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // "w.LT.1...... + /* 12E0 */ 0x00, 0x16, 0x06, 0x05, 0x00, 0x01, 0x00, 0x00, 0x06, 0x16, 0x3D, 0x4F, 0xEA, 0x3F, 0x01, 0x4C, // ..........=O?.L + /* 12F0 */ 0xBE, 0x3C, 0x8D, 0x67, 0x1C, 0x40, 0x1E, 0x3B, 0xC5, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // <.g.@.;1...... + /* 1300 */ 0x00, 0x17, 0x04, 0x19, 0x00, 0x00, 0x00, 0x00, 0xC2, 0x2D, 0x68, 0x2C, 0x68, 0x8B, 0x63, 0x4F, // ........-h,h.cO + /* 1310 */ 0xA1, 0x65, 0xAE, 0x29, 0x1D, 0x4C, 0xF1, 0x38, 0xDC, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // e).L81...... + /* 1320 */ 0x00, 0x17, 0x04, 0x19, 0x00, 0x00, 0x00, 0x00, 0x08, 0xFF, 0xD8, 0xCF, 0xD7, 0xC0, 0x2B, 0x45, // .........+E + /* 1330 */ 0x9F, 0x60, 0xEF, 0x5C, 0x70, 0xC3, 0x20, 0x94, 0xF5, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .`\p .1...... + /* 1340 */ 0x00, 0x17, 0x04, 0x19, 0x00, 0x00, 0x00, 0x00, 0x50, 0x49, 0xF5, 0xD4, 0xF2, 0x26, 0xB4, 0x4F, // ........PI&O + /* 1350 */ 0xBA, 0x21, 0xFF, 0xAB, 0x16, 0xAF, 0xCA, 0xDE, 0x0E, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // !..2...... + /* 1360 */ 0x00, 0x17, 0x04, 0x19, 0x00, 0x00, 0x00, 0x00, 0x72, 0xE8, 0xE7, 0x8C, 0x8C, 0x18, 0x98, 0x4B, // ........r....K + /* 1370 */ 0x9D, 0x90, 0xF8, 0xF9, 0x0B, 0x7A, 0xAD, 0x02, 0x29, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ...z.)2...... + /* 1380 */ 0x01, 0x18, 0x04, 0x05, 0x00, 0x00, 0x01, 0x00, 0x70, 0xD4, 0xE5, 0xCE, 0x3B, 0x6E, 0xCC, 0x4F, // ........p;nO + /* 1390 */ 0x8C, 0x2B, 0xD1, 0x74, 0x28, 0x56, 0x8A, 0x9F, 0x3C, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .+t(V..<2...... + /* 13A0 */ 0x01, 0x18, 0x04, 0x05, 0x00, 0x00, 0x01, 0x00, 0xB8, 0xD0, 0x47, 0x89, 0x3B, 0xC3, 0xE1, 0x43, // ........G.;C + /* 13B0 */ 0x8C, 0x56, 0x9B, 0x67, 0x4C, 0x05, 0x28, 0x32, 0x4E, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .V.gL.(2N2...... + /* 13C0 */ 0x01, 0x18, 0x04, 0x05, 0x00, 0x00, 0x01, 0x00, 0x39, 0x66, 0x6B, 0xCA, 0xD6, 0x4A, 0xAE, 0x40, // ........9fkJ@ + /* 13D0 */ 0xA5, 0x75, 0x14, 0xDE, 0xE0, 0x7F, 0x64, 0x30, 0x61, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // u..d0a2...... + /* 13E0 */ 0x01, 0x18, 0x04, 0x05, 0x00, 0x00, 0x01, 0x00, 0x40, 0x96, 0xED, 0x09, 0x20, 0xF0, 0x0A, 0x40, // ........@.. .@ + /* 13F0 */ 0xAC, 0xD8, 0xD7, 0xD8, 0x67, 0xDF, 0xD9, 0xC2, 0x76, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // gv2...... + /* 1400 */ 0x01, 0x18, 0x04, 0x05, 0x00, 0x00, 0x01, 0x00, 0x49, 0x4E, 0x3D, 0xEF, 0x3D, 0xA5, 0x81, 0x4D, // ........IN==.M + /* 1410 */ 0xA2, 0xB1, 0x2C, 0xA6, 0xC2, 0x55, 0x6B, 0x2C, 0x8A, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ,Uk,.2...... + /* 1420 */ 0x01, 0x18, 0x04, 0x05, 0x00, 0x00, 0x01, 0x00, 0x5C, 0x6F, 0x58, 0xAB, 0x56, 0x52, 0x32, 0x46, // ........\oXVR2F + /* 1430 */ 0x96, 0x2F, 0xFE, 0xFD, 0x8B, 0x49, 0xE6, 0xF4, 0x9E, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ./.I.2...... + /* 1440 */ 0x01, 0x18, 0x04, 0x05, 0x00, 0x00, 0x01, 0x00, 0x92, 0xC1, 0xB7, 0xEC, 0xAB, 0x73, 0xED, 0x4D, // .........sM + /* 1450 */ 0xAC, 0xF4, 0x23, 0x99, 0xB0, 0x95, 0xD0, 0xCC, 0xB2, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // #..̲2...... + /* 1460 */ 0x01, 0x18, 0x04, 0x05, 0x00, 0x00, 0x01, 0x00, 0x1D, 0x3B, 0x59, 0x45, 0xB1, 0xDF, 0x91, 0x4E, // .........;YE.N + /* 1470 */ 0xBB, 0xFB, 0x2D, 0x5D, 0x0C, 0xE2, 0x22, 0x7A, 0xC6, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // -]."z2...... + /* 1480 */ 0x01, 0x18, 0x04, 0x05, 0x00, 0x00, 0x01, 0x00, 0x60, 0x77, 0x32, 0x6F, 0x5C, 0x8C, 0x7C, 0x41, // ........`w2o\.|A + /* 1490 */ 0x9B, 0x61, 0x83, 0x6A, 0x98, 0x28, 0x7E, 0x0C, 0xDD, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .a.j.(~.2...... + /* 14A0 */ 0x01, 0x18, 0x04, 0x05, 0x00, 0x00, 0x01, 0x00, 0xF7, 0x3F, 0x13, 0xDF, 0x14, 0xBF, 0x95, 0x4F, // ........?...O + /* 14B0 */ 0xAF, 0xE3, 0x7B, 0x48, 0xE7, 0xE3, 0x31, 0xEF, 0xFB, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // {H12...... + /* 14C0 */ 0x01, 0x18, 0x04, 0x05, 0x00, 0x00, 0x01, 0x00, 0x61, 0xBF, 0xC7, 0x5D, 0xC9, 0x5E, 0x96, 0x49, // ........a]^.I + /* 14D0 */ 0x9C, 0xCB, 0xDF, 0x80, 0x6A, 0x2D, 0x0E, 0xFE, 0x13, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..j-..3...... + /* 14E0 */ 0x01, 0x18, 0x04, 0x05, 0x00, 0x00, 0x01, 0x00, 0x75, 0x4F, 0x0C, 0xB5, 0x9B, 0x59, 0xE8, 0x43, // ........uO..YC + /* 14F0 */ 0x8D, 0xCD, 0x10, 0x81, 0xA7, 0x96, 0x72, 0x41, 0x30, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ....rA03...... + /* 1500 */ 0x01, 0x18, 0x04, 0x05, 0x00, 0x00, 0x01, 0x00, 0x87, 0x9E, 0x50, 0xEA, 0xA1, 0x07, 0x45, 0x4A, // ..........P.EJ + /* 1510 */ 0x9E, 0xDC, 0xEB, 0xA5, 0xA3, 0x9F, 0x36, 0xAF, 0x46, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .륣.6F3...... + /* 1520 */ 0x01, 0x18, 0x04, 0x05, 0x00, 0x00, 0x01, 0x00, 0x78, 0xA6, 0xA2, 0x9D, 0x6B, 0xFB, 0x67, 0x4E, // ........x.kgN + /* 1530 */ 0xAB, 0x84, 0x60, 0xDD, 0x6A, 0x9C, 0x81, 0x9A, 0x68, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .`j...h3...... + /* 1540 */ 0x01, 0x18, 0x04, 0x05, 0x00, 0x00, 0x01, 0x00, 0x05, 0x61, 0x23, 0x92, 0x67, 0xBB, 0x4F, 0x49, // .........a#.gOI + /* 1550 */ 0x94, 0xC7, 0x7F, 0x7A, 0x60, 0x79, 0x29, 0xBD, 0x7D, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..z`y)}3...... + /* 1560 */ 0x01, 0x18, 0x04, 0x05, 0x00, 0x00, 0x01, 0x00, 0x9C, 0x38, 0x58, 0xE5, 0xC3, 0x83, 0x29, 0x4B, // .........8X.)K + /* 1570 */ 0xAD, 0xFE, 0x5E, 0x4D, 0x7F, 0x46, 0xC3, 0x58, 0x97, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ^M.FX.3...... + /* 1580 */ 0x01, 0x18, 0x04, 0x05, 0x00, 0x00, 0x01, 0x00, 0xFF, 0x33, 0xD8, 0x9E, 0x92, 0x4F, 0x36, 0x4F, // ........3..O6O + /* 1590 */ 0xB3, 0x70, 0x86, 0x83, 0xA4, 0xF1, 0x32, 0x75, 0xAD, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // p..2u3...... + /* 15A0 */ 0x01, 0x18, 0x04, 0x05, 0x00, 0x00, 0x01, 0x00, 0xE7, 0x82, 0x08, 0x2D, 0xE7, 0xA4, 0x3B, 0x42, // ..........-;B + /* 15B0 */ 0x8C, 0xCC, 0x70, 0xD9, 0x1E, 0x01, 0x58, 0xB1, 0xC8, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .p..X3...... + /* 15C0 */ 0x01, 0x18, 0x04, 0x05, 0x00, 0x00, 0x01, 0x00, 0x2C, 0x62, 0xE7, 0x6E, 0xD8, 0x18, 0x05, 0x40, // ........,bn..@ + /* 15D0 */ 0x9F, 0xB7, 0x92, 0xDB, 0x64, 0x4A, 0x27, 0x9B, 0xD9, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..dJ'.3...... + /* 15E0 */ 0x02, 0x19, 0x05, 0x05, 0x00, 0x00, 0x02, 0x00, 0x52, 0x1D, 0x46, 0xF7, 0x2B, 0x7C, 0xB2, 0x43, // ........R.F+|C + /* 15F0 */ 0x87, 0x44, 0xEA, 0x95, 0x8E, 0x0B, 0xD0, 0x9A, 0xEC, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .D....3...... + /* 1600 */ 0x02, 0x19, 0x05, 0x05, 0x00, 0x00, 0x02, 0x00, 0x40, 0x80, 0x0B, 0xA3, 0x8A, 0xD6, 0x3F, 0x42, // ........@...?B + /* 1610 */ 0xB0, 0xB5, 0x9C, 0xE2, 0x92, 0xEA, 0x5A, 0x8F, 0xFE, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..Z.3...... + /* 1620 */ 0x02, 0x19, 0x05, 0x05, 0x00, 0x00, 0x02, 0x00, 0xE3, 0x11, 0x9F, 0x1B, 0x5C, 0xC8, 0x1B, 0x4E, // ...........\.N + /* 1630 */ 0xBB, 0x29, 0x87, 0x9A, 0xD2, 0xC9, 0x09, 0xE3, 0x13, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // )....4...... + /* 1640 */ 0x02, 0x19, 0x05, 0x05, 0x00, 0x00, 0x02, 0x00, 0x6B, 0x1C, 0x98, 0xDC, 0x8E, 0xFC, 0x0F, 0x42, // ........k....B + /* 1650 */ 0xAA, 0x43, 0xF8, 0xF3, 0x3E, 0x5C, 0x09, 0x23, 0x24, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // C>\.#$4...... + /* 1660 */ 0x02, 0x19, 0x05, 0x05, 0x00, 0x00, 0x02, 0x00, 0xE6, 0xF3, 0xE1, 0xEF, 0xA2, 0xAE, 0x44, 0x41, // ........DA + /* 1670 */ 0xA2, 0x08, 0x32, 0xAA, 0x87, 0x2B, 0x65, 0x45, 0x36, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .2.+eE64...... + /* 1680 */ 0x02, 0x19, 0x05, 0x05, 0x00, 0x00, 0x02, 0x00, 0xFA, 0x3A, 0x1C, 0x77, 0xC5, 0x50, 0x3F, 0x44, // ........:.wP?D + /* 1690 */ 0xB1, 0x51, 0xFF, 0x25, 0x46, 0xD8, 0x63, 0xA0, 0x4A, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Q%Fc.J4...... + /* 16A0 */ 0x02, 0x19, 0x05, 0x05, 0x00, 0x00, 0x02, 0x00, 0x49, 0x26, 0x76, 0x8C, 0xD1, 0x97, 0x53, 0x49, // ........I&v..SI + /* 16B0 */ 0xAD, 0x27, 0xB7, 0xE2, 0xC2, 0x5B, 0x97, 0x2E, 0x5E, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // '[..^4...... + /* 16C0 */ 0x02, 0x19, 0x05, 0x05, 0x00, 0x00, 0x02, 0x00, 0x9C, 0xDA, 0x22, 0xB3, 0xE2, 0xA2, 0x58, 0x40, // ........."X@ + /* 16D0 */ 0x9E, 0x4E, 0xF5, 0x9A, 0x69, 0x70, 0xBD, 0x69, 0x75, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .N.ipiu4...... + /* 16E0 */ 0x02, 0x19, 0x05, 0x05, 0x00, 0x00, 0x02, 0x00, 0x4A, 0x12, 0x5D, 0x4A, 0x20, 0xE6, 0xBA, 0x44, // ........J.]J D + /* 16F0 */ 0xB6, 0xFF, 0x65, 0x89, 0x61, 0xB3, 0x3B, 0x9A, 0x93, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // e.a;..4...... + /* 1700 */ 0x02, 0x19, 0x05, 0x05, 0x00, 0x00, 0x02, 0x00, 0xD1, 0x28, 0x7A, 0x42, 0x7C, 0xD1, 0xBF, 0x4A, // ........(zB|ѿJ + /* 1710 */ 0xB7, 0x17, 0x32, 0xC7, 0x80, 0xBA, 0x6F, 0x07, 0xAB, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .2.o.4...... + /* 1720 */ 0x02, 0x19, 0x05, 0x05, 0x00, 0x00, 0x02, 0x00, 0xF1, 0x9F, 0xC7, 0x00, 0x50, 0x68, 0x3D, 0x44, // ..........Ph=D + /* 1730 */ 0xBF, 0x61, 0x71, 0xCD, 0xE0, 0xDE, 0x30, 0x5F, 0xC8, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // aq0_4...... + /* 1740 */ 0x02, 0x19, 0x05, 0x05, 0x00, 0x00, 0x02, 0x00, 0x38, 0xFB, 0x3A, 0xB1, 0x79, 0xCD, 0xE5, 0x4A, // ........8:yJ + /* 1750 */ 0x9F, 0x7F, 0xEE, 0xD0, 0x58, 0xD7, 0x50, 0xCA, 0xDE, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..XP4...... + /* 1760 */ 0x02, 0x19, 0x05, 0x05, 0x00, 0x00, 0x02, 0x00, 0x0E, 0xC1, 0x3A, 0xE1, 0xD0, 0x75, 0xFF, 0x4A, // .........:uJ + /* 1770 */ 0xA0, 0xCD, 0x76, 0x49, 0x82, 0xCF, 0x54, 0x1C, 0xF3, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .vI.T.4...... + /* 1780 */ 0x02, 0x19, 0x05, 0x05, 0x00, 0x00, 0x02, 0x00, 0xF0, 0xFA, 0x4E, 0xAC, 0x1F, 0xF8, 0x61, 0x4F, // ........N.aO + /* 1790 */ 0xBD, 0xF7, 0xEA, 0x32, 0xB0, 0x2A, 0xB1, 0x17, 0x09, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 2*..5...... + /* 17A0 */ 0x02, 0x19, 0x05, 0x05, 0x00, 0x00, 0x02, 0x00, 0xC6, 0xB1, 0xF5, 0xD9, 0x86, 0x53, 0x5A, 0x49, // ........Ʊ.SZI + /* 17B0 */ 0x88, 0xF9, 0x9A, 0xD6, 0xB4, 0x1A, 0xC9, 0xB3, 0x24, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..ִ.ɳ$5...... + /* 17C0 */ 0x02, 0x19, 0x05, 0x05, 0x00, 0x00, 0x02, 0x00, 0xE2, 0x38, 0xB5, 0x44, 0x34, 0xFB, 0x32, 0x47, // ........8D42G + /* 17D0 */ 0x81, 0xE4, 0x64, 0x4C, 0x17, 0xD2, 0xE7, 0x46, 0x35, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .dL.F55...... + /* 17E0 */ 0x02, 0x1A, 0x05, 0x05, 0x00, 0x01, 0x00, 0x00, 0xA0, 0xBF, 0x73, 0x93, 0xB3, 0x97, 0x87, 0x45, // .........s...E + /* 17F0 */ 0xAB, 0x73, 0x30, 0x93, 0x44, 0x61, 0xD5, 0x5C, 0x56, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // s0.Da\V5...... + /* 1800 */ 0x02, 0x1A, 0x05, 0x05, 0x00, 0x01, 0x00, 0x00, 0xB4, 0x6E, 0x28, 0xAA, 0x6F, 0x55, 0xEB, 0x4E, // ........n(oUN + /* 1810 */ 0x96, 0x7C, 0xC1, 0xB7, 0x71, 0xB7, 0x67, 0x3E, 0x76, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .|qg>v5...... + /* 1820 */ 0x02, 0x1A, 0x05, 0x05, 0x00, 0x01, 0x00, 0x00, 0x56, 0x82, 0xCC, 0x7C, 0xAA, 0xFB, 0xC6, 0x49, // ........V.|I + /* 1830 */ 0xB2, 0xA9, 0xF5, 0xAF, 0xB4, 0x25, 0x7C, 0xD2, 0x97, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // %|.5...... + /* 1840 */ 0x02, 0x1A, 0x05, 0x05, 0x00, 0x01, 0x00, 0x00, 0x17, 0xFE, 0x3D, 0xC5, 0x00, 0xCC, 0x67, 0x49, // .........=.gI + /* 1850 */ 0xB1, 0x88, 0xA0, 0x88, 0xA9, 0x65, 0x49, 0x4D, 0xBA, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ...eIM5...... + /* 1860 */ 0x02, 0x1A, 0x05, 0x05, 0x00, 0x01, 0x00, 0x00, 0x7D, 0xA8, 0x16, 0x28, 0xED, 0xE1, 0x97, 0x40, // ........}.(.@ + /* 1870 */ 0xB3, 0x11, 0xE2, 0x34, 0x1C, 0x57, 0xB1, 0x79, 0xD9, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .4.Wy5...... + /* 1880 */ 0x02, 0x1A, 0x05, 0x05, 0x00, 0x01, 0x00, 0x00, 0x08, 0xF9, 0xC0, 0x67, 0x4F, 0x18, 0x64, 0x4F, // .........gO.dO + /* 1890 */ 0x82, 0x50, 0x12, 0xDB, 0x79, 0x7A, 0xB3, 0xC3, 0xF9, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .P.yz5...... + /* 18A0 */ 0x02, 0x1A, 0x05, 0x05, 0x00, 0x01, 0x00, 0x00, 0x7A, 0x4E, 0xCE, 0x7B, 0x80, 0xDD, 0x82, 0x46, // ........zN{..F + /* 18B0 */ 0x98, 0xFA, 0xF9, 0x93, 0x72, 0x58, 0x03, 0xD2, 0x1B, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..rX..6...... + /* 18C0 */ 0x02, 0x1A, 0x05, 0x05, 0x00, 0x01, 0x00, 0x00, 0x0A, 0x0C, 0xC1, 0x1E, 0xF6, 0x54, 0x3E, 0x45, // ...........T>E + /* 18D0 */ 0xB8, 0x5A, 0x6F, 0xA1, 0xBB, 0xFE, 0xA9, 0xB7, 0x3D, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Zo=6...... + /* 18E0 */ 0x02, 0x1A, 0x05, 0x05, 0x00, 0x01, 0x00, 0x00, 0xBF, 0xB5, 0xD2, 0x87, 0x7B, 0xD4, 0xFB, 0x41, // .........{A + /* 18F0 */ 0xAF, 0x62, 0x71, 0xC3, 0x82, 0xF5, 0xCC, 0x85, 0x62, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // bq..b6...... + /* 1900 */ 0x02, 0x1A, 0x05, 0x05, 0x00, 0x01, 0x00, 0x00, 0xA9, 0x50, 0xFE, 0x3C, 0x03, 0x0E, 0x29, 0x4B, // ........P<..)K + /* 1910 */ 0x97, 0x54, 0x9F, 0x19, 0x3F, 0x07, 0xB7, 0x1F, 0x8E, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .T..?...6...... + /* 1920 */ 0x02, 0x1A, 0x05, 0x05, 0x00, 0x01, 0x00, 0x00, 0x57, 0x9E, 0xE4, 0x39, 0x68, 0xAE, 0xE3, 0x4E, // ........W.9hN + /* 1930 */ 0xB0, 0x98, 0x26, 0x48, 0x0D, 0xF3, 0xDA, 0x96, 0xB4, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .&H..6...... + /* 1940 */ 0x02, 0x1A, 0x05, 0x05, 0x00, 0x01, 0x00, 0x00, 0x17, 0x21, 0xAA, 0x15, 0x79, 0x8F, 0xA8, 0x49, // .........!.y.I + /* 1950 */ 0x83, 0x17, 0x75, 0x30, 0x26, 0xD6, 0xA0, 0x54, 0xDF, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..u0&.T6...... + /* 1960 */ 0x02, 0x1A, 0x05, 0x05, 0x00, 0x01, 0x00, 0x00, 0x0E, 0xD6, 0xBF, 0xCF, 0x5F, 0x0B, 0x7D, 0x42, // .........ֿ_.}B + /* 1970 */ 0x91, 0x7C, 0xA4, 0xDF, 0x42, 0xA8, 0x0E, 0x44, 0x03, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .|B.D.7...... + /* 1980 */ 0x02, 0x1A, 0x05, 0x05, 0x00, 0x01, 0x00, 0x00, 0x81, 0xCC, 0x12, 0x70, 0x87, 0x88, 0xE9, 0x42, // ..........p..B + /* 1990 */ 0xB1, 0x7D, 0x4E, 0x5E, 0x42, 0x76, 0x0F, 0x0D, 0x27, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // }N^Bv..'7...... + /* 19A0 */ 0x02, 0x1A, 0x05, 0x05, 0x00, 0x01, 0x00, 0x00, 0xB6, 0x7E, 0x9C, 0xDE, 0x85, 0x5A, 0x0D, 0x42, // ........~..Z.B + /* 19B0 */ 0x97, 0x03, 0xFF, 0xF1, 0x1B, 0xDD, 0x4D, 0x43, 0x50, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ...MCP7...... + /* 19C0 */ 0x02, 0x1A, 0x05, 0x05, 0x00, 0x01, 0x00, 0x00, 0x0C, 0xFC, 0xC0, 0x67, 0xBA, 0xDE, 0x1B, 0x40, // .........g.@ + /* 19D0 */ 0xBF, 0x8B, 0x9C, 0x8A, 0xD8, 0x39, 0x58, 0x04, 0x6F, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ...9X.o7...... + /* 19E0 */ 0x02, 0x1B, 0x06, 0x05, 0x00, 0x00, 0x03, 0x00, 0x36, 0x5D, 0xE6, 0xC3, 0x1F, 0x14, 0x2F, 0x4D, // ........6]../M + /* 19F0 */ 0xA3, 0x03, 0xA8, 0x42, 0xEE, 0x75, 0x6A, 0x29, 0x82, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .Buj).7...... + /* 1A00 */ 0x02, 0x1B, 0x06, 0x05, 0x00, 0x00, 0x03, 0x00, 0xCB, 0xBC, 0xAA, 0x9C, 0xB1, 0x61, 0x4B, 0x4B, // ........˼.aKK + /* 1A10 */ 0x8B, 0xEC, 0xD1, 0x0A, 0x3C, 0x3A, 0xC2, 0xCE, 0x94, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..<:.7...... + /* 1A20 */ 0x02, 0x1B, 0x06, 0x05, 0x00, 0x00, 0x03, 0x00, 0x6E, 0xEA, 0x14, 0xE9, 0xFA, 0xA5, 0x39, 0x44, // ........n.9D + /* 1A30 */ 0xA3, 0x94, 0xA9, 0xBB, 0x32, 0x93, 0xCA, 0x09, 0xA6, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .2..7...... + /* 1A40 */ 0x02, 0x1B, 0x06, 0x05, 0x00, 0x00, 0x03, 0x00, 0x59, 0xCE, 0xCA, 0xD8, 0xD2, 0x33, 0xC7, 0x4A, // ........Y3J + /* 1A50 */ 0x9B, 0x1B, 0x9B, 0x72, 0x33, 0x9C, 0x51, 0xC8, 0xBA, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ...r3.QȺ7...... + /* 1A60 */ 0x02, 0x1B, 0x06, 0x05, 0x00, 0x00, 0x03, 0x00, 0x65, 0x92, 0x9D, 0xEC, 0x1E, 0x9D, 0xD0, 0x4E, // ........e....N + /* 1A70 */ 0x83, 0x8A, 0xCD, 0xC2, 0x0F, 0x25, 0x51, 0xA1, 0xCE, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ...%Q7...... + /* 1A80 */ 0x02, 0x1B, 0x06, 0x05, 0x00, 0x00, 0x03, 0x00, 0xBA, 0x1B, 0x0B, 0xD7, 0x93, 0xB8, 0x44, 0x45, // ...........DE + /* 1A90 */ 0x96, 0xE2, 0xB7, 0xA3, 0x18, 0x09, 0x1C, 0x33, 0xE2, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .ⷣ...37...... + /* 1AA0 */ 0x02, 0x1B, 0x06, 0x05, 0x00, 0x00, 0x03, 0x00, 0x6F, 0x59, 0x50, 0xD4, 0x4D, 0x89, 0xE0, 0x49, // ........oYPM.I + /* 1AB0 */ 0x96, 0x6A, 0xFD, 0x39, 0xED, 0x4C, 0x4C, 0x64, 0xF9, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .j9LLd7...... + /* 1AC0 */ 0x02, 0x1B, 0x06, 0x05, 0x00, 0x00, 0x03, 0x00, 0x97, 0x41, 0x41, 0x4F, 0xC2, 0x0F, 0x01, 0x4C, // .........AAO..L + /* 1AD0 */ 0xB6, 0x8A, 0x86, 0xCB, 0xB9, 0xAC, 0x25, 0x4C, 0x17, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..˹%L.8...... + /* 1AE0 */ 0x02, 0x1B, 0x06, 0x05, 0x00, 0x00, 0x03, 0x00, 0x10, 0x81, 0x9B, 0x82, 0x6F, 0x0E, 0x49, 0x43, // ............o.IC + /* 1AF0 */ 0xBC, 0xA4, 0x42, 0x80, 0x35, 0x77, 0x78, 0x8D, 0x2F, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // B.5wx./8...... + /* 1B00 */ 0x02, 0x1B, 0x06, 0x05, 0x00, 0x00, 0x03, 0x00, 0xBC, 0xDA, 0x7D, 0xDA, 0xBE, 0x3F, 0x47, 0x44, // ........}ھ?GD + /* 1B10 */ 0x9E, 0x01, 0x6A, 0xB7, 0x44, 0x0B, 0x4C, 0xD4, 0x4B, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..jD.LK8...... + /* 1B20 */ 0x02, 0x1B, 0x06, 0x05, 0x00, 0x00, 0x03, 0x00, 0x45, 0xCA, 0xBA, 0xCB, 0x6A, 0x55, 0x16, 0x44, // ........EʺjU.D + /* 1B30 */ 0xAD, 0x03, 0xBD, 0xA5, 0x98, 0xEA, 0xA7, 0xC8, 0x68, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..h8...... + /* 1B40 */ 0x02, 0x1B, 0x06, 0x05, 0x00, 0x00, 0x03, 0x00, 0xCB, 0x06, 0x1A, 0x04, 0xB8, 0xC5, 0x72, 0x47, // ...........rG + /* 1B50 */ 0x80, 0x9F, 0x41, 0x6D, 0x03, 0xD1, 0x66, 0x54, 0x89, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..Am.fT.8...... + /* 1B60 */ 0x02, 0x1B, 0x06, 0x05, 0x00, 0x00, 0x03, 0x00, 0xE1, 0x4E, 0xE0, 0x83, 0x8D, 0xFA, 0x6D, 0x43, // ........N..mC + /* 1B70 */ 0x89, 0x94, 0xD3, 0x1A, 0x86, 0x2C, 0xAB, 0x77, 0x9F, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ....,w.8...... + /* 1B80 */ 0x02, 0x1B, 0x06, 0x05, 0x00, 0x00, 0x03, 0x00, 0x3D, 0xA2, 0xDF, 0xDE, 0xD1, 0x6E, 0xA6, 0x45, // ........=nE + /* 1B90 */ 0x85, 0xDC, 0x63, 0xCA, 0xE0, 0x54, 0x6D, 0xE6, 0xBE, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .cTm8...... + /* 1BA0 */ 0x02, 0x1B, 0x06, 0x05, 0x00, 0x00, 0x03, 0x00, 0xC1, 0x01, 0xF3, 0x6B, 0x4A, 0xB9, 0xE9, 0x43, // .........kJC + /* 1BB0 */ 0xBA, 0x31, 0xD4, 0x94, 0x59, 0x8C, 0x47, 0xFB, 0xD3, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 1.Y.G8...... + /* 1BC0 */ 0x02, 0x1B, 0x06, 0x05, 0x00, 0x00, 0x03, 0x00, 0xE3, 0xAB, 0x34, 0xB2, 0x57, 0x08, 0x9C, 0x4F, // ........4W..O + /* 1BD0 */ 0xB0, 0x5A, 0x4D, 0xC3, 0x14, 0xF8, 0x55, 0x57, 0xE9, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ZM.UW8...... + /* 1BE0 */ 0x02, 0x1B, 0x06, 0x05, 0x00, 0x00, 0x03, 0x00, 0x21, 0x78, 0x2A, 0xAA, 0x27, 0x18, 0x2C, 0x4C, // ........!x*'.,L + /* 1BF0 */ 0x8F, 0x1D, 0x45, 0x13, 0xA3, 0x4D, 0xDA, 0x97, 0x03, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..E.M..9...... + /* 1C00 */ 0x02, 0x1B, 0x06, 0x05, 0x00, 0x00, 0x03, 0x00, 0x20, 0xE6, 0x1F, 0x36, 0xF4, 0x64, 0xB5, 0x41, // ........ .6dA + /* 1C10 */ 0xBA, 0x77, 0x84, 0xF8, 0xE0, 0x79, 0xB1, 0xF7, 0x1E, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // w.y.9...... + /* 1C20 */ 0x02, 0x1B, 0x06, 0x05, 0x00, 0x00, 0x03, 0x00, 0xDF, 0xBA, 0x11, 0xBB, 0xAA, 0xD8, 0x0E, 0x47, // ........ߺ..G + /* 1C30 */ 0x93, 0x11, 0x20, 0xEA, 0xF8, 0x0F, 0xE5, 0xCC, 0x3D, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .. .=9...... + /* 1C40 */ 0x02, 0x1B, 0x06, 0x05, 0x00, 0x00, 0x03, 0x00, 0x85, 0x88, 0xC8, 0x0B, 0x8C, 0x71, 0x1D, 0x49, // ............q.I + /* 1C50 */ 0x92, 0x1F, 0x6F, 0x21, 0x43, 0x49, 0xE7, 0x9C, 0x4E, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..o!CI.N9...... + /* 1C60 */ 0x02, 0x1B, 0x06, 0x05, 0x00, 0x00, 0x03, 0x00, 0x0C, 0x4D, 0x7C, 0xFC, 0x85, 0x2E, 0xB9, 0x4B, // .........M|..K + /* 1C70 */ 0xAF, 0xD4, 0x01, 0xED, 0x14, 0x76, 0xB5, 0xE9, 0x78, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..vx9...... + /* 1C80 */ 0x02, 0x1B, 0x06, 0x05, 0x00, 0x00, 0x03, 0x00, 0x19, 0x66, 0x0F, 0x50, 0x93, 0xEF, 0x75, 0x4B, // .........f.P.uK + /* 1C90 */ 0xBC, 0xB4, 0x82, 0x81, 0x99, 0x98, 0xA3, 0xCA, 0x9C, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .....9...... + /* 1CA0 */ 0x02, 0x1B, 0x06, 0x05, 0x00, 0x00, 0x03, 0x00, 0xEB, 0xCE, 0x9B, 0x9E, 0x36, 0xE7, 0x26, 0x4F, // ..........6&O + /* 1CB0 */ 0x88, 0xDE, 0x76, 0x3F, 0x87, 0xDC, 0xC4, 0x85, 0xBE, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .v?..9...... + /* 1CC0 */ 0x02, 0x1C, 0x06, 0x05, 0x00, 0x00, 0x05, 0x00, 0xE9, 0x54, 0x78, 0x23, 0xFC, 0x79, 0x97, 0x44, // ........Tx#y.D + /* 1CD0 */ 0xA0, 0xC1, 0xA7, 0x09, 0x69, 0x69, 0x1C, 0x6B, 0xD1, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..ii.k9...... + /* 1CE0 */ 0x02, 0x1C, 0x06, 0x05, 0x00, 0x00, 0x05, 0x00, 0x01, 0xA3, 0xF8, 0xC8, 0xF5, 0x19, 0x32, 0x41, // ..........2A + /* 1CF0 */ 0x96, 0xCE, 0x2D, 0xE9, 0xD4, 0xAD, 0xBD, 0x33, 0xE3, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .-ԭ39...... + /* 1D00 */ 0x02, 0x1C, 0x06, 0x05, 0x00, 0x00, 0x05, 0x00, 0x61, 0xFD, 0x31, 0x31, 0x4F, 0x5E, 0x08, 0x43, // ........a11O^.C + /* 1D10 */ 0x8D, 0x6D, 0x62, 0xBE, 0x19, 0x87, 0xC9, 0x2C, 0xF7, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .mb..,9...... + /* 1D20 */ 0x02, 0x1C, 0x06, 0x05, 0x00, 0x00, 0x05, 0x00, 0x5F, 0x8B, 0xDD, 0x85, 0xA4, 0xEA, 0xF3, 0x4A, // ........_..J + /* 1D30 */ 0xA6, 0x28, 0xCC, 0xE9, 0xE7, 0x7C, 0x9A, 0x03, 0x0E, 0x3A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // (|...:...... + /* 1D40 */ 0x02, 0x1C, 0x06, 0x05, 0x00, 0x00, 0x05, 0x00, 0x3F, 0xBF, 0xA2, 0x2C, 0x9E, 0x94, 0x6A, 0x44, // ........?,..jD + /* 1D50 */ 0x82, 0xC7, 0xE2, 0x5A, 0x15, 0xEC, 0x78, 0xC4, 0x2C, 0x3A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .Z.x,:...... + /* 1D60 */ 0x02, 0x1C, 0x06, 0x05, 0x00, 0x00, 0x05, 0x00, 0xE3, 0xF0, 0x77, 0x17, 0x92, 0x73, 0x98, 0x41, // ........w..s.A + /* 1D70 */ 0x97, 0xEA, 0x8A, 0xE4, 0xDE, 0x6F, 0x63, 0x81, 0x44, 0x3A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..oc.D:...... + /* 1D80 */ 0x02, 0x1C, 0x06, 0x05, 0x00, 0x00, 0x05, 0x00, 0xCA, 0x4C, 0x3E, 0x9D, 0x72, 0xE1, 0xF1, 0x46, // ........L>.rF + /* 1D90 */ 0xA2, 0xF4, 0x1D, 0x21, 0x07, 0x05, 0x14, 0x44, 0x61, 0x3A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .!...Da:...... + /* 1DA0 */ 0x02, 0x1C, 0x06, 0x05, 0x00, 0x00, 0x05, 0x00, 0x6E, 0x6C, 0x4C, 0x73, 0xBA, 0xB0, 0x98, 0x42, // ........nlLs.B + /* 1DB0 */ 0xA8, 0x91, 0x67, 0x17, 0x72, 0xB2, 0xBD, 0x1B, 0x77, 0x3A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .g.r.w:...... + /* 1DC0 */ 0x02, 0x1C, 0x06, 0x05, 0x00, 0x00, 0x05, 0x00, 0x4B, 0xA7, 0x12, 0x69, 0xFB, 0xA5, 0x1A, 0x40, // ........K.i.@ + /* 1DD0 */ 0xBF, 0xDB, 0x2E, 0x3A, 0xB4, 0x6F, 0x4B, 0x02, 0x96, 0x3A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .:oK..:...... + /* 1DE0 */ 0x02, 0x1C, 0x06, 0x05, 0x00, 0x00, 0x05, 0x00, 0x8F, 0xF0, 0x5C, 0x5B, 0x1A, 0xB8, 0x1D, 0x43, // .........\[..C + /* 1DF0 */ 0xB0, 0x80, 0x34, 0x50, 0xD8, 0x62, 0x05, 0x65, 0xAB, 0x3A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .4Pb.e:...... + /* 1E00 */ 0x02, 0x1C, 0x06, 0x05, 0x00, 0x00, 0x05, 0x00, 0xF3, 0x7D, 0x6D, 0xE0, 0xD0, 0xAA, 0x9D, 0x41, // ........}mЪ.A + /* 1E10 */ 0x8D, 0xFB, 0x0A, 0xC3, 0x7E, 0x2B, 0xDF, 0x39, 0xC1, 0x3A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ..~+9:...... + /* 1E20 */ 0x02, 0x1C, 0x06, 0x05, 0x00, 0x00, 0x05, 0x00, 0xFE, 0x34, 0x98, 0x05, 0xEA, 0xA8, 0xFF, 0x4B, // ........4..K + /* 1E30 */ 0xB6, 0x7B, 0x4D, 0x00, 0x6B, 0x54, 0x47, 0xD3, 0xDC, 0x3A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // {M.kTG:...... + /* 1E40 */ 0x02, 0x1C, 0x06, 0x05, 0x00, 0x00, 0x05, 0x00, 0xD4, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ ...... + /* 1E50 */ 0x00, 0xB5, 0xB2, 0x5B, 0x00, 0x00, 0x00, 0x00, 0x63, 0x45, 0x00, 0x00, 0x1C, 0x0E, 0x00, 0x00, // .[....cE...... + /* 1E60 */ 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF2, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ ...... + /* 1E70 */ 0x80, 0xE2, 0x9F, 0x57, 0x00, 0x00, 0x00, 0x00, 0x39, 0x38, 0x00, 0x00, 0x1C, 0x0E, 0x00, 0x00, // ..W....98...... + /* 1E80 */ 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .........!...... + /* 1E90 */ 0x00, 0x7A, 0x60, 0x52, 0x00, 0x00, 0x00, 0x00, 0x80, 0x25, 0x00, 0x00, 0x01, 0x19, 0x00, 0x00, // .z`R.....%...... + /* 1EA0 */ 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2D, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........-!...... + /* 1EB0 */ 0x80, 0xD2, 0x89, 0x50, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x23, 0x00, 0x00, 0x32, 0x15, 0x00, 0x00, // ..P....#..2... + /* 1EC0 */ 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........E!...... + /* 1ED0 */ 0x80, 0xFC, 0x62, 0x4D, 0x00, 0x00, 0x00, 0x00, 0xB1, 0x1D, 0x00, 0x00, 0x01, 0xD7, 0x00, 0x00, // .bM.......... + /* 1EE0 */ 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........d!...... + /* 1EF0 */ 0x00, 0x31, 0x1B, 0x4A, 0x00, 0x00, 0x00, 0x00, 0x72, 0x17, 0x00, 0x00, 0x01, 0xD7, 0x00, 0x00, // .1.J....r...... + /* 1F00 */ 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x33, 0x36, 0x31, 0x32, 0x2D, 0x30, 0x30, // ........03612-00 + /* 1F10 */ 0x32, 0x30, 0x36, 0x2D, 0x35, 0x35, 0x36, 0x2D, 0x31, 0x32, 0x33, 0x37, 0x32, 0x37, 0x2D, 0x30, // 206-556-123727-0 + /* 1F20 */ 0x33, 0x2D, 0x31, 0x30, 0x33, 0x33, 0x2D, 0x31, 0x37, 0x37, 0x36, 0x33, 0x2E, 0x30, 0x30, 0x30, // 3-1033-17763.000 + /* 1F30 */ 0x30, 0x2D, 0x32, 0x39, 0x37, 0x32, 0x30, 0x31, 0x38, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, // 0-2972018.Window + /* 1F40 */ 0x73, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, // s.Windows Server + /* 1F50 */ 0x20, 0x32, 0x30, 0x31, 0x39, 0x00, 0x30, 0x33, 0x36, 0x31, 0x32, 0x2D, 0x30, 0x30, 0x30, 0x39, // 2019.03612-0009 + /* 1F60 */ 0x36, 0x2D, 0x31, 0x39, 0x39, 0x2D, 0x37, 0x39, 0x39, 0x31, 0x38, 0x38, 0x2D, 0x30, 0x33, 0x2D, // 6-199-799188-03- + /* 1F70 */ 0x31, 0x30, 0x33, 0x33, 0x2D, 0x31, 0x37, 0x37, 0x36, 0x33, 0x2E, 0x30, 0x30, 0x30, 0x30, 0x2D, // 1033-17763.0000- + /* 1F80 */ 0x32, 0x39, 0x37, 0x32, 0x30, 0x31, 0x38, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x32, 0x30, // 2972018.Office20 + /* 1F90 */ 0x31, 0x30, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x32, 0x30, 0x31, 0x30, 0x00, 0x30, // 10.Office 2010.0 + /* 1FA0 */ 0x33, 0x36, 0x31, 0x32, 0x2D, 0x30, 0x30, 0x32, 0x30, 0x36, 0x2D, 0x32, 0x34, 0x30, 0x2D, 0x37, // 3612-00206-240-7 + /* 1FB0 */ 0x31, 0x39, 0x36, 0x33, 0x39, 0x2D, 0x30, 0x33, 0x2D, 0x31, 0x30, 0x33, 0x33, 0x2D, 0x31, 0x37, // 19639-03-1033-17 + /* 1FC0 */ 0x37, 0x36, 0x33, 0x2E, 0x30, 0x30, 0x30, 0x30, 0x2D, 0x32, 0x39, 0x37, 0x32, 0x30, 0x31, 0x38, // 763.0000-2972018 + /* 1FD0 */ 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x32, 0x30, 0x31, 0x33, 0x00, 0x4F, 0x66, 0x66, 0x69, // .Office2013.Offi + /* 1FE0 */ 0x63, 0x65, 0x20, 0x32, 0x30, 0x31, 0x33, 0x00, 0x30, 0x33, 0x36, 0x31, 0x32, 0x2D, 0x30, 0x30, // ce 2013.03612-00 + /* 1FF0 */ 0x32, 0x30, 0x36, 0x2D, 0x34, 0x33, 0x38, 0x2D, 0x30, 0x30, 0x34, 0x35, 0x33, 0x32, 0x2D, 0x30, // 206-438-004532-0 + /* 2000 */ 0x33, 0x2D, 0x31, 0x30, 0x33, 0x33, 0x2D, 0x31, 0x37, 0x37, 0x36, 0x33, 0x2E, 0x30, 0x30, 0x30, // 3-1033-17763.000 + /* 2010 */ 0x30, 0x2D, 0x32, 0x39, 0x37, 0x32, 0x30, 0x31, 0x38, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, // 0-2972018.Office + /* 2020 */ 0x32, 0x30, 0x31, 0x36, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x32, 0x30, 0x31, 0x36, // 2016.Office 2016 + /* 2030 */ 0x00, 0x30, 0x33, 0x36, 0x31, 0x32, 0x2D, 0x30, 0x33, 0x38, 0x35, 0x38, 0x2D, 0x30, 0x35, 0x33, // .03612-03858-053 + /* 2040 */ 0x2D, 0x30, 0x38, 0x39, 0x35, 0x31, 0x36, 0x2D, 0x30, 0x33, 0x2D, 0x31, 0x30, 0x33, 0x33, 0x2D, // -089516-03-1033- + /* 2050 */ 0x31, 0x37, 0x37, 0x36, 0x33, 0x2E, 0x30, 0x30, 0x30, 0x30, 0x2D, 0x32, 0x39, 0x37, 0x32, 0x30, // 17763.0000-29720 + /* 2060 */ 0x31, 0x38, 0x00, 0x57, 0x69, 0x6E, 0x43, 0x68, 0x69, 0x6E, 0x61, 0x47, 0x6F, 0x76, 0x00, 0x57, // 18.WinChinaGov.W + /* 2070 */ 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, 0x43, 0x68, 0x69, 0x6E, 0x61, 0x20, // indows 10 China + /* 2080 */ 0x47, 0x6F, 0x76, 0x65, 0x72, 0x6E, 0x6D, 0x65, 0x6E, 0x74, 0x00, 0x30, 0x33, 0x36, 0x31, 0x32, // Government.03612 + /* 2090 */ 0x2D, 0x30, 0x30, 0x32, 0x30, 0x36, 0x2D, 0x36, 0x38, 0x34, 0x2D, 0x31, 0x33, 0x37, 0x36, 0x36, // -00206-684-13766 + /* 20A0 */ 0x39, 0x2D, 0x30, 0x33, 0x2D, 0x31, 0x30, 0x33, 0x33, 0x2D, 0x31, 0x37, 0x37, 0x36, 0x33, 0x2E, // 9-03-1033-17763. + /* 20B0 */ 0x30, 0x30, 0x30, 0x30, 0x2D, 0x32, 0x39, 0x37, 0x32, 0x30, 0x31, 0x38, 0x00, 0x4F, 0x66, 0x66, // 0000-2972018.Off + /* 20C0 */ 0x69, 0x63, 0x65, 0x32, 0x30, 0x31, 0x39, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x32, // ice2019.Office 2 + /* 20D0 */ 0x30, 0x31, 0x39, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, 0x31, // 019.Windows 10 1 + /* 20E0 */ 0x38, 0x30, 0x39, 0x20, 0x2F, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x31, // 809 / Server 201 + /* 20F0 */ 0x39, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, 0x31, 0x36, 0x30, // 9.Windows 10 160 + /* 2100 */ 0x37, 0x20, 0x2F, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x31, 0x36, 0x00, // 7 / Server 2016. + /* 2110 */ 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x38, 0x2E, 0x31, 0x20, 0x2F, 0x20, 0x53, 0x65, // Windows 8.1 / Se + /* 2120 */ 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x31, 0x32, 0x20, 0x52, 0x32, 0x00, 0x57, 0x69, 0x6E, // rver 2012 R2.Win + /* 2130 */ 0x64, 0x6F, 0x77, 0x73, 0x20, 0x38, 0x20, 0x2F, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, // dows 8 / Server + /* 2140 */ 0x32, 0x30, 0x31, 0x32, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x37, 0x20, 0x2F, // 2012.Windows 7 / + /* 2150 */ 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x30, 0x38, 0x20, 0x52, 0x32, 0x20, // Server 2008 R2 + /* 2160 */ 0x53, 0x50, 0x31, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x56, 0x69, 0x73, 0x74, // SP1.Windows Vist + /* 2170 */ 0x61, 0x20, 0x2F, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x30, 0x38, 0x20, // a / Server 2008 + /* 2180 */ 0x53, 0x50, 0x32, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x00, 0x4F, 0x66, 0x66, 0x69, // SP2.Windows.Offi + /* 2190 */ 0x63, 0x65, 0x32, 0x30, 0x31, 0x30, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x32, 0x30, 0x31, // ce2010.Office201 + /* 21A0 */ 0x33, 0x2B, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, // 3+.Windows Serve + /* 21B0 */ 0x72, 0x20, 0x32, 0x30, 0x31, 0x39, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x31, // r 2019.Windows 1 + /* 21C0 */ 0x30, 0x20, 0x32, 0x30, 0x31, 0x39, 0x20, 0x28, 0x56, 0x6F, 0x6C, 0x75, 0x6D, 0x65, 0x29, 0x00, // 0 2019 (Volume). + /* 21D0 */ 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, 0x55, 0x6E, 0x6B, 0x6E, 0x6F, // Windows 10 Unkno + /* 21E0 */ 0x77, 0x6E, 0x20, 0x28, 0x56, 0x6F, 0x6C, 0x75, 0x6D, 0x65, 0x29, 0x00, 0x57, 0x69, 0x6E, 0x64, // wn (Volume).Wind + /* 21F0 */ 0x6F, 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, 0x43, 0x68, 0x69, 0x6E, 0x61, 0x20, 0x47, 0x6F, 0x76, // ows 10 China Gov + /* 2200 */ 0x65, 0x72, 0x6E, 0x6D, 0x65, 0x6E, 0x74, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, // ernment.Windows + /* 2210 */ 0x31, 0x30, 0x20, 0x32, 0x30, 0x31, 0x36, 0x20, 0x28, 0x56, 0x6F, 0x6C, 0x75, 0x6D, 0x65, 0x29, // 10 2016 (Volume) + /* 2220 */ 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, 0x28, 0x52, 0x65, 0x74, // .Windows 10 (Ret + /* 2230 */ 0x61, 0x69, 0x6C, 0x29, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, // ail).Windows 10 + /* 2240 */ 0x32, 0x30, 0x31, 0x35, 0x20, 0x28, 0x56, 0x6F, 0x6C, 0x75, 0x6D, 0x65, 0x29, 0x00, 0x57, 0x69, // 2015 (Volume).Wi + /* 2250 */ 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x37, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, // ndows 7.Windows + /* 2260 */ 0x38, 0x20, 0x28, 0x52, 0x65, 0x74, 0x61, 0x69, 0x6C, 0x29, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, // 8 (Retail).Windo + /* 2270 */ 0x77, 0x73, 0x20, 0x38, 0x20, 0x28, 0x56, 0x6F, 0x6C, 0x75, 0x6D, 0x65, 0x29, 0x00, 0x57, 0x69, // ws 8 (Volume).Wi + /* 2280 */ 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x38, 0x2E, 0x31, 0x20, 0x28, 0x52, 0x65, 0x74, 0x61, 0x69, // ndows 8.1 (Retai + /* 2290 */ 0x6C, 0x29, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x38, 0x2E, 0x31, 0x20, 0x28, // l).Windows 8.1 ( + /* 22A0 */ 0x56, 0x6F, 0x6C, 0x75, 0x6D, 0x65, 0x29, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, // Volume).Windows + /* 22B0 */ 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, // Preview.Windows + /* 22C0 */ 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x30, 0x38, 0x20, 0x41, 0x20, 0x28, 0x57, // Server 2008 A (W + /* 22D0 */ 0x65, 0x62, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x48, 0x50, 0x43, 0x29, 0x00, 0x57, 0x69, 0x6E, 0x64, // eb and HPC).Wind + /* 22E0 */ 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x30, 0x38, 0x20, // ows Server 2008 + /* 22F0 */ 0x42, 0x20, 0x28, 0x53, 0x74, 0x61, 0x6E, 0x64, 0x61, 0x72, 0x64, 0x20, 0x61, 0x6E, 0x64, 0x20, // B (Standard and + /* 2300 */ 0x45, 0x6E, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x29, 0x00, 0x57, 0x69, 0x6E, 0x64, // Enterprise).Wind + /* 2310 */ 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x30, 0x38, 0x20, // ows Server 2008 + /* 2320 */ 0x43, 0x20, 0x28, 0x44, 0x61, 0x74, 0x61, 0x63, 0x65, 0x6E, 0x74, 0x65, 0x72, 0x29, 0x00, 0x57, // C (Datacenter).W + /* 2330 */ 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, // indows Server 20 + /* 2340 */ 0x30, 0x38, 0x20, 0x52, 0x32, 0x20, 0x41, 0x20, 0x28, 0x57, 0x65, 0x62, 0x20, 0x61, 0x6E, 0x64, // 08 R2 A (Web and + /* 2350 */ 0x20, 0x48, 0x50, 0x43, 0x29, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, // HPC).Windows Se + /* 2360 */ 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x30, 0x38, 0x20, 0x52, 0x32, 0x20, 0x42, 0x20, 0x28, // rver 2008 R2 B ( + /* 2370 */ 0x53, 0x74, 0x61, 0x6E, 0x64, 0x61, 0x72, 0x64, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x45, 0x6E, 0x74, // Standard and Ent + /* 2380 */ 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x29, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, // erprise).Windows + /* 2390 */ 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x30, 0x38, 0x20, 0x52, 0x32, 0x20, // Server 2008 R2 + /* 23A0 */ 0x43, 0x20, 0x28, 0x44, 0x61, 0x74, 0x61, 0x63, 0x65, 0x6E, 0x74, 0x65, 0x72, 0x29, 0x00, 0x57, // C (Datacenter).W + /* 23B0 */ 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, // indows Server 20 + /* 23C0 */ 0x31, 0x32, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, // 12.Windows Serve + /* 23D0 */ 0x72, 0x20, 0x32, 0x30, 0x31, 0x32, 0x20, 0x52, 0x32, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, // r 2012 R2.Window + /* 23E0 */ 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x31, 0x36, 0x00, 0x57, 0x69, // s Server 2016.Wi + /* 23F0 */ 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x50, 0x72, 0x65, // ndows Server Pre + /* 2400 */ 0x76, 0x69, 0x65, 0x77, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x56, 0x69, 0x73, // view.Windows Vis + /* 2410 */ 0x74, 0x61, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x32, 0x30, 0x31, 0x30, 0x00, 0x4F, // ta.Office 2010.O + /* 2420 */ 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x32, 0x30, 0x31, 0x33, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, // ffice 2013.Offic + /* 2430 */ 0x65, 0x20, 0x32, 0x30, 0x31, 0x33, 0x20, 0x28, 0x50, 0x72, 0x65, 0x2D, 0x52, 0x65, 0x6C, 0x65, // e 2013 (Pre-Rele + /* 2440 */ 0x61, 0x73, 0x65, 0x29, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x32, 0x30, 0x31, 0x36, // ase).Office 2016 + /* 2450 */ 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x32, 0x30, 0x31, 0x39, 0x00, 0x57, 0x69, 0x6E, // .Office 2019.Win + /* 2460 */ 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x31, 0x39, // dows Server 2019 + /* 2470 */ 0x20, 0x41, 0x52, 0x4D, 0x36, 0x34, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, // ARM64.Windows S + /* 2480 */ 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x31, 0x39, 0x20, 0x41, 0x7A, 0x75, 0x72, 0x65, // erver 2019 Azure + /* 2490 */ 0x20, 0x43, 0x6F, 0x72, 0x65, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, // Core.Windows Se + /* 24A0 */ 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x31, 0x39, 0x20, 0x44, 0x61, 0x74, 0x61, 0x63, 0x65, // rver 2019 Datace + /* 24B0 */ 0x6E, 0x74, 0x65, 0x72, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, // nter.Windows Ser + /* 24C0 */ 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x31, 0x39, 0x20, 0x45, 0x73, 0x73, 0x65, 0x6E, 0x74, 0x69, // ver 2019 Essenti + /* 24D0 */ 0x61, 0x6C, 0x73, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, // als.Windows Serv + /* 24E0 */ 0x65, 0x72, 0x20, 0x32, 0x30, 0x31, 0x39, 0x20, 0x53, 0x74, 0x61, 0x6E, 0x64, 0x61, 0x72, 0x64, // er 2019 Standard + /* 24F0 */ 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, // .Windows Server + /* 2500 */ 0x32, 0x30, 0x31, 0x39, 0x20, 0x44, 0x61, 0x74, 0x61, 0x63, 0x65, 0x6E, 0x74, 0x65, 0x72, 0x20, // 2019 Datacenter + /* 2510 */ 0x28, 0x53, 0x65, 0x6D, 0x69, 0x2D, 0x41, 0x6E, 0x6E, 0x75, 0x61, 0x6C, 0x20, 0x43, 0x68, 0x61, // (Semi-Annual Cha + /* 2520 */ 0x6E, 0x6E, 0x65, 0x6C, 0x29, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, // nnel).Windows Se + /* 2530 */ 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x31, 0x39, 0x20, 0x53, 0x74, 0x61, 0x6E, 0x64, 0x61, // rver 2019 Standa + /* 2540 */ 0x72, 0x64, 0x20, 0x28, 0x53, 0x65, 0x6D, 0x69, 0x2D, 0x41, 0x6E, 0x6E, 0x75, 0x61, 0x6C, 0x20, // rd (Semi-Annual + /* 2550 */ 0x43, 0x68, 0x61, 0x6E, 0x6E, 0x65, 0x6C, 0x29, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, // Channel).Windows + /* 2560 */ 0x20, 0x31, 0x30, 0x20, 0x45, 0x6E, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x20, 0x4C, // 10 Enterprise L + /* 2570 */ 0x54, 0x53, 0x43, 0x20, 0x32, 0x30, 0x31, 0x39, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, // TSC 2019.Windows + /* 2580 */ 0x20, 0x31, 0x30, 0x20, 0x45, 0x6E, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x20, 0x4C, // 10 Enterprise L + /* 2590 */ 0x54, 0x53, 0x43, 0x20, 0x32, 0x30, 0x31, 0x39, 0x20, 0x4E, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, // TSC 2019 N.Windo + /* 25A0 */ 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, 0x45, 0x6E, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, // ws 10 Enterprise + /* 25B0 */ 0x20, 0x47, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, 0x45, 0x6E, // G.Windows 10 En + /* 25C0 */ 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x20, 0x47, 0x4E, 0x00, 0x57, 0x69, 0x6E, 0x64, // terprise GN.Wind + /* 25D0 */ 0x6F, 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, 0x45, 0x6E, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, // ows 10 Enterpris + /* 25E0 */ 0x65, 0x20, 0x32, 0x30, 0x31, 0x36, 0x20, 0x4C, 0x54, 0x53, 0x42, 0x00, 0x57, 0x69, 0x6E, 0x64, // e 2016 LTSB.Wind + /* 25F0 */ 0x6F, 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, 0x45, 0x6E, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, // ows 10 Enterpris + /* 2600 */ 0x65, 0x20, 0x32, 0x30, 0x31, 0x36, 0x20, 0x4C, 0x54, 0x53, 0x42, 0x20, 0x4E, 0x00, 0x57, 0x69, // e 2016 LTSB N.Wi + /* 2610 */ 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, 0x48, 0x6F, 0x6D, 0x65, 0x00, 0x57, 0x69, // ndows 10 Home.Wi + /* 2620 */ 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, 0x48, 0x6F, 0x6D, 0x65, 0x20, 0x43, 0x6F, // ndows 10 Home Co + /* 2630 */ 0x75, 0x6E, 0x74, 0x72, 0x79, 0x20, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x00, 0x57, // untry Specific.W + /* 2640 */ 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, 0x48, 0x6F, 0x6D, 0x65, 0x20, 0x4E, // indows 10 Home N + /* 2650 */ 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, 0x48, 0x6F, 0x6D, 0x65, // .Windows 10 Home + /* 2660 */ 0x20, 0x53, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20, 0x4C, 0x61, 0x6E, 0x67, 0x75, 0x61, 0x67, 0x65, // Single Language + /* 2670 */ 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, 0x45, 0x64, 0x75, 0x63, // .Windows 10 Educ + /* 2680 */ 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x31, 0x30, // ation.Windows 10 + /* 2690 */ 0x20, 0x45, 0x64, 0x75, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x4E, 0x00, 0x57, 0x69, 0x6E, // Education N.Win + /* 26A0 */ 0x64, 0x6F, 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, 0x45, 0x6E, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, // dows 10 Enterpri + /* 26B0 */ 0x73, 0x65, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, 0x45, 0x6E, // se.Windows 10 En + /* 26C0 */ 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x20, 0x32, 0x30, 0x31, 0x35, 0x20, 0x4C, 0x54, // terprise 2015 LT + /* 26D0 */ 0x53, 0x42, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, 0x45, 0x6E, // SB.Windows 10 En + /* 26E0 */ 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x20, 0x32, 0x30, 0x31, 0x35, 0x20, 0x4C, 0x54, // terprise 2015 LT + /* 26F0 */ 0x53, 0x42, 0x20, 0x4E, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, // SB N.Windows 10 + /* 2700 */ 0x45, 0x6E, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x20, 0x4E, 0x00, 0x57, 0x69, 0x6E, // Enterprise N.Win + /* 2710 */ 0x64, 0x6F, 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, 0x50, 0x72, 0x6F, 0x66, 0x65, 0x73, 0x73, 0x69, // dows 10 Professi + /* 2720 */ 0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x57, 0x6F, 0x72, 0x6B, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6F, 0x6E, // onal Workstation + /* 2730 */ 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, 0x50, 0x72, 0x6F, 0x66, // .Windows 10 Prof + /* 2740 */ 0x65, 0x73, 0x73, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x57, 0x6F, 0x72, 0x6B, 0x73, 0x74, 0x61, // essional Worksta + /* 2750 */ 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x4E, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x31, // tion N.Windows 1 + /* 2760 */ 0x30, 0x20, 0x50, 0x72, 0x6F, 0x66, 0x65, 0x73, 0x73, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x00, 0x57, // 0 Professional.W + /* 2770 */ 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, 0x50, 0x72, 0x6F, 0x66, 0x65, 0x73, // indows 10 Profes + /* 2780 */ 0x73, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x45, 0x64, 0x75, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, // sional Education + /* 2790 */ 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, 0x50, 0x72, 0x6F, 0x66, // .Windows 10 Prof + /* 27A0 */ 0x65, 0x73, 0x73, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x45, 0x64, 0x75, 0x63, 0x61, 0x74, 0x69, // essional Educati + /* 27B0 */ 0x6F, 0x6E, 0x20, 0x4E, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, // on N.Windows 10 + /* 27C0 */ 0x50, 0x72, 0x6F, 0x66, 0x65, 0x73, 0x73, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x4E, 0x00, 0x57, // Professional N.W + /* 27D0 */ 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, 0x50, 0x72, 0x6F, 0x66, 0x65, 0x73, // indows 10 Profes + /* 27E0 */ 0x73, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x00, 0x57, // sional Preview.W + /* 27F0 */ 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, 0x45, 0x6E, 0x74, 0x65, 0x72, 0x70, // indows 10 Enterp + /* 2800 */ 0x72, 0x69, 0x73, 0x65, 0x20, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x00, 0x57, 0x69, 0x6E, // rise Preview.Win + /* 2810 */ 0x64, 0x6F, 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, 0x45, 0x6E, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, // dows 10 Enterpri + /* 2820 */ 0x73, 0x65, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6C, 0x20, 0x44, // se for Virtual D + /* 2830 */ 0x65, 0x73, 0x6B, 0x74, 0x6F, 0x70, 0x73, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, // esktops.Windows + /* 2840 */ 0x31, 0x30, 0x20, 0x52, 0x65, 0x6D, 0x6F, 0x74, 0x65, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, // 10 Remote Server + /* 2850 */ 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, 0x53, 0x20, 0x28, 0x4C, // .Windows 10 S (L + /* 2860 */ 0x65, 0x61, 0x6E, 0x29, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x37, 0x20, 0x45, // ean).Windows 7 E + /* 2870 */ 0x6E, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, // nterprise.Window + /* 2880 */ 0x73, 0x20, 0x37, 0x20, 0x45, 0x6E, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x20, 0x45, // s 7 Enterprise E + /* 2890 */ 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x37, 0x20, 0x45, 0x6E, 0x74, 0x65, 0x72, // .Windows 7 Enter + /* 28A0 */ 0x70, 0x72, 0x69, 0x73, 0x65, 0x20, 0x4E, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, // prise N.Windows + /* 28B0 */ 0x37, 0x20, 0x50, 0x72, 0x6F, 0x66, 0x65, 0x73, 0x73, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x00, 0x57, // 7 Professional.W + /* 28C0 */ 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x37, 0x20, 0x50, 0x72, 0x6F, 0x66, 0x65, 0x73, 0x73, // indows 7 Profess + /* 28D0 */ 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x45, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, // ional E.Windows + /* 28E0 */ 0x37, 0x20, 0x50, 0x72, 0x6F, 0x66, 0x65, 0x73, 0x73, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x4E, // 7 Professional N + /* 28F0 */ 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x37, 0x20, 0x45, 0x6D, 0x62, 0x65, 0x64, // .Windows 7 Embed + /* 2900 */ 0x64, 0x65, 0x64, 0x20, 0x50, 0x4F, 0x53, 0x52, 0x65, 0x61, 0x64, 0x79, 0x00, 0x57, 0x69, 0x6E, // ded POSReady.Win + /* 2910 */ 0x64, 0x6F, 0x77, 0x73, 0x20, 0x37, 0x20, 0x45, 0x6D, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x20, // dows 7 Embedded + /* 2920 */ 0x53, 0x74, 0x61, 0x6E, 0x64, 0x61, 0x72, 0x64, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, // Standard.Windows + /* 2930 */ 0x20, 0x37, 0x20, 0x54, 0x68, 0x69, 0x6E, 0x50, 0x43, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, // 7 ThinPC.Window + /* 2940 */ 0x73, 0x20, 0x38, 0x20, 0x43, 0x6F, 0x72, 0x65, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, // s 8 Core.Windows + /* 2950 */ 0x20, 0x38, 0x20, 0x43, 0x6F, 0x72, 0x65, 0x20, 0x43, 0x6F, 0x75, 0x6E, 0x74, 0x72, 0x79, 0x20, // 8 Core Country + /* 2960 */ 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, // Specific.Windows + /* 2970 */ 0x20, 0x38, 0x20, 0x43, 0x6F, 0x72, 0x65, 0x20, 0x4E, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, // 8 Core N.Window + /* 2980 */ 0x73, 0x20, 0x38, 0x20, 0x43, 0x6F, 0x72, 0x65, 0x20, 0x53, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20, // s 8 Core Single + /* 2990 */ 0x4C, 0x61, 0x6E, 0x67, 0x75, 0x61, 0x67, 0x65, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, // Language.Windows + /* 29A0 */ 0x20, 0x38, 0x20, 0x50, 0x72, 0x6F, 0x66, 0x65, 0x73, 0x73, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x20, // 8 Professional + /* 29B0 */ 0x57, 0x4D, 0x43, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x38, 0x20, 0x45, 0x6D, // WMC.Windows 8 Em + /* 29C0 */ 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x20, 0x49, 0x6E, 0x64, 0x75, 0x73, 0x74, 0x72, 0x79, 0x20, // bedded Industry + /* 29D0 */ 0x50, 0x72, 0x6F, 0x66, 0x65, 0x73, 0x73, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x00, 0x57, 0x69, 0x6E, // Professional.Win + /* 29E0 */ 0x64, 0x6F, 0x77, 0x73, 0x20, 0x38, 0x20, 0x45, 0x6D, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x20, // dows 8 Embedded + /* 29F0 */ 0x49, 0x6E, 0x64, 0x75, 0x73, 0x74, 0x72, 0x79, 0x20, 0x45, 0x6E, 0x74, 0x65, 0x72, 0x70, 0x72, // Industry Enterpr + /* 2A00 */ 0x69, 0x73, 0x65, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x38, 0x20, 0x45, 0x6E, // ise.Windows 8 En + /* 2A10 */ 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, // terprise.Windows + /* 2A20 */ 0x20, 0x38, 0x20, 0x45, 0x6E, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x20, 0x4E, 0x00, // 8 Enterprise N. + /* 2A30 */ 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x38, 0x20, 0x50, 0x72, 0x6F, 0x66, 0x65, 0x73, // Windows 8 Profes + /* 2A40 */ 0x73, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x38, // sional.Windows 8 + /* 2A50 */ 0x20, 0x50, 0x72, 0x6F, 0x66, 0x65, 0x73, 0x73, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x4E, 0x00, // Professional N. + /* 2A60 */ 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x38, 0x2E, 0x31, 0x20, 0x43, 0x6F, 0x72, 0x65, // Windows 8.1 Core + /* 2A70 */ 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x38, 0x2E, 0x31, 0x20, 0x43, 0x6F, 0x72, // .Windows 8.1 Cor + /* 2A80 */ 0x65, 0x20, 0x41, 0x52, 0x4D, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x38, 0x2E, // e ARM.Windows 8. + /* 2A90 */ 0x31, 0x20, 0x43, 0x6F, 0x72, 0x65, 0x20, 0x43, 0x6F, 0x75, 0x6E, 0x74, 0x72, 0x79, 0x20, 0x53, // 1 Core Country S + /* 2AA0 */ 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, // pecific.Windows + /* 2AB0 */ 0x38, 0x2E, 0x31, 0x20, 0x43, 0x6F, 0x72, 0x65, 0x20, 0x4E, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, // 8.1 Core N.Windo + /* 2AC0 */ 0x77, 0x73, 0x20, 0x38, 0x2E, 0x31, 0x20, 0x43, 0x6F, 0x72, 0x65, 0x20, 0x53, 0x69, 0x6E, 0x67, // ws 8.1 Core Sing + /* 2AD0 */ 0x6C, 0x65, 0x20, 0x4C, 0x61, 0x6E, 0x67, 0x75, 0x61, 0x67, 0x65, 0x00, 0x57, 0x69, 0x6E, 0x64, // le Language.Wind + /* 2AE0 */ 0x6F, 0x77, 0x73, 0x20, 0x38, 0x2E, 0x31, 0x20, 0x50, 0x72, 0x6F, 0x66, 0x65, 0x73, 0x73, 0x69, // ows 8.1 Professi + /* 2AF0 */ 0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x53, 0x74, 0x75, 0x64, 0x65, 0x6E, 0x74, 0x00, 0x57, 0x69, 0x6E, // onal Student.Win + /* 2B00 */ 0x64, 0x6F, 0x77, 0x73, 0x20, 0x38, 0x2E, 0x31, 0x20, 0x50, 0x72, 0x6F, 0x66, 0x65, 0x73, 0x73, // dows 8.1 Profess + /* 2B10 */ 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x53, 0x74, 0x75, 0x64, 0x65, 0x6E, 0x74, 0x20, 0x4E, 0x00, // ional Student N. + /* 2B20 */ 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x38, 0x2E, 0x31, 0x20, 0x50, 0x72, 0x6F, 0x66, // Windows 8.1 Prof + /* 2B30 */ 0x65, 0x73, 0x73, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x57, 0x4D, 0x43, 0x00, 0x57, 0x69, 0x6E, // essional WMC.Win + /* 2B40 */ 0x64, 0x6F, 0x77, 0x73, 0x20, 0x38, 0x2E, 0x31, 0x20, 0x43, 0x6F, 0x72, 0x65, 0x20, 0x43, 0x6F, // dows 8.1 Core Co + /* 2B50 */ 0x6E, 0x6E, 0x65, 0x63, 0x74, 0x65, 0x64, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, // nnected.Windows + /* 2B60 */ 0x38, 0x2E, 0x31, 0x20, 0x43, 0x6F, 0x72, 0x65, 0x20, 0x43, 0x6F, 0x6E, 0x6E, 0x65, 0x63, 0x74, // 8.1 Core Connect + /* 2B70 */ 0x65, 0x64, 0x20, 0x43, 0x6F, 0x75, 0x6E, 0x74, 0x72, 0x79, 0x20, 0x53, 0x70, 0x65, 0x63, 0x69, // ed Country Speci + /* 2B80 */ 0x66, 0x69, 0x63, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x38, 0x2E, 0x31, 0x20, // fic.Windows 8.1 + /* 2B90 */ 0x43, 0x6F, 0x72, 0x65, 0x20, 0x43, 0x6F, 0x6E, 0x6E, 0x65, 0x63, 0x74, 0x65, 0x64, 0x20, 0x4E, // Core Connected N + /* 2BA0 */ 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x38, 0x2E, 0x31, 0x20, 0x43, 0x6F, 0x72, // .Windows 8.1 Cor + /* 2BB0 */ 0x65, 0x20, 0x43, 0x6F, 0x6E, 0x6E, 0x65, 0x63, 0x74, 0x65, 0x64, 0x20, 0x53, 0x69, 0x6E, 0x67, // e Connected Sing + /* 2BC0 */ 0x6C, 0x65, 0x20, 0x4C, 0x61, 0x6E, 0x67, 0x75, 0x61, 0x67, 0x65, 0x00, 0x57, 0x69, 0x6E, 0x64, // le Language.Wind + /* 2BD0 */ 0x6F, 0x77, 0x73, 0x20, 0x38, 0x2E, 0x31, 0x20, 0x45, 0x6E, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, // ows 8.1 Enterpri + /* 2BE0 */ 0x73, 0x65, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x38, 0x2E, 0x31, 0x20, 0x45, // se.Windows 8.1 E + /* 2BF0 */ 0x6E, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x20, 0x4E, 0x00, 0x57, 0x69, 0x6E, 0x64, // nterprise N.Wind + /* 2C00 */ 0x6F, 0x77, 0x73, 0x20, 0x38, 0x2E, 0x31, 0x20, 0x50, 0x72, 0x6F, 0x66, 0x65, 0x73, 0x73, 0x69, // ows 8.1 Professi + /* 2C10 */ 0x6F, 0x6E, 0x61, 0x6C, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x38, 0x2E, 0x31, // onal.Windows 8.1 + /* 2C20 */ 0x20, 0x50, 0x72, 0x6F, 0x66, 0x65, 0x73, 0x73, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x4E, 0x00, // Professional N. + /* 2C30 */ 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x38, 0x2E, 0x31, 0x20, 0x45, 0x6D, 0x62, 0x65, // Windows 8.1 Embe + /* 2C40 */ 0x64, 0x64, 0x65, 0x64, 0x20, 0x49, 0x6E, 0x64, 0x75, 0x73, 0x74, 0x72, 0x79, 0x20, 0x50, 0x72, // dded Industry Pr + /* 2C50 */ 0x6F, 0x66, 0x65, 0x73, 0x73, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, // ofessional.Windo + /* 2C60 */ 0x77, 0x73, 0x20, 0x38, 0x2E, 0x31, 0x20, 0x45, 0x6D, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x20, // ws 8.1 Embedded + /* 2C70 */ 0x49, 0x6E, 0x64, 0x75, 0x73, 0x74, 0x72, 0x79, 0x20, 0x41, 0x75, 0x74, 0x6F, 0x6D, 0x6F, 0x74, // Industry Automot + /* 2C80 */ 0x69, 0x76, 0x65, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x38, 0x2E, 0x31, 0x20, // ive.Windows 8.1 + /* 2C90 */ 0x45, 0x6D, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x20, 0x49, 0x6E, 0x64, 0x75, 0x73, 0x74, 0x72, // Embedded Industr + /* 2CA0 */ 0x79, 0x20, 0x45, 0x6E, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x00, 0x57, 0x69, 0x6E, // y Enterprise.Win + /* 2CB0 */ 0x64, 0x6F, 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, 0x45, 0x6E, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, // dows 10 Enterpri + /* 2CC0 */ 0x73, 0x65, 0x20, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, // se Preview.Windo + /* 2CD0 */ 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, 0x50, 0x72, 0x6F, 0x66, 0x65, 0x73, 0x73, 0x69, 0x6F, 0x6E, // ws 10 Profession + /* 2CE0 */ 0x61, 0x6C, 0x20, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, // al Preview.Windo + /* 2CF0 */ 0x77, 0x73, 0x20, 0x31, 0x30, 0x20, 0x50, 0x72, 0x6F, 0x66, 0x65, 0x73, 0x73, 0x69, 0x6F, 0x6E, // ws 10 Profession + /* 2D00 */ 0x61, 0x6C, 0x20, 0x57, 0x4D, 0x43, 0x20, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x00, 0x57, // al WMC Preview.W + /* 2D10 */ 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x38, 0x2E, 0x78, 0x20, 0x50, 0x72, 0x65, 0x76, 0x69, // indows 8.x Previ + /* 2D20 */ 0x65, 0x77, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x38, 0x2E, 0x78, 0x20, 0x50, // ew.Windows 8.x P + /* 2D30 */ 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x20, 0x41, 0x52, 0x4D, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, // review ARM.Windo + /* 2D40 */ 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x30, 0x38, 0x20, 0x57, // ws Server 2008 W + /* 2D50 */ 0x65, 0x62, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, // eb.Windows Serve + /* 2D60 */ 0x72, 0x20, 0x32, 0x30, 0x30, 0x38, 0x20, 0x43, 0x6F, 0x6D, 0x70, 0x75, 0x74, 0x65, 0x20, 0x43, // r 2008 Compute C + /* 2D70 */ 0x6C, 0x75, 0x73, 0x74, 0x65, 0x72, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, // luster.Windows S + /* 2D80 */ 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x30, 0x38, 0x20, 0x53, 0x74, 0x61, 0x6E, 0x64, // erver 2008 Stand + /* 2D90 */ 0x61, 0x72, 0x64, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, // ard.Windows Serv + /* 2DA0 */ 0x65, 0x72, 0x20, 0x32, 0x30, 0x30, 0x38, 0x20, 0x53, 0x74, 0x61, 0x6E, 0x64, 0x61, 0x72, 0x64, // er 2008 Standard + /* 2DB0 */ 0x20, 0x77, 0x69, 0x74, 0x68, 0x6F, 0x75, 0x74, 0x20, 0x48, 0x79, 0x70, 0x65, 0x72, 0x2D, 0x56, // without Hyper-V + /* 2DC0 */ 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, // .Windows Server + /* 2DD0 */ 0x32, 0x30, 0x30, 0x38, 0x20, 0x45, 0x6E, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x00, // 2008 Enterprise. + /* 2DE0 */ 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, // Windows Server 2 + /* 2DF0 */ 0x30, 0x30, 0x38, 0x20, 0x45, 0x6E, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x20, 0x77, // 008 Enterprise w + /* 2E00 */ 0x69, 0x74, 0x68, 0x6F, 0x75, 0x74, 0x20, 0x48, 0x79, 0x70, 0x65, 0x72, 0x2D, 0x56, 0x00, 0x57, // ithout Hyper-V.W + /* 2E10 */ 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, // indows Server 20 + /* 2E20 */ 0x30, 0x38, 0x20, 0x44, 0x61, 0x74, 0x61, 0x63, 0x65, 0x6E, 0x74, 0x65, 0x72, 0x00, 0x57, 0x69, // 08 Datacenter.Wi + /* 2E30 */ 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x30, // ndows Server 200 + /* 2E40 */ 0x38, 0x20, 0x44, 0x61, 0x74, 0x61, 0x63, 0x65, 0x6E, 0x74, 0x65, 0x72, 0x20, 0x77, 0x69, 0x74, // 8 Datacenter wit + /* 2E50 */ 0x68, 0x6F, 0x75, 0x74, 0x20, 0x48, 0x79, 0x70, 0x65, 0x72, 0x2D, 0x56, 0x00, 0x57, 0x69, 0x6E, // hout Hyper-V.Win + /* 2E60 */ 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x30, 0x38, // dows Server 2008 + /* 2E70 */ 0x20, 0x66, 0x6F, 0x72, 0x20, 0x49, 0x74, 0x61, 0x6E, 0x69, 0x75, 0x6D, 0x00, 0x57, 0x69, 0x6E, // for Itanium.Win + /* 2E80 */ 0x64, 0x6F, 0x77, 0x73, 0x20, 0x4D, 0x75, 0x6C, 0x74, 0x69, 0x50, 0x6F, 0x69, 0x6E, 0x74, 0x20, // dows MultiPoint + /* 2E90 */ 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x31, 0x30, 0x00, 0x57, 0x69, 0x6E, 0x64, // Server 2010.Wind + /* 2EA0 */ 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x30, 0x38, 0x20, // ows Server 2008 + /* 2EB0 */ 0x52, 0x32, 0x20, 0x57, 0x65, 0x62, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, // R2 Web.Windows S + /* 2EC0 */ 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x30, 0x38, 0x20, 0x52, 0x32, 0x20, 0x48, 0x50, // erver 2008 R2 HP + /* 2ED0 */ 0x43, 0x20, 0x45, 0x64, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, // C Edition.Window + /* 2EE0 */ 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x30, 0x38, 0x20, 0x52, 0x32, // s Server 2008 R2 + /* 2EF0 */ 0x20, 0x53, 0x74, 0x61, 0x6E, 0x64, 0x61, 0x72, 0x64, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, // Standard.Window + /* 2F00 */ 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x30, 0x38, 0x20, 0x52, 0x32, // s Server 2008 R2 + /* 2F10 */ 0x20, 0x45, 0x6E, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x00, 0x57, 0x69, 0x6E, 0x64, // Enterprise.Wind + /* 2F20 */ 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x30, 0x38, 0x20, // ows Server 2008 + /* 2F30 */ 0x52, 0x32, 0x20, 0x44, 0x61, 0x74, 0x61, 0x63, 0x65, 0x6E, 0x74, 0x65, 0x72, 0x00, 0x57, 0x69, // R2 Datacenter.Wi + /* 2F40 */ 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x30, // ndows Server 200 + /* 2F50 */ 0x38, 0x20, 0x52, 0x32, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x49, 0x74, 0x61, 0x6E, 0x69, 0x75, 0x6D, // 8 R2 for Itanium + /* 2F60 */ 0x20, 0x45, 0x6E, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x00, 0x57, 0x69, 0x6E, 0x64, // Enterprise.Wind + /* 2F70 */ 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x31, 0x32, 0x20, // ows Server 2012 + /* 2F80 */ 0x44, 0x61, 0x74, 0x61, 0x63, 0x65, 0x6E, 0x74, 0x65, 0x72, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, // Datacenter.Windo + /* 2F90 */ 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x31, 0x32, 0x20, 0x4D, // ws Server 2012 M + /* 2FA0 */ 0x75, 0x6C, 0x74, 0x69, 0x50, 0x6F, 0x69, 0x6E, 0x74, 0x20, 0x50, 0x72, 0x65, 0x6D, 0x69, 0x75, // ultiPoint Premiu + /* 2FB0 */ 0x6D, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, // m.Windows Server + /* 2FC0 */ 0x20, 0x32, 0x30, 0x31, 0x32, 0x20, 0x4D, 0x75, 0x6C, 0x74, 0x69, 0x50, 0x6F, 0x69, 0x6E, 0x74, // 2012 MultiPoint + /* 2FD0 */ 0x20, 0x53, 0x74, 0x61, 0x6E, 0x64, 0x61, 0x72, 0x64, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, // Standard.Window + /* 2FE0 */ 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x31, 0x32, 0x20, 0x53, 0x74, // s Server 2012 St + /* 2FF0 */ 0x61, 0x6E, 0x64, 0x61, 0x72, 0x64, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, // andard.Windows S + /* 3000 */ 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x31, 0x32, 0x20, 0x52, 0x32, 0x20, 0x43, 0x6C, // erver 2012 R2 Cl + /* 3010 */ 0x6F, 0x75, 0x64, 0x20, 0x53, 0x74, 0x6F, 0x72, 0x61, 0x67, 0x65, 0x00, 0x57, 0x69, 0x6E, 0x64, // oud Storage.Wind + /* 3020 */ 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x31, 0x32, 0x20, // ows Server 2012 + /* 3030 */ 0x52, 0x32, 0x20, 0x44, 0x61, 0x74, 0x61, 0x63, 0x65, 0x6E, 0x74, 0x65, 0x72, 0x00, 0x57, 0x69, // R2 Datacenter.Wi + /* 3040 */ 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x31, // ndows Server 201 + /* 3050 */ 0x32, 0x20, 0x52, 0x32, 0x20, 0x45, 0x73, 0x73, 0x65, 0x6E, 0x74, 0x69, 0x61, 0x6C, 0x73, 0x00, // 2 R2 Essentials. + /* 3060 */ 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, // Windows Server 2 + /* 3070 */ 0x30, 0x31, 0x32, 0x20, 0x52, 0x32, 0x20, 0x53, 0x74, 0x61, 0x6E, 0x64, 0x61, 0x72, 0x64, 0x00, // 012 R2 Standard. + /* 3080 */ 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, // Windows Server 2 + /* 3090 */ 0x30, 0x31, 0x36, 0x20, 0x41, 0x7A, 0x75, 0x72, 0x65, 0x20, 0x43, 0x6F, 0x72, 0x65, 0x00, 0x57, // 016 Azure Core.W + /* 30A0 */ 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, // indows Server 20 + /* 30B0 */ 0x31, 0x36, 0x20, 0x43, 0x6C, 0x6F, 0x75, 0x64, 0x20, 0x53, 0x74, 0x6F, 0x72, 0x61, 0x67, 0x65, // 16 Cloud Storage + /* 30C0 */ 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, // .Windows Server + /* 30D0 */ 0x32, 0x30, 0x31, 0x36, 0x20, 0x44, 0x61, 0x74, 0x61, 0x63, 0x65, 0x6E, 0x74, 0x65, 0x72, 0x00, // 2016 Datacenter. + /* 30E0 */ 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, // Windows Server 2 + /* 30F0 */ 0x30, 0x31, 0x36, 0x20, 0x45, 0x73, 0x73, 0x65, 0x6E, 0x74, 0x69, 0x61, 0x6C, 0x73, 0x00, 0x57, // 016 Essentials.W + /* 3100 */ 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, // indows Server 20 + /* 3110 */ 0x31, 0x36, 0x20, 0x53, 0x74, 0x61, 0x6E, 0x64, 0x61, 0x72, 0x64, 0x00, 0x57, 0x69, 0x6E, 0x64, // 16 Standard.Wind + /* 3120 */ 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x31, 0x36, 0x20, // ows Server 2016 + /* 3130 */ 0x41, 0x52, 0x4D, 0x36, 0x34, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, // ARM64.Windows Se + /* 3140 */ 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x31, 0x36, 0x20, 0x44, 0x61, 0x74, 0x61, 0x63, 0x65, // rver 2016 Datace + /* 3150 */ 0x6E, 0x74, 0x65, 0x72, 0x20, 0x28, 0x53, 0x65, 0x6D, 0x69, 0x2D, 0x41, 0x6E, 0x6E, 0x75, 0x61, // nter (Semi-Annua + /* 3160 */ 0x6C, 0x20, 0x43, 0x68, 0x61, 0x6E, 0x6E, 0x65, 0x6C, 0x29, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, // l Channel).Windo + /* 3170 */ 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x31, 0x36, 0x20, 0x53, // ws Server 2016 S + /* 3180 */ 0x74, 0x61, 0x6E, 0x64, 0x61, 0x72, 0x64, 0x20, 0x28, 0x53, 0x65, 0x6D, 0x69, 0x2D, 0x41, 0x6E, // tandard (Semi-An + /* 3190 */ 0x6E, 0x75, 0x61, 0x6C, 0x20, 0x43, 0x68, 0x61, 0x6E, 0x6E, 0x65, 0x6C, 0x29, 0x00, 0x57, 0x69, // nual Channel).Wi + /* 31A0 */ 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x32, 0x30, 0x31, // ndows Server 201 + /* 31B0 */ 0x36, 0x20, 0x44, 0x61, 0x74, 0x61, 0x63, 0x65, 0x6E, 0x74, 0x65, 0x72, 0x20, 0x50, 0x72, 0x65, // 6 Datacenter Pre + /* 31C0 */ 0x76, 0x69, 0x65, 0x77, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x56, 0x69, 0x73, // view.Windows Vis + /* 31D0 */ 0x74, 0x61, 0x20, 0x42, 0x75, 0x73, 0x69, 0x6E, 0x65, 0x73, 0x73, 0x00, 0x57, 0x69, 0x6E, 0x64, // ta Business.Wind + /* 31E0 */ 0x6F, 0x77, 0x73, 0x20, 0x56, 0x69, 0x73, 0x74, 0x61, 0x20, 0x42, 0x75, 0x73, 0x69, 0x6E, 0x65, // ows Vista Busine + /* 31F0 */ 0x73, 0x73, 0x20, 0x4E, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x56, 0x69, 0x73, // ss N.Windows Vis + /* 3200 */ 0x74, 0x61, 0x20, 0x45, 0x6E, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x00, 0x57, 0x69, // ta Enterprise.Wi + /* 3210 */ 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x56, 0x69, 0x73, 0x74, 0x61, 0x20, 0x45, 0x6E, 0x74, 0x65, // ndows Vista Ente + /* 3220 */ 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x20, 0x4E, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, // rprise N.Office + /* 3230 */ 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x20, 0x32, 0x30, 0x31, 0x30, 0x00, 0x4F, 0x66, 0x66, 0x69, // Access 2010.Offi + /* 3240 */ 0x63, 0x65, 0x20, 0x45, 0x78, 0x63, 0x65, 0x6C, 0x20, 0x32, 0x30, 0x31, 0x30, 0x00, 0x4F, 0x66, // ce Excel 2010.Of + /* 3250 */ 0x66, 0x69, 0x63, 0x65, 0x20, 0x47, 0x72, 0x6F, 0x6F, 0x76, 0x65, 0x20, 0x32, 0x30, 0x31, 0x30, // fice Groove 2010 + /* 3260 */ 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x49, 0x6E, 0x66, 0x6F, 0x50, 0x61, 0x74, 0x68, // .Office InfoPath + /* 3270 */ 0x20, 0x32, 0x30, 0x31, 0x30, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x4D, 0x6F, 0x6E, // 2010.Office Mon + /* 3280 */ 0x64, 0x6F, 0x20, 0x31, 0x20, 0x32, 0x30, 0x31, 0x30, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, // do 1 2010.Office + /* 3290 */ 0x20, 0x4D, 0x6F, 0x6E, 0x64, 0x6F, 0x20, 0x32, 0x20, 0x32, 0x30, 0x31, 0x30, 0x00, 0x4F, 0x66, // Mondo 2 2010.Of + /* 32A0 */ 0x66, 0x69, 0x63, 0x65, 0x20, 0x4F, 0x6E, 0x65, 0x4E, 0x6F, 0x74, 0x65, 0x20, 0x32, 0x30, 0x31, // fice OneNote 201 + /* 32B0 */ 0x30, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x4F, 0x75, 0x74, 0x4C, 0x6F, 0x6F, 0x6B, // 0.Office OutLook + /* 32C0 */ 0x20, 0x32, 0x30, 0x31, 0x30, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x50, 0x6F, 0x77, // 2010.Office Pow + /* 32D0 */ 0x65, 0x72, 0x50, 0x6F, 0x69, 0x6E, 0x74, 0x20, 0x32, 0x30, 0x31, 0x30, 0x00, 0x4F, 0x66, 0x66, // erPoint 2010.Off + /* 32E0 */ 0x69, 0x63, 0x65, 0x20, 0x50, 0x72, 0x6F, 0x66, 0x65, 0x73, 0x73, 0x69, 0x6F, 0x6E, 0x61, 0x6C, // ice Professional + /* 32F0 */ 0x20, 0x50, 0x6C, 0x75, 0x73, 0x20, 0x32, 0x30, 0x31, 0x30, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, // Plus 2010.Offic + /* 3300 */ 0x65, 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, 0x63, 0x74, 0x20, 0x50, 0x72, 0x6F, 0x20, 0x32, 0x30, // e Project Pro 20 + /* 3310 */ 0x31, 0x30, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, 0x63, // 10.Office Projec + /* 3320 */ 0x74, 0x20, 0x53, 0x74, 0x61, 0x6E, 0x64, 0x61, 0x72, 0x64, 0x20, 0x32, 0x30, 0x31, 0x30, 0x00, // t Standard 2010. + /* 3330 */ 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x50, 0x75, 0x62, 0x6C, 0x69, 0x73, 0x68, 0x65, 0x72, // Office Publisher + /* 3340 */ 0x20, 0x32, 0x30, 0x31, 0x30, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x53, 0x6D, 0x61, // 2010.Office Sma + /* 3350 */ 0x6C, 0x6C, 0x20, 0x42, 0x75, 0x73, 0x69, 0x6E, 0x65, 0x73, 0x73, 0x20, 0x42, 0x61, 0x73, 0x69, // ll Business Basi + /* 3360 */ 0x63, 0x73, 0x20, 0x32, 0x30, 0x31, 0x30, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x53, // cs 2010.Office S + /* 3370 */ 0x74, 0x61, 0x6E, 0x64, 0x61, 0x72, 0x64, 0x20, 0x32, 0x30, 0x31, 0x30, 0x00, 0x4F, 0x66, 0x66, // tandard 2010.Off + /* 3380 */ 0x69, 0x63, 0x65, 0x20, 0x56, 0x69, 0x73, 0x69, 0x6F, 0x20, 0x50, 0x72, 0x65, 0x6D, 0x69, 0x75, // ice Visio Premiu + /* 3390 */ 0x6D, 0x20, 0x32, 0x30, 0x31, 0x30, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x56, 0x69, // m 2010.Office Vi + /* 33A0 */ 0x73, 0x69, 0x6F, 0x20, 0x50, 0x72, 0x6F, 0x20, 0x32, 0x30, 0x31, 0x30, 0x00, 0x4F, 0x66, 0x66, // sio Pro 2010.Off + /* 33B0 */ 0x69, 0x63, 0x65, 0x20, 0x56, 0x69, 0x73, 0x69, 0x6F, 0x20, 0x53, 0x74, 0x61, 0x6E, 0x64, 0x61, // ice Visio Standa + /* 33C0 */ 0x72, 0x64, 0x20, 0x32, 0x30, 0x31, 0x30, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x57, // rd 2010.Office W + /* 33D0 */ 0x6F, 0x72, 0x64, 0x20, 0x32, 0x30, 0x31, 0x30, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, // ord 2010.Office + /* 33E0 */ 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x20, 0x32, 0x30, 0x31, 0x33, 0x00, 0x4F, 0x66, 0x66, 0x69, // Access 2013.Offi + /* 33F0 */ 0x63, 0x65, 0x20, 0x45, 0x78, 0x63, 0x65, 0x6C, 0x20, 0x32, 0x30, 0x31, 0x33, 0x00, 0x4F, 0x66, // ce Excel 2013.Of + /* 3400 */ 0x66, 0x69, 0x63, 0x65, 0x20, 0x49, 0x6E, 0x66, 0x6F, 0x50, 0x61, 0x74, 0x68, 0x20, 0x32, 0x30, // fice InfoPath 20 + /* 3410 */ 0x31, 0x33, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x4C, 0x79, 0x6E, 0x63, 0x20, 0x32, // 13.Office Lync 2 + /* 3420 */ 0x30, 0x31, 0x33, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x4D, 0x6F, 0x6E, 0x64, 0x6F, // 013.Office Mondo + /* 3430 */ 0x20, 0x32, 0x30, 0x31, 0x33, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x4F, 0x6E, 0x65, // 2013.Office One + /* 3440 */ 0x4E, 0x6F, 0x74, 0x65, 0x20, 0x32, 0x30, 0x31, 0x33, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, // Note 2013.Office + /* 3450 */ 0x20, 0x4F, 0x75, 0x74, 0x4C, 0x6F, 0x6F, 0x6B, 0x20, 0x32, 0x30, 0x31, 0x33, 0x00, 0x4F, 0x66, // OutLook 2013.Of + /* 3460 */ 0x66, 0x69, 0x63, 0x65, 0x20, 0x50, 0x6F, 0x77, 0x65, 0x72, 0x50, 0x6F, 0x69, 0x6E, 0x74, 0x20, // fice PowerPoint + /* 3470 */ 0x32, 0x30, 0x31, 0x33, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x50, 0x72, 0x6F, 0x66, // 2013.Office Prof + /* 3480 */ 0x65, 0x73, 0x73, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x50, 0x6C, 0x75, 0x73, 0x20, 0x32, 0x30, // essional Plus 20 + /* 3490 */ 0x31, 0x33, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, 0x63, // 13.Office Projec + /* 34A0 */ 0x74, 0x20, 0x50, 0x72, 0x6F, 0x20, 0x32, 0x30, 0x31, 0x33, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, // t Pro 2013.Offic + /* 34B0 */ 0x65, 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, 0x63, 0x74, 0x20, 0x53, 0x74, 0x61, 0x6E, 0x64, 0x61, // e Project Standa + /* 34C0 */ 0x72, 0x64, 0x20, 0x32, 0x30, 0x31, 0x33, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x50, // rd 2013.Office P + /* 34D0 */ 0x75, 0x62, 0x6C, 0x69, 0x73, 0x68, 0x65, 0x72, 0x20, 0x32, 0x30, 0x31, 0x33, 0x00, 0x4F, 0x66, // ublisher 2013.Of + /* 34E0 */ 0x66, 0x69, 0x63, 0x65, 0x20, 0x53, 0x74, 0x61, 0x6E, 0x64, 0x61, 0x72, 0x64, 0x20, 0x32, 0x30, // fice Standard 20 + /* 34F0 */ 0x31, 0x33, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x56, 0x69, 0x73, 0x69, 0x6F, 0x20, // 13.Office Visio + /* 3500 */ 0x50, 0x72, 0x6F, 0x20, 0x32, 0x30, 0x31, 0x33, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, // Pro 2013.Office + /* 3510 */ 0x56, 0x69, 0x73, 0x69, 0x6F, 0x20, 0x53, 0x74, 0x61, 0x6E, 0x64, 0x61, 0x72, 0x64, 0x20, 0x32, // Visio Standard 2 + /* 3520 */ 0x30, 0x31, 0x33, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x57, 0x6F, 0x72, 0x64, 0x20, // 013.Office Word + /* 3530 */ 0x32, 0x30, 0x31, 0x33, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x41, 0x63, 0x63, 0x65, // 2013.Office Acce + /* 3540 */ 0x73, 0x73, 0x20, 0x32, 0x30, 0x31, 0x33, 0x20, 0x28, 0x50, 0x72, 0x65, 0x2D, 0x52, 0x65, 0x6C, // ss 2013 (Pre-Rel + /* 3550 */ 0x65, 0x61, 0x73, 0x65, 0x29, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x45, 0x78, 0x63, // ease).Office Exc + /* 3560 */ 0x65, 0x6C, 0x20, 0x32, 0x30, 0x31, 0x33, 0x20, 0x28, 0x50, 0x72, 0x65, 0x2D, 0x52, 0x65, 0x6C, // el 2013 (Pre-Rel + /* 3570 */ 0x65, 0x61, 0x73, 0x65, 0x29, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x47, 0x72, 0x6F, // ease).Office Gro + /* 3580 */ 0x6F, 0x76, 0x65, 0x20, 0x32, 0x30, 0x31, 0x33, 0x20, 0x28, 0x50, 0x72, 0x65, 0x2D, 0x52, 0x65, // ove 2013 (Pre-Re + /* 3590 */ 0x6C, 0x65, 0x61, 0x73, 0x65, 0x29, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x49, 0x6E, // lease).Office In + /* 35A0 */ 0x66, 0x6F, 0x50, 0x61, 0x74, 0x68, 0x20, 0x32, 0x30, 0x31, 0x33, 0x20, 0x28, 0x50, 0x72, 0x65, // foPath 2013 (Pre + /* 35B0 */ 0x2D, 0x52, 0x65, 0x6C, 0x65, 0x61, 0x73, 0x65, 0x29, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, // -Release).Office + /* 35C0 */ 0x20, 0x4C, 0x79, 0x6E, 0x63, 0x20, 0x32, 0x30, 0x31, 0x33, 0x20, 0x28, 0x50, 0x72, 0x65, 0x2D, // Lync 2013 (Pre- + /* 35D0 */ 0x52, 0x65, 0x6C, 0x65, 0x61, 0x73, 0x65, 0x29, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, // Release).Office + /* 35E0 */ 0x4D, 0x6F, 0x6E, 0x64, 0x6F, 0x20, 0x32, 0x30, 0x31, 0x33, 0x20, 0x28, 0x50, 0x72, 0x65, 0x2D, // Mondo 2013 (Pre- + /* 35F0 */ 0x52, 0x65, 0x6C, 0x65, 0x61, 0x73, 0x65, 0x29, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, // Release).Office + /* 3600 */ 0x4F, 0x6E, 0x65, 0x4E, 0x6F, 0x74, 0x65, 0x20, 0x32, 0x30, 0x31, 0x33, 0x20, 0x28, 0x50, 0x72, // OneNote 2013 (Pr + /* 3610 */ 0x65, 0x2D, 0x52, 0x65, 0x6C, 0x65, 0x61, 0x73, 0x65, 0x29, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, // e-Release).Offic + /* 3620 */ 0x65, 0x20, 0x4F, 0x75, 0x74, 0x6C, 0x6F, 0x6F, 0x6B, 0x20, 0x32, 0x30, 0x31, 0x33, 0x20, 0x28, // e Outlook 2013 ( + /* 3630 */ 0x50, 0x72, 0x65, 0x2D, 0x52, 0x65, 0x6C, 0x65, 0x61, 0x73, 0x65, 0x29, 0x00, 0x4F, 0x66, 0x66, // Pre-Release).Off + /* 3640 */ 0x69, 0x63, 0x65, 0x20, 0x50, 0x6F, 0x77, 0x65, 0x72, 0x50, 0x6F, 0x69, 0x6E, 0x74, 0x20, 0x32, // ice PowerPoint 2 + /* 3650 */ 0x30, 0x31, 0x33, 0x20, 0x28, 0x50, 0x72, 0x65, 0x2D, 0x52, 0x65, 0x6C, 0x65, 0x61, 0x73, 0x65, // 013 (Pre-Release + /* 3660 */ 0x29, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x50, 0x72, 0x6F, 0x66, 0x65, 0x73, 0x73, // ).Office Profess + /* 3670 */ 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x50, 0x6C, 0x75, 0x73, 0x20, 0x32, 0x30, 0x31, 0x33, 0x20, // ional Plus 2013 + /* 3680 */ 0x28, 0x50, 0x72, 0x65, 0x2D, 0x52, 0x65, 0x6C, 0x65, 0x61, 0x73, 0x65, 0x29, 0x00, 0x4F, 0x66, // (Pre-Release).Of + /* 3690 */ 0x66, 0x69, 0x63, 0x65, 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, 0x63, 0x74, 0x20, 0x50, 0x72, 0x6F, // fice Project Pro + /* 36A0 */ 0x20, 0x32, 0x30, 0x31, 0x33, 0x20, 0x28, 0x50, 0x72, 0x65, 0x2D, 0x52, 0x65, 0x6C, 0x65, 0x61, // 2013 (Pre-Relea + /* 36B0 */ 0x73, 0x65, 0x29, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, // se).Office Proje + /* 36C0 */ 0x63, 0x74, 0x20, 0x53, 0x74, 0x61, 0x6E, 0x64, 0x61, 0x72, 0x64, 0x20, 0x32, 0x30, 0x31, 0x33, // ct Standard 2013 + /* 36D0 */ 0x20, 0x28, 0x50, 0x72, 0x65, 0x2D, 0x52, 0x65, 0x6C, 0x65, 0x61, 0x73, 0x65, 0x29, 0x00, 0x4F, // (Pre-Release).O + /* 36E0 */ 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x50, 0x75, 0x62, 0x6C, 0x69, 0x73, 0x68, 0x65, 0x72, 0x20, // ffice Publisher + /* 36F0 */ 0x32, 0x30, 0x31, 0x33, 0x20, 0x28, 0x50, 0x72, 0x65, 0x2D, 0x52, 0x65, 0x6C, 0x65, 0x61, 0x73, // 2013 (Pre-Releas + /* 3700 */ 0x65, 0x29, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x56, 0x69, 0x73, 0x69, 0x6F, 0x20, // e).Office Visio + /* 3710 */ 0x50, 0x72, 0x6F, 0x20, 0x32, 0x30, 0x31, 0x33, 0x20, 0x28, 0x50, 0x72, 0x65, 0x2D, 0x52, 0x65, // Pro 2013 (Pre-Re + /* 3720 */ 0x6C, 0x65, 0x61, 0x73, 0x65, 0x29, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x56, 0x69, // lease).Office Vi + /* 3730 */ 0x73, 0x69, 0x6F, 0x20, 0x53, 0x74, 0x61, 0x6E, 0x64, 0x61, 0x72, 0x64, 0x20, 0x32, 0x30, 0x31, // sio Standard 201 + /* 3740 */ 0x33, 0x20, 0x28, 0x50, 0x72, 0x65, 0x2D, 0x52, 0x65, 0x6C, 0x65, 0x61, 0x73, 0x65, 0x29, 0x00, // 3 (Pre-Release). + /* 3750 */ 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x57, 0x6F, 0x72, 0x64, 0x20, 0x32, 0x30, 0x31, 0x33, // Office Word 2013 + /* 3760 */ 0x20, 0x28, 0x50, 0x72, 0x65, 0x2D, 0x52, 0x65, 0x6C, 0x65, 0x61, 0x73, 0x65, 0x29, 0x00, 0x4F, // (Pre-Release).O + /* 3770 */ 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x20, 0x32, 0x30, 0x31, // ffice Access 201 + /* 3780 */ 0x36, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x45, 0x78, 0x63, 0x65, 0x6C, 0x20, 0x32, // 6.Office Excel 2 + /* 3790 */ 0x30, 0x31, 0x36, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x4D, 0x6F, 0x6E, 0x64, 0x6F, // 016.Office Mondo + /* 37A0 */ 0x20, 0x32, 0x30, 0x31, 0x36, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x4D, 0x6F, 0x6E, // 2016.Office Mon + /* 37B0 */ 0x64, 0x6F, 0x20, 0x52, 0x20, 0x32, 0x30, 0x31, 0x36, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, // do R 2016.Office + /* 37C0 */ 0x20, 0x4F, 0x6E, 0x65, 0x4E, 0x6F, 0x74, 0x65, 0x20, 0x32, 0x30, 0x31, 0x36, 0x00, 0x4F, 0x66, // OneNote 2016.Of + /* 37D0 */ 0x66, 0x69, 0x63, 0x65, 0x20, 0x4F, 0x75, 0x74, 0x6C, 0x6F, 0x6F, 0x6B, 0x20, 0x32, 0x30, 0x31, // fice Outlook 201 + /* 37E0 */ 0x36, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x50, 0x6F, 0x77, 0x65, 0x72, 0x70, 0x6F, // 6.Office Powerpo + /* 37F0 */ 0x69, 0x6E, 0x74, 0x20, 0x32, 0x30, 0x31, 0x36, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, // int 2016.Office + /* 3800 */ 0x50, 0x72, 0x6F, 0x66, 0x65, 0x73, 0x73, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x20, 0x50, 0x6C, 0x75, // Professional Plu + /* 3810 */ 0x73, 0x20, 0x32, 0x30, 0x31, 0x36, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x50, 0x72, // s 2016.Office Pr + /* 3820 */ 0x6F, 0x6A, 0x65, 0x63, 0x74, 0x20, 0x50, 0x72, 0x6F, 0x20, 0x32, 0x30, 0x31, 0x36, 0x00, 0x4F, // oject Pro 2016.O + /* 3830 */ 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, 0x63, 0x74, 0x20, 0x50, 0x72, // ffice Project Pr + /* 3840 */ 0x6F, 0x20, 0x32, 0x30, 0x31, 0x36, 0x20, 0x43, 0x32, 0x52, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, // o 2016 C2R.Offic + /* 3850 */ 0x65, 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, 0x63, 0x74, 0x20, 0x53, 0x74, 0x61, 0x6E, 0x64, 0x61, // e Project Standa + /* 3860 */ 0x72, 0x64, 0x20, 0x32, 0x30, 0x31, 0x36, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x50, // rd 2016.Office P + /* 3870 */ 0x72, 0x6F, 0x6A, 0x65, 0x63, 0x74, 0x20, 0x53, 0x74, 0x61, 0x6E, 0x64, 0x61, 0x72, 0x64, 0x20, // roject Standard + /* 3880 */ 0x32, 0x30, 0x31, 0x36, 0x20, 0x43, 0x32, 0x52, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, // 2016 C2R.Office + /* 3890 */ 0x50, 0x75, 0x62, 0x6C, 0x69, 0x73, 0x68, 0x65, 0x72, 0x20, 0x32, 0x30, 0x31, 0x36, 0x00, 0x4F, // Publisher 2016.O + /* 38A0 */ 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x53, 0x6B, 0x79, 0x70, 0x65, 0x20, 0x66, 0x6F, 0x72, 0x20, // ffice Skype for + /* 38B0 */ 0x42, 0x75, 0x73, 0x69, 0x6E, 0x65, 0x73, 0x73, 0x20, 0x32, 0x30, 0x31, 0x36, 0x00, 0x4F, 0x66, // Business 2016.Of + /* 38C0 */ 0x66, 0x69, 0x63, 0x65, 0x20, 0x53, 0x74, 0x61, 0x6E, 0x64, 0x61, 0x72, 0x64, 0x20, 0x32, 0x30, // fice Standard 20 + /* 38D0 */ 0x31, 0x36, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x56, 0x69, 0x73, 0x69, 0x6F, 0x20, // 16.Office Visio + /* 38E0 */ 0x50, 0x72, 0x6F, 0x20, 0x32, 0x30, 0x31, 0x36, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, // Pro 2016.Office + /* 38F0 */ 0x56, 0x69, 0x73, 0x69, 0x6F, 0x20, 0x50, 0x72, 0x6F, 0x20, 0x32, 0x30, 0x31, 0x36, 0x20, 0x43, // Visio Pro 2016 C + /* 3900 */ 0x32, 0x52, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x56, 0x69, 0x73, 0x69, 0x6F, 0x20, // 2R.Office Visio + /* 3910 */ 0x53, 0x74, 0x61, 0x6E, 0x64, 0x61, 0x72, 0x64, 0x20, 0x32, 0x30, 0x31, 0x36, 0x00, 0x4F, 0x66, // Standard 2016.Of + /* 3920 */ 0x66, 0x69, 0x63, 0x65, 0x20, 0x56, 0x69, 0x73, 0x69, 0x6F, 0x20, 0x53, 0x74, 0x61, 0x6E, 0x64, // fice Visio Stand + /* 3930 */ 0x61, 0x72, 0x64, 0x20, 0x32, 0x30, 0x31, 0x36, 0x20, 0x43, 0x32, 0x52, 0x00, 0x4F, 0x66, 0x66, // ard 2016 C2R.Off + /* 3940 */ 0x69, 0x63, 0x65, 0x20, 0x57, 0x6F, 0x72, 0x64, 0x20, 0x32, 0x30, 0x31, 0x36, 0x00, 0x4F, 0x66, // ice Word 2016.Of + /* 3950 */ 0x66, 0x69, 0x63, 0x65, 0x20, 0x50, 0x72, 0x6F, 0x66, 0x65, 0x73, 0x73, 0x69, 0x6F, 0x6E, 0x61, // fice Professiona + /* 3960 */ 0x6C, 0x20, 0x50, 0x6C, 0x75, 0x73, 0x20, 0x32, 0x30, 0x31, 0x39, 0x20, 0x43, 0x32, 0x52, 0x20, // l Plus 2019 C2R + /* 3970 */ 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x50, // Preview.Office P + /* 3980 */ 0x72, 0x6F, 0x6A, 0x65, 0x63, 0x74, 0x20, 0x50, 0x72, 0x6F, 0x20, 0x32, 0x30, 0x31, 0x39, 0x20, // roject Pro 2019 + /* 3990 */ 0x43, 0x32, 0x52, 0x20, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x00, 0x4F, 0x66, 0x66, 0x69, // C2R Preview.Offi + /* 39A0 */ 0x63, 0x65, 0x20, 0x56, 0x69, 0x73, 0x69, 0x6F, 0x20, 0x50, 0x72, 0x6F, 0x20, 0x32, 0x30, 0x31, // ce Visio Pro 201 + /* 39B0 */ 0x39, 0x20, 0x43, 0x32, 0x52, 0x20, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x00, 0x4F, 0x66, // 9 C2R Preview.Of + /* 39C0 */ 0x66, 0x69, 0x63, 0x65, 0x20, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x20, 0x32, 0x30, 0x31, 0x39, // fice Access 2019 + /* 39D0 */ 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x45, 0x78, 0x63, 0x65, 0x6C, 0x20, 0x32, 0x30, // .Office Excel 20 + /* 39E0 */ 0x31, 0x39, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x4F, 0x75, 0x74, 0x6C, 0x6F, 0x6F, // 19.Office Outloo + /* 39F0 */ 0x6B, 0x20, 0x32, 0x30, 0x31, 0x39, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x50, 0x6F, // k 2019.Office Po + /* 3A00 */ 0x77, 0x65, 0x72, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x20, 0x32, 0x30, 0x31, 0x39, 0x00, 0x4F, 0x66, // werpoint 2019.Of + /* 3A10 */ 0x66, 0x69, 0x63, 0x65, 0x20, 0x50, 0x72, 0x6F, 0x66, 0x65, 0x73, 0x73, 0x69, 0x6F, 0x6E, 0x61, // fice Professiona + /* 3A20 */ 0x6C, 0x20, 0x50, 0x6C, 0x75, 0x73, 0x20, 0x32, 0x30, 0x31, 0x39, 0x00, 0x4F, 0x66, 0x66, 0x69, // l Plus 2019.Offi + /* 3A30 */ 0x63, 0x65, 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, 0x63, 0x74, 0x20, 0x50, 0x72, 0x6F, 0x20, 0x32, // ce Project Pro 2 + /* 3A40 */ 0x30, 0x31, 0x39, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x50, 0x72, 0x6F, 0x6A, 0x65, // 019.Office Proje + /* 3A50 */ 0x63, 0x74, 0x20, 0x53, 0x74, 0x61, 0x6E, 0x64, 0x61, 0x72, 0x64, 0x20, 0x32, 0x30, 0x31, 0x39, // ct Standard 2019 + /* 3A60 */ 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x50, 0x75, 0x62, 0x6C, 0x69, 0x73, 0x68, 0x65, // .Office Publishe + /* 3A70 */ 0x72, 0x20, 0x32, 0x30, 0x31, 0x39, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x53, 0x6B, // r 2019.Office Sk + /* 3A80 */ 0x79, 0x70, 0x65, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x42, 0x75, 0x73, 0x69, 0x6E, 0x65, 0x73, 0x73, // ype for Business + /* 3A90 */ 0x20, 0x32, 0x30, 0x31, 0x39, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x53, 0x74, 0x61, // 2019.Office Sta + /* 3AA0 */ 0x6E, 0x64, 0x61, 0x72, 0x64, 0x20, 0x32, 0x30, 0x31, 0x39, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, // ndard 2019.Offic + /* 3AB0 */ 0x65, 0x20, 0x56, 0x69, 0x73, 0x69, 0x6F, 0x20, 0x50, 0x72, 0x6F, 0x20, 0x32, 0x30, 0x31, 0x39, // e Visio Pro 2019 + /* 3AC0 */ 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x20, 0x56, 0x69, 0x73, 0x69, 0x6F, 0x20, 0x53, 0x74, // .Office Visio St + /* 3AD0 */ 0x61, 0x6E, 0x64, 0x61, 0x72, 0x64, 0x20, 0x32, 0x30, 0x31, 0x39, 0x00, 0x4F, 0x66, 0x66, 0x69, // andard 2019.Offi + /* 3AE0 */ 0x63, 0x65, 0x20, 0x57, 0x6F, 0x72, 0x64, 0x20, 0x32, 0x30, 0x31, 0x39, 0x00, // ce Word 2019. +}; + +#elif defined(NO_STRICT_MODES) + +uint8_t DefaultKmsData[] = +{ + /* 0000 */ 0x4B, 0x4D, 0x44, 0x00, 0x00, 0x00, 0x02, 0x00, 0x06, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, // KMD............. + /* 0010 */ 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................ + /* 0020 */ 0x08, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........h....... + /* 0030 */ 0x28, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // (.......(....... + /* 0040 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE8, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ............... + /* 0050 */ 0x00, 0xB5, 0xB2, 0x5B, 0x00, 0x00, 0x00, 0x00, 0xCE, 0x00, 0x00, 0x00, 0xC0, 0x97, 0xD7, 0x20, // .[........ + /* 0060 */ 0xBF, 0xC4, 0x08, 0x22, 0x00, 0x00, 0x00, 0x00, 0x23, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ."....#....... + /* 0070 */ 0x80, 0x4F, 0x3E, 0x4C, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0xC0, 0x7F, 0xDC, 0x0B, // .O>L....`..... + /* 0080 */ 0x7F, 0x6A, 0xFE, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x61, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .j.....a....... + /* 0090 */ 0x00, 0x11, 0x07, 0x51, 0x00, 0x00, 0x00, 0x00, 0xCE, 0x00, 0x00, 0x00, 0x80, 0x8E, 0xF2, 0x0D, // ...Q.......... + /* 00A0 */ 0xFF, 0x3F, 0x42, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x9F, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ?B............. + /* 00B0 */ 0x00, 0x9A, 0x00, 0x56, 0x00, 0x00, 0x00, 0x00, 0xCE, 0x00, 0x00, 0x00, 0x40, 0x17, 0x0C, 0x1A, // ...V.......@... + /* 00C0 */ 0xBF, 0xC8, 0x5B, 0x1B, 0x00, 0x00, 0x00, 0x00, 0xDD, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // [............ + /* 00D0 */ 0x80, 0x33, 0xE4, 0x58, 0x00, 0x00, 0x00, 0x00, 0x12, 0x0F, 0x00, 0x00, 0xC0, 0xE1, 0xE4, 0x00, // .3X......... + /* 00E0 */ 0xFF, 0xC9, 0x9A, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .;............ + /* 00F0 */ 0x00, 0x29, 0xA8, 0x5B, 0x00, 0x00, 0x00, 0x00, 0xCE, 0x00, 0x00, 0x00, 0x80, 0x5A, 0xB2, 0x27, // .)[........Z' + /* 0100 */ 0x7F, 0x87, 0xE3, 0x28, 0x00, 0x00, 0x00, 0x00, 0x34, 0x27, 0xC9, 0x55, 0x82, 0xD6, 0x71, 0x4D, // ..(....4'U.qM + /* 0110 */ 0x98, 0x3E, 0xD6, 0xEC, 0x3F, 0x16, 0x05, 0x9F, 0x5A, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .>?...Z....... + /* 0120 */ 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x81, 0x28, 0xA5, 0x59, 0x89, 0xA9, 0x9D, 0x47, // ...2.....(Y..G + /* 0130 */ 0xAF, 0x46, 0xF2, 0x75, 0xC6, 0x37, 0x06, 0x63, 0x5A, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Fu7.cZ....... + /* 0140 */ 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x01, 0x00, 0x15, 0xCE, 0xF1, 0x0F, 0x89, 0xA9, 0x9D, 0x47, // ............G + /* 0150 */ 0xAF, 0x46, 0xF2, 0x75, 0xC6, 0x37, 0x06, 0x63, 0x5A, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Fu7.cZ....... + /* 0160 */ 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x05, 0x00, 0x23, 0xBF, 0xA0, 0x7B, 0xF5, 0xD0, 0x72, 0x40, // ........#.{r@ + /* 0170 */ 0x91, 0xD9, 0xD5, 0x5A, 0xF5, 0xA4, 0x81, 0xB6, 0x5A, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .Z.Z....... + /* 0180 */ 0x00, 0x00, 0x06, 0x19, 0x00, 0x00, 0x04, 0x00, 0x46, 0xF9, 0x5A, 0xE8, 0x25, 0x2E, 0xB7, 0x47, // ........FZ%.G + /* 0190 */ 0x83, 0xE1, 0xBE, 0xBC, 0xEB, 0xEA, 0xC6, 0x11, 0x5A, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .ᾼ.Z....... + /* 01A0 */ 0x01, 0x00, 0x04, 0x05, 0x00, 0x00, 0x01, 0x00, 0xBF, 0xF1, 0xA6, 0xE6, 0x40, 0x9D, 0xC3, 0x40, // ........@.@ + /* 01B0 */ 0xAA, 0x9F, 0xC7, 0x7B, 0xA2, 0x15, 0x78, 0xC0, 0x5A, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .{.xZ....... + /* 01C0 */ 0x02, 0x00, 0x05, 0x05, 0x00, 0x00, 0x02, 0x00, 0x68, 0x79, 0x4C, 0xAA, 0xDA, 0xB9, 0x80, 0x46, // ........hyLڹ.F + /* 01D0 */ 0x92, 0xB6, 0xAC, 0xB2, 0x5E, 0x2F, 0x86, 0x6C, 0x5A, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .^/.lZ....... + /* 01E0 */ 0x02, 0x00, 0x05, 0x05, 0x00, 0x01, 0x00, 0x00, 0x1B, 0xF6, 0xB5, 0x85, 0x0B, 0x32, 0xE3, 0x4B, // ...........2K + /* 01F0 */ 0x81, 0x4A, 0xB7, 0x6B, 0x2B, 0xFA, 0xFC, 0x82, 0x5A, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .Jk+.Z....... + /* 0200 */ 0x02, 0x00, 0x06, 0x05, 0x00, 0x00, 0x03, 0x00, 0xB1, 0x9E, 0x7D, 0x61, 0x36, 0xEF, 0x82, 0x4F, // .........}a6.O + /* 0210 */ 0x86, 0xE0, 0xA6, 0x5A, 0xE0, 0x7B, 0x96, 0xC6, 0x5A, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .Z{.Z....... + /* 0220 */ 0x02, 0x00, 0x06, 0x05, 0x00, 0x00, 0x05, 0x00, 0x5A, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........Z....... + /* 0230 */ 0x00, 0xB5, 0xB2, 0x5B, 0x00, 0x00, 0x00, 0x00, 0x63, 0x45, 0x00, 0x00, 0x1C, 0x0E, 0x00, 0x00, // .[....cE...... + /* 0240 */ 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5A, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........Z....... + /* 0250 */ 0x80, 0xE2, 0x9F, 0x57, 0x00, 0x00, 0x00, 0x00, 0x39, 0x38, 0x00, 0x00, 0x1C, 0x0E, 0x00, 0x00, // ..W....98...... + /* 0260 */ 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5A, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........Z....... + /* 0270 */ 0x00, 0x7A, 0x60, 0x52, 0x00, 0x00, 0x00, 0x00, 0x80, 0x25, 0x00, 0x00, 0x01, 0x19, 0x00, 0x00, // .z`R.....%...... + /* 0280 */ 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5A, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........Z....... + /* 0290 */ 0x80, 0xD2, 0x89, 0x50, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x23, 0x00, 0x00, 0x32, 0x15, 0x00, 0x00, // ..P....#..2... + /* 02A0 */ 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5A, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........Z....... + /* 02B0 */ 0x80, 0xFC, 0x62, 0x4D, 0x00, 0x00, 0x00, 0x00, 0xB1, 0x1D, 0x00, 0x00, 0x01, 0xD7, 0x00, 0x00, // .bM.......... + /* 02C0 */ 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5A, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........Z....... + /* 02D0 */ 0x00, 0x31, 0x1B, 0x4A, 0x00, 0x00, 0x00, 0x00, 0x72, 0x17, 0x00, 0x00, 0x01, 0xD7, 0x00, 0x00, // .1.J....r...... + /* 02E0 */ 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x33, 0x36, 0x31, 0x32, 0x2D, 0x30, 0x30, // ........03612-00 + /* 02F0 */ 0x32, 0x30, 0x36, 0x2D, 0x35, 0x35, 0x36, 0x2D, 0x31, 0x32, 0x33, 0x37, 0x32, 0x37, 0x2D, 0x30, // 206-556-123727-0 + /* 0300 */ 0x33, 0x2D, 0x31, 0x30, 0x33, 0x33, 0x2D, 0x31, 0x37, 0x37, 0x36, 0x33, 0x2E, 0x30, 0x30, 0x30, // 3-1033-17763.000 + /* 0310 */ 0x30, 0x2D, 0x32, 0x39, 0x37, 0x32, 0x30, 0x31, 0x38, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, // 0-2972018.Window + /* 0320 */ 0x73, 0x00, 0x00, 0x30, 0x33, 0x36, 0x31, 0x32, 0x2D, 0x30, 0x30, 0x30, 0x39, 0x36, 0x2D, 0x31, // s..03612-00096-1 + /* 0330 */ 0x39, 0x39, 0x2D, 0x37, 0x39, 0x39, 0x31, 0x38, 0x38, 0x2D, 0x30, 0x33, 0x2D, 0x31, 0x30, 0x33, // 99-799188-03-103 + /* 0340 */ 0x33, 0x2D, 0x31, 0x37, 0x37, 0x36, 0x33, 0x2E, 0x30, 0x30, 0x30, 0x30, 0x2D, 0x32, 0x39, 0x37, // 3-17763.0000-297 + /* 0350 */ 0x32, 0x30, 0x31, 0x38, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x32, 0x30, 0x31, 0x30, 0x00, // 2018.Office2010. + /* 0360 */ 0x00, 0x30, 0x33, 0x36, 0x31, 0x32, 0x2D, 0x30, 0x30, 0x32, 0x30, 0x36, 0x2D, 0x32, 0x34, 0x30, // .03612-00206-240 + /* 0370 */ 0x2D, 0x37, 0x31, 0x39, 0x36, 0x33, 0x39, 0x2D, 0x30, 0x33, 0x2D, 0x31, 0x30, 0x33, 0x33, 0x2D, // -719639-03-1033- + /* 0380 */ 0x31, 0x37, 0x37, 0x36, 0x33, 0x2E, 0x30, 0x30, 0x30, 0x30, 0x2D, 0x32, 0x39, 0x37, 0x32, 0x30, // 17763.0000-29720 + /* 0390 */ 0x31, 0x38, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x32, 0x30, 0x31, 0x33, 0x00, 0x00, 0x30, // 18.Office2013..0 + /* 03A0 */ 0x33, 0x36, 0x31, 0x32, 0x2D, 0x30, 0x30, 0x32, 0x30, 0x36, 0x2D, 0x34, 0x33, 0x38, 0x2D, 0x30, // 3612-00206-438-0 + /* 03B0 */ 0x30, 0x34, 0x35, 0x33, 0x32, 0x2D, 0x30, 0x33, 0x2D, 0x31, 0x30, 0x33, 0x33, 0x2D, 0x31, 0x37, // 04532-03-1033-17 + /* 03C0 */ 0x37, 0x36, 0x33, 0x2E, 0x30, 0x30, 0x30, 0x30, 0x2D, 0x32, 0x39, 0x37, 0x32, 0x30, 0x31, 0x38, // 763.0000-2972018 + /* 03D0 */ 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x32, 0x30, 0x31, 0x36, 0x00, 0x00, 0x30, 0x33, 0x36, // .Office2016..036 + /* 03E0 */ 0x31, 0x32, 0x2D, 0x30, 0x33, 0x38, 0x35, 0x38, 0x2D, 0x30, 0x35, 0x33, 0x2D, 0x30, 0x38, 0x39, // 12-03858-053-089 + /* 03F0 */ 0x35, 0x31, 0x36, 0x2D, 0x30, 0x33, 0x2D, 0x31, 0x30, 0x33, 0x33, 0x2D, 0x31, 0x37, 0x37, 0x36, // 516-03-1033-1776 + /* 0400 */ 0x33, 0x2E, 0x30, 0x30, 0x30, 0x30, 0x2D, 0x32, 0x39, 0x37, 0x32, 0x30, 0x31, 0x38, 0x00, 0x57, // 3.0000-2972018.W + /* 0410 */ 0x69, 0x6E, 0x43, 0x68, 0x69, 0x6E, 0x61, 0x47, 0x6F, 0x76, 0x00, 0x00, 0x30, 0x33, 0x36, 0x31, // inChinaGov..0361 + /* 0420 */ 0x32, 0x2D, 0x30, 0x30, 0x32, 0x30, 0x36, 0x2D, 0x36, 0x38, 0x34, 0x2D, 0x31, 0x33, 0x37, 0x36, // 2-00206-684-1376 + /* 0430 */ 0x36, 0x39, 0x2D, 0x30, 0x33, 0x2D, 0x31, 0x30, 0x33, 0x33, 0x2D, 0x31, 0x37, 0x37, 0x36, 0x33, // 69-03-1033-17763 + /* 0440 */ 0x2E, 0x30, 0x30, 0x30, 0x30, 0x2D, 0x32, 0x39, 0x37, 0x32, 0x30, 0x31, 0x38, 0x00, 0x4F, 0x66, // .0000-2972018.Of + /* 0450 */ 0x66, 0x69, 0x63, 0x65, 0x32, 0x30, 0x31, 0x39, 0x00, 0x00, 0x55, 0x6E, 0x6B, 0x6E, 0x6F, 0x77, // fice2019..Unknow + /* 0460 */ 0x6E, 0x00, // n. +}; + +#else // !defined(NO_STRICT_MODES) + +uint8_t DefaultKmsData[] = +{ + /* 0000 */ 0x4B, 0x4D, 0x44, 0x00, 0x00, 0x00, 0x02, 0x00, 0x06, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, // KMD............. + /* 0010 */ 0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................ + /* 0020 */ 0x08, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........h....... + /* 0030 */ 0x08, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ................ + /* 0040 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC8, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ............... + /* 0050 */ 0x00, 0xB5, 0xB2, 0x5B, 0x00, 0x00, 0x00, 0x00, 0xCE, 0x00, 0x00, 0x00, 0xC0, 0x97, 0xD7, 0x20, // .[........ + /* 0060 */ 0xBF, 0xC4, 0x08, 0x22, 0x00, 0x00, 0x00, 0x00, 0x03, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ."............ + /* 0070 */ 0x80, 0x4F, 0x3E, 0x4C, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0xC0, 0x7F, 0xDC, 0x0B, // .O>L....`..... + /* 0080 */ 0x7F, 0x6A, 0xFE, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x41, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .j.....A....... + /* 0090 */ 0x00, 0x11, 0x07, 0x51, 0x00, 0x00, 0x00, 0x00, 0xCE, 0x00, 0x00, 0x00, 0x80, 0x8E, 0xF2, 0x0D, // ...Q.......... + /* 00A0 */ 0xFF, 0x3F, 0x42, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ?B............. + /* 00B0 */ 0x00, 0x9A, 0x00, 0x56, 0x00, 0x00, 0x00, 0x00, 0xCE, 0x00, 0x00, 0x00, 0x40, 0x17, 0x0C, 0x1A, // ...V.......@... + /* 00C0 */ 0xBF, 0xC8, 0x5B, 0x1B, 0x00, 0x00, 0x00, 0x00, 0xBD, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // [............ + /* 00D0 */ 0x80, 0x33, 0xE4, 0x58, 0x00, 0x00, 0x00, 0x00, 0x12, 0x0F, 0x00, 0x00, 0xC0, 0xE1, 0xE4, 0x00, // .3X......... + /* 00E0 */ 0xFF, 0xC9, 0x9A, 0x3B, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .;........... + /* 00F0 */ 0x00, 0x29, 0xA8, 0x5B, 0x00, 0x00, 0x00, 0x00, 0xCE, 0x00, 0x00, 0x00, 0x80, 0x5A, 0xB2, 0x27, // .)[........Z' + /* 0100 */ 0x7F, 0x87, 0xE3, 0x28, 0x00, 0x00, 0x00, 0x00, 0x34, 0x27, 0xC9, 0x55, 0x82, 0xD6, 0x71, 0x4D, // ..(....4'U.qM + /* 0110 */ 0x98, 0x3E, 0xD6, 0xEC, 0x3F, 0x16, 0x05, 0x9F, 0x3A, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .>?...:....... + /* 0120 */ 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x81, 0x28, 0xA5, 0x59, 0x89, 0xA9, 0x9D, 0x47, // ...2.....(Y..G + /* 0130 */ 0xAF, 0x46, 0xF2, 0x75, 0xC6, 0x37, 0x06, 0x63, 0x3A, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Fu7.c:....... + /* 0140 */ 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x01, 0x00, 0x15, 0xCE, 0xF1, 0x0F, 0x89, 0xA9, 0x9D, 0x47, // ............G + /* 0150 */ 0xAF, 0x46, 0xF2, 0x75, 0xC6, 0x37, 0x06, 0x63, 0x3A, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Fu7.c:....... + /* 0160 */ 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x05, 0x00, 0xFB, 0xB1, 0x49, 0x84, 0xEA, 0xF0, 0x7A, 0x49, // ........I.zI + /* 0170 */ 0x99, 0xAB, 0x66, 0xCA, 0x96, 0xE9, 0xA0, 0xF5, 0x3A, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .f..:....... + /* 0180 */ 0x00, 0x00, 0x06, 0x05, 0x00, 0x00, 0x00, 0x00, 0x59, 0x56, 0xB1, 0x11, 0x03, 0xE6, 0xF1, 0x4C, // ........YV..L + /* 0190 */ 0x9C, 0x1F, 0xF0, 0xEC, 0x01, 0xB8, 0x18, 0x88, 0x3A, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .....:....... + /* 01A0 */ 0x00, 0x00, 0x06, 0x19, 0x00, 0x00, 0x00, 0x00, 0x36, 0xD6, 0x7C, 0xD2, 0x62, 0x19, 0xE9, 0x44, // ........6|b.D + /* 01B0 */ 0x8B, 0x4F, 0x27, 0xB6, 0xC2, 0x3E, 0xFB, 0x85, 0x3A, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .O'>.:....... + /* 01C0 */ 0x00, 0x00, 0x06, 0x19, 0x00, 0x00, 0x00, 0x00, 0x23, 0xBF, 0xA0, 0x7B, 0xF5, 0xD0, 0x72, 0x40, // ........#.{r@ + /* 01D0 */ 0x91, 0xD9, 0xD5, 0x5A, 0xF5, 0xA4, 0x81, 0xB6, 0x3A, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .Z.:....... + /* 01E0 */ 0x00, 0x00, 0x06, 0x19, 0x00, 0x00, 0x04, 0x00, 0xC0, 0xE3, 0x9F, 0x96, 0xEC, 0xA3, 0x1A, 0x49, // ...........I + /* 01F0 */ 0x9F, 0x25, 0x42, 0x36, 0x05, 0xDE, 0xB3, 0x65, 0x3A, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .%B6.޳e:....... + /* 0200 */ 0x00, 0x00, 0x06, 0x19, 0x00, 0x00, 0x00, 0x00, 0x58, 0x13, 0xC5, 0xE1, 0x3E, 0xFE, 0x03, 0x42, // ........X.>.B + /* 0210 */ 0xA4, 0xA2, 0x3B, 0x6B, 0x20, 0xC9, 0x73, 0x4E, 0x3A, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ;k sN:....... + /* 0220 */ 0x00, 0x00, 0x06, 0x19, 0x01, 0x00, 0x00, 0x00, 0x4F, 0x13, 0xE2, 0x58, 0x11, 0x8E, 0x17, 0x4D, // ........O.X...M + /* 0230 */ 0x9C, 0xB2, 0x91, 0x06, 0x9C, 0x15, 0x11, 0x48, 0x3A, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ......H:....... + /* 0240 */ 0x00, 0x00, 0x06, 0x19, 0x00, 0x00, 0x00, 0x00, 0x19, 0x52, 0xDE, 0x7F, 0xFA, 0xFB, 0x4A, 0x48, // .........R.JH + /* 0250 */ 0x82, 0xC9, 0x34, 0xD1, 0xAD, 0x53, 0xE8, 0x56, 0x3A, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .4ѭSV:....... + /* 0260 */ 0x00, 0x00, 0x04, 0x19, 0x00, 0x00, 0x00, 0x00, 0x3B, 0x7B, 0xB9, 0xBB, 0xA4, 0x8C, 0x28, 0x4A, // ........;{.(J + /* 0270 */ 0x97, 0x17, 0x89, 0xFA, 0xBD, 0x42, 0xC4, 0xAC, 0x3A, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ...BĬ:....... + /* 0280 */ 0x00, 0x00, 0x05, 0x19, 0x01, 0x00, 0x00, 0x00, 0x58, 0xB3, 0x40, 0x3C, 0x48, 0x59, 0xAF, 0x45, // ........X@C + /* 0430 */ 0xB9, 0x0A, 0x39, 0x89, 0x29, 0x23, 0xC6, 0x57, 0x3A, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .9.)#W:....... + /* 0440 */ 0x00, 0x00, 0x06, 0x05, 0x00, 0x01, 0x00, 0x00, 0xDC, 0x64, 0x2A, 0x21, 0xB1, 0x43, 0x3D, 0x4D, // ........d*!C=M + /* 0450 */ 0xA3, 0x0C, 0x2F, 0xC6, 0x9D, 0x20, 0x95, 0xC6, 0x3A, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ./. .:....... + /* 0460 */ 0x00, 0x00, 0x04, 0x19, 0x00, 0x00, 0x00, 0x00, 0x46, 0xF9, 0x5A, 0xE8, 0x25, 0x2E, 0xB7, 0x47, // ........FZ%.G + /* 0470 */ 0x83, 0xE1, 0xBE, 0xBC, 0xEB, 0xEA, 0xC6, 0x11, 0x3A, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .ᾼ.:....... + /* 0480 */ 0x01, 0x00, 0x04, 0x05, 0x00, 0x00, 0x01, 0x00, 0xBF, 0xF1, 0xA6, 0xE6, 0x40, 0x9D, 0xC3, 0x40, // ........@.@ + /* 0490 */ 0xAA, 0x9F, 0xC7, 0x7B, 0xA2, 0x15, 0x78, 0xC0, 0x3A, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .{.x:....... + /* 04A0 */ 0x02, 0x00, 0x05, 0x05, 0x00, 0x00, 0x02, 0x00, 0x68, 0x79, 0x4C, 0xAA, 0xDA, 0xB9, 0x80, 0x46, // ........hyLڹ.F + /* 04B0 */ 0x92, 0xB6, 0xAC, 0xB2, 0x5E, 0x2F, 0x86, 0x6C, 0x3A, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .^/.l:....... + /* 04C0 */ 0x02, 0x00, 0x05, 0x05, 0x00, 0x01, 0x00, 0x00, 0x1B, 0xF6, 0xB5, 0x85, 0x0B, 0x32, 0xE3, 0x4B, // ...........2K + /* 04D0 */ 0x81, 0x4A, 0xB7, 0x6B, 0x2B, 0xFA, 0xFC, 0x82, 0x3A, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .Jk+.:....... + /* 04E0 */ 0x02, 0x00, 0x06, 0x05, 0x00, 0x00, 0x03, 0x00, 0xB1, 0x9E, 0x7D, 0x61, 0x36, 0xEF, 0x82, 0x4F, // .........}a6.O + /* 04F0 */ 0x86, 0xE0, 0xA6, 0x5A, 0xE0, 0x7B, 0x96, 0xC6, 0x3A, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // .Z{.:....... + /* 0500 */ 0x02, 0x00, 0x06, 0x05, 0x00, 0x00, 0x05, 0x00, 0x3A, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........:....... + /* 0510 */ 0x00, 0xB5, 0xB2, 0x5B, 0x00, 0x00, 0x00, 0x00, 0x63, 0x45, 0x00, 0x00, 0x1C, 0x0E, 0x00, 0x00, // .[....cE...... + /* 0520 */ 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3A, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........:....... + /* 0530 */ 0x80, 0xE2, 0x9F, 0x57, 0x00, 0x00, 0x00, 0x00, 0x39, 0x38, 0x00, 0x00, 0x1C, 0x0E, 0x00, 0x00, // ..W....98...... + /* 0540 */ 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3A, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........:....... + /* 0550 */ 0x00, 0x7A, 0x60, 0x52, 0x00, 0x00, 0x00, 0x00, 0x80, 0x25, 0x00, 0x00, 0x01, 0x19, 0x00, 0x00, // .z`R.....%...... + /* 0560 */ 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3A, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........:....... + /* 0570 */ 0x80, 0xD2, 0x89, 0x50, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x23, 0x00, 0x00, 0x32, 0x15, 0x00, 0x00, // ..P....#..2... + /* 0580 */ 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3A, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........:....... + /* 0590 */ 0x80, 0xFC, 0x62, 0x4D, 0x00, 0x00, 0x00, 0x00, 0xB1, 0x1D, 0x00, 0x00, 0x01, 0xD7, 0x00, 0x00, // .bM.......... + /* 05A0 */ 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3A, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........:....... + /* 05B0 */ 0x00, 0x31, 0x1B, 0x4A, 0x00, 0x00, 0x00, 0x00, 0x72, 0x17, 0x00, 0x00, 0x01, 0xD7, 0x00, 0x00, // .1.J....r...... + /* 05C0 */ 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x33, 0x36, 0x31, 0x32, 0x2D, 0x30, 0x30, // ........03612-00 + /* 05D0 */ 0x32, 0x30, 0x36, 0x2D, 0x35, 0x35, 0x36, 0x2D, 0x31, 0x32, 0x33, 0x37, 0x32, 0x37, 0x2D, 0x30, // 206-556-123727-0 + /* 05E0 */ 0x33, 0x2D, 0x31, 0x30, 0x33, 0x33, 0x2D, 0x31, 0x37, 0x37, 0x36, 0x33, 0x2E, 0x30, 0x30, 0x30, // 3-1033-17763.000 + /* 05F0 */ 0x30, 0x2D, 0x32, 0x39, 0x37, 0x32, 0x30, 0x31, 0x38, 0x00, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, // 0-2972018.Window + /* 0600 */ 0x73, 0x00, 0x00, 0x30, 0x33, 0x36, 0x31, 0x32, 0x2D, 0x30, 0x30, 0x30, 0x39, 0x36, 0x2D, 0x31, // s..03612-00096-1 + /* 0610 */ 0x39, 0x39, 0x2D, 0x37, 0x39, 0x39, 0x31, 0x38, 0x38, 0x2D, 0x30, 0x33, 0x2D, 0x31, 0x30, 0x33, // 99-799188-03-103 + /* 0620 */ 0x33, 0x2D, 0x31, 0x37, 0x37, 0x36, 0x33, 0x2E, 0x30, 0x30, 0x30, 0x30, 0x2D, 0x32, 0x39, 0x37, // 3-17763.0000-297 + /* 0630 */ 0x32, 0x30, 0x31, 0x38, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x32, 0x30, 0x31, 0x30, 0x00, // 2018.Office2010. + /* 0640 */ 0x00, 0x30, 0x33, 0x36, 0x31, 0x32, 0x2D, 0x30, 0x30, 0x32, 0x30, 0x36, 0x2D, 0x32, 0x34, 0x30, // .03612-00206-240 + /* 0650 */ 0x2D, 0x37, 0x31, 0x39, 0x36, 0x33, 0x39, 0x2D, 0x30, 0x33, 0x2D, 0x31, 0x30, 0x33, 0x33, 0x2D, // -719639-03-1033- + /* 0660 */ 0x31, 0x37, 0x37, 0x36, 0x33, 0x2E, 0x30, 0x30, 0x30, 0x30, 0x2D, 0x32, 0x39, 0x37, 0x32, 0x30, // 17763.0000-29720 + /* 0670 */ 0x31, 0x38, 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x32, 0x30, 0x31, 0x33, 0x00, 0x00, 0x30, // 18.Office2013..0 + /* 0680 */ 0x33, 0x36, 0x31, 0x32, 0x2D, 0x30, 0x30, 0x32, 0x30, 0x36, 0x2D, 0x34, 0x33, 0x38, 0x2D, 0x30, // 3612-00206-438-0 + /* 0690 */ 0x30, 0x34, 0x35, 0x33, 0x32, 0x2D, 0x30, 0x33, 0x2D, 0x31, 0x30, 0x33, 0x33, 0x2D, 0x31, 0x37, // 04532-03-1033-17 + /* 06A0 */ 0x37, 0x36, 0x33, 0x2E, 0x30, 0x30, 0x30, 0x30, 0x2D, 0x32, 0x39, 0x37, 0x32, 0x30, 0x31, 0x38, // 763.0000-2972018 + /* 06B0 */ 0x00, 0x4F, 0x66, 0x66, 0x69, 0x63, 0x65, 0x32, 0x30, 0x31, 0x36, 0x00, 0x00, 0x30, 0x33, 0x36, // .Office2016..036 + /* 06C0 */ 0x31, 0x32, 0x2D, 0x30, 0x33, 0x38, 0x35, 0x38, 0x2D, 0x30, 0x35, 0x33, 0x2D, 0x30, 0x38, 0x39, // 12-03858-053-089 + /* 06D0 */ 0x35, 0x31, 0x36, 0x2D, 0x30, 0x33, 0x2D, 0x31, 0x30, 0x33, 0x33, 0x2D, 0x31, 0x37, 0x37, 0x36, // 516-03-1033-1776 + /* 06E0 */ 0x33, 0x2E, 0x30, 0x30, 0x30, 0x30, 0x2D, 0x32, 0x39, 0x37, 0x32, 0x30, 0x31, 0x38, 0x00, 0x57, // 3.0000-2972018.W + /* 06F0 */ 0x69, 0x6E, 0x43, 0x68, 0x69, 0x6E, 0x61, 0x47, 0x6F, 0x76, 0x00, 0x00, 0x30, 0x33, 0x36, 0x31, // inChinaGov..0361 + /* 0700 */ 0x32, 0x2D, 0x30, 0x30, 0x32, 0x30, 0x36, 0x2D, 0x36, 0x38, 0x34, 0x2D, 0x31, 0x33, 0x37, 0x36, // 2-00206-684-1376 + /* 0710 */ 0x36, 0x39, 0x2D, 0x30, 0x33, 0x2D, 0x31, 0x30, 0x33, 0x33, 0x2D, 0x31, 0x37, 0x37, 0x36, 0x33, // 69-03-1033-17763 + /* 0720 */ 0x2E, 0x30, 0x30, 0x30, 0x30, 0x2D, 0x32, 0x39, 0x37, 0x32, 0x30, 0x31, 0x38, 0x00, 0x4F, 0x66, // .0000-2972018.Of + /* 0730 */ 0x66, 0x69, 0x63, 0x65, 0x32, 0x30, 0x31, 0x39, 0x00, 0x00, 0x55, 0x6E, 0x6B, 0x6E, 0x6F, 0x77, // fice2019..Unknow + /* 0740 */ 0x6E, 0x00, // n. +}; + +#endif // // !defined(NO_STRICT_MODES) + +__pure size_t getDefaultKmsDataSize() +{ + return sizeof(DefaultKmsData); +} + +#endif // NO_INTERNAL_DATA + diff --git a/vlmcsd/src/kmsdata.h b/vlmcsd/src/kmsdata.h new file mode 100644 index 0000000..ec629fa --- /dev/null +++ b/vlmcsd/src/kmsdata.h @@ -0,0 +1,19 @@ +#ifndef KMSDATA_SERVER_H +#define KMSDATA_SERVER_H + +#ifndef CONFIG +#define CONFIG "config.h" +#endif // CONFIG +#include CONFIG + +#ifndef NO_INTERNAL_DATA + +#include "types.h" + +extern uint8_t DefaultKmsData[]; +__pure size_t getDefaultKmsDataSize(); + +#endif // NO_INTERNAL_DATA + +#endif // KMSDATA_SERVER_H + diff --git a/vlmcsd/src/libkms-test.c b/vlmcsd/src/libkms-test.c new file mode 100644 index 0000000..3e22bbf --- /dev/null +++ b/vlmcsd/src/libkms-test.c @@ -0,0 +1,42 @@ +#include +#include +#include + +#include "libkms.h" +#include "kms.h" +#include "endian.h" + +static const char ePID[] = { 'T', 0, 'E', 0, 'S', 0, 'T', 0, 0, 0 }; + +__stdcall BOOL KmsCallBack(const REQUEST *const baseRequest, RESPONSE *const baseResponse, BYTE *const hwId, const char* const ipstr) +{ + printf("libvlmcs-test.c: Entered KmsCallBack for client %s\n", ipstr); + + memcpy(&baseResponse->CMID, &baseRequest->CMID, sizeof(GUID)); + memcpy(&baseResponse->ClientTime, &baseRequest->ClientTime, sizeof(FILETIME)); + memcpy(&baseResponse->KmsPID, ePID, sizeof(ePID)); + + baseResponse->Version = baseRequest->Version; + baseResponse->Count = LE32(LE32(baseRequest->N_Policy) << 1); + baseResponse->PIDSize = sizeof(ePID); + baseResponse->VLActivationInterval = LE32(120); + baseResponse->VLRenewalInterval = LE32(10080); + + if (hwId && baseResponse->MajorVer > 5) memcpy(hwId, "\x01\x02\x03\x04\x05\x06\x07\x08", 8); + + return TRUE; +} + +int main(int argc, char** argv) +{ + int version = GetLibKmsVersion(); + + if (version < 0x30001) + { + fprintf(stderr, "KMS library version %u.%u or greater required\n", (unsigned int)(version >> 16), (unsigned int)(version & 0xffff)); + } + + printf("%s: Program start\n", GetEmulatorVersion()); + StartKmsServer(1688, KmsCallBack); + return 0; +} diff --git a/vlmcsd/src/libkms.c b/vlmcsd/src/libkms.c new file mode 100644 index 0000000..d4b8153 --- /dev/null +++ b/vlmcsd/src/libkms.c @@ -0,0 +1,208 @@ +/* + * libkms.c + */ + +#ifndef CONFIG +#define CONFIG "config.h" +#endif // CONFIG +#include CONFIG + +#ifdef EXTERNAL +#undef EXTERNAL +#endif + +#define EXTERNAL dllexport + +#define DLLVERSION 0x40000 + +#include "libkms.h" +#include "shared_globals.h" +#include "network.h" +#include "helpers.h" + +#ifndef _WIN32 +#include +#include +#include +#include +#include +#endif // WIN32 + +static int_fast8_t IsServerStarted = FALSE; + +#ifdef _WIN32 +#ifndef USE_MSRPC + +static int_fast8_t SocketsInitialized = FALSE; +WSADATA wsadata; + +static int initializeWinSockets() +{ + if (SocketsInitialized) return 0; + SocketsInitialized = TRUE; + return WSAStartup(0x0202, &wsadata); +} + +#endif // USE_MSRPC +#endif // _WIN32 + +EXTERNC __declspec(EXTERNAL) char* __cdecl GetErrorMessage() +{ + return ErrorMessage; +} + +EXTERNC __declspec(EXTERNAL)SOCKET __cdecl ConnectToServer(const char* host, const char* port, const int addressFamily) +{ + SOCKET sock; + *ErrorMessage = 0; + +# if defined(_WIN32) && !defined(USE_MSRPC) + initializeWinSockets(); +# endif // defined(_WIN32) && !defined(USE_MSRPC) + + size_t adrlen = strlen(host) + 16; + char* RemoteAddr = (char*)alloca(adrlen); + vlmcsd_snprintf(RemoteAddr, adrlen, "[%s]:%s", host, port); + sock = connectToAddress(RemoteAddr, addressFamily, FALSE); + + if (sock == INVALID_RPCCTX) + { + printerrorf("Fatal: Could not connect to %s\n", RemoteAddr); + return sock; + } + + return sock; +} + +EXTERNC __declspec(EXTERNAL)RpcStatus __cdecl BindRpc(const SOCKET sock, const int_fast8_t useMultiplexedRpc, const int_fast8_t useRpcNDR64, const int_fast8_t useRpcBTFN, PRpcDiag_t rpcDiag) +{ + *ErrorMessage = 0; + UseMultiplexedRpc = useMultiplexedRpc; + UseClientRpcNDR64 = useRpcNDR64; + UseClientRpcBTFN = useRpcBTFN; + return rpcBindClient(sock, FALSE, rpcDiag); +} + +EXTERNC __declspec(EXTERNAL) void __cdecl CloseConnection(const SOCKET sock) +{ + socketclose(sock); +} + + +EXTERNC __declspec(EXTERNAL)DWORD __cdecl SendKMSRequest(const SOCKET sock, RESPONSE* baseResponse, REQUEST* baseRequest, RESPONSE_RESULT* result, BYTE *hwid) +{ + *ErrorMessage = 0; + return SendActivationRequest(sock, baseResponse, baseRequest, result, hwid); +} + +EXTERNC __declspec(EXTERNAL)int_fast8_t __cdecl IsDisconnected(const SOCKET sock) +{ + return isDisconnected(sock); +} + + +EXTERNC __declspec(EXTERNAL)DWORD __cdecl StartKmsServer(const int port, RequestCallback_t requestCallback) +{ +#ifndef SIMPLE_SOCKETS + char listenAddress[64]; + + if (IsServerStarted) return SOCKET_EALREADY; + +# ifdef _WIN32 + int error = initializeWinSockets(); + if (error) return error; +# endif // _WIN32 + + CreateResponseBase = requestCallback; + + int maxsockets = 0; + int_fast8_t haveIPv4 = FALSE; + int_fast8_t haveIPv6 = FALSE; + + if (checkProtocolStack(AF_INET)) { haveIPv4 = TRUE; maxsockets++; } + if (checkProtocolStack(AF_INET6)) { haveIPv6 = TRUE; maxsockets++; } + + if (!maxsockets) return SOCKET_EAFNOSUPPORT; + + SocketList = (SOCKET*)vlmcsd_malloc(sizeof(SOCKET) * (size_t)maxsockets); + numsockets = 0; + + if (haveIPv4) + { + snprintf(listenAddress, 64, "0.0.0.0:%u", (unsigned int)port); + addListeningSocket(listenAddress); + } + + if (haveIPv6) + { + snprintf(listenAddress, 64, "[::]:%u", (unsigned int)port); + addListeningSocket(listenAddress); + } + + if (!numsockets) + { + free(SocketList); + return SOCKET_EADDRNOTAVAIL; + } + + IsServerStarted = TRUE; + + runServer(); + + IsServerStarted = FALSE; + return 0; + +# else // SIMPLE_SOCKETS + + if (IsServerStarted) return SOCKET_EALREADY; + int error; + +# ifdef _WIN32 + error = initializeWinSockets(); + if (error) return error; +# endif // _WIN32 + + defaultport = vlmcsd_malloc(16); + vlmcsd_snprintf((char*)defaultport, (size_t)16, "%i", port); + + CreateResponseBase = requestCallback; + error = listenOnAllAddresses(); + free(defaultport); + if (error) return error; + + IsServerStarted = TRUE; + runServer(); + IsServerStarted = FALSE; + + return 0; + + +# endif // SIMPLE_SOCKETS +} + + +EXTERNC __declspec(EXTERNAL)DWORD __cdecl StopKmsServer() +{ + if (!IsServerStarted) return VLMCSD_EPERM; + + closeAllListeningSockets(); + +# ifndef SIMPLE_SOCKETS + if (SocketList) free(SocketList); +# endif + + return 0; +} + + +EXTERNC __declspec(EXTERNAL) int __cdecl GetLibKmsVersion() +{ + return DLLVERSION; +} + + +EXTERNC __declspec(EXTERNAL) const char* const __cdecl GetEmulatorVersion() +{ + return VERSION; +} + diff --git a/vlmcsd/src/libkms.h b/vlmcsd/src/libkms.h new file mode 100644 index 0000000..ece9d1c --- /dev/null +++ b/vlmcsd/src/libkms.h @@ -0,0 +1,34 @@ +/* + * libkms.h + */ + +#ifndef LIBKMS_H_ +#define LIBKMS_H_ + +#include "types.h" +#include "kms.h" +#include "rpc.h" +#include "vlmcs.h" + +#ifndef EXTERNC +#ifdef __cplusplus +#define EXTERNC EXTERN "C" +#else +#define EXTERNC +#endif +#endif + +EXTERNC __declspec(EXTERNAL) DWORD __cdecl SendKMSRequest(const SOCKET sock, RESPONSE* baseResponse, REQUEST* baseRequest, RESPONSE_RESULT* result, BYTE *hwid); +EXTERNC __declspec(EXTERNAL) DWORD __cdecl StartKmsServer(const int port, RequestCallback_t requestCallback); +EXTERNC __declspec(EXTERNAL) DWORD __cdecl StopKmsServer(); +EXTERNC __declspec(EXTERNAL) int __cdecl GetLibKmsVersion(); +EXTERNC __declspec(EXTERNAL) const char* const __cdecl GetEmulatorVersion(); +EXTERNC __declspec(EXTERNAL) SOCKET __cdecl ConnectToServer(const char* host, const char* port, const int addressFamily); +EXTERNC __declspec(EXTERNAL) char* __cdecl GetErrorMessage(); +EXTERNC __declspec(EXTERNAL) void __cdecl CloseConnection(const SOCKET sock); +EXTERNC __declspec(EXTERNAL) RpcStatus __cdecl BindRpc(const SOCKET sock, const int_fast8_t useMultiplexedRpc, const int_fast8_t useRpcNDR64, const int_fast8_t useRpcBTFN, PRpcDiag_t rpcDiag); +EXTERNC __declspec(EXTERNAL) int_fast8_t __cdecl IsDisconnected(const SOCKET sock); +//EXTERN_C __declspec(EXTERNAL) unsigned int __cdecl GetRandom32(); + + +#endif /* LIBKMS_H_ */ diff --git a/vlmcsd/src/msrpc-client.c b/vlmcsd/src/msrpc-client.c new file mode 100644 index 0000000..12ae8f0 --- /dev/null +++ b/vlmcsd/src/msrpc-client.c @@ -0,0 +1,192 @@ +#ifndef CONFIG +#define CONFIG "config.h" +#endif // CONFIG +#include CONFIG + +#ifdef USE_MSRPC + +#if !defined(_WIN32) && !defined(__CYGWIN__) +#error MSRPC is only available with native Windows or Cygwin +#endif + +#include "msrpc-client.h" +#include +#include "output.h" +#include "helpers.h" + +#if __amd64 || defined(_M_AMD64) // 64-bit + +#ifndef _M_AMD64 +#define _M_AMD64 +#endif // _M_AMD64 + +#include "KMSServer_c_x64_mingw_gcc.c" + +#else // 32-bit + +#include "KMSServer_c_mingw_gcc.c" + +#endif // 32-bit + +static RPC_CSTR stringBinding; +jmp_buf jmp; +RPC_STATUS PreviousRpcCallFailed = RPC_S_OK; + + +/* + * Creates an RPC string binding that is used to connect to the server. + * Input is host:port, e.g. "[::1]:1688" or "127.0.0.1:1688" + * Output is for example "ncacn_ip_tcp:127.0.0.1[endpoint=1688]" + */ +#if !__amd64 +#pragma GCC optimize("O0") ////TODO: Find out why gcc needs -O0 for RPC handling +#endif + +static RPC_STATUS createStringBinding(char *const addr, RPC_CSTR* stringBinding) +{ + char *szHost, *szPort; + + parseAddress(addr, &szHost, &szPort); + + return RpcStringBindingComposeA + ( + NULL, /* UUID */ + (RPC_CSTR)"ncacn_ip_tcp", /* use TCP */ + (RPC_CSTR)szHost, /* host name or IP address */ + (RPC_CSTR)szPort, /* endpoint (TCP port here) */ + NULL, /* options */ + stringBinding /* resulting string binding */ + ); +} + + +/* + * This does not actually connect to a TCP port because MS RPC doesn't connect + * before the actual RPC call is made. So this a stub + */ +RpcCtx connectToAddress(char *const addr, const int AddressFamily_unused, int_fast8_t showHostName_unused) +{ + RPC_STATUS status; + + printf("Connecting to %s ... ", addr); + + if ((status = createStringBinding(addr, &stringBinding)) != RPC_S_OK) + { + printerrorf("%s\n", win_strerror(status)); + return !0; + } + + if (PreviousRpcCallFailed) + { + printerrorf("%s\n", win_strerror(PreviousRpcCallFailed)); + return !0; + } + + printf("successful\n"); + return 0; +} + + +/* + * Does not do RPC binding on the wire. Just initializes the interface + */ +RpcStatus rpcBindClient(const RpcCtx handle, const int_fast8_t verbose, PRpcDiag_t rpcDiag) +{ + RPC_STATUS status; + + if ((status = RpcBindingFromStringBindingA(stringBinding, &KMSServer_v1_0_c_ifspec)) != RPC_S_OK) + { + errorout("\n%s\n", win_strerror(status)); + } + + rpcDiag->HasRpcDiag = FALSE; + return status; +} + + +/* + * You never know if you have a TCP connection or not + * This returns true if the previous RPC call failed + */ +int_fast8_t isDisconnected(const RpcCtx handle) +{ + return PreviousRpcCallFailed; +} + + +/* + * This is the exception handler because the RPC call may + * throw an SEH exception and gcc does not support + * __try / __except as MSVC does. + */ +static LONG WINAPI rpcException (LPEXCEPTION_POINTERS exception_pointers) +{ + DWORD exception = exception_pointers->ExceptionRecord->ExceptionCode; + if (!exception) exception = (DWORD)~0; + longjmp(jmp, exception_pointers->ExceptionRecord->ExceptionCode); + return EXCEPTION_EXECUTE_HANDLER; +} + +/* + * This actually calls the RPC server + */ +#define try SetUnhandledExceptionFilter(rpcException); RPC_STATUS exception = setjmp(jmp); if (!exception) +#define catch else +RpcStatus rpcSendRequest(const RpcCtx handle, BYTE* KmsRequest, const size_t requestSize, BYTE **KmsResponse, size_t* responseSize) +{ + *KmsResponse = NULL; // Let midl_user_allocate do the job + + try + { + exception = RequestActivation(KMSServer_v1_0_c_ifspec, (int)requestSize, KmsRequest, (int*)responseSize, KmsResponse); + } + catch + { + errorout("\n%s", win_strerror(exception)); + } + + PreviousRpcCallFailed = exception; + SetUnhandledExceptionFilter(NULL); + + return exception; + +} +#undef catch +#undef try + + +/* + * Only frees local handles. Cannot close the TCP connection + */ +RpcStatus closeRpc(const RpcCtx handle) +{ + RPC_STATUS status; + + if ((status = RpcBindingFree(&KMSServer_v1_0_c_ifspec)) != RPC_S_OK) return status; + status = RpcStringFreeA(&stringBinding); + //Ctx = INVALID_RPCCTX; + return status; +} + + +#if !MULTI_CALL_BINARY +// Memory allocation function for RPC. +void *__RPC_USER midl_user_allocate(size_t len) +{ + return vlmcsd_malloc(len); +} + + +// Memory deallocation function for RPC. +void __RPC_USER midl_user_free(void __RPC_FAR *ptr) +{ + if (ptr) free(ptr); + ptr = NULL; +} + +#endif // !MULTI_CALL_BINARY + + +#endif // USE_MSRPC + + diff --git a/vlmcsd/src/msrpc-client.h b/vlmcsd/src/msrpc-client.h new file mode 100644 index 0000000..603e3b8 --- /dev/null +++ b/vlmcsd/src/msrpc-client.h @@ -0,0 +1,26 @@ +/* + * msrpc-client.h + */ + +#ifdef USE_MSRPC +#ifndef MSRPC_CLIENT_H_ +#define MSRPC_CLIENT_H_ + +#include "types.h" +#include "shared_globals.h" +#include +#include "output.h" + +typedef int_fast8_t RpcCtx; +typedef RPC_STATUS RpcStatus; + +RpcCtx connectToAddress(char *const addr, const int AddressFamily_unused, int_fast8_t showHostName); +int_fast8_t isDisconnected(const RpcCtx handle); +RpcStatus rpcBindClient(const RpcCtx handle, const int_fast8_t verbose, PRpcDiag_t rpcDiag); +RpcStatus rpcSendRequest(const RpcCtx handle, BYTE* KmsRequest, size_t requestSize, BYTE **KmsResponse, size_t *responseSize); +RpcStatus closeRpc(RpcCtx s); + +#define INVALID_RPCCTX ((RpcCtx)~0) +#endif // USE_MSRPC + +#endif /* MSRPC_CLIENT_H_ */ diff --git a/vlmcsd/src/msrpc-server.c b/vlmcsd/src/msrpc-server.c new file mode 100644 index 0000000..24ee946 --- /dev/null +++ b/vlmcsd/src/msrpc-server.c @@ -0,0 +1,311 @@ +#ifndef CONFIG +#define CONFIG "config.h" +#endif // CONFIG +#include CONFIG + +#ifdef USE_MSRPC + +#if !defined(_WIN32) && !defined(__CYGWIN__) +#error MSRPC is only available with native Windows or Cygwin +#endif + +#if _WIN32 && !defined(NO_PRIVATE_IP_DETECT) +#include +#endif + +#include "msrpc-server.h" +#include "output.h" +#include "kms.h" +#include "helpers.h" +#include "shared_globals.h" +#include "ntservice.h" +#include "endian.h" +#include "types.h" + +#if __amd64 || defined(_M_AMD64) // 64-bit + +#ifndef _M_AMD64 +#define _M_AMD64 +#endif // _M_AMD64 + +#include "KMSServer_s2_x64_mingw_gcc.c" + +#else // 32-bit + +#include "KMSServer_s2_mingw_gcc.c" + +#endif // 32-bit + + +#if !defined(NO_LIMIT) +#define MAXCALLS MaxTasks +#else // defined(NO_LIMIT) +#define MAXCALLS RPC_C_LISTEN_MAX_CALLS_DEFAULT +#endif + + + + +/* + * This is the main run loop for the KMS server + * We actually just setup things (must be after Cygwin fork) and then sleep + */ +int runServer() +{ +# if !defined(NO_SOCKETS) && !defined(NO_SIGHUP) && !defined(_WIN32) + + // The RPC setup survives a Cygwin exec without problems but no daemonizing + // SIGHUP is currently disabled for Cygwin. So this code should never compile + + if (IsRestarted) + { +# ifndef NO_LOG + logger("vlmcsd %s started successfully\n", Version); +# endif // NO_LOG + } + else +# endif // !defined(NO_SOCKETS) && !defined(NO_SIGHUP) && !defined(_WIN32) + { + RPC_STATUS status; + + // Endpoint is actually a TCP port for "ncacn_ip_tcp" + status = RpcServerUseProtseqEpA + ( + (RPC_CSTR)"ncacn_ip_tcp", + RPC_C_PROTSEQ_MAX_REQS_DEFAULT, + (RPC_CSTR)defaultport, + NULL + ); + + if (status) + { + printerrorf("Fatal: Cannot bind to port %s: %s\n", defaultport, win_strerror(status)); + return status; + } + +# ifndef NO_LOG + logger("Listening on port %s\n", defaultport); +# endif // NO_LOG + + // Registers the KMSServer interface. + status = RpcServerRegisterIf2 + ( + KMSServer_v1_0_s_ifspec, + NULL, + NULL, + RPC_IF_ALLOW_CALLBACKS_WITH_NO_AUTH | RPC_IF_AUTOLISTEN, + MAXCALLS, + MAX_RESPONSE_SIZE, // currently set to sizeof(RESPONSE_V6) + NULL + ); + + if (status) + { + printerrorf("Fatal: Cannot register RPC interface: %s\n", win_strerror(status)); + return status; + } + +# ifndef NO_LOG + logger("vlmcsd %s started successfully\n", Version); +# endif // NO_LOG + + if (IsNTService) ReportServiceStatus(SERVICE_RUNNING, NO_ERROR, 200); + } + + // We could run RpcServerListen here but we need something + // that can be signaled from Cygwin. So we just sleep 24h (POSIX sleep, no Windows Sleep), + // wake up for some nanoseconds and sleep again. + + while(TRUE) sleep(86400); // Sleep one day +} + + + +/* + * Get's the IP address from an RPC_BINDING_HANDLE. Caller must call RpcStringFreeA to + * release memory allocated in *ipAddress + */ +#ifndef NO_LOG +RPC_STATUS getClientIp(const RPC_BINDING_HANDLE clientBinding, RPC_CSTR *ipAddress) +{ + RPC_STATUS result; + RPC_CSTR stringBinding; + RPC_BINDING_HANDLE serverBinding; + + // Fix for wine (disabled by default, because vlmcsd runs natively on all platforms where wine runs) + // Feel free to #define SUPPORT_WINE if you really want to run the Windows version with MS RPC (Wine RPC in this case) + #ifdef SUPPORT_WINE + HMODULE h = GetModuleHandleA("kernel32.dll"); + + if (h) + { + // Since wine simply terminates the thread when RpcBindingServerFromClient is called, we exit with an error + if (GetProcAddress(h, "wine_get_unix_file_name")) return RPC_S_CANNOT_SUPPORT; + } + #endif // SUPPORT_WINE + + if ((result = RpcBindingServerFromClient(clientBinding, &serverBinding)) != RPC_S_OK) return result; + + if ((result = RpcBindingToStringBindingA(serverBinding, &stringBinding)) != RPC_S_OK) + { + RpcBindingFree(&serverBinding); + return result; + } + + result = RpcStringBindingParseA(stringBinding, NULL, NULL, ipAddress, NULL, NULL); + RpcStringFreeA(&stringBinding); + RpcBindingFree(&serverBinding); + + return result; +} +#endif // NO_LOG + + +#ifndef NO_PRIVATE_IP_DETECT +static int_fast8_t IsPrivateIPAddress(char* ipAddress) +{ + int family = strchr(ipAddress,'.') ? AF_INET : AF_INET6; + + switch(family) + { + case AF_INET: + { + int i; + char* current; + char* next; + uint32_t ip; + + for (ip = 0, i = 0, current = ipAddress; i < 4; i++, current = next + 1) + { + ip = (ip << 8) | strtoul(current, &next, 10); + if (*next != '.') break; + } + + if + ( + (ip & 0xff000000) == 0x7f000000 || // 127.x.x.x localhost + (ip & 0xffff0000) == 0xc0a80000 || // 192.168.x.x private routeable + (ip & 0xffff0000) == 0xa9fe0000 || // 169.254.x.x link local + (ip & 0xff000000) == 0x0a000000 || // 10.x.x.x private routeable + (ip & 0xfff00000) == 0xac100000 // 172.16-31.x.x private routeable + ) + { + return TRUE; + } + + break; + } + + case AF_INET6: + { + if (!strcmp(ipAddress, "::1")) return TRUE; + if (strchr(ipAddress, ':') - ipAddress != 4) break; + + int16_t firstWord; + hex2bin((BYTE*)&firstWord, ipAddress, 2); + if ((BE16(firstWord) & 0xe000) != 0x2000) return TRUE; + } + + } + + return FALSE; +} +#endif // NO_PRIVATE_IP_DETECT + +/* + * This is the callback function for the RPC request as defined in KMSServer.idl + * Output from the MIDL compiler has been modified manually to support gcc (and compatible compilers) + * as well as Cygwin and MingW-w64 toolchains. + */ +int ProcessActivationRequest(handle_t IDL_handle, int requestSize, unsigned char *request, int *responseSize, unsigned char **response) +{ + RPC_CSTR clientIpAddress; + RPC_STATUS result; + int status = 0; + + result = getClientIp(IDL_handle, &clientIpAddress); + +# ifndef NO_LOG + + logger("RPC connection accepted: %s\n", !result ? (const char*)clientIpAddress : "Unknown IP"); + +# endif // NO_LOG + +# ifndef NO_PRIVATE_IP_DETECT + if (result && (PublicIPProtectionLevel & 2)) + { +# ifndef NO_LOG + logger ("Cannot verify that client has a private IP address\n"); +# endif + + return 0x80070000 | RPC_S_ACCESS_DENIED; + } + + if (!result && (PublicIPProtectionLevel & 2) && !IsPrivateIPAddress((char*)clientIpAddress)) + { +# ifndef NO_LOG + logger("Client with public IP address rejected\n"); +# endif + + RpcStringFreeA(&clientIpAddress); + return 0x80070000 | RPC_S_ACCESS_DENIED; + } +# endif // NO_PRIVATE_IP_DETECT + + // Discard any packet smaller than a v4 request + if (requestSize < (int)sizeof(REQUEST_V4)) + { + if (!result) RpcStringFreeA(&clientIpAddress); + return 0x8007000D; + } + + *response = (uint8_t *)midl_user_allocate(MAX_RESPONSE_SIZE); + int kmsStatus = 0x8007000D; + int version = LE32(((REQUEST*)(request))->Version); + + switch(version) + { + case 0x40000: + kmsStatus = CreateResponseV4((REQUEST_V4 *)request, *response, (char*)clientIpAddress); + break; + case 0x50000: + case 0x60000: + kmsStatus = CreateResponseV6((REQUEST_V6 *) request, *response, (char*)clientIpAddress); + break; + default: +# ifndef NO_LOG + logger("Fatal: KMSv%u.%u unsupported\n", version >> 16, version & 0xffff); +# endif // NO_LOG + break; + } + + if (kmsStatus < 0) + { + status = kmsStatus; + } + else + { + *responseSize = kmsStatus; + } + + if (!result) RpcStringFreeA(&clientIpAddress); + return status; +} + + +// Memory allocation function for RPC. +void *__RPC_USER midl_user_allocate(size_t len) +{ + return vlmcsd_malloc(len); +} + + +// Memory deallocation function for RPC. +void __RPC_USER midl_user_free(void __RPC_FAR *ptr) +{ + if (ptr) free(ptr); + ptr = NULL; +} + + +#endif // USE_MSRPC diff --git a/vlmcsd/src/msrpc-server.h b/vlmcsd/src/msrpc-server.h new file mode 100644 index 0000000..cae9c4d --- /dev/null +++ b/vlmcsd/src/msrpc-server.h @@ -0,0 +1,10 @@ +/* + * msrpc-server.h + */ + +#ifndef MSRPC_SERVER_H_ +#define MSRPC_SERVER_H_ + +int runServer(); + +#endif /* MSRPC_SERVER_H_ */ diff --git a/vlmcsd/src/nameser.h b/vlmcsd/src/nameser.h new file mode 100644 index 0000000..a774798 --- /dev/null +++ b/vlmcsd/src/nameser.h @@ -0,0 +1,569 @@ +/* $NetBSD: nameser.h,v 1.19 2005/12/26 19:01:47 perry Exp $ */ + +/* + * Copyright (c) 1983, 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Id: nameser.h,v 1.2.2.4.4.1 2004/03/09 08:33:30 marka Exp + */ + +#ifndef _ARPA_NAMESER_H_ +#define _ARPA_NAMESER_H_ + +#define BIND_4_COMPAT + +#include +#include + +/* + * Revision information. This is the release date in YYYYMMDD format. + * It can change every day so the right thing to do with it is use it + * in preprocessor commands such as "#if (__NAMESER > 19931104)". Do not + * compare for equality; rather, use it to determine whether your libbind.a + * contains a new enough lib/nameser/ to support the feature you need. + */ + +#define __NAMESER 19991006 /* New interface version stamp. */ + +/* + * Define constants based on RFC 883, RFC 1034, RFC 1035 + */ +#define NS_PACKETSZ 512 /* default UDP packet size */ +#define NS_MAXDNAME 1025 /* maximum domain name */ +#define NS_MAXMSG 65535 /* maximum message size */ +#define NS_MAXCDNAME 255 /* maximum compressed domain name */ +#define NS_MAXLABEL 63 /* maximum length of domain label */ +#define NS_HFIXEDSZ 12 /* #/bytes of fixed data in header */ +#define NS_QFIXEDSZ 4 /* #/bytes of fixed data in query */ +#define NS_RRFIXEDSZ 10 /* #/bytes of fixed data in r record */ +#define NS_INT32SZ 4 /* #/bytes of data in a uint32_t */ +#define NS_INT16SZ 2 /* #/bytes of data in a uint16_t */ +#define NS_INT8SZ 1 /* #/bytes of data in a uint8_t */ +#define NS_INADDRSZ 4 /* IPv4 T_A */ +#define NS_IN6ADDRSZ 16 /* IPv6 T_AAAA */ +#define NS_CMPRSFLGS 0xc0 /* Flag bits indicating name compression. */ +#define NS_DEFAULTPORT 53 /* For both TCP and UDP. */ + +/* + * These can be expanded with synonyms, just keep ns_parse.c:ns_parserecord() + * in synch with it. + */ +typedef enum __ns_sect { + ns_s_qd = 0, /* Query: Question. */ + ns_s_zn = 0, /* Update: Zone. */ + ns_s_an = 1, /* Query: Answer. */ + ns_s_pr = 1, /* Update: Prerequisites. */ + ns_s_ns = 2, /* Query: Name servers. */ + ns_s_ud = 2, /* Update: Update. */ + ns_s_ar = 3, /* Query|Update: Additional records. */ + ns_s_max = 4 +} ns_sect; + +/* + * This is a message handle. It is caller allocated and has no dynamic data. + * This structure is intended to be opaque to all but ns_parse.c, thus the + * leading _'s on the member names. Use the accessor functions, not the _'s. + */ +typedef struct __ns_msg { + const u_char *_msg, *_eom; + uint16_t _id, _flags, _counts[ns_s_max]; + const u_char *_sections[ns_s_max]; + ns_sect _sect; + int _rrnum; + const u_char *_msg_ptr; +} ns_msg; + +/* Private data structure - do not use from outside library. */ +struct _ns_flagdata { int mask, shift; }; +extern const struct _ns_flagdata _ns_flagdata[]; + +/* Accessor macros - this is part of the public interface. */ + +#define ns_msg_id(handle) ((handle)._id + 0) +#define ns_msg_base(handle) ((handle)._msg + 0) +#define ns_msg_end(handle) ((handle)._eom + 0) +#define ns_msg_size(handle) ((size_t)((handle)._eom - (handle)._msg)) +#define ns_msg_count(handle, section) ((handle)._counts[section] + 0) + +/* + * This is a parsed record. It is caller allocated and has no dynamic data. + */ +typedef struct __ns_rr { + char name[NS_MAXDNAME]; + uint16_t type; + uint16_t rr_class; + uint32_t ttl; + uint16_t rdlength; + const u_char * rdata; +} ns_rr; + +/* Accessor macros - this is part of the public interface. */ +#define ns_rr_name(rr) (((rr).name[0] != '\0') ? (rr).name : ".") +#define ns_rr_type(rr) ((ns_type)((rr).type + 0)) +#define ns_rr_class(rr) ((ns_class)((rr).rr_class + 0)) +#define ns_rr_ttl(rr) ((u_long)(rr).ttl + 0) +#define ns_rr_rdlen(rr) ((size_t)(rr).rdlength + 0) +#define ns_rr_rdata(rr) ((rr).rdata + 0) + +/* + * These don't have to be in the same order as in the packet flags word, + * and they can even overlap in some cases, but they will need to be kept + * in synch with ns_parse.c:ns_flagdata[]. + */ +typedef enum __ns_flag { + ns_f_qr, /* Question/Response. */ + ns_f_opcode, /* Operation code. */ + ns_f_aa, /* Authoritative Answer. */ + ns_f_tc, /* Truncation occurred. */ + ns_f_rd, /* Recursion Desired. */ + ns_f_ra, /* Recursion Available. */ + ns_f_z, /* MBZ. */ + ns_f_ad, /* Authentic Data (DNSSEC). */ + ns_f_cd, /* Checking Disabled (DNSSEC). */ + ns_f_rcode, /* Response code. */ + ns_f_max +} ns_flag; + +/* + * Currently defined opcodes. + */ +typedef enum __ns_opcode { + ns_o_query = 0, /* Standard query. */ + ns_o_iquery = 1, /* Inverse query (deprecated/unsupported). */ + ns_o_status = 2, /* Name server status query (unsupported). */ + /* Opcode 3 is undefined/reserved. */ + ns_o_notify = 4, /* Zone change notification. */ + ns_o_update = 5, /* Zone update message. */ + ns_o_max = 6 +} ns_opcode; + +/* + * Currently defined response codes. + */ +typedef enum __ns_rcode { + ns_r_noerror = 0, /* No error occurred. */ + ns_r_formerr = 1, /* Format error. */ + ns_r_servfail = 2, /* Server failure. */ + ns_r_nxdomain = 3, /* Name error. */ + ns_r_notimpl = 4, /* Unimplemented. */ + ns_r_refused = 5, /* Operation refused. */ + /* these are for BIND_UPDATE */ + ns_r_yxdomain = 6, /* Name exists */ + ns_r_yxrrset = 7, /* RRset exists */ + ns_r_nxrrset = 8, /* RRset does not exist */ + ns_r_notauth = 9, /* Not authoritative for zone */ + ns_r_notzone = 10, /* Zone of record different from zone section */ + ns_r_max = 11, + /* The following are EDNS extended rcodes */ + ns_r_badvers = 16, + /* The following are TSIG errors */ + ns_r_badsig = 16, + ns_r_badkey = 17, + ns_r_badtime = 18 +} ns_rcode; + +/* BIND_UPDATE */ +typedef enum __ns_update_operation { + ns_uop_delete = 0, + ns_uop_add = 1, + ns_uop_max = 2 +} ns_update_operation; + +/* + * This structure is used for TSIG authenticated messages + */ +struct ns_tsig_key { + char name[NS_MAXDNAME], alg[NS_MAXDNAME]; + unsigned char *data; + int len; +}; +typedef struct ns_tsig_key ns_tsig_key; + +/* + * This structure is used for TSIG authenticated TCP messages + */ +struct ns_tcp_tsig_state { + int counter; + struct dst_key *key; + void *ctx; + unsigned char sig[NS_PACKETSZ]; + int siglen; +}; +typedef struct ns_tcp_tsig_state ns_tcp_tsig_state; + +#define NS_TSIG_FUDGE 300 +#define NS_TSIG_TCP_COUNT 100 +#define NS_TSIG_ALG_HMAC_MD5 "HMAC-MD5.SIG-ALG.REG.INT" + +#define NS_TSIG_ERROR_NO_TSIG -10 +#define NS_TSIG_ERROR_NO_SPACE -11 +#define NS_TSIG_ERROR_FORMERR -12 + +/* + * Currently defined type values for resources and queries. + */ +typedef enum __ns_type { + ns_t_invalid = 0, /* Cookie. */ + ns_t_a = 1, /* Host address. */ + ns_t_ns = 2, /* Authoritative server. */ + ns_t_md = 3, /* Mail destination. */ + ns_t_mf = 4, /* Mail forwarder. */ + ns_t_cname = 5, /* Canonical name. */ + ns_t_soa = 6, /* Start of authority zone. */ + ns_t_mb = 7, /* Mailbox domain name. */ + ns_t_mg = 8, /* Mail group member. */ + ns_t_mr = 9, /* Mail rename name. */ + ns_t_null = 10, /* Null resource record. */ + ns_t_wks = 11, /* Well known service. */ + ns_t_ptr = 12, /* Domain name pointer. */ + ns_t_hinfo = 13, /* Host information. */ + ns_t_minfo = 14, /* Mailbox information. */ + ns_t_mx = 15, /* Mail routing information. */ + ns_t_txt = 16, /* Text strings. */ + ns_t_rp = 17, /* Responsible person. */ + ns_t_afsdb = 18, /* AFS cell database. */ + ns_t_x25 = 19, /* X_25 calling address. */ + ns_t_isdn = 20, /* ISDN calling address. */ + ns_t_rt = 21, /* Router. */ + ns_t_nsap = 22, /* NSAP address. */ + ns_t_nsap_ptr = 23, /* Reverse NSAP lookup (deprecated). */ + ns_t_sig = 24, /* Security signature. */ + ns_t_key = 25, /* Security key. */ + ns_t_px = 26, /* X.400 mail mapping. */ + ns_t_gpos = 27, /* Geographical position (withdrawn). */ + ns_t_aaaa = 28, /* Ip6 Address. */ + ns_t_loc = 29, /* Location Information. */ + ns_t_nxt = 30, /* Next domain (security). */ + ns_t_eid = 31, /* Endpoint identifier. */ + ns_t_nimloc = 32, /* Nimrod Locator. */ + ns_t_srv = 33, /* Server Selection. */ + ns_t_atma = 34, /* ATM Address */ + ns_t_naptr = 35, /* Naming Authority PoinTeR */ + ns_t_kx = 36, /* Key Exchange */ + ns_t_cert = 37, /* Certification record */ + ns_t_a6 = 38, /* IPv6 address (deprecates AAAA) */ + ns_t_dname = 39, /* Non-terminal DNAME (for IPv6) */ + ns_t_sink = 40, /* Kitchen sink (experimentatl) */ + ns_t_opt = 41, /* EDNS0 option (meta-RR) */ + ns_t_apl = 42, /* Address prefix list (RFC 3123) */ + ns_t_tkey = 249, /* Transaction key */ + ns_t_tsig = 250, /* Transaction signature. */ + ns_t_ixfr = 251, /* Incremental zone transfer. */ + ns_t_axfr = 252, /* Transfer zone of authority. */ + ns_t_mailb = 253, /* Transfer mailbox records. */ + ns_t_maila = 254, /* Transfer mail agent records. */ + ns_t_any = 255, /* Wildcard match. */ + ns_t_zxfr = 256, /* BIND-specific, nonstandard. */ + ns_t_max = 65536 +} ns_type; + +/* Exclusively a QTYPE? (not also an RTYPE) */ +#define ns_t_qt_p(t) (ns_t_xfr_p(t) || (t) == ns_t_any || \ + (t) == ns_t_mailb || (t) == ns_t_maila) +/* Some kind of meta-RR? (not a QTYPE, but also not an RTYPE) */ +#define ns_t_mrr_p(t) ((t) == ns_t_tsig || (t) == ns_t_opt) +/* Exclusively an RTYPE? (not also a QTYPE or a meta-RR) */ +#define ns_t_rr_p(t) (!ns_t_qt_p(t) && !ns_t_mrr_p(t)) +#define ns_t_udp_p(t) ((t) != ns_t_axfr && (t) != ns_t_zxfr) +#define ns_t_xfr_p(t) ((t) == ns_t_axfr || (t) == ns_t_ixfr || \ + (t) == ns_t_zxfr) + +/* + * Values for class field + */ +typedef enum __ns_class { + ns_c_invalid = 0, /* Cookie. */ + ns_c_in = 1, /* Internet. */ + ns_c_2 = 2, /* unallocated/unsupported. */ + ns_c_chaos = 3, /* MIT Chaos-net. */ + ns_c_hs = 4, /* MIT Hesiod. */ + /* Query class values which do not appear in resource records */ + ns_c_none = 254, /* for prereq. sections in update requests */ + ns_c_any = 255, /* Wildcard match. */ + ns_c_max = 65536 +} ns_class; + +/* DNSSEC constants. */ + +typedef enum __ns_key_types { + ns_kt_rsa = 1, /* key type RSA/MD5 */ + ns_kt_dh = 2, /* Diffie Hellman */ + ns_kt_dsa = 3, /* Digital Signature Standard (MANDATORY) */ + ns_kt_private = 254 /* Private key type starts with OID */ +} ns_key_types; + +typedef enum __ns_cert_types { + cert_t_pkix = 1, /* PKIX (X.509v3) */ + cert_t_spki = 2, /* SPKI */ + cert_t_pgp = 3, /* PGP */ + cert_t_url = 253, /* URL private type */ + cert_t_oid = 254 /* OID private type */ +} ns_cert_types; + +/* Flags field of the KEY RR rdata. */ +#define NS_KEY_TYPEMASK 0xC000 /* Mask for "type" bits */ +#define NS_KEY_TYPE_AUTH_CONF 0x0000 /* Key usable for both */ +#define NS_KEY_TYPE_CONF_ONLY 0x8000 /* Key usable for confidentiality */ +#define NS_KEY_TYPE_AUTH_ONLY 0x4000 /* Key usable for authentication */ +#define NS_KEY_TYPE_NO_KEY 0xC000 /* No key usable for either; no key */ +/* The type bits can also be interpreted independently, as single bits: */ +#define NS_KEY_NO_AUTH 0x8000 /* Key unusable for authentication */ +#define NS_KEY_NO_CONF 0x4000 /* Key unusable for confidentiality */ +#define NS_KEY_RESERVED2 0x2000 /* Security is *mandatory* if bit=0 */ +#define NS_KEY_EXTENDED_FLAGS 0x1000 /* reserved - must be zero */ +#define NS_KEY_RESERVED4 0x0800 /* reserved - must be zero */ +#define NS_KEY_RESERVED5 0x0400 /* reserved - must be zero */ +#define NS_KEY_NAME_TYPE 0x0300 /* these bits determine the type */ +#define NS_KEY_NAME_USER 0x0000 /* key is assoc. with user */ +#define NS_KEY_NAME_ENTITY 0x0200 /* key is assoc. with entity eg host */ +#define NS_KEY_NAME_ZONE 0x0100 /* key is zone key */ +#define NS_KEY_NAME_RESERVED 0x0300 /* reserved meaning */ +#define NS_KEY_RESERVED8 0x0080 /* reserved - must be zero */ +#define NS_KEY_RESERVED9 0x0040 /* reserved - must be zero */ +#define NS_KEY_RESERVED10 0x0020 /* reserved - must be zero */ +#define NS_KEY_RESERVED11 0x0010 /* reserved - must be zero */ +#define NS_KEY_SIGNATORYMASK 0x000F /* key can sign RR's of same name */ +#define NS_KEY_RESERVED_BITMASK ( NS_KEY_RESERVED2 | \ + NS_KEY_RESERVED4 | \ + NS_KEY_RESERVED5 | \ + NS_KEY_RESERVED8 | \ + NS_KEY_RESERVED9 | \ + NS_KEY_RESERVED10 | \ + NS_KEY_RESERVED11 ) +#define NS_KEY_RESERVED_BITMASK2 0xFFFF /* no bits defined here */ + +/* The Algorithm field of the KEY and SIG RR's is an integer, {1..254} */ +#define NS_ALG_MD5RSA 1 /* MD5 with RSA */ +#define NS_ALG_DH 2 /* Diffie Hellman KEY */ +#define NS_ALG_DSA 3 /* DSA KEY */ +#define NS_ALG_DSS NS_ALG_DSA +#define NS_ALG_EXPIRE_ONLY 253 /* No alg, no security */ +#define NS_ALG_PRIVATE_OID 254 /* Key begins with OID giving alg */ + +/* Protocol values */ +/* value 0 is reserved */ +#define NS_KEY_PROT_TLS 1 +#define NS_KEY_PROT_EMAIL 2 +#define NS_KEY_PROT_DNSSEC 3 +#define NS_KEY_PROT_IPSEC 4 +#define NS_KEY_PROT_ANY 255 + +/* Signatures */ +#define NS_MD5RSA_MIN_BITS 512 /* Size of a mod or exp in bits */ +#define NS_MD5RSA_MAX_BITS 4096 + /* Total of binary mod and exp */ +#define NS_MD5RSA_MAX_BYTES ((NS_MD5RSA_MAX_BITS+7/8)*2+3) + /* Max length of text sig block */ +#define NS_MD5RSA_MAX_BASE64 (((NS_MD5RSA_MAX_BYTES+2)/3)*4) +#define NS_MD5RSA_MIN_SIZE ((NS_MD5RSA_MIN_BITS+7)/8) +#define NS_MD5RSA_MAX_SIZE ((NS_MD5RSA_MAX_BITS+7)/8) + +#define NS_DSA_SIG_SIZE 41 +#define NS_DSA_MIN_SIZE 213 +#define NS_DSA_MAX_BYTES 405 + +/* Offsets into SIG record rdata to find various values */ +#define NS_SIG_TYPE 0 /* Type flags */ +#define NS_SIG_ALG 2 /* Algorithm */ +#define NS_SIG_LABELS 3 /* How many labels in name */ +#define NS_SIG_OTTL 4 /* Original TTL */ +#define NS_SIG_EXPIR 8 /* Expiration time */ +#define NS_SIG_SIGNED 12 /* Signature time */ +#define NS_SIG_FOOT 16 /* Key footprint */ +#define NS_SIG_SIGNER 18 /* Domain name of who signed it */ + +/* How RR types are represented as bit-flags in NXT records */ +#define NS_NXT_BITS 8 +#define NS_NXT_BIT_SET( n,p) (p[(n)/NS_NXT_BITS] |= (0x80>>((n)%NS_NXT_BITS))) +#define NS_NXT_BIT_CLEAR(n,p) (p[(n)/NS_NXT_BITS] &= ~(0x80>>((n)%NS_NXT_BITS))) +#define NS_NXT_BIT_ISSET(n,p) (p[(n)/NS_NXT_BITS] & (0x80>>((n)%NS_NXT_BITS))) +#define NS_NXT_MAX 127 + +/* + * EDNS0 extended flags, host order. + */ +#define NS_OPT_DNSSEC_OK 0x8000U + +/* + * Inline versions of get/put short/long. Pointer is advanced. + */ +#define NS_GET16(s, cp) do { \ + const u_char *t_cp = (const u_char *)(cp); \ + (s) = ((uint16_t)t_cp[0] << 8) \ + | ((uint16_t)t_cp[1]) \ + ; \ + (cp) += NS_INT16SZ; \ +} while (/*CONSTCOND*/0) + +#define NS_GET32(l, cp) do { \ + const u_char *t_cp = (const u_char *)(cp); \ + (l) = ((uint32_t)t_cp[0] << 24) \ + | ((uint32_t)t_cp[1] << 16) \ + | ((uint32_t)t_cp[2] << 8) \ + | ((uint32_t)t_cp[3]) \ + ; \ + (cp) += NS_INT32SZ; \ +} while (/*CONSTCOND*/0) + +#define NS_PUT16(s, cp) do { \ + uint32_t t_s = (uint32_t)(s); \ + u_char *t_cp = (u_char *)(cp); \ + *t_cp++ = t_s >> 8; \ + *t_cp = t_s; \ + (cp) += NS_INT16SZ; \ +} while (/*CONSTCOND*/0) + +#define NS_PUT32(l, cp) do { \ + uint32_t t_l = (uint32_t)(l); \ + u_char *t_cp = (u_char *)(cp); \ + *t_cp++ = t_l >> 24; \ + *t_cp++ = t_l >> 16; \ + *t_cp++ = t_l >> 8; \ + *t_cp = t_l; \ + (cp) += NS_INT32SZ; \ +} while (/*CONSTCOND*/0) + +/* + * ANSI C identifier hiding for bind's lib/nameser. + */ +#define ns_msg_getflag __ns_msg_getflag +#define ns_get16 __ns_get16 +#define ns_get32 __ns_get32 +#define ns_put16 __ns_put16 +#define ns_put32 __ns_put32 +#define ns_initparse __ns_initparse +#define ns_skiprr __ns_skiprr +#define ns_parserr __ns_parserr +#define ns_sprintrr __ns_sprintrr +#define ns_sprintrrf __ns_sprintrrf +#define ns_format_ttl __ns_format_ttl +#define ns_parse_ttl __ns_parse_ttl +#define ns_datetosecs __ns_datetosecs +#define ns_name_ntol __ns_name_ntol +#define ns_name_ntop __ns_name_ntop +#define ns_name_pton __ns_name_pton +#define ns_name_unpack __ns_name_unpack +#define ns_name_pack __ns_name_pack +#define ns_name_compress __ns_name_compress +#define ns_name_uncompress __ns_name_uncompress +#define ns_name_skip __ns_name_skip +#define ns_name_rollback __ns_name_rollback +#define ns_sign __ns_sign +#define ns_sign2 __ns_sign2 +#define ns_sign_tcp __ns_sign_tcp +#define ns_sign_tcp2 __ns_sign_tcp2 +#define ns_sign_tcp_init __ns_sign_tcp_init +#define ns_find_tsig __ns_find_tsig +#define ns_verify __ns_verify +#define ns_verify_tcp __ns_verify_tcp +#define ns_verify_tcp_init __ns_verify_tcp_init +#define ns_samedomain __ns_samedomain +#define ns_subdomain __ns_subdomain +#define ns_makecanon __ns_makecanon +#define ns_samename __ns_samename + +__BEGIN_DECLS +int ns_msg_getflag(ns_msg, int); +uint16_t ns_get16(const u_char *); +uint32_t ns_get32(const u_char *); +void ns_put16(uint16_t, u_char *); +void ns_put32(uint32_t, u_char *); +int ns_initparse(const u_char *, int, ns_msg *); +int ns_skiprr(const u_char *, const u_char *, ns_sect, int); +int ns_parserr(ns_msg *, ns_sect, int, ns_rr *); +int ns_sprintrr(const ns_msg *, const ns_rr *, + const char *, const char *, char *, size_t); +int ns_sprintrrf(const u_char *, size_t, const char *, + ns_class, ns_type, u_long, const u_char *, + size_t, const char *, const char *, + char *, size_t); +int ns_format_ttl(u_long, char *, size_t); +int ns_parse_ttl(const char *, u_long *); +uint32_t ns_datetosecs(const char *cp, int *errp); +int ns_name_ntol(const u_char *, u_char *, size_t); +int ns_name_ntop(const u_char *, char *, size_t); +int ns_name_pton(const char *, u_char *, size_t); +int ns_name_unpack(const u_char *, const u_char *, + const u_char *, u_char *, size_t); +int ns_name_pack(const u_char *, u_char *, int, + const u_char **, const u_char **); +int ns_name_uncompress(const u_char *, const u_char *, + const u_char *, char *, size_t); +int ns_name_compress(const char *, u_char *, size_t, + const u_char **, const u_char **); +int ns_name_skip(const u_char **, const u_char *); +void ns_name_rollback(const u_char *, const u_char **, + const u_char **); +int ns_sign(u_char *, int *, int, int, void *, + const u_char *, int, u_char *, int *, time_t); +int ns_sign2(u_char *, int *, int, int, void *, + const u_char *, int, u_char *, int *, time_t, + u_char **, u_char **); +int ns_sign_tcp(u_char *, int *, int, int, + ns_tcp_tsig_state *, int); +int ns_sign_tcp2(u_char *, int *, int, int, + ns_tcp_tsig_state *, int, + u_char **, u_char **); +int ns_sign_tcp_init(void *, const u_char *, int, + ns_tcp_tsig_state *); +u_char *ns_find_tsig(u_char *, u_char *); +int ns_verify(u_char *, int *, void *, + const u_char *, int, u_char *, int *, + time_t *, int); +int ns_verify_tcp(u_char *, int *, ns_tcp_tsig_state *, int); +int ns_verify_tcp_init(void *, const u_char *, int, + ns_tcp_tsig_state *); +int ns_samedomain(const char *, const char *); +int ns_subdomain(const char *, const char *); +int ns_makecanon(const char *, char *, size_t); +int ns_samename(const char *, const char *); +__END_DECLS + +#ifdef BIND_4_COMPAT +#include "nameser_compat.h" +#endif + +#endif /* !_ARPA_NAMESER_H_ */ diff --git a/vlmcsd/src/nameser_compat.h b/vlmcsd/src/nameser_compat.h new file mode 100644 index 0000000..f2bdefd --- /dev/null +++ b/vlmcsd/src/nameser_compat.h @@ -0,0 +1,236 @@ +/* $NetBSD: nameser_compat.h,v 1.1.1.2 2004/11/07 01:28:27 christos Exp $ */ + +/* Copyright (c) 1983, 1989 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * from nameser.h 8.1 (Berkeley) 6/2/93 + * Id: nameser_compat.h,v 1.1.2.3.4.2 2004/07/01 04:43:41 marka Exp + */ + +#ifndef _ARPA_NAMESER_COMPAT_ +#define _ARPA_NAMESER_COMPAT_ + +#define __BIND 19950621 /* (DEAD) interface version stamp. */ + +#include + +#ifndef BYTE_ORDER +#if (BSD >= 199103) +# include +#else +#ifdef __linux +# include +#else +#define LITTLE_ENDIAN 1234 /* least-significant byte first (vax, pc) */ +#define BIG_ENDIAN 4321 /* most-significant byte first (IBM, net) */ +#define PDP_ENDIAN 3412 /* LSB first in word, MSW first in long (pdp)*/ + +#if defined(vax) || defined(ns32000) || defined(sun386) || defined(i386) || \ + defined(MIPSEL) || defined(_MIPSEL) || defined(BIT_ZERO_ON_RIGHT) || \ + defined(__alpha__) || defined(__alpha) || \ + (defined(__Lynx__) && defined(__x86__)) +#define BYTE_ORDER LITTLE_ENDIAN +#endif + +#if defined(sel) || defined(pyr) || defined(mc68000) || defined(sparc) || \ + defined(is68k) || defined(tahoe) || defined(ibm032) || defined(ibm370) || \ + defined(MIPSEB) || defined(_MIPSEB) || defined(_IBMR2) || defined(DGUX) ||\ + defined(apollo) || defined(__convex__) || defined(_CRAY) || \ + defined(__hppa) || defined(__hp9000) || \ + defined(__hp9000s300) || defined(__hp9000s700) || \ + defined(__hp3000s900) || defined(__hpux) || defined(MPE) || \ + defined (BIT_ZERO_ON_LEFT) || defined(m68k) || defined(__sparc) || \ + (defined(__Lynx__) && \ + (defined(__68k__) || defined(__sparc__) || defined(__powerpc__))) +#define BYTE_ORDER BIG_ENDIAN +#endif +#endif /* __linux */ +#endif /* BSD */ +#endif /* BYTE_ORDER */ + +#if !defined(BYTE_ORDER) || \ + (BYTE_ORDER != BIG_ENDIAN && BYTE_ORDER != LITTLE_ENDIAN && \ + BYTE_ORDER != PDP_ENDIAN) + /* you must determine what the correct bit order is for + * your compiler - the next line is an intentional error + * which will force your compiles to bomb until you fix + * the above macros. + */ + #error "Undefined or invalid BYTE_ORDER"; +#endif + +/* + * Structure for query header. The order of the fields is machine- and + * compiler-dependent, depending on the byte/bit order and the layout + * of bit fields. We use bit fields only in int variables, as this + * is all ANSI requires. This requires a somewhat confusing rearrangement. + */ + +typedef struct { + unsigned id :16; /* query identification number */ +#if BYTE_ORDER == BIG_ENDIAN + /* fields in third byte */ + unsigned qr: 1; /* response flag */ + unsigned opcode: 4; /* purpose of message */ + unsigned aa: 1; /* authoritive answer */ + unsigned tc: 1; /* truncated message */ + unsigned rd: 1; /* recursion desired */ + /* fields in fourth byte */ + unsigned ra: 1; /* recursion available */ + unsigned unused :1; /* unused bits (MBZ as of 4.9.3a3) */ + unsigned ad: 1; /* authentic data from named */ + unsigned cd: 1; /* checking disabled by resolver */ + unsigned rcode :4; /* response code */ +#endif +#if BYTE_ORDER == LITTLE_ENDIAN || BYTE_ORDER == PDP_ENDIAN + /* fields in third byte */ + unsigned rd :1; /* recursion desired */ + unsigned tc :1; /* truncated message */ + unsigned aa :1; /* authoritive answer */ + unsigned opcode :4; /* purpose of message */ + unsigned qr :1; /* response flag */ + /* fields in fourth byte */ + unsigned rcode :4; /* response code */ + unsigned cd: 1; /* checking disabled by resolver */ + unsigned ad: 1; /* authentic data from named */ + unsigned unused :1; /* unused bits (MBZ as of 4.9.3a3) */ + unsigned ra :1; /* recursion available */ +#endif + /* remaining bytes */ + unsigned qdcount :16; /* number of question entries */ + unsigned ancount :16; /* number of answer entries */ + unsigned nscount :16; /* number of authority entries */ + unsigned arcount :16; /* number of resource entries */ +} HEADER; + +#define PACKETSZ NS_PACKETSZ +#define MAXDNAME NS_MAXDNAME +#define MAXCDNAME NS_MAXCDNAME +#define MAXLABEL NS_MAXLABEL +#define HFIXEDSZ NS_HFIXEDSZ +#define QFIXEDSZ NS_QFIXEDSZ +#define RRFIXEDSZ NS_RRFIXEDSZ +#define INT32SZ NS_INT32SZ +#define INT16SZ NS_INT16SZ +#define INT8SZ NS_INT8SZ +#define INADDRSZ NS_INADDRSZ +#define IN6ADDRSZ NS_IN6ADDRSZ +#define INDIR_MASK NS_CMPRSFLGS +#define NAMESERVER_PORT NS_DEFAULTPORT + +#define S_ZONE ns_s_zn +#define S_PREREQ ns_s_pr +#define S_UPDATE ns_s_ud +#define S_ADDT ns_s_ar + +#define QUERY ns_o_query +#define IQUERY ns_o_iquery +#define STATUS ns_o_status +#define NS_NOTIFY_OP ns_o_notify +#define NS_UPDATE_OP ns_o_update + +#define NOERROR ns_r_noerror +#define FORMERR ns_r_formerr +#define SERVFAIL ns_r_servfail +#define NXDOMAIN ns_r_nxdomain +#define NOTIMP ns_r_notimpl +#define REFUSED ns_r_refused +#define YXDOMAIN ns_r_yxdomain +#define YXRRSET ns_r_yxrrset +#define NXRRSET ns_r_nxrrset +#define NOTAUTH ns_r_notauth +#define NOTZONE ns_r_notzone +/*#define BADSIG ns_r_badsig*/ +/*#define BADKEY ns_r_badkey*/ +/*#define BADTIME ns_r_badtime*/ + + +#define DELETE ns_uop_delete +#define ADD ns_uop_add + +#define T_A ns_t_a +#define T_NS ns_t_ns +#define T_MD ns_t_md +#define T_MF ns_t_mf +#define T_CNAME ns_t_cname +#define T_SOA ns_t_soa +#define T_MB ns_t_mb +#define T_MG ns_t_mg +#define T_MR ns_t_mr +#define T_NULL ns_t_null +#define T_WKS ns_t_wks +#define T_PTR ns_t_ptr +#define T_HINFO ns_t_hinfo +#define T_MINFO ns_t_minfo +#define T_MX ns_t_mx +#define T_TXT ns_t_txt +#define T_RP ns_t_rp +#define T_AFSDB ns_t_afsdb +#define T_X25 ns_t_x25 +#define T_ISDN ns_t_isdn +#define T_RT ns_t_rt +#define T_NSAP ns_t_nsap +#define T_NSAP_PTR ns_t_nsap_ptr +#define T_SIG ns_t_sig +#define T_KEY ns_t_key +#define T_PX ns_t_px +#define T_GPOS ns_t_gpos +#define T_AAAA ns_t_aaaa +#define T_LOC ns_t_loc +#define T_NXT ns_t_nxt +#define T_EID ns_t_eid +#define T_NIMLOC ns_t_nimloc +#define T_SRV ns_t_srv +#define T_ATMA ns_t_atma +#define T_NAPTR ns_t_naptr +#define T_A6 ns_t_a6 +#define T_TSIG ns_t_tsig +#define T_IXFR ns_t_ixfr +#define T_AXFR ns_t_axfr +#define T_MAILB ns_t_mailb +#define T_MAILA ns_t_maila +#define T_ANY ns_t_any + +#define C_IN ns_c_in +#define C_CHAOS ns_c_chaos +#define C_HS ns_c_hs +/* BIND_UPDATE */ +#define C_NONE ns_c_none +#define C_ANY ns_c_any + +#define GETSHORT NS_GET16 +#define GETLONG NS_GET32 +#define PUTSHORT NS_PUT16 +#define PUTLONG NS_PUT32 + +#endif /* _ARPA_NAMESER_COMPAT_ */ diff --git a/vlmcsd/src/netlink-musl.h b/vlmcsd/src/netlink-musl.h new file mode 100644 index 0000000..e4346c0 --- /dev/null +++ b/vlmcsd/src/netlink-musl.h @@ -0,0 +1,107 @@ +#ifndef NETLINK_MUSL_H +#define NETLINK_MUSL_H + +#if !__linux__ +#error netlink-musl.h only works with a linux kernel +#endif + +#if __ANDROID__ +#error netlink-musl.h does not work with Android +#endif + +#include + +/* linux/netlink.h */ + +#define NETLINK_ROUTE 0 + +struct nlmsghdr { + uint32_t nlmsg_len; + uint16_t nlmsg_type; + uint16_t nlmsg_flags; + uint32_t nlmsg_seq; + uint32_t nlmsg_pid; +}; + +#define NLM_F_REQUEST 1 +#define NLM_F_MULTI 2 +#define NLM_F_ACK 4 + +#define NLM_F_ROOT 0x100 +#define NLM_F_MATCH 0x200 +#define NLM_F_ATOMIC 0x400 +#define NLM_F_DUMP (NLM_F_ROOT|NLM_F_MATCH) + +#define NLMSG_NOOP 0x1 +#define NLMSG_ERROR 0x2 +#define NLMSG_DONE 0x3 +#define NLMSG_OVERRUN 0x4 + +/* linux/rtnetlink.h */ + +#define RTM_NEWLINK 16 +#define RTM_GETLINK 18 +#define RTM_NEWADDR 20 +#define RTM_GETADDR 22 + +struct rtattr { + unsigned short rta_len; + unsigned short rta_type; +}; + +struct rtgenmsg { + unsigned char rtgen_family; +}; + +struct ifinfomsg { + unsigned char ifi_family; + unsigned char __ifi_pad; + unsigned short ifi_type; + int ifi_index; + unsigned ifi_flags; + unsigned ifi_change; +}; + +/* linux/if_link.h */ + +#define IFLA_ADDRESS 1 +#define IFLA_BROADCAST 2 +#define IFLA_IFNAME 3 +#define IFLA_STATS 7 + +/* linux/if_addr.h */ + +struct ifaddrmsg { + uint8_t ifa_family; + uint8_t ifa_prefixlen; + uint8_t ifa_flags; + uint8_t ifa_scope; + uint32_t ifa_index; +}; + +#define IFA_ADDRESS 1 +#define IFA_LOCAL 2 +#define IFA_LABEL 3 +#define IFA_BROADCAST 4 + +/* musl */ + +#define NETLINK_ALIGN(len) (((len)+3) & ~3) +#define NLMSG_DATA(nlh) ((void*)((char*)(nlh)+sizeof(struct nlmsghdr))) +#define NLMSG_DATALEN(nlh) ((nlh)->nlmsg_len-sizeof(struct nlmsghdr)) +#define NLMSG_DATAEND(nlh) ((char*)(nlh)+(nlh)->nlmsg_len) +#define NLMSG_NEXT(nlh) (struct nlmsghdr*)((char*)(nlh)+NETLINK_ALIGN((nlh)->nlmsg_len)) +#define NLMSG_OK(nlh,end) ((char*)(end)-(char*)(nlh) >= sizeof(struct nlmsghdr)) + +#define RTA_DATA(rta) ((void*)((char*)(rta)+sizeof(struct rtattr))) +#define RTA_DATALEN(rta) ((rta)->rta_len-sizeof(struct rtattr)) +#define RTA_DATAEND(rta) ((char*)(rta)+(rta)->rta_len) +#define RTA_NEXT(rta) (struct rtattr*)((char*)(rta)+NETLINK_ALIGN((rta)->rta_len)) +#define RTA_OK(nlh,end) ((char*)(end)-(char*)(rta) >= sizeof(struct rtattr)) + +#define NLMSG_RTA(nlh,len) ((void*)((char*)(nlh)+sizeof(struct nlmsghdr)+NETLINK_ALIGN(len))) +#define NLMSG_RTAOK(rta,nlh) RTA_OK(rta,NLMSG_DATAEND(nlh)) + +int __rtnetlink_enumerate(int link_af, int addr_af, int (*cb)(void *ctx, struct nlmsghdr *h), void *ctx); + +#endif // NETLINK_MUSL_H diff --git a/vlmcsd/src/network.c b/vlmcsd/src/network.c new file mode 100644 index 0000000..8f06dfe --- /dev/null +++ b/vlmcsd/src/network.c @@ -0,0 +1,1071 @@ +#ifndef CONFIG +#define CONFIG "config.h" +#endif // CONFIG +#include CONFIG + +#ifndef USE_MSRPC + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include "types.h" + +#if HAVE_GETIFADDR && _WIN32 +#include +#endif + +#include + +#ifndef _WIN32 +#include +#include +#include +#include +#include +#include + +#if HAVE_GETIFADDR + +#if __ANDROID__ +#include "ifaddrs-android.h" +#elif defined(GETIFADDRS_MUSL) +#include "ifaddrs-musl.h" +#else // getifaddrs from OS +#include +#endif // getifaddrs from OS + +#endif // HAVE_GETIFADDR +#endif // !WIN32 + +#include "network.h" +#include "endian.h" +//#include "output.h" +#include "helpers.h" +#include "shared_globals.h" +#include "rpc.h" + +#ifndef _WIN32 +typedef ssize_t(*sendrecv_t)(int, void*, size_t, int); +#else +typedef int (WINAPI *sendrecv_t)(SOCKET, void*, int, int); +#endif + + +// Send or receive a fixed number of bytes regardless if received in one or more chunks +int_fast8_t sendrecv(SOCKET sock, BYTE *data, int len, int_fast8_t do_send) +{ + int n; + sendrecv_t f = do_send + ? (sendrecv_t)send + : (sendrecv_t)recv; + + do + { + n = f(sock, data, len, 0); + } while ( + (n < 0 && socket_errno == SOCKET_EINTR) || (n > 0 && (data += n, (len -= n) > 0))); + + return !len; +} + + +static int_fast8_t ip2str(char *restrict result, const size_t resultLength, const struct sockaddr *const restrict socketAddress, const socklen_t socketLength) +{ + static const char *const fIPv4 = "%s:%s"; + static const char *const fIPv6 = "[%s]:%s"; + char ipAddress[64], portNumber[8]; + + if (getnameinfo + ( + socketAddress, + socketLength, + ipAddress, + sizeof(ipAddress), + portNumber, + sizeof(portNumber), + NI_NUMERICHOST | NI_NUMERICSERV + )) + { + return FALSE; + } + + if ((unsigned int)vlmcsd_snprintf(result, resultLength, socketAddress->sa_family == AF_INET6 ? fIPv6 : fIPv4, ipAddress, portNumber) > resultLength) return FALSE; + return TRUE; +} + + +static int_fast8_t getSocketList(struct addrinfo **saList, const char *const addr, const int flags, const int AddressFamily) +{ + int status; + char *szHost, *szPort; + const size_t len = strlen(addr) + 1; + + // Don't alloca too much + if (len > 264) return FALSE; + + char *addrcopy = (char*)alloca(len); + memcpy(addrcopy, addr, len); + + parseAddress(addrcopy, &szHost, &szPort); + + struct addrinfo hints; + + memset(&hints, 0, sizeof(struct addrinfo)); + + hints.ai_family = AddressFamily; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + hints.ai_flags = flags; + + if ((status = getaddrinfo(szHost, szPort, &hints, saList))) + { + printerrorf("Warning: %s: %s\n", addr, gai_strerror(status)); + return FALSE; + } + + return TRUE; +} + + +static int_fast8_t setBlockingEnabled(SOCKET fd, int_fast8_t blocking) +{ + if (fd == INVALID_SOCKET) return FALSE; + +#ifdef _WIN32 + + unsigned long mode = blocking ? 0 : 1; + return (ioctlsocket(fd, FIONBIO, &mode) == 0) ? TRUE : FALSE; + +#else // POSIX + + int flags = fcntl(fd, F_GETFL, 0); + + if (flags < 0) return FALSE; + + flags = blocking ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK); + return (fcntl(fd, F_SETFL, flags) == 0) ? TRUE : FALSE; + +#endif // POSIX +} + + +int_fast8_t isDisconnected(const SOCKET s) +{ + char buffer[1]; + + if (!setBlockingEnabled(s, FALSE)) return TRUE; + + const int n = recv(s, buffer, 1, MSG_PEEK); + + if (!setBlockingEnabled(s, TRUE)) return TRUE; + if (n == 0) return TRUE; + + return FALSE; +} + + +#if !defined(NO_PRIVATE_IP_DETECT) +// Check, if a sockaddr is a private IPv4 or IPv6 address +static int_fast8_t isPrivateIPAddress(struct sockaddr* addr, socklen_t* length) +{ + union v6addr + { + uint8_t bytes[16]; + uint16_t words[8]; + uint32_t dwords[4]; + uint64_t qwords[2]; + }; + + if (addr == NULL) return FALSE; + + switch (addr->sa_family) + { + case AF_INET6: + { + union v6addr* ipv6addr = (union v6addr*)&((struct sockaddr_in6*)addr)->sin6_addr; + + if + ( + (ipv6addr->qwords[0] != 0 || BE64(ipv6addr->qwords[1]) != 1) && // ::1 IPv6 localhost + (BE16(ipv6addr->words[0]) & 0xe000) == 0x2000 // !2000::/3 + ) + { + return FALSE; + } + + if (length) *length = sizeof(struct sockaddr_in6); + break; + } + + case AF_INET: + { + const uint32_t ipv4addr = BE32(((struct sockaddr_in*)addr)->sin_addr.s_addr); + + if + ( + (ipv4addr & 0xff000000) != 0x7f000000 && // 127.x.x.x localhost + (ipv4addr & 0xffff0000) != 0xc0a80000 && // 192.168.x.x private routeable + (ipv4addr & 0xffff0000) != 0xa9fe0000 && // 169.254.x.x link local + (ipv4addr & 0xff000000) != 0x0a000000 && // 10.x.x.x private routeable + (ipv4addr & 0xfff00000) != 0xac100000 // 172.16-31.x.x private routeable + ) + { + return FALSE; + } + + if (length) *length = sizeof(struct sockaddr_in); + break; + } + + default: + return FALSE; + } + + return TRUE; +} +#endif // !defined(NO_PRIVATE_IP_DETECT) + + +// Connect to TCP address addr (e.g. "kms.example.com:1688") and return an +// open socket for the connection if successful or INVALID_SOCKET otherwise +SOCKET connectToAddress(const char *const addr, const int AddressFamily, int_fast8_t showHostName) +{ + struct addrinfo *saList, *sa; + SOCKET s = INVALID_SOCKET; + char szAddr[128]; + + if (!getSocketList(&saList, addr, 0, AddressFamily)) return INVALID_SOCKET; + + for (sa = saList; sa; sa = sa->ai_next) + { + // struct sockaddr_in* addr4 = (struct sockaddr_in*)sa->ai_addr; + // struct sockaddr_in6* addr6 = (struct sockaddr_in6*)sa->ai_addr; + + if (ip2str(szAddr, sizeof(szAddr), sa->ai_addr, (socklen_t)sa->ai_addrlen)) + { + showHostName ? printf("Connecting to %s (%s) ... ", addr, szAddr) : printf("Connecting to %s ... ", szAddr); + fflush(stdout); + } + + s = socket(sa->ai_family, SOCK_STREAM, IPPROTO_TCP); + +# if !defined(NO_TIMEOUT) && !__minix__ +# ifndef _WIN32 // Standard Posix timeout structure + + struct timeval to; + to.tv_sec = 10; + to.tv_usec = 0; + +# else // Windows requires a DWORD with milliseconds + + DWORD to = 10000; + +# endif // _WIN32 + + setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (sockopt_t)&to, sizeof(to)); + setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, (sockopt_t)&to, sizeof(to)); +# endif // !defined(NO_TIMEOUT) && !__minix__ + + if (!connect(s, sa->ai_addr, (int)sa->ai_addrlen)) + { + printf("successful\n"); + break; + } + + printerrorf("%s: %s\n", szAddr, socket_errno == SOCKET_EINPROGRESS ? "Timed out" : vlmcsd_strerror(socket_errno)); + + socketclose(s); + s = INVALID_SOCKET; + } + + freeaddrinfo(saList); + return s; +} + +// fix for lame tomato toolchain +# if !defined(IPV6_V6ONLY) && defined(__linux__) +# define IPV6_V6ONLY (26) +# endif // !defined(IPV6_V6ONLY) && defined(__linux__) + + +#ifndef NO_SOCKETS + +static int_fast8_t allowSocketReuse(SOCKET s) +{ +# if !__CYGWIN__ + + BOOL socketOption = TRUE; + +# if !_WIN32 +# define VLMCSD_SOCKET_OPTION SO_REUSEADDR +# else // _WIN32 +# define VLMCSD_SOCKET_OPTION SO_EXCLUSIVEADDRUSE +# endif // _WIN32 + + if (setsockopt(s, SOL_SOCKET, VLMCSD_SOCKET_OPTION, (sockopt_t)&socketOption, sizeof(socketOption))) + { +# ifdef _PEDANTIC + printerrorf("Warning: Socket option SO_REUSEADDR unsupported: %s\n", vlmcsd_strerror(socket_errno)); +# endif // _PEDANTIC + } + +# undef VLMCSD_SOCKET_OPTION +# endif // !__CYGWIN__ + + return 0; +} + + +#ifdef SIMPLE_SOCKETS + +int listenOnAllAddresses() +{ + uint32_t port_listen; + + if (!stringToInt(defaultport, 1, 65535, &port_listen)) + { + printerrorf("Fatal: Port must be numeric between 1 and 65535.\n"); + exit(VLMCSD_EINVAL); + } + +# if defined(AF_INET6) && defined(IPV6_V6ONLY) + + struct sockaddr_in6 addr; + memset(&addr, 0, sizeof(addr)); + addr.sin6_family = AF_INET6; + addr.sin6_port = BE16((uint16_t)port_listen); + addr.sin6_addr = in6addr_any; + BOOL v6only = FALSE; + s_server = socket(AF_INET6, SOCK_STREAM, 0); + + if (s_server == INVALID_SOCKET + || allowSocketReuse(s_server) + || setsockopt(s_server, IPPROTO_IPV6, IPV6_V6ONLY, (sockopt_t)&v6only, sizeof(v6only)) + || bind(s_server, (struct sockaddr *)&addr, sizeof(addr)) + || listen(s_server, SOMAXCONN)) + { + socketclose(s_server); +# endif // defined(AF_INET6) && defined(IPV6_V6ONLY) + struct sockaddr_in addr4 = { + .sin_family = AF_INET, + .sin_port = BE16((uint16_t)port_listen), + .sin_addr.s_addr = BE32(INADDR_ANY) + }; + + s_server = socket(AF_INET, SOCK_STREAM, 0); + + if (s_server == INVALID_SOCKET + || allowSocketReuse(s_server) + || bind(s_server, (struct sockaddr *)&addr4, sizeof(addr4)) + || listen(s_server, SOMAXCONN)) + { + int error = socket_errno; + printerrorf("Fatal: Cannot bind to TCP port %u: %s\n", port_listen, vlmcsd_strerror(error)); + return error; + } + +# if defined(AF_INET6) && defined(IPV6_V6ONLY) + } +# endif // defined(AF_INET6) && defined(IPV6_V6ONLY) + +#ifndef NO_LOG + logger("Listening on TCP port %u\n", port_listen); +#endif // NO_LOG + + return 0; +} + +#else // !SIMPLE_SOCKETS + + +#if HAVE_GETIFADDR && !defined(NO_PRIVATE_IP_DETECT) +// Get list of private IP addresses. +// Returns 0 on success or an errno error code on failure +void getPrivateIPAddresses(int* numAddresses, char*** ipAddresses) +{ +# if _WIN32 + + PIP_ADAPTER_ADDRESSES firstAdapter, currentAdapter; + + DWORD dwRetVal; + ULONG outBufLen = 16384; + const ULONG flags = GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME; + + firstAdapter = (PIP_ADAPTER_ADDRESSES)vlmcsd_malloc(outBufLen); + + if ((dwRetVal = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, firstAdapter, &outBufLen)) == ERROR_BUFFER_OVERFLOW) + { + free(firstAdapter); + firstAdapter = (PIP_ADAPTER_ADDRESSES)vlmcsd_malloc(outBufLen); + dwRetVal = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, firstAdapter, &outBufLen); + } + + if (dwRetVal != NO_ERROR) + { + printerrorf("FATAL: Could not get network address list: %s\n", vlmcsd_strerror(dwRetVal)); + exit(dwRetVal); + } + + for (currentAdapter = firstAdapter, *numAddresses = 0; currentAdapter != NULL; currentAdapter = currentAdapter->Next) + { + PIP_ADAPTER_UNICAST_ADDRESS currentAddress; + int length; + + if (currentAdapter->OperStatus != IfOperStatusUp) continue; + + for (currentAddress = currentAdapter->FirstUnicastAddress; currentAddress != NULL; currentAddress = currentAddress->Next) + { + if (isPrivateIPAddress(currentAddress->Address.lpSockaddr, &length)) (*numAddresses)++; + } + } + + *ipAddresses = (char**)vlmcsd_malloc(*numAddresses * sizeof(char*)); + + for (currentAdapter = firstAdapter, *numAddresses = 0; currentAdapter != NULL; currentAdapter = currentAdapter->Next) + { + PIP_ADAPTER_UNICAST_ADDRESS currentAddress; + int length; + + if (currentAdapter->OperStatus != IfOperStatusUp) continue; + + for (currentAddress = currentAdapter->FirstUnicastAddress; currentAddress != NULL; currentAddress = currentAddress->Next) + { + if (!isPrivateIPAddress(currentAddress->Address.lpSockaddr, &length)) continue; + + char *ipAddress = (char*)vlmcsd_malloc(64); + const int error = getnameinfo(currentAddress->Address.lpSockaddr, currentAddress->Address.iSockaddrLength, ipAddress, 64, NULL, 0, NI_NUMERICHOST); + + if (error) + { + printerrorf("WARNING: Could not get IP address from interface list: %s\n", gai_strerror(error)); + *ipAddress = 0; + } + + (*ipAddresses)[(*numAddresses)++] = ipAddress; + } + } + + free(firstAdapter); + +# else // !_WIN32 + + struct ifaddrs *addrs, *addr; + + if (getifaddrs(&addrs)) + { + printerrorf("FATAL: Could not get network address list: %s\n", vlmcsd_strerror(errno)); + exit(errno); + } + + socklen_t length; + + for (addr = addrs, *numAddresses = 0; addr != NULL; addr = addr->ifa_next) + { + if (!isPrivateIPAddress(addr->ifa_addr, &length)) continue; + (*numAddresses)++; + } + + *ipAddresses = (char**)vlmcsd_malloc(*numAddresses * sizeof(char*)); + + for (addr = addrs, *numAddresses = 0; addr != NULL; addr = addr->ifa_next) + { + if (!isPrivateIPAddress(addr->ifa_addr, &length)) continue; + + char *ipAddress = (char*)vlmcsd_malloc(64); + int error = getnameinfo(addr->ifa_addr, length, ipAddress, 64, NULL, 0, NI_NUMERICHOST); + + if (error) + { + printerrorf("WARNING: Could not get IP address from interface list: %s\n", gai_strerror(error)); + *ipAddress = 0; + } + +# if __UCLIBC__ || __gnu_hurd__ + + size_t adrlen = strlen(ipAddress); + + if + ( + addr->ifa_addr->sa_family == AF_INET6 && + adrlen > 5 && + !strchr(ipAddress, '%') && + (BE16(*(uint16_t*)&((struct sockaddr_in6*)addr->ifa_addr)->sin6_addr) & 0xffc0) == 0xfe80 + ) + { + size_t ifnamelen = strlen(addr->ifa_name); + char* workaroundIpAddress = (char*)vlmcsd_malloc(adrlen + ifnamelen + 2); + strcpy(workaroundIpAddress, ipAddress); + strcat(workaroundIpAddress, "%"); + strcat(workaroundIpAddress, addr->ifa_name); + (*ipAddresses)[(*numAddresses)++] = workaroundIpAddress; + free(ipAddress); + } + else + { + (*ipAddresses)[(*numAddresses)++] = ipAddress; + } +# else // !(__UCLIBC__ || __gnu_hurd__) + + (*ipAddresses)[(*numAddresses)++] = ipAddress; + +# endif // !(__UCLIBC__ || __gnu_hurd__) + } + + freeifaddrs(addrs); + +# endif // !_WIN32 +} +#endif // HAVE_GETIFADDR && !defined(NO_PRIVATE_IP_DETECT) + + + +// Create a Listening socket for addrinfo sa and return socket s +// szHost and szPort are for logging only +static int listenOnAddress(const struct addrinfo *const ai, SOCKET *s) +{ + int error; + char ipstr[64]; + + ip2str(ipstr, sizeof(ipstr), ai->ai_addr, (socklen_t)ai->ai_addrlen); + + //*s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); + *s = socket(ai->ai_family, SOCK_STREAM, IPPROTO_TCP); + + if (*s == INVALID_SOCKET) + { + error = socket_errno; + printerrorf("Warning: %s error. %s\n", ai->ai_family == AF_INET6 ? cIPv6 : cIPv4, vlmcsd_strerror(error)); + return error; + } + +# if !defined(_WIN32) && !defined(NO_SIGHUP) + + int flags = fcntl(*s, F_GETFD, 0); + + if (flags != -1) + { + flags |= FD_CLOEXEC; + fcntl(*s, F_SETFD, flags); + } +# ifdef _PEDANTIC + else + { + printerrorf("Warning: Could not set FD_CLOEXEC flag on %s: %s\n", ipstr, vlmcsd_strerror(errno)); + } +# endif // _PEDANTIC + +# endif // !defined(_WIN32) && !defined(NO_SIGHUP) + + BOOL socketOption = TRUE; + +# ifdef IPV6_V6ONLY + if (ai->ai_family == AF_INET6 && setsockopt(*s, IPPROTO_IPV6, IPV6_V6ONLY, (sockopt_t)&socketOption, sizeof(socketOption))) + { +# ifdef _PEDANTIC +# if defined(_WIN32) || defined(__CYGWIN__) + // if (IsWindowsVistaOrGreater()) //Doesn't work with older version of MingW32-w64 toolchain + if ((GetVersion() & 0xff) > 5) + { +# endif // _WIN32 + printerrorf("Warning: %s does not support socket option IPV6_V6ONLY: %s\n", ipstr, vlmcsd_strerror(socket_errno)); +# if defined(_WIN32) || defined(__CYGWIN__) + } +# endif // _WIN32 +# endif // _PEDANTIC + } +# endif + + allowSocketReuse(*s); + +# if HAVE_FREEBIND +# if (defined(IP_NONLOCALOK) || __FreeBSD_kernel__ || __FreeBSD__) && !defined(IPV6_BINDANY) +# define IPV6_BINDANY 64 +# endif // (defined(IP_NONLOCALOK) || __FreeBSD_kernel__ || __FreeBSD__) && !defined(IPV6_BINDANY) + + if (freebind) + { +# if defined(IP_FREEBIND) // Linux + if (setsockopt(*s, IPPROTO_IP, IP_FREEBIND, (sockopt_t)&socketOption, sizeof(socketOption))) + { + printerrorf("Warning: Cannot use FREEBIND on %s: %s\n", ipstr, vlmcsd_strerror(socket_errno)); + } +# endif // defined(IP_FREEBIND) + +# if defined(IP_BINDANY) // FreeBSD IPv4 + if (ai->ai_family == AF_INET && setsockopt(*s, IPPROTO_IP, IP_BINDANY, (sockopt_t)&socketOption, sizeof(socketOption))) + { + printerrorf("Warning: Cannot use BINDANY on %s: %s\n", ipstr, vlmcsd_strerror(socket_errno)); + } +# endif // defined(IP_BINDANY) + +# if defined(IPV6_BINDANY) // FreeBSD IPv6 + if (ai->ai_family == AF_INET6 && setsockopt(*s, IPPROTO_IP, IPV6_BINDANY, (sockopt_t)&socketOption, sizeof(socketOption))) + { +# ifdef _PEDANTIC // FreeBSD defines the symbol but doesn't have BINDANY in IPv6 (Kame stack doesn't have it) + printerrorf("Warning: Cannot use BINDANY on %s: %s\n", ipstr, vlmcsd_strerror(socket_errno)); +# endif + } +# endif // defined(IPV6_BINDANY) + +# if defined(IP_NONLOCALOK) && !defined(IP_BINDANY) // FreeBSD with GNU userspace IPv4 + if (ai->ai_family == AF_INET && setsockopt(*s, IPPROTO_IP, IP_NONLOCALOK, (sockopt_t)&socketOption, sizeof(socketOption))) + { + printerrorf("Warning: Cannot use BINDANY on %s: %s\n", ipstr, vlmcsd_strerror(socket_errno)); + } +# endif // defined(IP_NONLOCALOK) && !defined(IP_BINDANY) + } + +# endif // HAVE_FREEBIND + + if (bind(*s, ai->ai_addr, (int)ai->ai_addrlen) || listen(*s, SOMAXCONN)) + { + error = socket_errno; + printerrorf("Warning: %s: %s\n", ipstr, vlmcsd_strerror(error)); + socketclose(*s); + return error; + } + +# ifndef NO_LOG + logger("Listening on %s\n", ipstr); +# endif + + return 0; +} + +// Adds a listening socket for an address string, +// e.g. 127.0.0.1:1688 or [2001:db8:dead:beef::1]:1688 +BOOL addListeningSocket(const char *const addr) +{ + struct addrinfo *aiList, *ai; + int result = FALSE; + SOCKET *s = SocketList + numsockets; + + if (getSocketList(&aiList, addr, AI_PASSIVE | AI_NUMERICHOST, AF_UNSPEC)) + { + for (ai = aiList; ai; ai = ai->ai_next) + { + // struct sockaddr_in* addr4 = (struct sockaddr_in*)sa->ai_addr; + // struct sockaddr_in6* addr6 = (struct sockaddr_in6*)sa->ai_addr; + + if (numsockets >= FD_SETSIZE) + { +#ifdef _PEDANTIC // Do not report this error in normal builds to keep file size low + printerrorf("Warning: Cannot listen on %s. Your OS only supports %u listening sockets in an FD_SET.\n", addr, FD_SETSIZE); +#endif + break; + } + + if (!listenOnAddress(ai, s)) + { + numsockets++; + result = TRUE; + } + else + { + exitOnWarningLevel(1); + } + } + + freeaddrinfo(aiList); + } + return result; +} + + +// Just create some dummy sockets to see if we have a specific protocol (IPv4 or IPv6) +__pure int_fast8_t checkProtocolStack(const int addressfamily) +{ + SOCKET s; // = INVALID_SOCKET; + + s = socket(addressfamily, SOCK_STREAM, 0); + const int_fast8_t success = (s != INVALID_SOCKET); + + socketclose(s); + return success; +} + + +// Build an fd_set of all listening socket then use select to wait for an incoming connection +static SOCKET network_accept_any() +{ + fd_set ListeningSocketsList; + SOCKET maxSocket, sock; + int i; + int status; + + FD_ZERO(&ListeningSocketsList); + maxSocket = 0; + + for (i = 0; i < numsockets; i++) + { + FD_SET(SocketList[i], &ListeningSocketsList); + if (SocketList[i] > maxSocket) maxSocket = SocketList[i]; + } + + status = select((int)maxSocket + 1, &ListeningSocketsList, NULL, NULL, NULL); + + if (status < 0) return INVALID_SOCKET; + + sock = INVALID_SOCKET; + + for (i = 0; i < numsockets; i++) + { + if (FD_ISSET(SocketList[i], &ListeningSocketsList)) + { + sock = SocketList[i]; + break; + } + } + + if (sock == INVALID_SOCKET) + return INVALID_SOCKET; + else + return accept(sock, NULL, NULL); +} +#endif // !SIMPLE_SOCKETS + + +void closeAllListeningSockets() +{ +# ifdef SIMPLE_SOCKETS + + socketclose(s_server); + +# else // !SIMPLE_SOCKETS + + int i; + + for (i = 0; i < numsockets; i++) + { + socketclose(SocketList[i]); + } + +#endif // !SIMPLE_SOCKETS +} +#endif // NO_SOCKETS + + +static void serveClient(const SOCKET s_client, const DWORD RpcAssocGroup) +{ +# if !defined(NO_TIMEOUT) && !__minix__ + +# ifndef _WIN32 // Standard Posix timeout structure + + struct timeval to; + to.tv_sec = ServerTimeout; + to.tv_usec = 0; + +#else // Windows requires a DWORD with milliseconds + + DWORD to = ServerTimeout * 1000; + +# endif // _WIN32 + +# if !defined(NO_LOG) && defined(_PEDANTIC) + + const int result = + setsockopt(s_client, SOL_SOCKET, SO_RCVTIMEO, (sockopt_t)&to, sizeof(to)) || + setsockopt(s_client, SOL_SOCKET, SO_SNDTIMEO, (sockopt_t)&to, sizeof(to)); + + if (result) logger("Warning: Set timeout failed: %s\n", vlmcsd_strerror(socket_errno)); + +# else // !(!defined(NO_LOG) && defined(_PEDANTIC)) + + setsockopt(s_client, SOL_SOCKET, SO_RCVTIMEO, (sockopt_t)&to, sizeof(to)); + setsockopt(s_client, SOL_SOCKET, SO_SNDTIMEO, (sockopt_t)&to, sizeof(to)); + +# endif // !(!defined(NO_LOG) && defined(_PEDANTIC)) + +# endif // !defined(NO_TIMEOUT) && !__minix__ + + char ipstr[64]; + socklen_t len; + struct sockaddr_storage addr; + + len = sizeof(addr); + + if (getpeername(s_client, (struct sockaddr*)&addr, &len) || + !ip2str(ipstr, sizeof(ipstr), (struct sockaddr*)&addr, len)) + { +# if !defined(NO_LOG) && defined(_PEDANTIC) + logger("Fatal: Cannot determine client's IP address: %s\n", vlmcsd_strerror(errno)); +# endif // !defined(NO_LOG) && defined(_PEDANTIC) + socketclose(s_client); + return; + } + + +# ifndef NO_LOG + const char *const connection_type = addr.ss_family == AF_INET6 ? cIPv6 : cIPv4; + static const char *const cAccepted = "accepted"; + static const char *const cClosed = "closed"; + static const char *const fIP = "%s connection %s: %s.\n"; + + logger(fIP, connection_type, cAccepted, ipstr); +#endif // NO_LOG + +# if !defined(NO_PRIVATE_IP_DETECT) + + if (!(PublicIPProtectionLevel & 2) || isPrivateIPAddress((struct sockaddr*)&addr, NULL)) + { + rpcServer(s_client, RpcAssocGroup, ipstr); + } +# ifndef NO_LOG + else + { + logger("Client with public IP address rejected\n"); + } +# endif // NO_LOG + +# else // defined(NO_PRIVATE_IP_DETECT) + + rpcServer(s_client, RpcAssocGroup, ipstr); + +# endif // defined(NO_PRIVATE_IP_DETECT) + +# ifndef NO_LOG + logger(fIP, connection_type, cClosed, ipstr); +# endif // NO_LOG + + socketclose(s_client); +} + + +#ifndef NO_SOCKETS +static void post_sem(void) +{ +#if !defined(NO_LIMIT) && !__minix__ + if (!InetdMode && MaxTasks != SEM_VALUE_MAX) + { + semaphore_post(MaxTaskSemaphore); + } +#endif // !defined(NO_LIMIT) && !__minix__ +} + + +static void wait_sem(void) +{ +#if !defined(NO_LIMIT) && !__minix__ + if (!InetdMode && MaxTasks != SEM_VALUE_MAX) + { + semaphore_wait(MaxTaskSemaphore); + } +#endif // !defined(NO_LIMIT) && !__minix__ +} +#endif // NO_SOCKETS + +#if defined(USE_THREADS) && !defined(NO_SOCKETS) + +#if defined(_WIN32) || defined(__CYGWIN__) // Win32 Threads +static DWORD WINAPI serveClientThreadProc(PCLDATA clData) +#else // Posix threads +static void *serveClientThreadProc(PCLDATA clData) +#endif // Thread proc is identical in WIN32 and Posix threads +{ + serveClient(clData->socket, clData->RpcAssocGroup); + free(clData); + post_sem(); + + return 0; +} + +#endif // USE_THREADS + + +#ifndef NO_SOCKETS + +#if defined(USE_THREADS) && (defined(_WIN32) || defined(__CYGWIN__)) // Windows Threads +static int serveClientAsyncWinThreads(PCLDATA thr_CLData) +{ + wait_sem(); + + HANDLE h = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)serveClientThreadProc, thr_CLData, 0, NULL); + + if (h) + { + CloseHandle(h); + return NO_ERROR; + } + else + { + socketclose(thr_CLData->socket); + free(thr_CLData); + post_sem(); + return GetLastError(); + } +} +#endif // defined(USE_THREADS) && defined(_WIN32) // Windows Threads + + +#if defined(USE_THREADS) && !defined(_WIN32) && !defined(__CYGWIN__) // Posix Threads +static int ServeClientAsyncPosixThreads(const PCLDATA thr_CLData) +{ + pthread_t p_thr; + pthread_attr_t attr; + int error; + + wait_sem(); + + // Must set detached state to avoid memory leak + if ((error = pthread_attr_init(&attr)) || + (error = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)) || + (error = pthread_create(&p_thr, &attr, (void * (*)(void *))serveClientThreadProc, thr_CLData))) + { + socketclose(thr_CLData->socket); + free(thr_CLData); + post_sem(); + return error; + } + + return 0; +} +#endif // defined(USE_THREADS) && !defined(_WIN32) // Posix Threads + +#ifndef USE_THREADS // fork() implementation +static void ChildSignalHandler(const int signal) +{ + if (signal == SIGHUP) return; + + post_sem(); + +#ifndef NO_LOG + logger("Warning: Child killed/crashed by %s\n", strsignal(signal)); +#endif // NO_LOG + + exit(ECHILD); +} + +static int ServeClientAsyncFork(const SOCKET s_client, const DWORD RpcAssocGroup) +{ + int pid; + wait_sem(); + + if ((pid = fork()) < 0) + { + return errno; + } + else if (pid) + { + // Parent process + socketclose(s_client); + return 0; + } + else + { + // Child process + + // Setup a Child Handler for most common termination signals + struct sigaction sa; + + sa.sa_flags = 0; + sa.sa_handler = ChildSignalHandler; + + static int signallist[] = { SIGHUP, SIGINT, SIGTERM, SIGSEGV, SIGILL, SIGFPE, SIGBUS }; + + if (!sigemptyset(&sa.sa_mask)) + { + uint_fast8_t i; + + for (i = 0; i < vlmcsd_countof(signallist); i++) + { + sigaction(signallist[i], &sa, NULL); + } + } + + serveClient(s_client, RpcAssocGroup); + post_sem(); + exit(0); + } +} +#endif + + +int serveClientAsync(const SOCKET s_client, const DWORD RpcAssocGroup) +{ +#ifndef USE_THREADS // fork() implementation + + return ServeClientAsyncFork(s_client, RpcAssocGroup); + +#else // threads implementation + + PCLDATA thr_CLData = (PCLDATA)vlmcsd_malloc(sizeof(CLDATA)); + thr_CLData->socket = s_client; + thr_CLData->RpcAssocGroup = RpcAssocGroup; + +#if defined(_WIN32) || defined (__CYGWIN__) // Windows threads + + return serveClientAsyncWinThreads(thr_CLData); + +#else // Posix Threads + + return ServeClientAsyncPosixThreads(thr_CLData); + +#endif // Posix Threads + +#endif // USE_THREADS +} + +#endif // NO_SOCKETS + + +int runServer() +{ + DWORD RpcAssocGroup = rand32(); + + // If compiled for inetd-only mode just serve the stdin socket +#ifdef NO_SOCKETS + serveClient(STDIN_FILENO, RpcAssocGroup); + return 0; +#else +// In inetd mode just handle the stdin socket + if (InetdMode) + { + serveClient(STDIN_FILENO, RpcAssocGroup); + return 0; + } + + for (;;) + { + int error; + SOCKET s_client; + +# ifdef SIMPLE_SOCKETS + if ((s_client = accept(s_server, NULL, NULL)) == INVALID_SOCKET) +# else // Standalone mode fully featured sockets + if ((s_client = network_accept_any()) == INVALID_SOCKET) +# endif // Standalone mode fully featured sockets + { + error = socket_errno; + if (error == SOCKET_EINTR || error == SOCKET_ECONNABORTED) continue; + +# ifdef _NTSERVICE + if (ServiceShutdown) return 0; +# endif + +# ifndef NO_LOG + logger("Fatal: %s\n", vlmcsd_strerror(error)); +# endif + + return error; + } + + RpcAssocGroup++; + +# if !defined(NO_LOG) && defined(_PEDANTIC) + if ((error = serveClientAsync(s_client, RpcAssocGroup))) + { +# ifdef USE_THREADS + logger("Warning: Could not create client thread: %s\n", vlmcsd_strerror(error)); +# else // !USE_THREADS + logger("Warning: Could not fork client: %s\n", vlmcsd_strerror(error)); +# endif // !USE_THREADS + } +# else // NO_LOG || !_PEDANTIC + serveClientAsync(s_client, RpcAssocGroup); +# endif // NO_LOG || !_PEDANTIC + } +# endif // NO_SOCKETS +} + +#endif // USE_MSRPC diff --git a/vlmcsd/src/network.h b/vlmcsd/src/network.h new file mode 100644 index 0000000..987b6c2 --- /dev/null +++ b/vlmcsd/src/network.h @@ -0,0 +1,48 @@ +#ifndef INCLUDED_NETWORK_H +#define INCLUDED_NETWORK_H + +#ifndef CONFIG +#define CONFIG "config.h" +#endif // CONFIG +#include CONFIG + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include "types.h" +#include "output.h" + +#if _MSC_VER +//typedef signed char int_fast8_t; +//typedef unsigned char BYTE; +//typedef UINT_PTR size_t; +//typedef unsigned long DWORD; +#define STDIN_FILENO 0 +#endif + +int_fast8_t sendrecv(SOCKET sock, BYTE *data, int len, int_fast8_t do_send); + +#define _recv(s, d, l) sendrecv(s, (BYTE *)d, l, 0) +#define _send(s, d, l) sendrecv(s, (BYTE *)d, l, !0) + +#ifndef NO_SOCKETS + +void closeAllListeningSockets(); +#ifdef SIMPLE_SOCKETS +int listenOnAllAddresses(); +#endif // SIMPLE_SOCKETS +BOOL addListeningSocket(const char *const addr); +__pure int_fast8_t checkProtocolStack(const int addressfamily); + +#if HAVE_GETIFADDR +void getPrivateIPAddresses(int* numAddresses, char*** ipAddresses); +#endif // HAVE_GETIFADDR + +#endif // NO_SOCKETS + +int runServer(); +SOCKET connectToAddress(const char *const addr, const int AddressFamily, int_fast8_t showHostName); +int_fast8_t isDisconnected(const SOCKET s); + +#endif // INCLUDED_NETWORK_H diff --git a/vlmcsd/src/ns_name.c b/vlmcsd/src/ns_name.c new file mode 100644 index 0000000..3e09928 --- /dev/null +++ b/vlmcsd/src/ns_name.c @@ -0,0 +1,355 @@ +/* + * Copyright (c) 1996,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* + * Modified by Hotbird64 for use with vlmcs. + */ + +#ifndef CONFIG +#define CONFIG "config.h" +#endif // CONFIG +#include CONFIG + +#ifdef DNS_PARSER_INTERNAL +#ifndef NO_DNS + +#include +#include +#include +#include +#include +#include +#include + +#include "types.h" +#include "ns_name.h" + +#ifdef SPRINTF_CHAR +# define SPRINTF(x) strlen(sprintf/**/x) +#else +# define SPRINTF(x) ((size_t)sprintf x) +#endif + +#define NS_TYPE_ELT 0x40 /* EDNS0 extended label type */ +#define DNS_LABELTYPE_BITSTRING 0x41 + +#define NS_MAXCDNAME 255 +#define NS_CMPRSFLGS 0xc0 + +/* Data. */ + +static char digits[] = "0123456789"; + + +/* Forward. */ + +static int special_vlmcsd(int); +static int printable_vlmcsd(int); +static int labellen_vlmcsd(const uint8_t *); +static int decode_bitstring_vlmcsd(const char **, char *, const char *); + +/* + * ns_name_ntop(src, dst, dstsiz) + * Convert an encoded domain name to printable ascii as per RFC1035. + * return: + * Number of bytes written to buffer, or -1 (with errno set) + * notes: + * The root is returned as "." + * All other domains are returned in non absolute form + */ +static int +ns_name_ntop_vlmcsd(const uint8_t *src, char *dst, size_t dstsiz) +{ + const uint8_t *cp; + char *dn, *eom; + uint8_t c; + uint32_t n; + int l; + + cp = src; + dn = dst; + eom = dst + dstsiz; + + while ((n = *cp++) != 0) { + if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) { + /* Some kind of compression pointer. */ + errno = EMSGSIZE; + return (-1); + } + if (dn != dst) { + if (dn >= eom) { + errno = EMSGSIZE; + return (-1); + } + *dn++ = '.'; + } + if ((l = labellen_vlmcsd(cp - 1)) < 0) { + errno = EMSGSIZE; /* XXX */ + return(-1); + } + if (dn + l >= eom) { + errno = EMSGSIZE; + return (-1); + } + if ((n & NS_CMPRSFLGS) == NS_TYPE_ELT) { + int m; + + if (n != DNS_LABELTYPE_BITSTRING) { + /* XXX: labellen should reject this case */ + errno = EINVAL; + return(-1); + } + if ((m = decode_bitstring_vlmcsd((const char **)&cp, dn, eom)) < 0) + { + errno = EMSGSIZE; + return(-1); + } + dn += m; + continue; + } + for ((void)NULL; l > 0; l--) { + c = *cp++; + if (special_vlmcsd(c)) { + if (dn + 1 >= eom) { + errno = EMSGSIZE; + return (-1); + } + *dn++ = '\\'; + *dn++ = (char)c; + } else if (!printable_vlmcsd(c)) { + if (dn + 3 >= eom) { + errno = EMSGSIZE; + return (-1); + } + *dn++ = '\\'; + *dn++ = digits[c / 100]; + *dn++ = digits[(c % 100) / 10]; + *dn++ = digits[c % 10]; + } else { + if (dn >= eom) { + errno = EMSGSIZE; + return (-1); + } + *dn++ = (char)c; + } + } + } + if (dn == dst) { + if (dn >= eom) { + errno = EMSGSIZE; + return (-1); + } + *dn++ = '.'; + } + if (dn >= eom) { + errno = EMSGSIZE; + return (-1); + } + *dn++ = '\0'; + return (dn - dst); +} + +static int +ns_name_unpack_vlmcsd(const uint8_t *msg, const uint8_t *eom, const uint8_t *src, + uint8_t *dst, size_t dstsiz) +{ + const uint8_t *srcp, *dstlim; + uint8_t *dstp; + int n, len, checked, l; + + len = -1; + checked = 0; + dstp = dst; + srcp = src; + dstlim = dst + dstsiz; + if (srcp < msg || srcp >= eom) { + errno = EMSGSIZE; + return (-1); + } + /* Fetch next label in domain name. */ + while ((n = *srcp++) != 0) { + /* Check for indirection. */ + switch (n & NS_CMPRSFLGS) { + case 0: + case NS_TYPE_ELT: + /* Limit checks. */ + if ((l = labellen_vlmcsd(srcp - 1)) < 0) { + errno = EMSGSIZE; + return(-1); + } + if (dstp + l + 1 >= dstlim || srcp + l >= eom) { + errno = EMSGSIZE; + return (-1); + } + checked += l + 1; + *dstp++ = n; + memcpy(dstp, srcp, l); + dstp += l; + srcp += l; + break; + + case NS_CMPRSFLGS: + if (srcp >= eom) { + errno = EMSGSIZE; + return (-1); + } + if (len < 0) + len = srcp - src + 1; + srcp = msg + (((n & 0x3f) << 8) | (*srcp & 0xff)); + if (srcp < msg || srcp >= eom) { /* Out of range. */ + errno = EMSGSIZE; + return (-1); + } + checked += 2; + /* + * Check for loops in the compressed name; + * if we've looked at the whole message, + * there must be a loop. + */ + if (checked >= eom - msg) { + errno = EMSGSIZE; + return (-1); + } + break; + + default: + errno = EMSGSIZE; + return (-1); /* flag error */ + } + } + *dstp = '\0'; + if (len < 0) + len = srcp - src; + return (len); +} + + +/* + * ns_name_uncompress_vlmcsd(msg, eom, src, dst, dstsiz) + * Expand compressed domain name to presentation format. + * return: + * Number of bytes read out of `src', or -1 (with errno set). + * note: + * Root domain returns as "." not "". + */ +int +ns_name_uncompress_vlmcsd(uint8_t *msg, uint8_t *eom, uint8_t *src, + char *dst, size_t dstsiz) +{ + uint8_t tmp[NS_MAXCDNAME]; + int n; + + if ((n = ns_name_unpack_vlmcsd(msg, eom, src, tmp, sizeof tmp)) == -1) + return (-1); + if (ns_name_ntop_vlmcsd(tmp, dst, dstsiz) == -1) + return (-1); + return (n); +} + +/* + * special(ch) + * Thinking in noninternationalized USASCII (per the DNS spec), + * is this characted special ("in need of quoting") ? + * return: + * boolean. + */ +static int +special_vlmcsd(int ch) { + switch (ch) { + case 0x22: /* '"' */ + case 0x2E: /* '.' */ + case 0x3B: /* ';' */ + case 0x5C: /* '\\' */ + case 0x28: /* '(' */ + case 0x29: /* ')' */ + /* Special modifiers in zone files. */ + case 0x40: /* '@' */ + case 0x24: /* '$' */ + return (1); + default: + return (0); + } +} + +/* + * printable(ch) + * Thinking in noninternationalized USASCII (per the DNS spec), + * is this character visible and not a space when printed ? + * return: + * boolean. + */ +static int +printable_vlmcsd(int ch) { + return (ch > 0x20 && ch < 0x7f); +} + +static int +decode_bitstring_vlmcsd(const char **cpp, char *dn, const char *eom) +{ + const char *cp = *cpp; + char *beg = dn, tc; + int b, blen, plen; + + if ((blen = (*cp & 0xff)) == 0) + blen = 256; + plen = (blen + 3) / 4; + plen += sizeof("\\[x/]") + (blen > 99 ? 3 : (blen > 9) ? 2 : 1); + if (dn + plen >= eom) + return(-1); + + cp++; + dn += SPRINTF((dn, "\\[x")); + for (b = blen; b > 7; b -= 8, cp++) + dn += SPRINTF((dn, "%02x", *cp & 0xff)); + if (b > 4) { + tc = *cp++; + dn += SPRINTF((dn, "%02x", tc & (0xff << (8 - b)))); + } else if (b > 0) { + tc = *cp++; + dn += SPRINTF((dn, "%1x", + ((tc >> 4) & 0x0f) & (0x0f << (4 - b)))); + } + dn += SPRINTF((dn, "/%d]", blen)); + + *cpp = cp; + return(dn - beg); +} + +static int +labellen_vlmcsd(const uint8_t *lp) +{ + int bitlen; + uint8_t l = *lp; + + if ((l & NS_CMPRSFLGS) == NS_CMPRSFLGS) { + /* should be avoided by the caller */ + return(-1); + } + + if ((l & NS_CMPRSFLGS) == NS_TYPE_ELT) { + if (l == DNS_LABELTYPE_BITSTRING) { + if ((bitlen = *(lp + 1)) == 0) + bitlen = 256; + return((bitlen + 7 ) / 8 + 1); + } + return(-1); /* unknwon ELT */ + } + return(l); +} + +#endif // !NO_DNS +#endif // DNS_PARSER_INTERNAL diff --git a/vlmcsd/src/ns_name.h b/vlmcsd/src/ns_name.h new file mode 100644 index 0000000..b7ba2eb --- /dev/null +++ b/vlmcsd/src/ns_name.h @@ -0,0 +1,9 @@ + +#ifndef NS_NAME_H_ +#define NS_NAME_H_ + +int +ns_name_uncompress_vlmcsd(uint8_t *msg, uint8_t *eom, uint8_t *src, + char *dst, size_t dstsiz); + +#endif /* NS_NAME_H_ */ diff --git a/vlmcsd/src/ns_parse.c b/vlmcsd/src/ns_parse.c new file mode 100644 index 0000000..84c26ad --- /dev/null +++ b/vlmcsd/src/ns_parse.c @@ -0,0 +1,206 @@ +/* + * Copyright (c) 1996,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* + * Modified by Hotbird64 for use with vlmcs. + */ + +#ifndef CONFIG +#define CONFIG "config.h" +#endif // CONFIG +#include CONFIG + +#ifdef DNS_PARSER_INTERNAL +#ifndef NO_DNS + +/* Import. */ + +#include +#include +#include + +#include "types.h" +#include "endian.h" +#include "ns_name.h" +#include "ns_parse.h" + +/* Macros. */ + +#define NS_GET16_VLMCSD(s, cp) do { \ + (s) = GET_UA16BE(cp); \ + (cp) += NS_INT16SZ; \ +} while (0) + +#define NS_GET32_VLMCSD(l, cp) do { \ + (l) = GET_UA32BE(cp); \ + (cp) += NS_INT32SZ; \ +} while (0) + +#define RETERR(err) do { errno = (err); return (-1); } while (0) + +/* Forward. */ + +static void setsection_vlmcsd(ns_msg_vlmcsd *msg, ns_sect_vlmcsd sect); + + +static int dn_skipname_vlmcsd(unsigned char *s, unsigned char *end) +{ + unsigned char *p; + for (p=s; p=192) + {if (p+1 0; count--) { + int b, rdlength; + + b = dn_skipname_vlmcsd(ptr, eom); + if (b < 0) + RETERR(EMSGSIZE); + ptr += b/*Name*/ + NS_INT16SZ/*Type*/ + NS_INT16SZ/*Class*/; + if (section != ns_s_qd_vlmcsd) { + if (ptr + NS_INT32SZ + NS_INT16SZ > eom) + RETERR(EMSGSIZE); + ptr += NS_INT32SZ/*TTL*/; + NS_GET16_VLMCSD(rdlength, ptr); + ptr += rdlength/*RData*/; + } + } + if (ptr > eom) + RETERR(EMSGSIZE); + return (ptr - optr); +} + +int +ns_initparse_vlmcsd(uint8_t *msg, int msglen, ns_msg_vlmcsd *handle) { + uint8_t *eom = msg + msglen; + int i; + + memset(handle, 0x5e, sizeof *handle); + handle->_msg = msg; + handle->_eom = eom; + if (msg + NS_INT16SZ > eom) + RETERR(EMSGSIZE); + NS_GET16_VLMCSD(handle->_id, msg); + if (msg + NS_INT16SZ > eom) + RETERR(EMSGSIZE); + NS_GET16_VLMCSD(handle->_flags, msg); + for (i = 0; i < ns_s_max_vlmcsd; i++) { + if (msg + NS_INT16SZ > eom) + RETERR(EMSGSIZE); + NS_GET16_VLMCSD(handle->_counts[i], msg); + } + for (i = 0; i < ns_s_max_vlmcsd; i++) + if (handle->_counts[i] == 0) + handle->_sections[i] = NULL; + else { + int b = ns_skiprr_vlmcsd(msg, eom, (ns_sect_vlmcsd)i, + handle->_counts[i]); + + if (b < 0) + return (-1); + handle->_sections[i] = msg; + msg += b; + } + if (msg > eom) + RETERR(EMSGSIZE); + handle->_eom = msg; + setsection_vlmcsd(handle, ns_s_max_vlmcsd); + return (0); +} + +int +ns_parserr_vlmcsd(ns_msg_vlmcsd *handle, ns_sect_vlmcsd section, int rrnum, ns_rr_vlmcsd *rr) { + int b; + + /* Make section right. */ + if (section >= ns_s_max_vlmcsd) + RETERR(ENODEV); + if (section != handle->_sect) + setsection_vlmcsd(handle, section); + + /* Make rrnum right. */ + if (rrnum == -1) + rrnum = handle->_rrnum; + if (rrnum < 0 || rrnum >= handle->_counts[(int)section]) + RETERR(ENODEV); + if (rrnum < handle->_rrnum) + setsection_vlmcsd(handle, section); + if (rrnum > handle->_rrnum) { + b = ns_skiprr_vlmcsd(handle->_msg_ptr, handle->_eom, section, + rrnum - handle->_rrnum); + + if (b < 0) + return (-1); + handle->_msg_ptr += b; + handle->_rrnum = rrnum; + } + + /* Do the parse. */ + b = ns_name_uncompress_vlmcsd(handle->_msg, handle->_eom, + handle->_msg_ptr, rr->name, NS_MAXDNAME); + if (b < 0) + return (-1); + handle->_msg_ptr += b; + if (handle->_msg_ptr + NS_INT16SZ + NS_INT16SZ > handle->_eom) + RETERR(EMSGSIZE); + NS_GET16_VLMCSD(rr->type, handle->_msg_ptr); + NS_GET16_VLMCSD(rr->rr_class, handle->_msg_ptr); + if (section == ns_s_qd_vlmcsd) { + rr->ttl = 0; + rr->rdlength = 0; + rr->rdata = NULL; + } else { + if (handle->_msg_ptr + NS_INT32SZ + NS_INT16SZ > handle->_eom) + RETERR(EMSGSIZE); + NS_GET32_VLMCSD(rr->ttl, handle->_msg_ptr); + NS_GET16_VLMCSD(rr->rdlength, handle->_msg_ptr); + if (handle->_msg_ptr + rr->rdlength > handle->_eom) + RETERR(EMSGSIZE); + rr->rdata = handle->_msg_ptr; + handle->_msg_ptr += rr->rdlength; + } + if (++handle->_rrnum > handle->_counts[(int)section]) + setsection_vlmcsd(handle, (ns_sect_vlmcsd)((int)section + 1)); + + /* All done. */ + return (0); +} + +/* Private. */ + +static void +setsection_vlmcsd(ns_msg_vlmcsd *msg, ns_sect_vlmcsd sect) { + msg->_sect = sect; + if (sect == ns_s_max_vlmcsd) { + msg->_rrnum = -1; + msg->_msg_ptr = NULL; + } else { + msg->_rrnum = 0; + msg->_msg_ptr = msg->_sections[(int)sect]; + } +} + +#endif // !NO_DNS +#endif // DNS_PARSER_INTERNAL diff --git a/vlmcsd/src/ns_parse.h b/vlmcsd/src/ns_parse.h new file mode 100644 index 0000000..59d8354 --- /dev/null +++ b/vlmcsd/src/ns_parse.h @@ -0,0 +1,73 @@ + +#ifndef NS_PARSE_H_ +#define NS_PARSE_H_ + +#ifndef NS_INT16SZ +#define NS_INT16SZ (sizeof(uint16_t)) +#endif // NS_INT16SZ + +#ifndef NS_INT32SZ +#define NS_INT32SZ (sizeof(uint32_t)) +#endif // NS_INT32SZ + +#ifndef NS_MAXDNAME +#define NS_MAXDNAME 1025 +#endif + +#define ns_msg_id_vlmcsd(handle) ((handle)._id + 0) +#define ns_msg_base_vlmcsd(handle) ((handle)._msg + 0) +#define ns_msg_end_vlmcsd(handle) ((handle)._eom + 0) +#define ns_msg_size_vlmcsd(handle) ((handle)._eom - (handle)._msg) +#define ns_msg_count_vlmcsd(handle, section) ((handle)._counts[section] + 0) + +#define ns_rr_name_vlmcsd(rr) (((rr).name[0] != '\0') ? (rr).name : ".") +#define ns_rr_type_vlmcsd(rr) ((ns_type)((rr).type + 0)) +#define ns_rr_class_vlmcsd(rr) ((ns_class)((rr).rr_class + 0)) +#define ns_rr_ttl_vlmcsd(rr) ((rr).ttl + 0) +#define ns_rr_rdlen_vlmcsd(rr) ((rr).rdlength + 0) +#define ns_rr_rdata_vlmcsd(rr) ((rr).rdata + 0) + +#define ns_msg_id_vlmcsd(handle) ((handle)._id + 0) +#define ns_msg_base_vlmcsd(handle) ((handle)._msg + 0) +#define ns_msg_end_vlmcsd(handle) ((handle)._eom + 0) +#define ns_msg_size_vlmcsd(handle) ((handle)._eom - (handle)._msg) +#define ns_msg_count_vlmcsd(handle, section) ((handle)._counts[section] + 0) + + +typedef enum __ns_sect_vlmcsd { + ns_s_qd_vlmcsd = 0, /*%< Query: Question. */ + ns_s_zn_vlmcsd = 0, /*%< Update: Zone. */ + ns_s_an_vlmcsd = 1, /*%< Query: Answer. */ + ns_s_pr_vlmcsd = 1, /*%< Update: Prerequisites. */ + ns_s_ns_vlmcsd = 2, /*%< Query: Name servers. */ + ns_s_ud_vlmcsd = 2, /*%< Update: Update. */ + ns_s_ar_vlmcsd = 3, /*%< Query|Update: Additional records. */ + ns_s_max_vlmcsd = 4 +} ns_sect_vlmcsd; + +typedef struct __ns_msg_vlmcsd { + uint8_t *_msg, *_eom; + uint16_t _id, _flags, _counts[ns_s_max_vlmcsd]; + uint8_t *_sections[ns_s_max_vlmcsd]; + ns_sect_vlmcsd _sect; + int _rrnum; + uint8_t *_msg_ptr; +} ns_msg_vlmcsd; + + +typedef struct __ns_rr_vlmcsd { + char name[NS_MAXDNAME]; + uint16_t type; + uint16_t rr_class; + uint32_t ttl; + uint16_t rdlength; + uint8_t * rdata; +} ns_rr_vlmcsd; + +int ns_initparse_vlmcsd(uint8_t *msg, int msglen, ns_msg_vlmcsd *handle); + +int ns_parserr_vlmcsd(ns_msg_vlmcsd *handle, ns_sect_vlmcsd section, int rrnum, ns_rr_vlmcsd *rr); + + + +#endif /* NS_PARSE_H_ */ diff --git a/vlmcsd/src/ntservice.c b/vlmcsd/src/ntservice.c new file mode 100644 index 0000000..b1bb534 --- /dev/null +++ b/vlmcsd/src/ntservice.c @@ -0,0 +1,335 @@ +#ifndef CONFIG +#define CONFIG "config.h" +#endif // CONFIG +#include CONFIG + +#include "ntservice.h" +#include "shared_globals.h" +#include "vlmcsd.h" +#include "output.h" +#include "helpers.h" + +#ifdef _NTSERVICE + +SERVICE_STATUS gSvcStatus; +SERVICE_STATUS_HANDLE gSvcStatusHandle; + +VOID WINAPI ServiceCtrlHandler(DWORD dwCtrl) +{ + // Handle the requested control code. + switch (dwCtrl) + { + case SERVICE_CONTROL_STOP: + case SERVICE_CONTROL_SHUTDOWN: + + ServiceShutdown = TRUE; + ReportServiceStatus(SERVICE_STOP_PENDING, NO_ERROR, 0); + + // Remove PID file and free ressources + cleanup(); +# if __CYGWIN__ || defined(USE_MSRPC) + ReportServiceStatus(SERVICE_STOPPED, NO_ERROR, 0); +# endif // __CYGWIN__ + + default: + break; + } +} + +static VOID WINAPI ServiceMain(const int argc_unused, CARGV argv_unused) +{ + // Register the handler function for the service + + if (!((gSvcStatusHandle = RegisterServiceCtrlHandler(NT_SERVICE_NAME, ServiceCtrlHandler)))) + { + return; + } + + // These SERVICE_STATUS members remain as set here + + gSvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; + gSvcStatus.dwServiceSpecificExitCode = 0; + + // Run the actual program + ReportServiceStatus(SERVICE_STOPPED, newmain(), 3000); +} + +SERVICE_TABLE_ENTRY NTServiceDispatchTable[] = { + { + (LPSTR)NT_SERVICE_NAME, + (LPSERVICE_MAIN_FUNCTION)ServiceMain + }, + { + NULL, + NULL + } +}; + +VOID ReportServiceStatus(const DWORD dwCurrentState, const DWORD dwWin32ExitCode, const DWORD dwWaitHint) +{ + static DWORD dwCheckPoint = 1; + + // Fill in the SERVICE_STATUS structure. + + gSvcStatus.dwCurrentState = dwCurrentState; + gSvcStatus.dwWin32ExitCode = dwWin32ExitCode; + gSvcStatus.dwWaitHint = dwWaitHint; + + if (dwCurrentState == SERVICE_START_PENDING) + gSvcStatus.dwControlsAccepted = 0; + else + gSvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP; + + if ((dwCurrentState == SERVICE_RUNNING) || + (dwCurrentState == SERVICE_STOPPED)) + gSvcStatus.dwCheckPoint = 0; + else + gSvcStatus.dwCheckPoint = dwCheckPoint++; + + // Report the status of the service to the SCM. + SetServiceStatus(gSvcStatusHandle, &gSvcStatus); +} + +/*VOID ServiceReportEvent(char *szFunction) +{ + HANDLE hEventSource; + const char *eventStrings[2]; + TCHAR Buffer[80]; + + hEventSource = RegisterEventSource(NULL, NT_SERVICE_NAME); + + if (hEventSource) + { + snprintf(Buffer, 80, "%s failed with %d", szFunction, GetLastError()); + + eventStrings[0] = NT_SERVICE_NAME; + eventStrings[1] = Buffer; + + ReportEvent(hEventSource, // event log handle + EVENTLOG_ERROR_TYPE, // event type + 0, // event category + 00, // event identifier + NULL, // no security identifier + 2, // size of lpszStrings array + 0, // no binary data + eventStrings, // array of strings + NULL); // no binary data + + DeregisterEventSource(hEventSource); + } +}*/ + +//Returns 0=Error, 1=Success, 2=Doesn't exist + + +static uint_fast8_t OpenAndRemoveService(DWORD *dwPreviousState, SC_HANDLE *schSCManager) +{ + SERVICE_STATUS status; + uint_fast8_t i; + SC_HANDLE installedService; + uint_fast8_t result = 1; + BOOL closeManager = FALSE; + + // Allow NULL for both Arguments + if (!dwPreviousState) dwPreviousState = (DWORD*)alloca(sizeof(*dwPreviousState)); + if (!schSCManager) + { + schSCManager = (SC_HANDLE*)alloca(sizeof(*schSCManager)); + closeManager = TRUE; + } + + *schSCManager = OpenSCManager( + NULL, // local computer + NULL, // ServicesActive database + SC_MANAGER_ALL_ACCESS); // full access rights + + if (!*schSCManager) return 0; + + if (!((installedService = OpenService(*schSCManager, NT_SERVICE_NAME, SERVICE_ALL_ACCESS)))) + { + result = 2; + } + else + { + *dwPreviousState = SERVICE_STOPPED; + if (QueryServiceStatus(installedService, &status)) *dwPreviousState = status.dwCurrentState; + + ControlService(installedService, SERVICE_CONTROL_STOP, &status); + + for (i = 0; i < 10; i++) + { + QueryServiceStatus(installedService, &status); + // Give it 100 ms after it reported SERVICE_STOPPED. Subsequent CreateService will fail otherwise + Sleep(100); + if (status.dwCurrentState == SERVICE_STOPPED) break; + } + + if (!DeleteService(installedService)) result = 0; + CloseServiceHandle(installedService); + } + + if (closeManager) CloseServiceHandle(*schSCManager); + return result; +} + +static VOID ServiceInstaller(const char *restrict ServiceUser, const char *const ServicePassword) +{ + SC_HANDLE schSCManager; + SC_HANDLE schService; + char szPath[MAX_PATH] = "\""; + + if (!GetModuleFileName(NULL, szPath + sizeof(char), MAX_PATH - 1)) + { + errorout("Cannot install service (%d)\n", (uint32_t)GetLastError()); + return; + } + + strcat(szPath, "\""); + + int i; + for (i = 1; i < global_argc; i++) + { + // Strip unneccessary parameters, especially the password + if (!strcmp(global_argv[i], "-s")) continue; + + if (!strcmp(global_argv[i], "-W") || + !strcmp(global_argv[i], "-U")) + { + i++; + continue; + } + + strcat(szPath, " "); + + if (strchr(global_argv[i], ' ')) + { + strcat(szPath, "\""); + strcat(szPath, global_argv[i]); + strcat(szPath, "\""); + } + else + strcat(szPath, global_argv[i]); + } + + // Get a handle to the SCM database. + + SERVICE_STATUS status; + DWORD dwPreviousState; + + if (!OpenAndRemoveService(&dwPreviousState, &schSCManager)) + { + errorout("Service removal failed (%d)\n", (uint32_t)GetLastError()); + return; + } + + char *tempUser = NULL; + + if (ServiceUser) + { + // Shortcuts for some well known users + if (!strcasecmp(ServiceUser, "/l")) ServiceUser = "NT AUTHORITY\\LocalService"; + if (!strcasecmp(ServiceUser, "/n")) ServiceUser = "NT AUTHORITY\\NetworkService"; + + // Allow Local Users without .\ , e.g. "johndoe" instead of ".\johndoe" + if (!strchr(ServiceUser, '\\')) + { + tempUser = (char*)vlmcsd_malloc(strlen(ServiceUser) + 3); + strcpy(tempUser, ".\\"); + strcat(tempUser, ServiceUser); + ServiceUser = tempUser; + } + } + + schService = CreateService( + schSCManager, // SCM database + NT_SERVICE_NAME, // name of service + NT_SERVICE_DISPLAY_NAME, // service name to display + SERVICE_ALL_ACCESS, // desired access + SERVICE_WIN32_OWN_PROCESS, // service type + SERVICE_AUTO_START, // start type + SERVICE_ERROR_NORMAL, // error control type + szPath, // path to service's binary + NULL, // no load ordering group + NULL, // no tag identifier + "tcpip\0", // depends on TCP/IP + ServiceUser, // LocalSystem account + ServicePassword); // no password + +# if __clang__ && (__CYGWIN__ || __MINGW64__ ) + // Workaround for clang not understanding some GCC asm syntax used in + ZeroMemory((char*)ServicePassword, strlen(ServicePassword)); +# else + SecureZeroMemory((char*)ServicePassword, strlen(ServicePassword)); +# endif + if (tempUser) free(tempUser); + + if (schService == NULL) + { + errorout("CreateService failed (%u)\n", (uint32_t)GetLastError()); + CloseServiceHandle(schSCManager); + return; + } + else + { + errorout("Service installed successfully\n"); + + if (dwPreviousState == SERVICE_RUNNING) + { + printf("Restarting " NT_SERVICE_NAME " service => "); + status.dwCurrentState = SERVICE_STOPPED; + + if (StartService(schService, 0, NULL)) + { + for (i = 0; i < 10; i++) + { + if (!QueryServiceStatus(schService, &status) || status.dwCurrentState != SERVICE_START_PENDING) break; + Sleep(100); + } + + if (status.dwCurrentState == SERVICE_RUNNING) + printf("Success\n"); + else if (status.dwCurrentState == SERVICE_START_PENDING) + printf("Not ready within a second\n"); + else + errorout("Error\n"); + } + else + errorout("Error %u\n", (uint32_t)GetLastError()); + } + } + + CloseServiceHandle(schService); + CloseServiceHandle(schSCManager); +} + +int NtServiceInstallation(const int_fast8_t installService, const char *restrict ServiceUser, const char *const ServicePassword) +{ + if (IsNTService) return 0; + + if (installService == 1) // Install + { + ServiceInstaller(ServiceUser, ServicePassword); + return(0); + } + + if (installService == 2) // Remove + { + switch (OpenAndRemoveService(NULL, NULL)) + { + case 0: + errorout("Error removing service %s\n", NT_SERVICE_NAME); + return(!0); + case 1: + printf("Service %s removed successfully\n", NT_SERVICE_NAME); + return(0); + default: + errorout("Service %s does not exist.\n", NT_SERVICE_NAME); + return(!0); + } + } + + // Do nothing + + return(0); +} +#endif // _NTSERVICE diff --git a/vlmcsd/src/ntservice.h b/vlmcsd/src/ntservice.h new file mode 100644 index 0000000..d3cac75 --- /dev/null +++ b/vlmcsd/src/ntservice.h @@ -0,0 +1,28 @@ +#ifndef INCLUDED_NTSERVICE_H +#define INCLUDED_NTSERVICE_H + +#ifndef CONFIG +#define CONFIG "config.h" +#endif // CONFIG +#include CONFIG + +#include "types.h" +#ifdef _NTSERVICE + +//#include + +#define NT_SERVICE_NAME "vlmcsd" +#define NT_SERVICE_DISPLAY_NAME "Key Management Server" + +extern SERVICE_TABLE_ENTRY NTServiceDispatchTable[]; + +VOID ReportServiceStatus(const DWORD, const DWORD, const DWORD); +int NtServiceInstallation(const int_fast8_t installService, const char *restrict ServiceUser, const char *const ServicePassword); + +#else // !_NTSERVICE + +#define ReportServiceStatus(x,y,z) + +#endif // _NTSERVICE + +#endif // INCLUDED_NTSERVICE_H diff --git a/vlmcsd/src/output.c b/vlmcsd/src/output.c new file mode 100644 index 0000000..0d95135 --- /dev/null +++ b/vlmcsd/src/output.c @@ -0,0 +1,667 @@ +#ifndef _DEFAULT_SOURCE +#define _DEFAULT_SOURCE +#endif // _DEFAULT_SOURCE + +#ifndef _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#endif + +#ifndef CONFIG +#define CONFIG "config.h" +#endif // CONFIG +#include CONFIG + +#include "output.h" +#include "shared_globals.h" +#include "endian.h" +#include "helpers.h" + +// ReSharper disable All + +#ifndef NO_LOG +static void vlogger(const char *message, va_list args) +{ + FILE *log; + +# ifdef _NTSERVICE + if (!IsNTService && logstdout) log = stdout; +# else + if (logstdout) log = stdout; +# endif + else + { + if (fn_log == NULL) return; + +# ifndef _WIN32 + if (!strcmp(fn_log, "syslog")) + { + openlog("vlmcsd", LOG_CONS | LOG_PID, LOG_USER); + + ////PORTABILITY: vsyslog is not in Posix but virtually all Unixes have it + vsyslog(LOG_INFO, message, args); + + closelog(); + return; + } +# endif // _WIN32 + + log = fopen(fn_log, "a"); + if (!log) return; + } + + time_t now = time(0); + +# ifdef USE_THREADS + char mbstr[2048]; +# else + char mbstr[24]; +# endif + + if (LogDateAndTime) + strftime(mbstr, sizeof(mbstr), "%Y-%m-%d %X: ", localtime(&now)); + else + *mbstr = 0; + +# ifndef USE_THREADS + + fprintf(log, "%s", mbstr); + vfprintf(log, message, args); + fflush(log); + +# else // USE_THREADS + + // We write everything to a string before we really log inside the critical section + // so formatting the output can be concurrent + int len = (int)strlen(mbstr); + //# if !_MSC_VER + + vlmcsd_vsnprintf(mbstr + len, sizeof(mbstr) - len, message, args); + //# else + // wvsprintf(mbstr + len, message, args); + //# endif + + lock_mutex(&logmutex); + fprintf(log, "%s", mbstr); + fflush(log); + unlock_mutex(&logmutex); + +# endif // USE_THREADS + if (log != stdout) fclose(log); +} + + +// Always sends to log output +int logger(const char *const fmt, ...) +{ + va_list args; + + va_start(args, fmt); + vlogger(fmt, args); + va_end(args); + return 0; +} + +#endif //NO_LOG + + +// Output to stderr if it is available or to log otherwise (e.g. if running as daemon/service) +int printerrorf(const char *const fmt, ...) +{ + int error = errno; + va_list arglist; + + va_start(arglist, fmt); + +# ifdef IS_LIBRARY + + size_t len = strlen(ErrorMessage); + vlmcsd_vsnprintf(ErrorMessage + len, MESSAGE_BUFFER_SIZE - len - 1, fmt, arglist); + +# else // !IS_LIBRARY + +# ifndef NO_LOG +# ifdef _NTSERVICE + if (InetdMode || IsNTService) +# else // !_NTSERVICE + if (InetdMode) +# endif // NTSERVIICE + vlogger(fmt, arglist); + else +# endif //NO_LOG + +# endif // IS_LIBRARY + { + vfprintf(stderr, fmt, arglist); + fflush(stderr); + } + + va_end(arglist); + errno = error; + return 0; +} + + +// Always output to stderr +int errorout(const char* fmt, ...) +{ + va_list args; + + va_start(args, fmt); + int i = vfprintf(stderr, fmt, args); + va_end(args); + fflush(stderr); + + return i; +} + + +#if !defined(NO_VERBOSE_LOG) && !defined(NO_LOG) +static const char *LicenseStatusText[] = +{ + "Unlicensed", "Licensed", "OOB grace", "OOT grace", "Non-Genuine", "Notification", "Extended grace" +}; +#endif // !defined(NO_VERBOSE_LOG) && !defined(NO_LOG) + + +void uuid2StringLE(const GUID *const guid, char *const string) +{ + sprintf(string, +# ifdef _WIN32 + "%08x-%04x-%04x-%04x-%012I64x", +# else + "%08x-%04x-%04x-%04x-%012llx", +# endif + (unsigned int)LE32(guid->Data1), + (unsigned int)LE16(guid->Data2), + (unsigned int)LE16(guid->Data3), + (unsigned int)BE16(*(uint16_t*)guid->Data4), + (unsigned long long)BE64(*(uint64_t*)(guid->Data4)) & 0xffffffffffffLL + ); +} + +#if !defined(NO_VERBOSE_LOG) && !defined(NO_LOG) +void logRequestVerbose(REQUEST* Request, const PRINTFUNC p) +{ + char guidBuffer[GUID_STRING_LENGTH + 1]; + char WorkstationBuffer[3 * WORKSTATION_NAME_BUFFER]; + char* productName; + + p("Protocol version : %u.%u\n", LE16(Request->MajorVer), LE16(Request->MinorVer)); + p("Client is a virtual machine : %s\n", LE32(Request->VMInfo) ? "Yes" : "No"); + p("Licensing status : %u (%s)\n", (uint32_t)LE32(Request->LicenseStatus), LE32(Request->LicenseStatus) < vlmcsd_countof(LicenseStatusText) ? LicenseStatusText[LE32(Request->LicenseStatus)] : "Unknown"); + p("Remaining time (0 = forever) : %i minutes\n", (uint32_t)LE32(Request->BindingExpiration)); + + uuid2StringLE(&Request->AppID, guidBuffer); + getProductIndex(&Request->AppID, KmsData->AppItemList, KmsData->AppItemCount, &productName, NULL); + p("Application ID : %s (%s)\n", guidBuffer, productName); + + uuid2StringLE(&Request->ActID, guidBuffer); + getProductIndex(&Request->ActID, KmsData->SkuItemList, KmsData->SkuItemCount, &productName, NULL); + p("SKU ID (aka Activation ID) : %s (%s)\n", guidBuffer, productName); + + uuid2StringLE(&Request->KMSID, guidBuffer); + getProductIndex(&Request->KMSID, KmsData->KmsItemList, KmsData->KmsItemCount, &productName, NULL); + p("KMS ID (aka KMS counted ID) : %s (%s)\n", guidBuffer, productName); + + uuid2StringLE(&Request->CMID, guidBuffer); + p("Client machine ID : %s\n", guidBuffer); + + uuid2StringLE(&Request->CMID_prev, guidBuffer); + p("Previous client machine ID : %s\n", guidBuffer); + + + char mbstr[64]; + time_t st; + st = fileTimeToUnixTime(&Request->ClientTime); + strftime(mbstr, sizeof(mbstr), "%Y-%m-%d %X", gmtime(&st)); + p("Client request timestamp (UTC) : %s\n", mbstr); + + ucs2_to_utf8(Request->WorkstationName, WorkstationBuffer, WORKSTATION_NAME_BUFFER, sizeof(WorkstationBuffer)); + + p("Workstation name : %s\n", WorkstationBuffer); + p("N count policy (minimum clients): %u\n", (uint32_t)LE32(Request->N_Policy)); +} + +void logResponseVerbose(const char *const ePID, const BYTE *const hwid, RESPONSE* response, const PRINTFUNC p) +{ + char guidBuffer[GUID_STRING_LENGTH + 1]; + + p("Protocol version : %u.%u\n", (uint32_t)LE16(response->MajorVer), (uint32_t)LE16(response->MinorVer)); + p("KMS host extended PID : %s\n", ePID); + if (LE16(response->MajorVer) > 5) +# ifndef _WIN32 + p("KMS host Hardware ID : %016llX\n", (unsigned long long)BE64(*(uint64_t*)hwid)); +# else // _WIN32 + p("KMS host Hardware ID : %016I64X\n", (unsigned long long)BE64(*(uint64_t*)hwid)); +# endif // WIN32 + + uuid2StringLE(&response->CMID, guidBuffer); + p("Client machine ID : %s\n", guidBuffer); + + char mbstr[64]; + time_t st; + + st = fileTimeToUnixTime(&response->ClientTime); + strftime(mbstr, sizeof(mbstr), "%Y-%m-%d %X", gmtime(&st)); + p("Client request timestamp (UTC) : %s\n", mbstr); + + p("KMS host current active clients : %u\n", (uint32_t)LE32(response->Count)); + p("Renewal interval policy : %u\n", (uint32_t)LE32(response->VLRenewalInterval)); + p("Activation interval policy : %u\n", (uint32_t)LE32(response->VLActivationInterval)); +} +#endif // !defined(NO_VERBOSE_LOG) && !defined(NO_LOG) + + +#ifndef NO_VERSION_INFORMATION +void printPlatform() +{ + int testNumber = 0x1234; + +# if _MSC_VER + printf("Compiler: VC++ %02i.%02i build %i\n", _MSC_VER / 100, _MSC_VER % 100, _MSC_FULL_VER % 100000); +# elif defined(VLMCSD_COMPILER) + printf + ( + "Compiler: %s\n", VLMCSD_COMPILER +# ifdef __VERSION__ + " " __VERSION__ +# endif // __VERSION__ + ); +# endif // VLMCSD_COMPILER + + printf + ( + "Intended platform:%s %s\n", "" + +# if __i386__ || _M_IX86 + " Intel x86" +# endif + +# if __x86_64__ || __amd64__ || _M_X64 || _M_AMD64 + " Intel x86_64" +# endif + +# if _M_ARM || __arm__ + " ARM" +# endif + +# if __thumb__ + " thumb" +# endif + +# if __aarch64__ + " ARM64" +# endif + +# if __hppa__ + " HP/PA RISC" +# endif + +# if __ia64__ + " Intel Itanium" +# endif + +# if __mips__ + " MIPS" +# endif + +# if defined(_MIPS_ARCH) + " " _MIPS_ARCH +# endif + +# if __mips16 + " mips16" +# endif + +# if __mips_micromips + " micromips" +# endif + +# if __ppc__ || __powerpc__ + " PowerPC" +# endif + +# if __powerpc64__ || __ppc64__ + " PowerPC64" +# endif + +# if __sparc__ + " SPARC" +# endif + +# if defined(__s390__) && !defined(__zarch__) && !defined(__s390x__) + " IBM S/390" +# endif + +# if __zarch__ || __s390x__ + " IBM z/Arch (S/390x)" +# endif + +# if __m68k__ + " Motorola 68k" +# endif + +# if __ANDROID__ + " Android" +# endif + +# if __ANDROID_API__ + " (API level " ANDROID_API_LEVEL ")" +# endif + +# if __FreeBSD__ || __FreeBSD_kernel__ + " FreeBSD" +# endif + +# if __NetBSD__ + " NetBSD" +# endif + +# if __OpenBSD__ + " OpenBSD" +# endif + +# if __DragonFly__ + " DragonFly BSD" +# endif + +# if defined(__CYGWIN__) && !defined(_WIN64) + " Cygwin32" +# endif + +# if defined(__CYGWIN__) && defined(_WIN64) + " Cygwin64" +# endif + +# if __GNU__ + " GNU" +# endif + +# if __gnu_hurd__ + " Hurd" +# endif + +# if __MACH__ + " Mach" +# endif + +# if __linux__ + " Linux" +# endif + +# if __APPLE__ && __MACH__ + " Darwin" +# endif + +# if __minix__ + " Minix" +# endif + +# if __QNX__ + " QNX" +# endif + +# if __svr4__ || __SVR4 + " SYSV R4" +# endif + +# if (defined(__sun__) || defined(sun) || defined(__sun)) && (defined(__SVR4) || defined(__svr4__)) + " Solaris" +# endif + +# if (defined(__sun__) || defined(sun) || defined(__sun)) && !defined(__SVR4) && !defined(__svr4__) + " SunOS" +# endif + +# if defined(_WIN32) && !defined(_WIN64) + " Windows32" +# endif + +# if defined(_WIN32) && defined(_WIN64) + " Windows64" +# endif + +# if __MVS__ || __TOS_MVS__ + " z/OS" +# endif + +# if defined(__GLIBC__) && !defined(__UCLIBC__) + " glibc" +# endif + +# if __UCLIBC__ + " uclibc" +# endif + +# if defined(__linux__) && !defined(__GLIBC__) && !defined(__UCLIBC__) && !defined(__ANDROID__) && !defined(__BIONIC__) + " musl" +# endif + + //# if _MIPSEL || __MIPSEL__ || __ARMEL__ || __THUMBEL__ + // " little-endian" + //# endif + // + //# if _MIPSEB || __MIPSEB__ || __ARMEB__ || __THUMBEB__ + // " big-endian" + //# endif + +# if __PIE__ || __pie__ + " PIE" +# endif + , + *((uint8_t*)&testNumber) == 0x34 ? "little-endian" : "big-endian" + ); + +} + + +void printCommonFlags() +{ + printf + ( + "Common flags:%s\n", "" + +# ifdef NO_EXTERNAL_DATA + " NO_EXTERNAL_DATA" +# endif // NO_EXTERNAL_DATA + +# ifdef NO_INTERNAL_DATA + " NO_INTERNAL_DATA" +# endif // NO_INTERNAL_DATA + +# if !defined(NO_EXTERNAL_DATA) + +# ifdef DATA_FILE + " DATA=" DATA_FILE +# endif // DATA_FILE + +# ifdef UNSAFE_DATA_LOAD + " UNSAFE_DATA_LOAD" +# endif // UNSAFE_DATA_LOAD + +# endif // !defined(NO_EXTERNAL_DATA) + +# ifdef USE_MSRPC + " USE_MSRPC" +# endif // USE_MSRPC + +# ifdef _CRYPTO_OPENSSL + " _CRYPTO_OPENSSL" +# endif // _CRYPTO_OPENSSL + +# ifdef _CRYPTO_POLARSSL + " _CRYPTO_POLARSSL" +# endif // _CRYPTO_POLARSSL + +# ifdef _CRYPTO_WINDOWS + " _CRYPTO_WINDOWS" +# endif // _CRYPTO_WINDOWS + +# if defined(_OPENSSL_SOFTWARE) && defined(_CRYPTO_OPENSSL) + " _OPENSSL_SOFTWARE" +# endif // _OPENSSL_SOFTWARE + +# if defined(_USE_AES_FROM_OPENSSL) && defined(_CRYPTO_OPENSSL) + " _USE_AES_FROM_OPENSSL" +# endif // _USE_AES_FROM_OPENSSL + +# if defined(_OPENSSL_NO_HMAC) && defined(_CRYPTO_OPENSSL) + " OPENSSL_HMAC=0" +# endif // _OPENSSL_NO_HMAC + +# ifdef _PEDANTIC + " _PEDANTIC" +# endif // _PEDANTIC + +# ifdef INCLUDE_BETAS + " INCLUDE_BETAS" +# endif // INCLUDE_BETAS + +# if __minix__ || defined(NO_TIMEOUT) + " NO_TIMEOUT=1" +# endif // __minix__ || defined(NO_TIMEOUT) + ); +} + + +void printClientFlags() +{ + printf + ( + "vlmcs flags:%s\n", "" + +# ifdef NO_DNS + " NO_DNS=1" +# endif + +# if !defined(NO_DNS) +# if defined(DNS_PARSER_INTERNAL) && !defined(_WIN32) + " DNS_PARSER=internal" +# else // !defined(DNS_PARSER_INTERNAL) || defined(_WIN32) + " DNS_PARSER=OS" +# endif // !defined(DNS_PARSER_INTERNAL) || defined(_WIN32) +# endif // !defined(NO_DNS) + +# if defined(DISPLAY_WIDTH) + " TERMINAL_WIDTH=" DISPLAY_WIDTH +# endif + ); +} + + +void printServerFlags() +{ + printf + ( + "vlmcsd flags:%s\n", "" + +# ifdef NO_LOG + " NO_LOG" +# endif // NO_LOG + +# ifdef NO_RANDOM_EPID + " NO_RANDOM_EPID" +# endif // NO_RANDOM_EPID + +# ifdef NO_INI_FILE + " NO_INI_FILE" +# endif // NO_INI_FILE + +# if !defined(NO_INI_FILE) && defined(INI_FILE) + " INI=" INI_FILE +# endif // !defined(NO_INI_FILE) + +# ifdef NO_PID_FILE + " NO_PID_FILE" +# endif // NO_PID_FILE + +# ifdef NO_USER_SWITCH + " NO_USER_SWITCH" +# endif // NO_USER_SWITCH + +# ifdef NO_HELP + " NO_HELP" +# endif // NO_HELP + +# ifdef NO_STRICT_MODES + " NO_STRICT_MODES" +# endif // NO_STRICT_MODES + +# ifdef NO_CUSTOM_INTERVALS + " NO_CUSTOM_INTERVALS" +# endif // NO_CUSTOM_INTERVALS + +# ifdef NO_SOCKETS + " NO_SOCKETS" +# endif // NO_SOCKETS + +# ifdef NO_CL_PIDS + " NO_CL_PIDS" +# endif // NO_CL_PIDS + +# ifdef NO_LIMIT + " NO_LIMIT" +# endif // NO_LIMIT + +# ifdef NO_SIGHUP + " NO_SIGHUP" +# endif // NO_SIGHUP + +# ifdef NO_PROCFS + " NOPROCFS=1" +# endif // NO_PROCFS + +# ifdef USE_THREADS + " THREADS=1" +# endif // USE_THREADS + +# ifdef USE_AUXV + " AUXV=1" +# endif // USE_AUXV + +# if defined(CHILD_HANDLER) || __minix__ + " CHILD_HANDLER=1" +# endif // defined(CHILD_HANDLER) || __minix__ + +# if !defined(NO_SOCKETS) && defined(SIMPLE_SOCKETS) + " SIMPLE_SOCKETS" +# endif // !defined(NO_SOCKETS) && defined(SIMPLE_SOCKETS) + +# ifdef SIMPLE_RPC + " SIMPLE_RPC" +# endif // SIMPLE_RPC + +# ifdef NO_STRICT_MODES + " NO_STRICT_MODES" +# endif // NO_STRICT_MODES + +# ifdef NO_CLIENT_LIST + " NO_CLIENT_LIST" +# endif // NO_CLIENT_LIST + +# if (_WIN32 || __CYGWIN__) && (!defined(USE_MSRPC) || defined(SUPPORT_WINE)) + " SUPPORT_WINE" +# endif // (_WIN32 || __CYGWIN__) && (!defined(USE_MSRPC) || defined(SUPPORT_WINE)) + +# if (_WIN32 || __CYGWIN__) && defined(NO_TAP) + " NO_TAP" +# endif // (_WIN32 || __CYGWIN__) && defined(NO_TAP) + +# if !HAVE_FREEBIND + " NO_FREEBIND" +# endif //!HAVE_FREEBIND + +# if !HAVE_GETIFADDR + " !HAVE_GETIFADDR" +# endif // !HAVE_GETIFADDR + +# if HAVE_GETIFADDR && defined(GETIFADDRS_MUSL) + " GETIFADDRS=musl" +# endif // HAVE_GETIFADDR && defined(GETIFADDRS_MUSL) + +# if defined(NO_PRIVATE_IP_DETECT) + " NO_PRIVATE_IP_DETECT" +# endif // defined(NO_PRIVATE_IP_DETECT) + ); +} +#endif // NO_VERSION_INFORMATION diff --git a/vlmcsd/src/output.h b/vlmcsd/src/output.h new file mode 100644 index 0000000..96b0bc1 --- /dev/null +++ b/vlmcsd/src/output.h @@ -0,0 +1,36 @@ +#ifndef INCLUDED_OUTPUT_H +#define INCLUDED_OUTPUT_H + +#ifndef CONFIG +#define CONFIG "config.h" +#endif // CONFIG +#include CONFIG + +#include +#include "types.h" +#include "kms.h" + +typedef int (*PRINTFUNC)(const char *const fmt, ...); + +int printerrorf(const char *const fmt, ...); +int errorout(const char* fmt, ...); +void logRequestVerbose(REQUEST* Request, const PRINTFUNC p); +void logResponseVerbose(const char *const ePID, const BYTE *const hwid, RESPONSE* response, const PRINTFUNC p); + +#ifndef NO_VERSION_INFORMATION +void printPlatform(); +void printCommonFlags(); +void printServerFlags(); +void printClientFlags(); +#endif // NO_VERSION_INFORMATION + +#ifndef NO_LOG +int logger(const char *const fmt, ...); +#endif //NO_LOG + +void uuid2StringLE(const GUID *const guid, char *const string); + +//void copy_arguments(int argc, char **argv, char ***new_argv); +//void destroy_arguments(int argc, char **argv); + +#endif // INCLUDED_OUTPUT_H diff --git a/vlmcsd/src/resolv.h b/vlmcsd/src/resolv.h new file mode 100644 index 0000000..3231106 --- /dev/null +++ b/vlmcsd/src/resolv.h @@ -0,0 +1,499 @@ +/* $NetBSD: resolv.h,v 1.31 2005/12/26 19:01:47 perry Exp $ */ + +/* + * Copyright (c) 1983, 1987, 1989 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (c) 1996-1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * @(#)resolv.h 8.1 (Berkeley) 6/2/93 + * Id: resolv.h,v 1.7.2.11.4.2 2004/06/25 00:41:05 marka Exp + */ + +#ifndef _RESOLV_PRIVATE_H_ +#define _RESOLV_PRIVATE_H_ + +#include +#include "resolv_static.h" + +/* + * Revision information. This is the release date in YYYYMMDD format. + * It can change every day so the right thing to do with it is use it + * in preprocessor commands such as "#if (__RES > 19931104)". Do not + * compare for equality; rather, use it to determine whether your resolver + * is new enough to contain a certain feature. + */ + +#define __RES 20030124 + +/* + * This used to be defined in res_query.c, now it's in herror.c. + * [XXX no it's not. It's in irs/irs_data.c] + * It was + * never extern'd by any *.h file before it was placed here. For thread + * aware programs, the last h_errno value set is stored in res->h_errno. + * + * XXX: There doesn't seem to be a good reason for exposing RES_SET_H_ERRNO + * (and __h_errno_set) to the public via . + * XXX: __h_errno_set is really part of IRS, not part of the resolver. + * If somebody wants to build and use a resolver that doesn't use IRS, + * what do they do? Perhaps something like + * #ifdef WANT_IRS + * # define RES_SET_H_ERRNO(r,x) __h_errno_set(r,x) + * #else + * # define RES_SET_H_ERRNO(r,x) (h_errno = (r)->res_h_errno = (x)) + * #endif + */ + +#define RES_SET_H_ERRNO(r,x) (h_errno = (r)->res_h_errno = (x)) +struct __res_state; /* forward */ + +/* + * Resolver configuration file. + * Normally not present, but may contain the address of the + * initial name server(s) to query and the domain search list. + */ + +#ifndef _PATH_RESCONF +#ifdef ANDROID_CHANGES +#define _PATH_RESCONF "/etc/ppp/resolv.conf" +#else +#define _PATH_RESCONF "/etc/resolv.conf" +#endif +#endif + +typedef enum { res_goahead, res_nextns, res_modified, res_done, res_error } + res_sendhookact; + +typedef res_sendhookact (*res_send_qhook)(struct sockaddr * const *, + const u_char **, int *, + u_char *, int, int *); + +typedef res_sendhookact (*res_send_rhook)(const struct sockaddr *, + const u_char *, int, u_char *, + int, int *); + +struct res_sym { + int number; /* Identifying number, like T_MX */ + const char * name; /* Its symbolic name, like "MX" */ + const char * humanname; /* Its fun name, like "mail exchanger" */ +}; + +/* + * Global defines and variables for resolver stub. + */ +#define MAXNS 3 /* max # name servers we'll track */ +#define MAXDFLSRCH 3 /* # default domain levels to try */ +#define MAXDNSRCH 6 /* max # domains in search path */ +#define LOCALDOMAINPARTS 2 /* min levels in name that is "local" */ + +#define RES_TIMEOUT 5 /* min. seconds between retries */ +#define MAXRESOLVSORT 10 /* number of net to sort on */ +#define RES_MAXNDOTS 15 /* should reflect bit field size */ +#define RES_MAXRETRANS 30 /* only for resolv.conf/RES_OPTIONS */ +#define RES_MAXRETRY 5 /* only for resolv.conf/RES_OPTIONS */ +#define RES_DFLRETRY 2 /* Default #/tries. */ +#define RES_MAXTIME 65535 /* Infinity, in milliseconds. */ + +struct __res_state_ext; + +struct __res_state { + int retrans; /* retransmission time interval */ + int retry; /* number of times to retransmit */ +#ifdef sun + u_int options; /* option flags - see below. */ +#else + u_long options; /* option flags - see below. */ +#endif + int nscount; /* number of name servers */ + struct sockaddr_in + nsaddr_list[MAXNS]; /* address of name server */ +#define nsaddr nsaddr_list[0] /* for backward compatibility */ + u_short id; /* current message id */ + char *dnsrch[MAXDNSRCH+1]; /* components of domain to search */ + char defdname[256]; /* default domain (deprecated) */ +#ifdef sun + u_int pfcode; /* RES_PRF_ flags - see below. */ +#else + u_long pfcode; /* RES_PRF_ flags - see below. */ +#endif + unsigned ndots:4; /* threshold for initial abs. query */ + unsigned nsort:4; /* number of elements in sort_list[] */ + char unused[3]; + struct { + struct in_addr addr; + uint32_t mask; + } sort_list[MAXRESOLVSORT]; +#ifdef __OLD_RES_STATE + char lookups[4]; +#else + res_send_qhook qhook; /* query hook */ + res_send_rhook rhook; /* response hook */ + int res_h_errno; /* last one set for this context */ + int _vcsock; /* PRIVATE: for res_send VC i/o */ + u_int _flags; /* PRIVATE: see below */ + u_int _pad; /* make _u 64 bit aligned */ + union { + /* On an 32-bit arch this means 512b total. */ + char pad[72 - 4*sizeof (int) - 2*sizeof (void *)]; + struct { + uint16_t nscount; + uint16_t nstimes[MAXNS]; /* ms. */ + int nssocks[MAXNS]; + struct __res_state_ext *ext; /* extention for IPv6 */ + } _ext; + } _u; +#endif + struct res_static rstatic[1]; +}; + +typedef struct __res_state *res_state; + +union res_sockaddr_union { + struct sockaddr_in sin; +#ifdef IN6ADDR_ANY_INIT + struct sockaddr_in6 sin6; +#endif +#ifdef ISC_ALIGN64 + int64_t __align64; /* 64bit alignment */ +#else + int32_t __align32; /* 32bit alignment */ +#endif + char __space[128]; /* max size */ +}; + +/* + * Resolver flags (used to be discrete per-module statics ints). + */ +#define RES_F_VC 0x00000001 /* socket is TCP */ +#define RES_F_CONN 0x00000002 /* socket is connected */ +#define RES_F_EDNS0ERR 0x00000004 /* EDNS0 caused errors */ +#define RES_F__UNUSED 0x00000008 /* (unused) */ +#define RES_F_LASTMASK 0x000000F0 /* ordinal server of last res_nsend */ +#define RES_F_LASTSHIFT 4 /* bit position of LASTMASK "flag" */ +#define RES_GETLAST(res) (((res)._flags & RES_F_LASTMASK) >> RES_F_LASTSHIFT) + +/* res_findzonecut2() options */ +#define RES_EXHAUSTIVE 0x00000001 /* always do all queries */ +#define RES_IPV4ONLY 0x00000002 /* IPv4 only */ +#define RES_IPV6ONLY 0x00000004 /* IPv6 only */ + +/* + * Resolver options (keep these in synch with res_debug.c, please) + */ +#define RES_INIT 0x00000001 /* address initialized */ +#define RES_DEBUG 0x00000002 /* print debug messages */ +#define RES_AAONLY 0x00000004 /* authoritative answers only (!IMPL)*/ +#define RES_USEVC 0x00000008 /* use virtual circuit */ +#define RES_PRIMARY 0x00000010 /* query primary server only (!IMPL) */ +#define RES_IGNTC 0x00000020 /* ignore trucation errors */ +#define RES_RECURSE 0x00000040 /* recursion desired */ +#define RES_DEFNAMES 0x00000080 /* use default domain name */ +#define RES_STAYOPEN 0x00000100 /* Keep TCP socket open */ +#define RES_DNSRCH 0x00000200 /* search up local domain tree */ +#define RES_INSECURE1 0x00000400 /* type 1 security disabled */ +#define RES_INSECURE2 0x00000800 /* type 2 security disabled */ +#define RES_NOALIASES 0x00001000 /* shuts off HOSTALIASES feature */ +#define RES_USE_INET6 0x00002000 /* use/map IPv6 in gethostbyname() */ +#define RES_ROTATE 0x00004000 /* rotate ns list after each query */ +#define RES_NOCHECKNAME 0x00008000 /* do not check names for sanity. */ +#define RES_KEEPTSIG 0x00010000 /* do not strip TSIG records */ +#define RES_BLAST 0x00020000 /* blast all recursive servers */ +#define RES_NOTLDQUERY 0x00100000 /* don't unqualified name as a tld */ +#define RES_USE_DNSSEC 0x00200000 /* use DNSSEC using OK bit in OPT */ +/* #define RES_DEBUG2 0x00400000 */ /* nslookup internal */ +/* KAME extensions: use higher bit to avoid conflict with ISC use */ +#define RES_USE_DNAME 0x10000000 /* use DNAME */ +#define RES_USE_EDNS0 0x40000000 /* use EDNS0 if configured */ +#define RES_NO_NIBBLE2 0x80000000 /* disable alternate nibble lookup */ + +#define RES_DEFAULT (RES_RECURSE | RES_DEFNAMES | \ + RES_DNSRCH | RES_NO_NIBBLE2) + +/* + * Resolver "pfcode" values. Used by dig. + */ +#define RES_PRF_STATS 0x00000001 +#define RES_PRF_UPDATE 0x00000002 +#define RES_PRF_CLASS 0x00000004 +#define RES_PRF_CMD 0x00000008 +#define RES_PRF_QUES 0x00000010 +#define RES_PRF_ANS 0x00000020 +#define RES_PRF_AUTH 0x00000040 +#define RES_PRF_ADD 0x00000080 +#define RES_PRF_HEAD1 0x00000100 +#define RES_PRF_HEAD2 0x00000200 +#define RES_PRF_TTLID 0x00000400 +#define RES_PRF_HEADX 0x00000800 +#define RES_PRF_QUERY 0x00001000 +#define RES_PRF_REPLY 0x00002000 +#define RES_PRF_INIT 0x00004000 +#define RES_PRF_TRUNC 0x00008000 +/* 0x00010000 */ + +/* Things involving an internal (static) resolver context. */ +__BEGIN_DECLS +extern struct __res_state *__res_get_state(void); +extern void __res_put_state(struct __res_state *); + +#ifndef ANDROID_CHANGES +/* + * Source and Binary compatibility; _res will not work properly + * with multi-threaded programs. + */ +extern struct __res_state *__res_state(void); +#define _res (*__res_state()) +#endif + +__END_DECLS + +#ifndef __BIND_NOSTATIC +#define fp_nquery __fp_nquery +#define fp_query __fp_query +#define hostalias __hostalias +#define p_query __p_query +#define res_close __res_close +#define res_opt __res_opt +#define res_isourserver __res_isourserver +#define res_querydomain __res_querydomain +#define res_send __res_send +#define res_sendsigned __res_sendsigned + +#ifdef BIND_RES_POSIX3 +#define dn_expand __dn_expand +#define res_init __res_init +#define res_query __res_query +#define res_search __res_search +#define res_mkquery __res_mkquery +#endif + +__BEGIN_DECLS +void fp_nquery(const u_char *, int, FILE *); +void fp_query(const u_char *, FILE *); +const char * hostalias(const char *); +void p_query(const u_char *); +void res_close(void); +int res_init(void); +int res_opt(int, u_char *, int, int); +int res_isourserver(const struct sockaddr_in *); +int res_mkquery(int, const char *, int, int, const u_char *, int, const u_char *, u_char *, int); +int res_query(const char *, int, int, u_char *, int); +int res_querydomain(const char *, const char *, int, int, u_char *, int); +int res_search(const char *, int, int, u_char *, int); +int res_send(const u_char *, int, u_char *, int); +int res_sendsigned(const u_char *, int, ns_tsig_key *, u_char *, int); +__END_DECLS +#endif + +#if !defined(SHARED_LIBBIND) || defined(LIB) +/* + * If libbind is a shared object (well, DLL anyway) + * these externs break the linker when resolv.h is + * included by a lib client (like named) + * Make them go away if a client is including this + * + */ +extern const struct res_sym __p_key_syms[]; +extern const struct res_sym __p_cert_syms[]; +extern const struct res_sym __p_class_syms[]; +extern const struct res_sym __p_type_syms[]; +extern const struct res_sym __p_rcode_syms[]; +#endif /* SHARED_LIBBIND */ + +#ifndef ADNROID_CHANGES +#define b64_ntop __b64_ntop +#define b64_pton __b64_pton +#endif + +#define dn_comp __dn_comp +#define dn_count_labels __dn_count_labels +#define dn_skipname __dn_skipname +#define fp_resstat __fp_resstat +#define loc_aton __loc_aton +#define loc_ntoa __loc_ntoa +#define p_cdname __p_cdname +#define p_cdnname __p_cdnname +#define p_class __p_class +#define p_fqname __p_fqname +#define p_fqnname __p_fqnname +#define p_option __p_option +#define p_secstodate __p_secstodate +#define p_section __p_section +#define p_time __p_time +#define p_type __p_type +#define p_rcode __p_rcode +#define p_sockun __p_sockun +#define putlong __putlong +#define putshort __putshort +#define res_dnok __res_dnok +#define res_findzonecut __res_findzonecut +#define res_findzonecut2 __res_findzonecut2 +#define res_hnok __res_hnok +#define res_hostalias __res_hostalias +#define res_mailok __res_mailok +#define res_nameinquery __res_nameinquery +#define res_nclose __res_nclose +#define res_ninit __res_ninit +#define res_nmkquery __res_nmkquery +#define res_pquery __res_pquery +#define res_nquery __res_nquery +#define res_nquerydomain __res_nquerydomain +#define res_nsearch __res_nsearch +#define res_nsend __res_nsend +#define res_nsendsigned __res_nsendsigned +#define res_nisourserver __res_nisourserver +#define res_ownok __res_ownok +#define res_queriesmatch __res_queriesmatch +#define res_randomid __res_randomid +#define sym_ntop __sym_ntop +#define sym_ntos __sym_ntos +#define sym_ston __sym_ston +#define res_nopt __res_nopt +#define res_ndestroy __res_ndestroy +#define res_nametoclass __res_nametoclass +#define res_nametotype __res_nametotype +#define res_setservers __res_setservers +#define res_getservers __res_getservers +#define res_buildprotolist __res_buildprotolist +#define res_destroyprotolist __res_destroyprotolist +#define res_destroyservicelist __res_destroyservicelist +#define res_get_nibblesuffix __res_get_nibblesuffix +#define res_get_nibblesuffix2 __res_get_nibblesuffix2 +#define res_ourserver_p __res_ourserver_p +#define res_protocolname __res_protocolname +#define res_protocolnumber __res_protocolnumber +#define res_send_setqhook __res_send_setqhook +#define res_send_setrhook __res_send_setrhook +#define res_servicename __res_servicename +#define res_servicenumber __res_servicenumber +__BEGIN_DECLS +int res_hnok(const char *); +int res_ownok(const char *); +int res_mailok(const char *); +int res_dnok(const char *); +int sym_ston(const struct res_sym *, const char *, int *); +const char * sym_ntos(const struct res_sym *, int, int *); +const char * sym_ntop(const struct res_sym *, int, int *); +#ifndef ANDROID_CHANGES +int b64_ntop(u_char const *, size_t, char *, size_t); +int b64_pton(char const *, u_char *, size_t); +#endif +int loc_aton(const char *, u_char *); +const char * loc_ntoa(const u_char *, char *); +int dn_skipname(const u_char *, const u_char *); +void putlong(uint32_t, u_char *); +void putshort(uint16_t, u_char *); +#ifndef __ultrix__ +uint16_t _getshort(const u_char *); +uint32_t _getlong(const u_char *); +#endif +const char * p_class(int); +const char * p_time(uint32_t); +const char * p_type(int); +const char * p_rcode(int); +const char * p_sockun(union res_sockaddr_union, char *, size_t); +const u_char * p_cdnname(const u_char *, const u_char *, int, FILE *); +const u_char * p_cdname(const u_char *, const u_char *, FILE *); +const u_char * p_fqnname(const u_char *, const u_char *, + int, char *, int); +const u_char * p_fqname(const u_char *, const u_char *, FILE *); +const char * p_option(u_long); +char * p_secstodate(u_long); +int dn_count_labels(const char *); +int dn_comp(const char *, u_char *, int, u_char **, u_char **); +int dn_expand(const u_char *, const u_char *, const u_char *, + char *, int); +u_int res_randomid(void); +int res_nameinquery(const char *, int, int, const u_char *, + const u_char *); +int res_queriesmatch(const u_char *, const u_char *, + const u_char *, const u_char *); +const char * p_section(int, int); +/* Things involving a resolver context. */ +int res_ninit(res_state); +int res_nisourserver(const res_state, const struct sockaddr_in *); +void fp_resstat(const res_state, FILE *); +void res_pquery(const res_state, const u_char *, int, FILE *); +const char * res_hostalias(const res_state, const char *, char *, size_t); +int res_nquery(res_state, const char *, int, int, u_char *, int); +int res_nsearch(res_state, const char *, int, int, u_char *, int); +int res_nquerydomain(res_state, const char *, const char *, + int, int, u_char *, int); +int res_nmkquery(res_state, int, const char *, int, int, + const u_char *, int, const u_char *, + u_char *, int); +int res_nsend(res_state, const u_char *, int, u_char *, int); +int res_nsendsigned(res_state, const u_char *, int, + ns_tsig_key *, u_char *, int); +int res_findzonecut(res_state, const char *, ns_class, int, + char *, size_t, struct in_addr *, int); +int res_findzonecut2(res_state, const char *, ns_class, int, + char *, size_t, + union res_sockaddr_union *, int); +void res_nclose(res_state); +int res_nopt(res_state, int, u_char *, int, int); +void res_send_setqhook(res_send_qhook); +void res_send_setrhook(res_send_rhook); +int __res_vinit(res_state, int); +void res_destroyservicelist(void); +const char * res_servicename(uint16_t, const char *); +const char * res_protocolname(int); +void res_destroyprotolist(void); +void res_buildprotolist(void); +const char * res_get_nibblesuffix(res_state); +const char * res_get_nibblesuffix2(res_state); +void res_ndestroy(res_state); +uint16_t res_nametoclass(const char *, int *); +uint16_t res_nametotype(const char *, int *); +void res_setservers(res_state, + const union res_sockaddr_union *, int); +int res_getservers(res_state, + union res_sockaddr_union *, int); + +int res_get_dns_changed(); +u_int res_randomid(void); + +__END_DECLS + +#endif /* !_RESOLV_PRIVATE_H_ */ diff --git a/vlmcsd/src/resolv_static.h b/vlmcsd/src/resolv_static.h new file mode 100644 index 0000000..481c954 --- /dev/null +++ b/vlmcsd/src/resolv_static.h @@ -0,0 +1,32 @@ +#ifndef _RESOLV_STATIC_H +#define _RESOLV_STATIC_H + +#include + +/* this structure contains all the variables that were declared + * 'static' in the original NetBSD resolver code. + * + * this caused vast amounts of crashes and memory corruptions + * when the resolver was being used by multiple threads. + * + * (note: the OpenBSD/FreeBSD resolver has similar 'issues') + */ + +#define MAXALIASES 35 +#define MAXADDRS 35 + +typedef struct res_static { + char* h_addr_ptrs[MAXADDRS + 1]; + char* host_aliases[MAXALIASES]; + char hostbuf[8*1024]; + u_int32_t host_addr[16 / sizeof(u_int32_t)]; /* IPv4 or IPv6 */ + FILE* hostf; + int stayopen; + const char* servent_ptr; + struct servent servent; + struct hostent host; +} *res_static; + +extern res_static __res_get_static(void); + +#endif /* _RESOLV_STATIC_H */ diff --git a/vlmcsd/src/rpc.c b/vlmcsd/src/rpc.c new file mode 100644 index 0000000..09324ee --- /dev/null +++ b/vlmcsd/src/rpc.c @@ -0,0 +1,1255 @@ +#ifndef _DEFAULT_SOURCE +#define _DEFAULT_SOURCE +#endif // _DEFAULT_SOURCE + +#ifndef CONFIG +#define CONFIG "config.h" +#endif // CONFIG +#include CONFIG + +#ifndef USE_MSRPC + +#include +#include +#include +#include +//#include +//#include +#if !defined(_WIN32) +#include +#include +#endif +#include "rpc.h" +#include "output.h" +//#include "crypto.h" +#include "endian.h" +#include "helpers.h" +#include "network.h" +#include "shared_globals.h" + +/* Forwards */ + +static int checkRpcHeader(const RPC_HEADER *const header, const BYTE desiredPacketType, const PRINTFUNC p); + + +/* Data definitions */ + +// All GUIDs are defined as BYTE[16] here. No big-endian/little-endian byteswapping required. +static const BYTE TransferSyntaxNDR32[] = { + 0x04, 0x5D, 0x88, 0x8A, 0xEB, 0x1C, 0xC9, 0x11, 0x9F, 0xE8, 0x08, 0x00, 0x2B, 0x10, 0x48, 0x60 +}; + +static const BYTE InterfaceUuid[] = { + 0x75, 0x21, 0xc8, 0x51, 0x4e, 0x84, 0x50, 0x47, 0xB0, 0xD8, 0xEC, 0x25, 0x55, 0x55, 0xBC, 0x06 +}; + +//#ifndef SIMPLE_RPC +static const BYTE TransferSyntaxNDR64[] = { + 0x33, 0x05, 0x71, 0x71, 0xba, 0xbe, 0x37, 0x49, 0x83, 0x19, 0xb5, 0xdb, 0xef, 0x9c, 0xcc, 0x36 +}; + +static const BYTE BindTimeFeatureNegotiation[] = { + 0x2c, 0x1c, 0xb7, 0x6c, 0x12, 0x98, 0x40, 0x45, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; +//#endif // SIMPLE_RPC + +// +// Dispatch RPC payload to kms.c +// +typedef int(*CreateResponse_t)(const void *const, void *const, const char* const); + +// ReSharper disable CppIncompatiblePointerConversion +static const struct { + unsigned int RequestSize; + CreateResponse_t CreateResponse; +} _Versions[] = { + { sizeof(REQUEST_V4), (CreateResponse_t)CreateResponseV4 }, + { sizeof(REQUEST_V6), (CreateResponse_t)CreateResponseV6 }, + { sizeof(REQUEST_V6), (CreateResponse_t)CreateResponseV6 } +}; +// ReSharper restore CppIncompatiblePointerConversion + +RPC_FLAGS RpcFlags; +static int_fast8_t firstPacketSent; +static DWORD CallId = 2; // M$ starts with CallId 2. So we do the same. + +// +// RPC request (server) +// +#if defined(_PEDANTIC) && !defined(NO_LOG) +static void CheckRpcRequest(const RPC_REQUEST64 *const Request, const unsigned int len, WORD* NdrCtx, WORD* Ndr64Ctx, WORD Ctx) +{ + uint_fast8_t kmsMajorVersion; + uint32_t requestSize = Ctx != *Ndr64Ctx ? sizeof(RPC_REQUEST) : sizeof(RPC_REQUEST64); + + if (len < requestSize) + { + logger("Fatal: RPC request (including header) must be at least %i bytes but is only %i bytes.\n", + (int)(sizeof(RPC_HEADER) + requestSize), + (int)(len + sizeof(RPC_HEADER)) + ); + + return; + } + + if (len < requestSize + sizeof(DWORD)) + { + logger("Fatal: KMS Request too small to contain version info (less than 4 bytes).\n"); + return; + } + + if (Ctx != *Ndr64Ctx) + kmsMajorVersion = (uint_fast8_t)LE16(((WORD*)Request->Ndr.Data)[1]); + else + kmsMajorVersion = (uint_fast8_t)LE16(((WORD*)Request->Ndr64.Data)[1]); + + if (kmsMajorVersion > 6) + { + logger("Fatal: KMSv%u is not supported.\n", (unsigned int)kmsMajorVersion); + } + else + { + if (len > _Versions[kmsMajorVersion - 4].RequestSize + requestSize) + logger("Warning: %u excess bytes in RPC request.\n", + len - (_Versions[kmsMajorVersion - 4].RequestSize + requestSize) + ); + } + + if (Ctx != *Ndr64Ctx && Ctx != *NdrCtx) + { + if (*Ndr64Ctx == RPC_INVALID_CTX) + { + logger("Warning: Context id should be %u but is %u.\n", (unsigned int)*NdrCtx, Ctx); + } + else + { + logger("Warning: Context id should be %u (NDR32) or %u (NDR64) but is %u.\n", + (unsigned int)*NdrCtx, + (unsigned int)*Ndr64Ctx, + Ctx + ); + } + } + + if (Request->Opnum) + logger("Warning: OpNum should be 0 but is %u.\n", + (unsigned int)LE16(Request->Opnum) + ); + + if (LE32(Request->AllocHint) != len - sizeof(RPC_REQUEST) + sizeof(Request->Ndr)) + logger("Warning: Allocation hint should be %u but is %u.\n", + len + sizeof(Request->Ndr), + LE32(Request->AllocHint) + ); + + if (Ctx != *Ndr64Ctx) + { + if (LE32(Request->Ndr.DataLength) != len - sizeof(RPC_REQUEST)) + logger("Warning: NDR32 data length field should be %u but is %u.\n", + len - sizeof(RPC_REQUEST), + LE32(Request->Ndr.DataLength) + ); + + if (LE32(Request->Ndr.DataSizeIs) != len - sizeof(RPC_REQUEST)) + logger("Warning: NDR32 data size field should be %u but is %u.\n", + len - sizeof(RPC_REQUEST), + LE32(Request->Ndr.DataSizeIs) + ); + } + else + { + if (LE64(Request->Ndr64.DataLength) != len - sizeof(RPC_REQUEST64)) + logger("Warning: NDR32 data length field should be %u but is %u.\n", + len - sizeof(RPC_REQUEST) + sizeof(Request->Ndr), + LE64(Request->Ndr64.DataLength) + ); + + if (LE64(Request->Ndr64.DataSizeIs) != len - sizeof(RPC_REQUEST64)) + logger("Warning: NDR32 data size field should be %u but is %u.\n", + len - sizeof(RPC_REQUEST64), + LE64(Request->Ndr64.DataSizeIs) + ); + } +} +#endif // defined(_PEDANTIC) && !defined(NO_LOG) + +/* + * check RPC request for (somewhat) correct size + * allow any size that does not cause CreateResponse to fail badly + */ +static unsigned int checkRpcRequestSize(const RPC_REQUEST64 *const Request, const unsigned int requestSize, WORD* NdrCtx, WORD* Ndr64Ctx) +{ + WORD Ctx = LE16(Request->ContextId); + +# if defined(_PEDANTIC) && !defined(NO_LOG) + CheckRpcRequest(Request, requestSize, NdrCtx, Ndr64Ctx, Ctx); +# endif // defined(_PEDANTIC) && !defined(NO_LOG) + + // Anything that is smaller than a v4 request is illegal + if (requestSize < sizeof(REQUEST_V4) + (Ctx != *Ndr64Ctx ? sizeof(RPC_REQUEST) : sizeof(RPC_REQUEST64))) return 0; + + // Get KMS major version + uint16_t majorIndex, minor; + DWORD version; + +# ifndef SIMPLE_RPC + + if (Ctx != *Ndr64Ctx) + { + version = LE32(*(DWORD*)Request->Ndr.Data); + } + else + { + version = LE32(*(DWORD*)Request->Ndr64.Data); + } + +# else // SIMPLE_RPC + + version = LE32(*(DWORD*)Request->Ndr.Data); + +# endif // SIMPLE_RPC + + majorIndex = (uint16_t)(version >> 16) - 4; + minor = (uint16_t)(version & 0xffff); + + // Only KMS v4, v5 and v6 are supported + if (majorIndex >= vlmcsd_countof(_Versions) || minor) + { +# ifndef NO_LOG + logger("Fatal: KMSv%hu.%hu unsupported\n", (unsigned short)majorIndex + 4, (unsigned short)minor); +# endif // NO_LOG + return 0; + } + + // Could check for equality but allow bigger requests to support buggy RPC clients (e.g. wine) + // Buffer overrun is check by caller. + return (requestSize >= _Versions[majorIndex].RequestSize); +} + +#ifndef SIMPLE_RPC +static int SendError(RPC_RESPONSE64 *const Response, DWORD nca_error) +{ + Response->Error.Code = nca_error; + Response->Error.Padding = 0; + Response->AllocHint = LE32(32); + Response->ContextId = 0; + return 32; +} +#endif // SIMPLE_RPC + +/* + * Handles the actual KMS request from the client. + * Calls KMS functions (CreateResponseV4 or CreateResponseV6) in kms.c + * Returns size of the KMS response packet or 0 on failure. + * + * The RPC packet size (excluding header) is actually in Response->AllocHint + */ +static int rpcRequest(const RPC_REQUEST64 *const Request, RPC_RESPONSE64 *const Response, const DWORD RpcAssocGroup_unused, const SOCKET sock_unused, WORD* NdrCtx, WORD* Ndr64Ctx, BYTE isValid, const char* const ipstr) +{ + int ResponseSize; // <0 = Errorcode (HRESULT) + BYTE* requestData; + BYTE* responseData; + BYTE* pRpcReturnCode; + int len; + +# ifndef SIMPLE_RPC + + const WORD Ctx = LE16(Request->ContextId); + + if (Ctx == *NdrCtx) + { + requestData = (BYTE*)&Request->Ndr.Data; + responseData = (BYTE*)&Response->Ndr.Data; + } + else if (Ctx == *Ndr64Ctx) + { + requestData = (BYTE*)&Request->Ndr64.Data; + responseData = (BYTE*)&Response->Ndr64.Data; + } + else + { + return SendError(Response, RPC_NCA_UNK_IF); + } + +# else // SIMPLE_RPC + + requestData = (BYTE*)&Request->Ndr.Data; + responseData = (BYTE*)&Response->Ndr.Data; + +# endif // SIMPLE_RPC + + ResponseSize = 0x8007000D; // Invalid Data + + if (isValid) + { + const uint16_t majorIndex = LE16(((WORD*)requestData)[1]) - 4; + if (!((ResponseSize = _Versions[majorIndex].CreateResponse(requestData, responseData, ipstr)))) ResponseSize = 0x8007000D; + } + +# ifndef SIMPLE_RPC + + if (Ctx != *Ndr64Ctx) + { + +# endif // !SIMPLE_RPC + if (ResponseSize < 0) + { + Response->Ndr.DataSizeMax = Response->Ndr.DataLength = 0; + len = sizeof(Response->Ndr) - sizeof(Response->Ndr.DataSizeIs); + } + else + { + Response->Ndr.DataSizeMax = LE32(0x00020000); + Response->Ndr.DataLength = Response->Ndr.DataSizeIs = LE32(ResponseSize); + len = ResponseSize + sizeof(Response->Ndr); + } + +# ifndef SIMPLE_RPC + + } + else + { + if (ResponseSize < 0) + { + Response->Ndr64.DataSizeMax = Response->Ndr64.DataLength = 0; + len = sizeof(Response->Ndr64) - sizeof(Response->Ndr64.DataSizeIs); + } + else + { + Response->Ndr64.DataSizeMax = LE64(0x00020000ULL); + Response->Ndr64.DataLength = Response->Ndr64.DataSizeIs = LE64((uint64_t)ResponseSize); + len = ResponseSize + sizeof(Response->Ndr64); + } + } + +# endif // !SIMPLE_RPC + + pRpcReturnCode = ((BYTE*)&Response->Ndr) + len; + PUT_UA32LE(pRpcReturnCode, ResponseSize < 0 ? ResponseSize : 0); + len += sizeof(DWORD); + + // Pad zeros to 32-bit align (seems not neccassary but Windows RPC does it this way) + const int pad = ((~len & 3) + 1) & 3; + memset(pRpcReturnCode + sizeof(DWORD), 0, pad); + len += pad; + + Response->AllocHint = LE32(len); + Response->ContextId = Request->ContextId; + + *((WORD*)&Response->CancelCount) = 0; // CancelCount + Pad1 + + return len + 8; +} + + +#if defined(_PEDANTIC) && !defined(NO_LOG) +static void CheckRpcBindRequest(const RPC_BIND_REQUEST *const Request, const unsigned int len) +{ + uint_fast8_t i, HasTransferSyntaxNDR32 = FALSE; + char guidBuffer1[GUID_STRING_LENGTH + 1], guidBuffer2[GUID_STRING_LENGTH + 1]; + + const uint32_t CapCtxItems = (len - sizeof(*Request) + sizeof(Request->CtxItems)) / sizeof(Request->CtxItems); + const DWORD NumCtxItems = LE32(Request->NumCtxItems); + + if (NumCtxItems < CapCtxItems) // Can't be too small because already handled by RpcBindSize + logger("Warning: Excess bytes in RPC bind request.\n"); + + for (i = 0; i < NumCtxItems; i++) + { + struct CtxItem const* ctxItem = Request->CtxItems + i; + if (!IsEqualGUID(&ctxItem->InterfaceUUID, InterfaceUuid)) + { + uuid2StringLE(&ctxItem->InterfaceUUID, guidBuffer1); + uuid2StringLE((GUID*)InterfaceUuid, guidBuffer2); + logger("Fatal: Interface UUID is %s but should be %s in Ctx item %u.\n", guidBuffer1, guidBuffer2, (unsigned int)i); + } + + if (ctxItem->NumTransItems != LE16(1)) + logger("Fatal: %u NDR32 transfer items detected in Ctx item %u, but only one is supported.\n", + (unsigned int)LE16(ctxItem->NumTransItems), (unsigned int)i + ); + + if (ctxItem->InterfaceVerMajor != LE16(1) || ctxItem->InterfaceVerMinor != 0) + logger("Warning: Interface version is %u.%u but should be 1.0.\n", + (unsigned int)LE16(ctxItem->InterfaceVerMajor), + (unsigned int)LE16(ctxItem->InterfaceVerMinor) + ); + + if (ctxItem->ContextId != LE16((WORD)i)) + logger("Warning: context id of Ctx item %u is %u.\n", (unsigned int)i, (unsigned int)ctxItem->ContextId); + + if (IsEqualGUID((GUID*)TransferSyntaxNDR32, &ctxItem->TransferSyntax)) + { + HasTransferSyntaxNDR32 = TRUE; + + if (ctxItem->SyntaxVersion != LE32(2)) + logger("NDR32 transfer syntax version is %u but should be 2.\n", LE32(ctxItem->SyntaxVersion)); + } + else if (IsEqualGUID((GUID*)TransferSyntaxNDR64, &ctxItem->TransferSyntax)) + { + if (ctxItem->SyntaxVersion != LE32(1)) + logger("NDR64 transfer syntax version is %u but should be 1.\n", LE32(ctxItem->SyntaxVersion)); + } + else if (!memcmp(BindTimeFeatureNegotiation, (BYTE*)(&ctxItem->TransferSyntax), 8)) + { + if (ctxItem->SyntaxVersion != LE32(1)) + logger("BTFN syntax version is %u but should be 1.\n", LE32(ctxItem->SyntaxVersion)); + } + } + + if (!HasTransferSyntaxNDR32) + logger("Warning: RPC bind request has no NDR32 CtxItem.\n"); +} +#endif // defined(_PEDANTIC) && !defined(NO_LOG) + + +/* + * Check, if we receive enough bytes to return a valid RPC bind response + */ +static unsigned int checkRpcBindSize(const RPC_BIND_REQUEST *const Request, const unsigned int RequestSize, WORD* NdrCtx_unused, WORD* Ndr64Ctx_unused) +{ + if (RequestSize < sizeof(RPC_BIND_REQUEST)) return FALSE; + + const unsigned int numCtxItems = LE32(Request->NumCtxItems); + + if (RequestSize < sizeof(RPC_BIND_REQUEST) - sizeof(Request->CtxItems[0]) + numCtxItems * sizeof(Request->CtxItems[0])) return FALSE; + +#if defined(_PEDANTIC) && !defined(NO_LOG) + CheckRpcBindRequest(Request, RequestSize); +#endif // defined(_PEDANTIC) && !defined(NO_LOG) + + return TRUE; +} + + +/* + * Accepts a bind or alter context request from the client and composes the bind response. + * Needs the socket because the tcp port number is part of the response. + * len is not used here. + * + * Returns TRUE on success. + */ +static int rpcBind(const RPC_BIND_REQUEST *const Request, RPC_BIND_RESPONSE* Response, const DWORD RpcAssocGroup, const SOCKET sock, WORD* NdrCtx, WORD* Ndr64Ctx, BYTE packetType, const char* const ipstr_unused) +{ + unsigned int i; + const DWORD numCtxItems = LE32(Request->NumCtxItems); + int_fast8_t IsNDR64possible = FALSE; + uint_fast8_t portNumberSize; + + socklen_t socklen; + struct sockaddr_storage addr; + + // M$ RPC does not do this. Pad bytes contain apparently random data + // memset(Response->SecondaryAddress, 0, sizeof(Response->SecondaryAddress)); + + socklen = sizeof addr; + + if ( + packetType == RPC_PT_ALTERCONTEXT_REQ || + getsockname(sock, (struct sockaddr*)&addr, &socklen) || + getnameinfo((struct sockaddr*)&addr, socklen, NULL, 0, (char*)Response->SecondaryAddress, sizeof(Response->SecondaryAddress), NI_NUMERICSERV)) + { + portNumberSize = 0; + Response->SecondaryAddressLength = 0; + } + else + { + portNumberSize = (uint_fast8_t)strlen((char*)Response->SecondaryAddress) + 1; + Response->SecondaryAddressLength = LE16(portNumberSize); + } + + Response->MaxXmitFrag = Request->MaxXmitFrag; + Response->MaxRecvFrag = Request->MaxRecvFrag; + Response->AssocGroup = LE32(RpcAssocGroup); + + // This is really ugly (but efficient) code to support padding after the secondary address field + if (portNumberSize < 3) + { + Response = (RPC_BIND_RESPONSE*)((BYTE*)Response - 4); + } + + Response->NumResults = Request->NumCtxItems; + +# ifndef SIMPLE_RPC + + for (i = 0; i < numCtxItems; i++) + { + const struct CtxItem* ctxItem = &Request->CtxItems[i]; + if (IsEqualGUID((GUID*)TransferSyntaxNDR32, &ctxItem->TransferSyntax)) + { + /*if (packetType == RPC_PT_BIND_REQ)*/ + *NdrCtx = LE16(ctxItem->ContextId); + } + + if (UseServerRpcNDR64 && IsEqualGUID((GUID*)TransferSyntaxNDR64, &ctxItem->TransferSyntax)) + { + IsNDR64possible = TRUE; + + /*if (packetType == RPC_PT_BIND_REQ)*/ + *Ndr64Ctx = LE16(ctxItem->ContextId); + } + } + +# endif // !SIMPLE_RPC + + for (i = 0; i < numCtxItems; i++) + { + struct CtxResults* result = Response->Results + i; + const GUID* ctxTransferSyntax = &Request->CtxItems[i].TransferSyntax; + +# ifndef SIMPLE_RPC + WORD nackReason = RPC_ABSTRACTSYNTAX_UNSUPPORTED; +# endif // !SIMPLE_RPC + + memset(&result->TransferSyntax, 0, sizeof(GUID)); + +# ifndef SIMPLE_RPC + const int isInterfaceUUID = IsEqualGUID(&Request->CtxItems[i].InterfaceUUID, (GUID*)InterfaceUuid); + if (isInterfaceUUID) nackReason = RPC_SYNTAX_UNSUPPORTED; +# else // SIMPLE_RPC +# define isInterfaceUUID TRUE +# endif // SIMPLE_RPC + + if (isInterfaceUUID && !IsNDR64possible && IsEqualGUID((GUID*)TransferSyntaxNDR32, ctxTransferSyntax)) + { + result->SyntaxVersion = LE32(2); + result->AckResult = result->AckReason = RPC_BIND_ACCEPT; + memcpy(&result->TransferSyntax, TransferSyntaxNDR32, sizeof(GUID)); + continue; + } + +# ifndef SIMPLE_RPC + + if (IsEqualGUID((GUID*)TransferSyntaxNDR64, ctxTransferSyntax)) + { + if (!UseServerRpcNDR64) nackReason = RPC_SYNTAX_UNSUPPORTED; + + if (isInterfaceUUID && IsNDR64possible) + { + result->SyntaxVersion = LE32(1); + result->AckResult = result->AckReason = RPC_BIND_ACCEPT; + memcpy(&result->TransferSyntax, TransferSyntaxNDR64, sizeof(GUID)); + continue; + } + } + + if (!memcmp(BindTimeFeatureNegotiation, ctxTransferSyntax, 8)) + { + nackReason = RPC_SYNTAX_UNSUPPORTED; + + if (UseServerRpcBTFN) + { + result->SyntaxVersion = 0; + result->AckResult = RPC_BIND_ACK; + + // Features requested are actually encoded in the GUID + result->AckReason = + ((WORD*)(ctxTransferSyntax))[4] & + (RPC_BTFN_SEC_CONTEXT_MULTIPLEX | RPC_BTFN_KEEP_ORPHAN); + + continue; + } + } + +# endif // !SIMPLE_RPC + + result->SyntaxVersion = 0; + result->AckResult = RPC_BIND_NACK; +# ifndef SIMPLE_RPC + result->AckReason = nackReason; +# else // SIMPLE_RPC +# undef isInterfaceUUID + result->AckReason = RPC_SYNTAX_UNSUPPORTED; +# endif // SIMPLE_RPC + } + + //if (!_st) return 0; + + return sizeof(RPC_BIND_RESPONSE) + numCtxItems * sizeof(struct CtxResults) - (portNumberSize < 3 ? 4 : 0); +} + + +// +// Main RPC handling routine +// +typedef unsigned int(*GetResponseSize_t)(const void *const request, const unsigned int requestSize, WORD* NdrCtx, WORD* Ndr64Ctx); +typedef int(*GetResponse_t)(const void* const request, void* response, const DWORD rpcAssocGroup, const SOCKET socket, WORD* NdrCtx, WORD* Ndr64Ctx, BYTE packetType, const char* const ipstr); + +// ReSharper disable CppIncompatiblePointerConversion +static const struct { + BYTE ResponsePacketType; + GetResponseSize_t CheckRequest; + GetResponse_t GetResponse; +} +_Actions[] = { + { RPC_PT_BIND_ACK, (GetResponseSize_t)checkRpcBindSize, (GetResponse_t)rpcBind }, + { RPC_PT_RESPONSE, (GetResponseSize_t)checkRpcRequestSize, (GetResponse_t)rpcRequest }, + { RPC_PT_ALTERCONTEXT_ACK, (GetResponseSize_t)checkRpcBindSize, (GetResponse_t)rpcBind }, +}; +// ReSharper restore CppIncompatiblePointerConversion + + +/* +* Initializes an RPC request header as needed for KMS, i.e. packet always fits in one fragment. +* size cannot be greater than fragment length negotiated during RPC bind. +*/ +static void createRpcHeader(RPC_HEADER* header, BYTE packetType, WORD size) +{ + header->PacketType = packetType; + header->PacketFlags = RPC_PF_FIRST | RPC_PF_LAST; + header->VersionMajor = 5; + header->VersionMinor = 0; + header->AuthLength = 0; + header->DataRepresentation = BE32(0x10000000); // Little endian, ASCII charset, IEEE floating point + header->CallId = LE32(CallId); + header->FragLength = LE16(size); +} + + +/* + * This is the main RPC server loop. Returns after KMS request has been serviced + * or a timeout has occured. + */ +void rpcServer(const SOCKET sock, const DWORD rpcAssocGroup, const char* const ipstr) +{ + RPC_HEADER rpcRequestHeader; + WORD NdrCtx = RPC_INVALID_CTX, Ndr64Ctx = RPC_INVALID_CTX; + + randomNumberInit(); + + while (_recv(sock, &rpcRequestHeader, sizeof(rpcRequestHeader))) + { + //int_fast8_t _st; + unsigned int request_len, response_len; + uint_fast8_t _a; + +#if defined(_PEDANTIC) && !defined(NO_LOG) + checkRpcHeader(&rpcRequestHeader, rpcRequestHeader.PacketType, &logger); +#endif // defined(_PEDANTIC) && !defined(NO_LOG) + + switch (rpcRequestHeader.PacketType) + { + case RPC_PT_BIND_REQ: _a = 0; break; + case RPC_PT_REQUEST: _a = 1; break; + case RPC_PT_ALTERCONTEXT_REQ: _a = 2; break; + default: return; + } + + request_len = LE16(rpcRequestHeader.FragLength) - sizeof(rpcRequestHeader); + + BYTE requestBuffer[MAX_REQUEST_SIZE + sizeof(RPC_RESPONSE64)]; + BYTE responseBuffer[MAX_RESPONSE_SIZE + sizeof(RPC_HEADER) + sizeof(RPC_RESPONSE64)]; + + RPC_HEADER *rpcResponseHeader = (RPC_HEADER *)responseBuffer; + RPC_RESPONSE* rpcResponse = (RPC_RESPONSE*)(responseBuffer + sizeof(rpcRequestHeader)); + + // The request is larger than the buffer size + if (request_len > MAX_REQUEST_SIZE + sizeof(RPC_REQUEST64)) return; + + // Unable to receive the complete request + if (!_recv(sock, requestBuffer, request_len)) return; + +# if !defined(SIMPLE_RPC) && defined(_PEDANTIC) + if (rpcRequestHeader.PacketType == RPC_PT_REQUEST && (rpcRequestHeader.VersionMajor != 5 || rpcRequestHeader.VersionMinor != 0)) + { + response_len = SendError((RPC_RESPONSE64*)rpcResponse, RPC_NCA_PROTO_ERROR); + } + else +# endif // !defined(SIMPLE_RPC) && defined(_PEDANTIC) + { + BYTE isValid = (BYTE)_Actions[_a].CheckRequest(requestBuffer, request_len, &NdrCtx, &Ndr64Ctx); + if (rpcRequestHeader.PacketType != RPC_PT_REQUEST && !isValid) return; + + // Unable to create a valid response from request + if (!((response_len = _Actions[_a].GetResponse(requestBuffer, rpcResponse, rpcAssocGroup, sock, &NdrCtx, &Ndr64Ctx, rpcRequestHeader.PacketType != RPC_PT_REQUEST ? rpcRequestHeader.PacketType : isValid, ipstr)))) return; + } + + memcpy(rpcResponseHeader, &rpcRequestHeader, sizeof(RPC_HEADER)); + +# ifndef SIMPLE_RPC + if (response_len == 32) + { + createRpcHeader(rpcResponseHeader, RPC_PT_FAULT, 0); + rpcResponseHeader->PacketFlags = RPC_PF_FIRST | RPC_PF_LAST | RPC_PF_NOT_EXEC; + } + else +# endif // SIMPLE_RPC + { + response_len += sizeof(RPC_HEADER); + rpcResponseHeader->PacketType = _Actions[_a].ResponsePacketType; + + if (rpcResponseHeader->PacketType == RPC_PT_ALTERCONTEXT_ACK) + { + rpcResponseHeader->PacketFlags = RPC_PF_FIRST | RPC_PF_LAST; + } + } + + rpcResponseHeader->FragLength = LE16((WORD)response_len); + + if (!_send(sock, responseBuffer, response_len)) return; + + if (DisconnectImmediately && (rpcResponseHeader->PacketType == RPC_PT_RESPONSE || rpcResponseHeader->PacketType == RPC_PT_FAULT)) + return; + } +} + + +/* RPC client functions */ + + +/* + * Checks RPC header. Returns 0 on success. + * This is mainly for debugging a non Microsoft KMS server that uses its own RPC code. + */ +static int checkRpcHeader(const RPC_HEADER *const header, const BYTE desiredPacketType, const PRINTFUNC p) +{ + int status = 0; + + if (header->PacketType != desiredPacketType) + { + p("Fatal: Received wrong RPC packet type. Expected %u but got %u\n", + (uint32_t)desiredPacketType, + header->PacketType + ); + status = RPC_S_PROTOCOL_ERROR; + } + + if (header->DataRepresentation != BE32(0x10000000)) + { + p("Fatal: RPC response does not conform to Microsoft's limited support of DCE RPC\n"); + status = RPC_S_PROTOCOL_ERROR; + } + + if (header->AuthLength != 0) + { + p("Fatal: RPC response requests authentication\n"); + status = RPC_S_UNKNOWN_AUTHN_TYPE; + } + + // vlmcsd does not support fragmented packets (not yet neccassary) + if ((header->PacketFlags & (RPC_PF_FIRST | RPC_PF_LAST)) != (RPC_PF_FIRST | RPC_PF_LAST)) + { + p("Fatal: RPC packet flags RPC_PF_FIRST and RPC_PF_LAST are not both set.\n"); + status = RPC_S_CANNOT_SUPPORT; + } + + if (header->PacketFlags & RPC_PF_CANCEL_PENDING) p("Warning: %s should not be set\n", "RPC_PF_CANCEL_PENDING"); + if (header->PacketFlags & RPC_PF_RESERVED) p("Warning: %s should not be set\n", "RPC_PF_RESERVED"); + if (header->PacketFlags & RPC_PF_NOT_EXEC) p("Warning: %s should not be set\n", "RPC_PF_NOT_EXEC"); + if (header->PacketFlags & RPC_PF_MAYBE) p("Warning: %s should not be set\n", "RPC_PF_MAYBE"); + if (header->PacketFlags & RPC_PF_OBJECT) p("Warning: %s should not be set\n", "RPC_PF_OBJECT"); + + if (header->VersionMajor != 5 || header->VersionMinor != 0) + { + p("Fatal: Expected RPC version 5.0 and got %u.%u\n", header->VersionMajor, header->VersionMinor); + status = RPC_S_INVALID_VERS_OPTION; + } + + return status; +} + + +/* + * Checks an RPC response header. Does basic header checks by calling checkRpcHeader() + * and then does additional checks if response header complies with the respective request header. + * PRINTFUNC p can be anything that has the same prototype as printf. + * Returns 0 on success. + */ + // ReSharper disable once CppIncompatiblePointerConversion +static int checkRpcResponseHeader(const RPC_HEADER *const ResponseHeader, const RPC_HEADER *const RequestHeader, const BYTE desiredPacketType, const PRINTFUNC p) +{ + static int_fast8_t WineBugDetected = FALSE; + int status = checkRpcHeader(ResponseHeader, desiredPacketType, p); + + if (desiredPacketType == RPC_PT_BIND_ACK) + { + if ((ResponseHeader->PacketFlags & RPC_PF_MULTIPLEX) != (RequestHeader->PacketFlags & RPC_PF_MULTIPLEX)) + { + p("Warning: RPC_PF_MULTIPLEX of RPC request and response should match\n"); + } + } + else + { + if (ResponseHeader->PacketFlags & RPC_PF_MULTIPLEX) + { + p("Warning: %s should not be set\n", "RPC_PF_MULTIPLEX"); + } + } + + if (!status && ResponseHeader->CallId == LE32(1)) + { + if (!WineBugDetected) + { + p("Warning: Buggy RPC of Wine detected. Call Id of Response is always 1\n"); + WineBugDetected = TRUE; + } + } + else if (ResponseHeader->CallId != RequestHeader->CallId) + { + p("Fatal: Sent Call Id %u but received answer for Call Id %u\n", + (uint32_t)LE32(RequestHeader->CallId), + (uint32_t)LE32(ResponseHeader->CallId) + ); + + status = RPC_S_PROTOCOL_ERROR; + } + + return status; +} + +/* + * Sends a KMS request via RPC and receives a response. + * Parameters are raw (encrypted) reqeuests / responses. + * Returns 0 on success. + */ +RpcStatus rpcSendRequest(const RpcCtx sock, const BYTE *const kmsRequest, const size_t requestSize, BYTE **kmsResponse, size_t *const responseSize) +{ +#define MAX_EXCESS_BYTES 16 + RPC_HEADER *RequestHeader, ResponseHeader; + RPC_REQUEST64 *RpcRequest; + RPC_RESPONSE64 _Response; + int status; + const int_fast8_t useNdr64 = RpcFlags.HasNDR64 && UseClientRpcNDR64 && firstPacketSent; + size_t size = sizeof(RPC_HEADER) + (useNdr64 ? sizeof(RPC_REQUEST64) : sizeof(RPC_REQUEST)) + requestSize; + size_t responseSize2; + + *kmsResponse = NULL; + + BYTE *_Request = (BYTE*)vlmcsd_malloc(size); + + RequestHeader = (RPC_HEADER*)_Request; + RpcRequest = (RPC_REQUEST64*)(_Request + sizeof(RPC_HEADER)); + + createRpcHeader(RequestHeader, RPC_PT_REQUEST, (WORD)size); + + // Increment CallId for next Request + CallId++; + + RpcRequest->Opnum = 0; + + if (useNdr64) + { + RpcRequest->ContextId = LE16(1); // We negotiate NDR64 always as context 1 + RpcRequest->AllocHint = LE32((DWORD)(requestSize + sizeof(RpcRequest->Ndr64))); + RpcRequest->Ndr64.DataLength = LE64((uint64_t)requestSize); + RpcRequest->Ndr64.DataSizeIs = LE64((uint64_t)requestSize); + memcpy(RpcRequest->Ndr64.Data, kmsRequest, requestSize); + } + else + { + RpcRequest->ContextId = 0; // We negotiate NDR32 always as context 0 + RpcRequest->AllocHint = LE32((DWORD)(requestSize + sizeof(RpcRequest->Ndr))); + RpcRequest->Ndr.DataLength = LE32((DWORD)requestSize); + RpcRequest->Ndr.DataSizeIs = LE32((DWORD)requestSize); + memcpy(RpcRequest->Ndr.Data, kmsRequest, requestSize); + } + + for (;;) + { + int bytesread; + + if (!_send(sock, _Request, (int)size)) + { + printerrorf("\nFatal: Could not send RPC request\n"); + status = RPC_S_COMM_FAILURE; + break; + } + + if (!_recv(sock, &ResponseHeader, sizeof(RPC_HEADER))) + { + printerrorf("\nFatal: No RPC response received from server\n"); + status = RPC_S_COMM_FAILURE; + break; + } + + if ((status = checkRpcResponseHeader(&ResponseHeader, RequestHeader, RPC_PT_RESPONSE, &printerrorf))) break; + + size = useNdr64 ? sizeof(RPC_RESPONSE64) : sizeof(RPC_RESPONSE); + + if (size > LE16(ResponseHeader.FragLength) - sizeof(ResponseHeader)) + size = LE16(ResponseHeader.FragLength) - sizeof(ResponseHeader); + + if (!_recv(sock, &_Response, (int)size)) + { + printerrorf("\nFatal: RPC response is incomplete\n"); + status = RPC_S_COMM_FAILURE; + break; + } + + if (_Response.CancelCount != 0) + { + printerrorf("\nFatal: RPC response cancel count is not 0\n"); + status = RPC_S_CALL_CANCELLED; + break; + } + + if (_Response.ContextId != (useNdr64 ? LE16(1) : 0)) + { + printerrorf("\nFatal: RPC response context id %u is not bound\n", (unsigned int)LE16(_Response.ContextId)); + status = RPC_X_SS_CONTEXT_DAMAGED; + break; + } + + int_fast8_t sizesMatch; + + if (useNdr64) + { + *responseSize = (size_t)LE64(_Response.Ndr64.DataLength); + responseSize2 = (size_t)LE64(_Response.Ndr64.DataSizeIs); + + if (/*!*responseSize ||*/ !_Response.Ndr64.DataSizeMax) + { + status = (int)LE32(_Response.Ndr64.status); + break; + } + + sizesMatch = (size_t)LE64(_Response.Ndr64.DataLength) == responseSize2; + } + else + { + *responseSize = (size_t)LE32(_Response.Ndr.DataLength); + responseSize2 = (size_t)LE32(_Response.Ndr.DataSizeIs); + + if (/*!*responseSize ||*/ !_Response.Ndr.DataSizeMax) + { + status = (int)LE32(_Response.Ndr.status); + break; + } + + sizesMatch = (size_t)LE32(_Response.Ndr.DataLength) == responseSize2; + } + + if (!sizesMatch) + { + printerrorf("\nFatal: NDR data length (%u) does not match NDR data size (%u)\n", + (uint32_t)*responseSize, + (uint32_t)LE32(_Response.Ndr.DataSizeIs) + ); + + status = RPC_S_PROTOCOL_ERROR; + break; + } + + *kmsResponse = (BYTE*)vlmcsd_malloc(*responseSize + MAX_EXCESS_BYTES); + + // If RPC stub is too short, assume missing bytes are zero (same ill behavior as MS RPC) + memset(*kmsResponse, 0, *responseSize + MAX_EXCESS_BYTES); + + // Read up to 16 bytes more than bytes expected to detect faulty KMS emulators + if ((bytesread = recv(sock, (char*)*kmsResponse, (int)(*responseSize) + MAX_EXCESS_BYTES, 0)) < (int)*responseSize) + { + printerrorf("\nFatal: No or incomplete KMS response received. Required %u bytes but only got %i\n", + (uint32_t)*responseSize, + (int32_t)(bytesread < 0 ? 0 : bytesread) + ); + + status = RPC_S_PROTOCOL_ERROR; + break; + } + + DWORD *pReturnCode; + + const size_t len = *responseSize + (useNdr64 ? sizeof(_Response.Ndr64) : sizeof(_Response.Ndr)) + sizeof(*pReturnCode); + const size_t pad = ((~len & 3) + 1) & 3; + + if (len + pad != LE32(_Response.AllocHint)) + { + printerrorf("\nWarning: RPC stub size is %u, should be %u (probably incorrect padding)\n", (uint32_t)LE32(_Response.AllocHint), (uint32_t)(len + pad)); + } + else + { + size_t i; + for (i = 0; i < pad; i++) + { + if (*(*kmsResponse + *responseSize + sizeof(*pReturnCode) + i)) + { + printerrorf("\nWarning: RPC stub data not padded to zeros according to Microsoft standard\n"); + break; + } + } + } + + pReturnCode = (DWORD*)(*kmsResponse + *responseSize + pad); + status = GET_UA32LE(pReturnCode); + //status = LE32(UA32(pReturnCode)); + + break; + } + + free(_Request); + firstPacketSent = TRUE; + return status; +#undef MAX_EXCESS_BYTES +} + + +static int_fast8_t IsNullGuid(const BYTE* guidPtr) +{ + int_fast8_t i; + + for (i = 0; i < 16; i++) + { + if (guidPtr[i]) return FALSE; + } + + return TRUE; +} + +/* + * Perform RPC client bind. Accepts a connected client socket. + * Returns 0 on success. RPC binding is required before any payload can be + * exchanged. It negotiates about protocol details. + */ +static RpcStatus rpcBindOrAlterClientContext(const RpcCtx sock, const BYTE packetType, const int_fast8_t verbose) +{ + RPC_HEADER *RequestHeader, ResponseHeader; + RPC_BIND_REQUEST *bindRequest; + RPC_BIND_RESPONSE *bindResponse; + int status; + const WORD ctxItems = 1 + (packetType == RPC_PT_BIND_REQ ? UseClientRpcNDR64 + UseClientRpcBTFN : 0); + const size_t rpcBindSize = (sizeof(RPC_HEADER) + sizeof(RPC_BIND_REQUEST) + (ctxItems - 1) * sizeof(bindRequest->CtxItems[0])); + WORD ctxIndex = 0; + WORD i; + WORD CtxBTFN = RPC_INVALID_CTX, CtxNDR64 = RPC_INVALID_CTX; + BYTE* request = (BYTE*)alloca(rpcBindSize); + + RequestHeader = (RPC_HEADER*)request; + bindRequest = (RPC_BIND_REQUEST*)(request + sizeof(RPC_HEADER)); + + createRpcHeader(RequestHeader, packetType, (WORD)rpcBindSize); + RequestHeader->PacketFlags |= UseMultiplexedRpc ? RPC_PF_MULTIPLEX : 0; + + bindRequest->AssocGroup = 0; + bindRequest->MaxRecvFrag = bindRequest->MaxXmitFrag = LE16(5840); + bindRequest->NumCtxItems = LE32(ctxItems); + + // data that is identical in all Ctx items + for (i = 0; i < ctxItems; i++) + { + struct CtxItem* ctxItem = bindRequest->CtxItems + i; + ctxItem->ContextId = LE16(i); + ctxItem->InterfaceVerMajor = LE16(1); + ctxItem->InterfaceVerMinor = 0; + ctxItem->NumTransItems = LE16(1); + ctxItem->SyntaxVersion = i ? LE32(1) : LE32(2); + + memcpy(&ctxItem->InterfaceUUID, InterfaceUuid, sizeof(GUID)); + } + + memcpy(&bindRequest->CtxItems[0].TransferSyntax, TransferSyntaxNDR32, sizeof(GUID)); + + if (UseClientRpcNDR64 && packetType == RPC_PT_BIND_REQ) + { + memcpy(&bindRequest->CtxItems[++ctxIndex].TransferSyntax, TransferSyntaxNDR64, sizeof(GUID)); + CtxNDR64 = ctxIndex; + } + + if (UseClientRpcBTFN && packetType == RPC_PT_BIND_REQ) + { + memcpy(&bindRequest->CtxItems[++ctxIndex].TransferSyntax, BindTimeFeatureNegotiation, sizeof(GUID)); + CtxBTFN = ctxIndex; + } + + if (!_send(sock, request, (int)rpcBindSize)) + { + printerrorf("\nFatal: Sending RPC bind request failed\n"); + return RPC_S_COMM_FAILURE; + } + + if (!_recv(sock, &ResponseHeader, sizeof(RPC_HEADER))) + { + printerrorf("\nFatal: Did not receive a response from server\n"); + return RPC_S_COMM_FAILURE; + } + + if ((status = checkRpcResponseHeader + ( + &ResponseHeader, + RequestHeader, + packetType == RPC_PT_BIND_REQ ? RPC_PT_BIND_ACK : RPC_PT_ALTERCONTEXT_ACK, + &printerrorf + ))) + { + return status; + } + + bindResponse = (RPC_BIND_RESPONSE*)vlmcsd_malloc(LE16(ResponseHeader.FragLength) - sizeof(RPC_HEADER)); + BYTE* bindResponseBytePtr = (BYTE*)bindResponse; + + if (!_recv(sock, bindResponse, LE16(ResponseHeader.FragLength) - sizeof(RPC_HEADER))) + { + printerrorf("\nFatal: Incomplete RPC bind acknowledgement received\n"); + free(bindResponseBytePtr); + return RPC_S_COMM_FAILURE; + } + + /* + * checking, whether a bind or alter context response is as expected. + * This check is very strict and checks whether a KMS emulator behaves exactly the same way + * as Microsoft's RPC does. + */ + status = 0; + + if (bindResponse->SecondaryAddressLength < LE16(3)) + bindResponse = (RPC_BIND_RESPONSE*)(bindResponseBytePtr - 4); + + if (bindResponse->NumResults != bindRequest->NumCtxItems) + { + printerrorf("\nFatal: Expected %u CTX items but got %u\n", + (uint32_t)LE32(bindRequest->NumCtxItems), + (uint32_t)LE32(bindResponse->NumResults) + ); + + status = RPC_S_PROTOCOL_ERROR; + } + + for (i = 0; i < ctxItems; i++) + { + const char* transferSyntaxName = + i == CtxBTFN ? "BTFN" : i == CtxNDR64 ? "NDR64" : "NDR32"; + + struct CtxResults* ctxResult = bindResponse->Results + i; + struct CtxItem* ctxItem = bindRequest->CtxItems + i; + if (ctxResult->AckResult == RPC_BIND_NACK) // transfer syntax was declined + { + if (!IsNullGuid((BYTE*)&ctxResult->TransferSyntax)) + { + printerrorf( + "\nWarning: Rejected transfer syntax %s did not return NULL Guid\n", + transferSyntaxName + ); + } + + if (ctxResult->SyntaxVersion) + { + printerrorf( + "\nWarning: Rejected transfer syntax %s did not return syntax version 0 but %u\n", + transferSyntaxName, + LE32(ctxResult->SyntaxVersion) + ); + } + + if (ctxResult->AckReason == RPC_ABSTRACTSYNTAX_UNSUPPORTED) + { + printerrorf( + "\nWarning: Transfer syntax %s does not support KMS activation\n", + transferSyntaxName + ); + } + else if (ctxResult->AckReason != RPC_SYNTAX_UNSUPPORTED) + { + printerrorf( + "\nWarning: Rejected transfer syntax %s did not return ack reason RPC_SYNTAX_UNSUPPORTED\n", + transferSyntaxName + ); + } + + continue; + } + + if (i == CtxBTFN) // BTFN + { + if (ctxResult->AckResult != RPC_BIND_ACK) + { + printerrorf("\nWarning: BTFN did not respond with RPC_BIND_ACK or RPC_BIND_NACK\n"); + } + + if (ctxResult->AckReason != LE16(3)) + { + printerrorf("\nWarning: BTFN did not return expected feature mask 0x3 but 0x%X\n", (unsigned int)LE16(ctxResult->AckReason)); + } + + if (verbose) printf("... BTFN "); + RpcFlags.HasBTFN = TRUE; + + continue; + } + + // NDR32 or NDR64 Ctx + if (ctxResult->AckResult != RPC_BIND_ACCEPT) + { + printerrorf( + "\nFatal: transfer syntax %s returned an invalid status, neither RPC_BIND_ACCEPT nor RPC_BIND_NACK\n", + transferSyntaxName + ); + + status = RPC_S_PROTOCOL_ERROR; + } + + if (!IsEqualGUID(&ctxResult->TransferSyntax, &ctxItem->TransferSyntax)) + { + printerrorf( + "\nFatal: Transfer syntax of RPC bind request and response does not match\n" + ); + + status = RPC_S_UNSUPPORTED_TRANS_SYN; + } + + if (ctxResult->SyntaxVersion != ctxItem->SyntaxVersion) + { + printerrorf("\nFatal: Expected transfer syntax version %u for %s but got %u\n", + (uint32_t)LE32(ctxItem->SyntaxVersion), + transferSyntaxName, + (uint32_t)LE32(ctxResult->SyntaxVersion) + ); + + status = RPC_S_UNSUPPORTED_TRANS_SYN; + } + + // The ack reason field is actually undefined here but Microsoft sets this to 0 + if (ctxResult->AckReason != 0) + { + printerrorf( + "\nWarning: Ack reason should be 0 but is %u\n", + LE16(ctxResult->AckReason) + ); + } + + if (!status) + { + if (i == CtxNDR64) + { + RpcFlags.HasNDR64 = TRUE; + if (verbose) printf("... NDR64 "); + } + if (!i) + { + RpcFlags.HasNDR32 = TRUE; + if (verbose) printf("... NDR32 "); + } + + } + } + + free(bindResponseBytePtr); + + if (!RpcFlags.HasNDR64 && !RpcFlags.HasNDR32) + { + printerrorf("\nFatal: Could neither negotiate NDR32 nor NDR64 with the RPC server\n"); + status = RPC_S_NO_PROTSEQS; + } + + return status; +} + +RpcStatus rpcBindClient(const RpcCtx sock, const int_fast8_t verbose, PRpcDiag_t rpcDiag) +{ + firstPacketSent = FALSE; + RpcFlags.mask = 0; + + RpcStatus status = + rpcBindOrAlterClientContext(sock, RPC_PT_BIND_REQ, verbose); + + if (status) goto end; + + if (!RpcFlags.HasNDR32) + status = rpcBindOrAlterClientContext(sock, RPC_PT_ALTERCONTEXT_REQ, verbose); + +end: + rpcDiag->HasRpcDiag = TRUE; + rpcDiag->HasNDR64 = !!RpcFlags.HasNDR64; + rpcDiag->HasBTFN = !!RpcFlags.HasBTFN; + return status; +} + +#endif // USE_MSRPC diff --git a/vlmcsd/src/rpc.h b/vlmcsd/src/rpc.h new file mode 100644 index 0000000..78b3a10 --- /dev/null +++ b/vlmcsd/src/rpc.h @@ -0,0 +1,323 @@ +#ifndef __rpc_h +#define __rpc_h + +#ifndef CONFIG +#define CONFIG "config.h" +#endif // CONFIG +#include CONFIG + +#include "types.h" +#include "shared_globals.h" + +#if !defined(_WIN32) && !defined(__CYGWIN__) +#define RPC_S_OK 0 +#define RPC_S_INVALID_ARG 87 +#define RPC_S_OUT_OF_MEMORY 14 +#define RPC_S_OUT_OF_THREADS 164 +#define RPC_S_INVALID_LEVEL RPC_S_INVALID_ARG +#define RPC_S_BUFFER_TOO_SMALL 122 +#define RPC_S_INVALID_SECURITY_DESC 1338 +#define RPC_S_ACCESS_DENIED 5 +#define RPC_S_SERVER_OUT_OF_MEMORY 1130 +#define RPC_S_ASYNC_CALL_PENDING 997 +#define RPC_S_UNKNOWN_PRINCIPAL 1332 +#define RPC_S_TIMEOUT 1460 +#define RPC_S_INVALID_STRING_BINDING 1700 +#define RPC_S_WRONG_KIND_OF_BINDING 1701 +#define RPC_S_INVALID_BINDING 1702 +#define RPC_S_PROTSEQ_NOT_SUPPORTED 1703 +#define RPC_S_INVALID_RPC_PROTSEQ 1704 +#define RPC_S_INVALID_STRING_UUID 1705 +#define RPC_S_INVALID_ENDPOINT_FORMAT 1706 +#define RPC_S_INVALID_NET_ADDR 1707 +#define RPC_S_NO_ENDPOINT_FOUND 1708 +#define RPC_S_INVALID_TIMEOUT 1709 +#define RPC_S_OBJECT_NOT_FOUND 1710 +#define RPC_S_ALREADY_REGISTERED 1711 +#define RPC_S_TYPE_ALREADY_REGISTERED 1712 +#define RPC_S_ALREADY_LISTENING 1713 +#define RPC_S_NO_PROTSEQS_REGISTERED 1714 +#define RPC_S_NOT_LISTENING 1715 +#define RPC_S_UNKNOWN_MGR_TYPE 1716 +#define RPC_S_UNKNOWN_IF 1717 +#define RPC_S_NO_BINDINGS 1718 +#define RPC_S_NO_PROTSEQS 1719 +#define RPC_S_CANT_CREATE_ENDPOINT 1720 +#define RPC_S_OUT_OF_RESOURCES 1721 +#define RPC_S_SERVER_UNAVAILABLE 1722 +#define RPC_S_SERVER_TOO_BUSY 1723 +#define RPC_S_INVALID_NETWORK_OPTIONS 1724 +#define RPC_S_NO_CALL_ACTIVE 1725 +#define RPC_S_CALL_FAILED 1726 +#define RPC_S_CALL_FAILED_DNE 1727 +#define RPC_S_PROTOCOL_ERROR 1728 +#define RPC_S_PROXY_ACCESS_DENIED 1729 +#define RPC_S_UNSUPPORTED_TRANS_SYN 1730 +#define RPC_S_UNSUPPORTED_TYPE 1732 +#define RPC_S_INVALID_TAG 1733 +#define RPC_S_INVALID_BOUND 1734 +#define RPC_S_NO_ENTRY_NAME 1735 +#define RPC_S_INVALID_NAME_SYNTAX 1736 +#define RPC_S_UNSUPPORTED_NAME_SYNTAX 1737 +#define RPC_S_UUID_NO_ADDRESS 1739 +#define RPC_S_DUPLICATE_ENDPOINT 1740 +#define RPC_S_UNKNOWN_AUTHN_TYPE 1741 +#define RPC_S_MAX_CALLS_TOO_SMALL 1742 +#define RPC_S_STRING_TOO_LONG 1743 +#define RPC_S_PROTSEQ_NOT_FOUND 1744 +#define RPC_S_PROCNUM_OUT_OF_RANGE 1745 +#define RPC_S_BINDING_HAS_NO_AUTH 1746 +#define RPC_S_UNKNOWN_AUTHN_SERVICE 1747 +#define RPC_S_UNKNOWN_AUTHN_LEVEL 1748 +#define RPC_S_INVALID_AUTH_IDENTITY 1749 +#define RPC_S_UNKNOWN_AUTHZ_SERVICE 1750 +#define EPT_S_INVALID_ENTRY 1751 +#define EPT_S_CANT_PERFORM_OP 1752 +#define EPT_S_NOT_REGISTERED 1753 +#define RPC_S_NOTHING_TO_EXPORT 1754 +#define RPC_S_INCOMPLETE_NAME 1755 +#define RPC_S_INVALID_VERS_OPTION 1756 +#define RPC_S_NO_MORE_MEMBERS 1757 +#define RPC_S_NOT_ALL_OBJS_UNEXPORTED 1758 +#define RPC_S_INTERFACE_NOT_FOUND 1759 +#define RPC_S_ENTRY_ALREADY_EXISTS 1760 +#define RPC_S_ENTRY_NOT_FOUND 1761 +#define RPC_S_NAME_SERVICE_UNAVAILABLE 1762 +#define RPC_S_INVALID_NAF_ID 1763 +#define RPC_S_CANNOT_SUPPORT 1764 +#define RPC_S_NO_CONTEXT_AVAILABLE 1765 +#define RPC_S_INTERNAL_ERROR 1766 +#define RPC_S_ZERO_DIVIDE 1767 +#define RPC_S_ADDRESS_ERROR 1768 +#define RPC_S_FP_DIV_ZERO 1769 +#define RPC_S_FP_UNDERFLOW 1770 +#define RPC_S_FP_OVERFLOW 1771 +#define RPC_X_NO_MORE_ENTRIES 1772 +#define RPC_X_SS_CHAR_TRANS_OPEN_FAIL 1773 +#define RPC_X_SS_CHAR_TRANS_SHORT_FILE 1774 +#define RPC_X_SS_IN_NULL_CONTEXT 1775 +#define RPC_X_SS_CONTEXT_DAMAGED 1777 +#define RPC_X_SS_HANDLES_MISMATCH 1778 +#define RPC_X_SS_CANNOT_GET_CALL_HANDLE 1779 +#define RPC_X_NULL_REF_POINTER 1780 +#define RPC_X_ENUM_VALUE_OUT_OF_RANGE 1781 +#define RPC_X_BYTE_COUNT_TOO_SMALL 1782 +#define RPC_X_BAD_STUB_DATA 1783 +#define RPC_S_CALL_IN_PROGRESS 1791 +#define RPC_S_NO_MORE_BINDINGS 1806 +#define RPC_S_NO_INTERFACES 1817 +#define RPC_S_CALL_CANCELLED 1818 +#define RPC_S_BINDING_INCOMPLETE 1819 +#define RPC_S_COMM_FAILURE 1820 +#define RPC_S_UNSUPPORTED_AUTHN_LEVEL 1821 +#define RPC_S_NO_PRINC_NAME 1822 +#define RPC_S_NOT_RPC_ERROR 1823 +#define RPC_S_UUID_LOCAL_ONLY 1824 +#define RPC_S_SEC_PKG_ERROR 1825 +#define RPC_S_NOT_CANCELLED 1826 +#define RPC_X_INVALID_ES_ACTION 1827 +#define RPC_X_WRONG_ES_VERSION 1828 +#define RPC_X_WRONG_STUB_VERSION 1829 +#define RPC_X_INVALID_PIPE_OBJECT 1830 +#define RPC_X_WRONG_PIPE_ORDER 1831 +#define RPC_X_WRONG_PIPE_VERSION 1832 +#define RPC_S_COOKIE_AUTH_FAILED 1833 +#define RPC_S_GROUP_MEMBER_NOT_FOUND 1898 +#define EPT_S_CANT_CREATE 1899 +#define RPC_S_INVALID_OBJECT 1900 +#define RPC_S_SEND_INCOMPLETE 1913 +#define RPC_S_INVALID_ASYNC_HANDLE 1914 +#define RPC_S_INVALID_ASYNC_CALL 1915 +#define RPC_X_PIPE_CLOSED 1916 +#define RPC_X_PIPE_DISCIPLINE_ERROR 1917 +#define RPC_X_PIPE_EMPTY 1918 +#define RPC_S_ENTRY_TYPE_MISMATCH 1922 +#define RPC_S_NOT_ALL_OBJS_EXPORTED 1923 +#define RPC_S_INTERFACE_NOT_EXPORTED 1924 +#define RPC_S_PROFILE_NOT_ADDED 1925 +#define RPC_S_PRF_ELT_NOT_ADDED 1926 +#define RPC_S_PRF_ELT_NOT_REMOVED 1927 +#define RPC_S_GRP_ELT_NOT_ADDED 1928 +#define RPC_S_GRP_ELT_NOT_REMOVED 1929 +#endif // !defined(_WIN32) && !_defined(__CYGWIN__) + + +typedef struct { + BYTE VersionMajor; + BYTE VersionMinor; + BYTE PacketType; + BYTE PacketFlags; + DWORD DataRepresentation; + WORD FragLength; + WORD AuthLength; + DWORD CallId; +} /*__packed*/ RPC_HEADER; + + +typedef struct { + WORD MaxXmitFrag; + WORD MaxRecvFrag; + DWORD AssocGroup; + DWORD NumCtxItems; + struct CtxItem { + WORD ContextId; + WORD NumTransItems; + GUID InterfaceUUID; + WORD InterfaceVerMajor; + WORD InterfaceVerMinor; + GUID TransferSyntax; + DWORD SyntaxVersion; + } CtxItems[1]; +} /*__packed*/ RPC_BIND_REQUEST; + +typedef struct { + WORD MaxXmitFrag; + WORD MaxRecvFrag; + DWORD AssocGroup; + WORD SecondaryAddressLength; + BYTE SecondaryAddress[6]; + DWORD NumResults; + struct CtxResults { + WORD AckResult; + WORD AckReason; + GUID TransferSyntax; + DWORD SyntaxVersion; + } Results[0]; +} /*__packed*/ RPC_BIND_RESPONSE; + + +typedef struct { + DWORD AllocHint; + WORD ContextId; + WORD Opnum; + struct { + DWORD DataLength; + DWORD DataSizeIs; + } Ndr; + BYTE Data[0]; +} /*__packed*/ RPC_REQUEST; + +typedef struct { + DWORD AllocHint; + WORD ContextId; + BYTE CancelCount; + BYTE Pad1; + struct { + DWORD DataLength; + DWORD DataSizeIs1; + DWORD DataSizeIs2; + } Ndr; + BYTE Data[0]; +} /*__packed*/ RPC_RESPONSE; + +typedef struct { + DWORD AllocHint; + WORD ContextId; + WORD Opnum; + union { + struct { + DWORD DataLength; + DWORD DataSizeIs; + BYTE Data[0]; + } Ndr; + struct { + uint64_t DataLength; + uint64_t DataSizeIs; + BYTE Data[0]; + } Ndr64; + }; +} /*__packed*/ RPC_REQUEST64; + +typedef struct { + DWORD AllocHint; + WORD ContextId; + BYTE CancelCount; + BYTE Pad1; + union { + struct { + DWORD DataLength; + DWORD DataSizeMax; + union + { + DWORD DataSizeIs; + DWORD status; + }; + BYTE Data[0]; + } Ndr; + struct { + uint64_t DataLength; + uint64_t DataSizeMax; + union + { + uint64_t DataSizeIs; + DWORD status; + }; + BYTE Data[0]; + } Ndr64; + struct + { + DWORD Code; + DWORD Padding; + } Error; + + }; +} /*__packed*/ RPC_RESPONSE64; + + +//#define RpcCtx SOCKET +typedef SOCKET RpcCtx; +typedef int RpcStatus; + +#define RPC_INVALID_CTX ((WORD)~0) + +#define RPC_BIND_ACCEPT (0) +#define RPC_BIND_NACK (LE16(2)) +#define RPC_BIND_ACK (LE16(3)) + +#define RPC_SYNTAX_UNSUPPORTED (LE16(2)) +#define RPC_ABSTRACTSYNTAX_UNSUPPORTED (LE16(1)) +#define RPC_NCA_UNK_IF (LE32(0x1c010003)) +#define RPC_NCA_PROTO_ERROR (LE32(0x1c01000b)) + +#define RPC_BTFN_SEC_CONTEXT_MULTIPLEX (LE16(1)) +#define RPC_BTFN_KEEP_ORPHAN (LE16(2)) + +#define INVALID_RPCCTX INVALID_SOCKET +#define closeRpc socketclose + +#define RPC_PT_REQUEST 0 +#define RPC_PT_RESPONSE 2 +#define RPC_PT_FAULT 3 +#define RPC_PT_BIND_REQ 11 +#define RPC_PT_BIND_ACK 12 +#define RPC_PT_ALTERCONTEXT_REQ 14 +#define RPC_PT_ALTERCONTEXT_ACK 15 + +#define RPC_PF_FIRST 1 +#define RPC_PF_LAST 2 +#define RPC_PF_CANCEL_PENDING 4 +#define RPC_PF_RESERVED 8 +#define RPC_PF_MULTIPLEX 16 +#define RPC_PF_NOT_EXEC 32 +#define RPC_PF_MAYBE 64 +#define RPC_PF_OBJECT 128 + + +typedef union _RPC_FLAGS +{ + DWORD mask; + struct { + uint32_t FlagsBTFN : 16; + BOOL HasNDR32 : 1; + BOOL HasNDR64 : 1; + BOOL HasBTFN : 1; + }; +} RPC_FLAGS, *PRPC_FLAGS; + +extern RPC_FLAGS RpcFlags; + +void rpcServer(const SOCKET sock, const DWORD rpcAssocGroup, const char* const ipstr); +RpcStatus rpcBindClient(const RpcCtx sock, const int_fast8_t verbose, PRpcDiag_t rpcDiag); +RpcStatus rpcSendRequest(const RpcCtx socket, const BYTE *const kmsRequest, const size_t requestSize, BYTE **kmsResponse, size_t *const responseSize); + +#endif // __rpc_h diff --git a/vlmcsd/src/shared_globals.c b/vlmcsd/src/shared_globals.c new file mode 100644 index 0000000..204b6cb --- /dev/null +++ b/vlmcsd/src/shared_globals.c @@ -0,0 +1,155 @@ +#ifndef CONFIG +#define CONFIG "config.h" +#endif // CONFIG +#include CONFIG + +#include "shared_globals.h" + +int global_argc, multi_argc = 0; +CARGV global_argv, multi_argv = NULL; +const char *const Version = VERSION; +DWORD VLActivationInterval = 60 * 2; // 2 hours +DWORD VLRenewalInterval = 60 * 24 * 7; // 7 days +int_fast8_t DisconnectImmediately = FALSE; +const char *const cIPv4 = "IPv4"; +const char *const cIPv6 = "IPv6"; + +#ifdef IS_LIBRARY +char ErrorMessage[MESSAGE_BUFFER_SIZE]; +#endif // IS_LIBRARY + +#ifndef NO_STRICT_MODES +uint32_t WhitelistingLevel = 0; +int_fast8_t CheckClientTime = FALSE; +#ifndef NO_CLIENT_LIST +int_fast8_t MaintainClients = FALSE; +int_fast8_t StartEmpty = FALSE; +#endif // NO_CLIENT_LIST +#endif // !NO_STRICT_MODES + +#ifndef USE_MSRPC +int_fast8_t UseMultiplexedRpc = TRUE; +#ifndef SIMPLE_RPC +int_fast8_t UseServerRpcNDR64 = TRUE; +int_fast8_t UseServerRpcBTFN = TRUE; +#endif // !SIMPLE_RPC +int_fast8_t UseClientRpcNDR64 = TRUE; +int_fast8_t UseClientRpcBTFN = TRUE; +#endif // USE_MSRPC + +#ifndef NO_SOCKETS +char *defaultport = (char*)"1688"; +#endif // NO_SOCKETS + +#if !defined(NO_PRIVATE_IP_DETECT) +uint32_t PublicIPProtectionLevel = 0; +#endif + +#if !defined(NO_RANDOM_EPID) || !defined(NO_CL_PIDS) || !defined(NO_INI_FILE) +KmsResponseParam_t* KmsResponseParameters; +#endif // !defined(NO_RANDOM_EPID) || !defined(NO_CL_PIDS) || !defined(NO_INI_FILE) + +#if !defined(NO_SOCKETS) && !defined(NO_SIGHUP) && !defined(_WIN32) +int_fast8_t IsRestarted = FALSE; +#endif // !defined(NO_SOCKETS) && !defined(NO_SIGHUP) && !defined(_WIN32) + +#if !defined(NO_TIMEOUT) && !__minix__ +DWORD ServerTimeout = 30; +#endif // !defined(NO_TIMEOUT) && !__minix__ + +#if !defined(NO_LIMIT) && !defined (NO_SOCKETS) && !__minix__ +#ifdef USE_MSRPC +uint32_t MaxTasks = RPC_C_LISTEN_MAX_CALLS_DEFAULT; +#else // !USE_MSRPC +uint32_t MaxTasks = SEM_VALUE_MAX; +#endif // !USE_MSRPC +#endif // !defined(NO_LIMIT) && !defined (NO_SOCKETS) && !__minix__ + +#ifndef NO_LOG +int_fast8_t LogDateAndTime = TRUE; +char *fn_log = NULL; +int_fast8_t logstdout = 0; +#ifndef NO_VERBOSE_LOG +int_fast8_t logverbose = 0; +#endif // NO_VERBOSE_LOG +#endif // NO_LOG + +#ifndef NO_SOCKETS +int_fast8_t ExitLevel = 0; + +#ifndef _WIN32 +int_fast8_t nodaemon = 0; +#endif // _WIN32 +int_fast8_t InetdMode = 0; +#else +#ifndef _WIN32 +int_fast8_t nodaemon = 1; +#endif // _WIN32 +int_fast8_t InetdMode = 1; +#endif // NO_SOCKETS + +PVlmcsdHeader_t KmsData = NULL; +#ifndef NO_EXTERNAL_DATA +#ifndef DATA_FILE +char *fn_data = NULL; +#else // DATA_FILE +char *fn_data = DATA_FILE; +#endif // DATA_FILE +#ifndef NO_INTERNAL_DATA +int_fast8_t ExplicitDataLoad = FALSE; +#endif // NO_INTERNAL_DATA +#endif // NO_EXTERNAL_DATA +const char *fn_exe = NULL; + +#ifndef NO_RANDOM_EPID +int_fast8_t RandomizationLevel = 1; +uint16_t Lcid = 0; +uint16_t HostBuild = 0; +#endif + +#if !defined(USE_MSRPC) && !defined(SIMPLE_RPC) +uint8_t IsNDR64Defined = FALSE; +#endif // !defined(USE_MSRPC) && !defined(SIMPLE_RPC) + + +#if !defined(NO_SOCKETS) && !defined(USE_MSRPC) +#ifdef SIMPLE_SOCKETS +SOCKET s_server; +#else +SOCKET *SocketList; +int numsockets = 0; +#endif + +#if !defined(NO_LIMIT) && !__minix__ +#ifndef _WIN32 // Posix +sem_t *MaxTaskSemaphore; +#else // _WIN32 +HANDLE MaxTaskSemaphore; +#endif // _WIN32 + +#endif // !defined(NO_LIMIT) && !__minix__ +#endif // !defined(NO_SOCKETS) && !defined(USE_MSRPC) + +#ifdef _NTSERVICE +int_fast8_t IsNTService = TRUE; +int_fast8_t ServiceShutdown = FALSE; +#endif // _NTSERVICE + +#ifndef NO_LOG +#ifdef USE_THREADS +#if !defined(_WIN32) && !defined(__CYGWIN__) +pthread_mutex_t logmutex = PTHREAD_MUTEX_INITIALIZER; +#else +CRITICAL_SECTION logmutex; +#endif // !defined(_WIN32) && !defined(__CYGWIN__) +#endif // USE_THREADS +#endif // NO_LOG + +#if HAVE_FREEBIND +int_fast8_t freebind = FALSE; +#endif // HAVE_FREEBIND + + + + + diff --git a/vlmcsd/src/shared_globals.h b/vlmcsd/src/shared_globals.h new file mode 100644 index 0000000..d5c9e70 --- /dev/null +++ b/vlmcsd/src/shared_globals.h @@ -0,0 +1,216 @@ +#ifndef INCLUDED_SHARED_GLOBALS_H +#define INCLUDED_SHARED_GLOBALS_H + +#ifndef CONFIG +#define CONFIG "config.h" +#endif // CONFIG +#include CONFIG + +#include + +#ifndef _WIN32 +#include +#include +#include +#include +#include +#include +#include +#if !__minix__ +#include +#endif // !__minix__ +#include +#include +#if !defined(NO_LIMIT) && !__minix__ +#include +#endif // !defined(NO_LIMIT) && !__minix__ +#else +//#ifndef USE_MSRPC +#include +#include +//#endif // USE_MSRPC +#include +#endif + +#include +#if !_MSC_VER +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include "types.h" +#include "kms.h" + +//#define MIN_CSVLK 6 +typedef struct +{ + const char* Epid; + const BYTE* HwId; + #ifndef NO_LOG + const char* EpidSource; + uint8_t IsRandom; + #endif // NO_LOG +} KmsResponseParam_t, *PKmsResponseParam_t; + +typedef struct +{ + int8_t HasRpcDiag; + int8_t HasBTFN; + int8_t HasNDR64; +} RpcDiag_t, *PRpcDiag_t; + +#if !defined(NO_LIMIT) && !__minix__ +#ifndef SEM_VALUE_MAX // Android does not define this +#ifdef __ANDROID__ +#define SEM_VALUE_MAX 0x3fffffff +#elif defined(_WIN32) +#define SEM_VALUE_MAX 0x7fffffff +#else +#define SEM_VALUE_MAX 0x7fff // Be cautious if unknown +#endif // __ANDROID__ +#endif // !defined(SEM_VALUE_MAX) +#endif // !defined(NO_LIMIT) && !__minix__ + +extern const char *const Version; + +//Fix for stupid eclipse parser +#ifndef UINT_MAX +#define UINT_MAX 4294967295 +#endif + +#define MESSAGE_BUFFER_SIZE 4096 +#ifdef IS_LIBRARY +extern char ErrorMessage[MESSAGE_BUFFER_SIZE]; +#endif // IS_LIBRARY + +extern int global_argc, multi_argc; +extern CARGV global_argv, multi_argv; +#ifndef _WIN32 +extern int_fast8_t nodaemon; +#endif // _WIN32 +extern DWORD VLActivationInterval; +extern DWORD VLRenewalInterval; +extern int_fast8_t DisconnectImmediately; +#if !defined(NO_RANDOM_EPID) || !defined(NO_CL_PIDS) || !defined(NO_INI_FILE) +extern KmsResponseParam_t* KmsResponseParameters; +#endif // !defined(NO_RANDOM_EPID) || !defined(NO_CL_PIDS) || !defined(NO_INI_FILE) +extern const char *const cIPv4; +extern const char *const cIPv6; +extern int_fast8_t InetdMode; +extern PVlmcsdHeader_t KmsData; +#ifndef NO_EXTERNAL_DATA +extern char* fn_data; +#ifndef NO_INTERNAL_DATA +extern int_fast8_t ExplicitDataLoad; +#endif // NO_INTERNAL_DATA +#endif // NO_EXTERNAL_DATA +extern const char* fn_exe; + +#ifndef NO_STRICT_MODES +extern uint32_t WhitelistingLevel; +extern int_fast8_t CheckClientTime; +#ifndef NO_CLIENT_LIST +extern int_fast8_t MaintainClients; +extern int_fast8_t StartEmpty; +#endif // NO_CLIENT_LIST +#endif // !NO_STRICT_MODES + + +#ifndef USE_MSRPC +extern int_fast8_t UseMultiplexedRpc; +#ifndef SIMPLE_RPC +extern int_fast8_t UseServerRpcNDR64; +extern int_fast8_t UseServerRpcBTFN; +#endif // !SIMPLE_RPC +extern int_fast8_t UseClientRpcNDR64; +extern int_fast8_t UseClientRpcBTFN; +#endif // USE_MSRPC + +#ifndef NO_SOCKETS +extern int_fast8_t ExitLevel; +extern char *defaultport; +#endif // NO_SOCKETS + +#if !defined(NO_PRIVATE_IP_DETECT) +extern uint32_t PublicIPProtectionLevel; +#endif + +#if !defined(NO_SOCKETS) && !defined(NO_SIGHUP) && !defined(_WIN32) +extern int_fast8_t IsRestarted; +#endif // !defined(NO_SOCKETS) && !defined(NO_SIGHUP) && !defined(_WIN32) + +#if !defined(NO_TIMEOUT) && !__minix__ +extern DWORD ServerTimeout; +#endif // !defined(NO_TIMEOUT) && !__minix__ + +#if !defined(NO_LIMIT) && !defined (NO_SOCKETS) && !__minix__ +extern uint32_t MaxTasks; +#endif // !defined(NO_LIMIT) && !defined (NO_SOCKETS) && !__minix__ + +#ifndef NO_LOG +extern int_fast8_t LogDateAndTime; +extern char *fn_log; +extern int_fast8_t logstdout; +#ifndef NO_VERBOSE_LOG +extern int_fast8_t logverbose; +#endif +#endif + +#if !defined(USE_MSRPC) && !defined(SIMPLE_RPC) +extern uint8_t IsNDR64Defined; +#endif + +#ifndef NO_RANDOM_EPID +extern int_fast8_t RandomizationLevel; +extern uint16_t Lcid; +extern uint16_t HostBuild; +#endif + +#if !defined(NO_SOCKETS) && !defined(USE_MSRPC) +#if defined(SIMPLE_SOCKETS) +extern SOCKET s_server; +#else // !defined(SIMPLE_SOCKETS) +extern SOCKET *SocketList; +extern int numsockets; +#endif // !defined(SIMPLE_SOCKETS) + +#if !defined(NO_LIMIT) && !__minix__ + +#ifndef _WIN32 +extern sem_t *MaxTaskSemaphore; +#else // _WIN32 +extern HANDLE MaxTaskSemaphore; +#endif // _WIN32 + +#endif // !defined(NO_LIMIT) && !__minix__ + +#endif // !defined(NO_SOCKETS) && !defined(USE_MSRPC) + +#ifdef _NTSERVICE +extern int_fast8_t IsNTService; +extern int_fast8_t ServiceShutdown; +#endif + +#ifndef NO_LOG +#ifdef USE_THREADS +#if !defined(_WIN32) && !defined(__CYGWIN__) +extern pthread_mutex_t logmutex; +#else +extern CRITICAL_SECTION logmutex; +#endif // _WIN32 +#endif // USE_THREADS +#endif // NO_LOG + +#if HAVE_FREEBIND +extern int_fast8_t freebind; +#endif // HAVE_FREEBIND + + +#endif // INCLUDED_SHARED_GLOBALS_H diff --git a/vlmcsd/src/tap-windows.h b/vlmcsd/src/tap-windows.h new file mode 100644 index 0000000..22b508a --- /dev/null +++ b/vlmcsd/src/tap-windows.h @@ -0,0 +1,77 @@ +/* + * TAP-Windows -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2014 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below). This particular file + * (tap-windows.h) is also licensed using the MIT license (see COPYRIGHT.MIT). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __TAP_WIN_H +#define __TAP_WIN_H + +/* + * ============= + * TAP IOCTLs + * ============= + */ + +#define TAP_WIN_CONTROL_CODE(request,method) \ + CTL_CODE (FILE_DEVICE_UNKNOWN, request, method, FILE_ANY_ACCESS) + +/* Present in 8.1 */ + +#define TAP_WIN_IOCTL_GET_MAC TAP_WIN_CONTROL_CODE (1, METHOD_BUFFERED) +#define TAP_WIN_IOCTL_GET_VERSION TAP_WIN_CONTROL_CODE (2, METHOD_BUFFERED) +#define TAP_WIN_IOCTL_GET_MTU TAP_WIN_CONTROL_CODE (3, METHOD_BUFFERED) +#define TAP_WIN_IOCTL_GET_INFO TAP_WIN_CONTROL_CODE (4, METHOD_BUFFERED) +#define TAP_WIN_IOCTL_CONFIG_POINT_TO_POINT TAP_WIN_CONTROL_CODE (5, METHOD_BUFFERED) +#define TAP_WIN_IOCTL_SET_MEDIA_STATUS TAP_WIN_CONTROL_CODE (6, METHOD_BUFFERED) +#define TAP_WIN_IOCTL_CONFIG_DHCP_MASQ TAP_WIN_CONTROL_CODE (7, METHOD_BUFFERED) +#define TAP_WIN_IOCTL_GET_LOG_LINE TAP_WIN_CONTROL_CODE (8, METHOD_BUFFERED) +#define TAP_WIN_IOCTL_CONFIG_DHCP_SET_OPT TAP_WIN_CONTROL_CODE (9, METHOD_BUFFERED) + +/* Added in 8.2 */ + +/* obsoletes TAP_WIN_IOCTL_CONFIG_POINT_TO_POINT */ +#define TAP_WIN_IOCTL_CONFIG_TUN TAP_WIN_CONTROL_CODE (10, METHOD_BUFFERED) + +/* + * ================= + * Registry keys + * ================= + */ + +#define ADAPTER_KEY "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}" + +#define NETWORK_CONNECTIONS_KEY "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}" + +/* + * ====================== + * Filesystem prefixes + * ====================== + */ + +#define USERMODEDEVICEDIR "\\\\.\\Global\\" +#define SYSDEVICEDIR "\\Device\\" +#define USERDEVICEDIR "\\DosDevices\\Global\\" +#define TAP_WIN_SUFFIX ".tap" + +#endif // __TAP_WIN_H + + diff --git a/vlmcsd/src/types.h b/vlmcsd/src/types.h new file mode 100644 index 0000000..a84997e --- /dev/null +++ b/vlmcsd/src/types.h @@ -0,0 +1,395 @@ +#ifndef __types_h +#define __types_h + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#ifndef _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#endif + +#ifndef CONFIG +#define CONFIG "config.h" +#endif // CONFIG +#include CONFIG + +#if defined(NO_INTERNAL_DATA) && defined(NO_EXTERNAL_DATA) +#error NO_INTERAL_DATA and NO_EXTERNAL_DATA cannot be used together +#endif + +#if defined(_WIN32) + +//#ifndef USE_MSRPC +#include +//#include +//#endif // USE_MSRPC +#endif // defined(_WIN32) + +#define ANDROID_API_LEVEL ANDROID_HELPER1(__ANDROID_API__) +#define ANDROID_HELPER1(s) ANDROID_HELPER2(s) +#define ANDROID_HELPER2(s) #s + +#if !_WIN32 && !__CYGWIN__ + +#if !__minix__ +#include +#endif // !__minix__ + +#define __declspec(x) __attribute__((__visibility__("default"))) +#endif + +#if !defined(EXTERNAL) +#define EXTERNAL dllimport +#endif + +#ifdef __cplusplus +#define EXTERNC extern "C" +#else +#define EXTERNC +#endif + +#include +//#include +#include + +#ifdef __ANDROID__ +#include +#endif // __ANDROID__ + +#ifndef _WIN32 +#include +#include +#endif // _WIN32 + + +#if __linux__ // Some versions of uclibc do not define IP_FREEBIND in the correct header file +#ifndef IP_FREEBIND +#define IP_FREEBIND 15 +#endif // IP_FREEBIND +#endif // __linux__ + +#ifdef NO_EXTERNAL_DATA +#ifndef UNSAFE_DATA_LOAD +#define UNSAFE_DATA_LOAD +#endif // UNSAFE_DATA_LOAD +#endif // NO_EXTERNAL_DATA + +#if (IP_BINDANY || IP_FREEBIND || IPV6_BINDANY || IP_NONLOCALOK) && !defined(NO_FREEBIND) && !defined(USE_MSRPC) && !defined(SIMPLE_SOCKETS) +#define HAVE_FREEBIND 1 +#endif + +#if !defined(NO_GETIFADDRS) && !defined(USE_MSRPC) && !defined(SIMPLE_SOCKETS) && !defined(NO_SOCKETS) && !defined(NO_PRIVATE_IP_DETECT) +#define HAVE_GETIFADDR 1 +#endif + +//#if (__minix__ || defined(NO_SOCKETS)) && !defined(NO_STRICT_MODES) +//#define NO_STRICT_MODES +//#endif // __minix__ && !defined(NO_STRICT_MODES) + +#if (defined(NO_STRICT_MODES) || defined(NO_SOCKETS)) && !defined(NO_CLIENT_LIST) +#define NO_CLIENT_LIST +#endif // defined(NO_STRICT_MODES) || defined(NO_SOCKETS) && !defined(NO_CLIENT_LIST) + +#if !_WIN32 && !__CYGWIN__ + +#if !defined(_POSIX_THREADS) || (!defined(_POSIX_THREAD_PROCESS_SHARED) && !defined(USE_THREADS) && !__ANDROID__) +#ifndef NO_CLIENT_LIST +#define NO_CLIENT_LIST +#endif // !NO_CLIENT_LIST +#endif // !defined(_POSIX_THREADS) || (!defined(_POSIX_THREAD_PROCESS_SHARED) && !defined(USE_THREADS)) + +#if !defined(_POSIX_THREADS) && !defined(NO_LIMIT) +#define NO_LIMIT +#endif // !defined(POSIX_THREADS) && !defined(NO_LIMIT) + +#endif // !_WIN32 && !__CYGWIN__ + +#ifndef alloca +#ifdef __GNUC__ +#define alloca(x) __builtin_alloca(x) +#endif // __GNUC__ +#endif // alloca + + +#ifndef alloca +#ifdef __has_builtin // clang feature test +#if __has_builtin(__builtin_alloca) +#define alloca(x) __builtin_alloca(x) +#endif // __has_builtin(__builtin_alloca) +#endif // __has_builtin +#endif // alloca + +#ifndef alloca +#if !_MSC_VER +#include +#else +#include +//#define alloca _malloca +#endif +//#define alloca _malloca +//#endif // _MSC_VER +#endif // alloca + +#ifndef __packed +#if _MSC_VER +#define __packed +#else // !_MSC_VER +#define __packed __attribute__((packed)) +#endif // !_MSC_VER +#endif + +#ifndef __pure +#if _MSC_VER +#define __pure +#else +#define __pure __attribute__((pure)) +#endif +#endif + +#ifndef __noreturn +#if _MSC_VER +#define __noreturn __declspec(noreturn) +#else +#define __noreturn __attribute__((noreturn)) +#endif +#endif + +#define restrict __restrict + +typedef struct __packed +{ + uint16_t val[0]; +} PACKED16; + +typedef struct __packed +{ + uint32_t val[0]; +} PACKED32; + +typedef struct __packed +{ + uint64_t val[0]; +} PACKED64; + +// Deal with Mingw32-w64 C++ header which defines a _countof that is incompatible with vlmcsd +#define vlmcsd_countof(x) ( sizeof(x) / sizeof(x[0]) ) + +// PATH_MAX is optional in Posix. We use a default of 260 here +#ifndef PATH_MAX +#ifdef _WIN32 +#define PATH_MAX MAX_PATH +#else +#define PATH_MAX 260 +#endif // _WIN32 +#endif // !PATH_MAX + +#if PATH_MAX > 260 +#define VLMCSD_PATH_MAX 260 +#else +#define VLMCSD_PATH_MAX PATH_MAX +#endif + +// Synchronization Objects + +// Mutexes +#ifdef USE_THREADS +#if !defined(_WIN32) && !defined(__CYGWIN__) +#define lock_mutex(x) pthread_mutex_lock(x) +#define unlock_mutex(x) pthread_mutex_unlock(x) +#else +#define lock_mutex(x) EnterCriticalSection(x) +#define unlock_mutex(x) LeaveCriticalSection(x) +#endif +#else // !USE_THREADS +//defines to nothing +#define lock_mutex(x) +#define unlock_mutex(x) +#endif // !USE_THREADS + +// Semaphores +#ifndef _WIN32 +#define semaphore_wait(x) sem_wait(x) +#define semaphore_post(x) sem_post(x) +#else // _WIN32 +#define semaphore_wait(x) WaitForSingleObject(x, INFINITE) +#define semaphore_post(x) ReleaseSemaphore(x, 1, NULL) +#endif // _WIN32 + +// Stupid MingW just uses rand() from msvcrt.dll which uses RAND_MAX of 0x7fff +#if RAND_MAX < 0x7fffffff +#define rand32() ((uint32_t)((rand() << 17) | (rand() << 2) | (rand() & 3))) +#elif RAND_MAX < 0xffffffff +#define rand32(x) ((uint32_t)((rand(x) << 1) | (rand(x) & 1))) +#else +#define rand32(x) (uint32_t)rand(x) +#endif + +#if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(NO_SOCKETS) +#define _NTSERVICE +#else +#ifndef NO_TAP +#define NO_TAP +#endif +#endif + +#if (defined(__CYGWIN__) || defined(_WIN32) || defined(NO_SOCKETS)) && !defined(NO_SIGHUP) +#define NO_SIGHUP +#endif // (defined(__CYGWIN__) || defined(_WIN32) || defined(NO_SOCKETS)) && !defined(NO_SIGHUP) + +#ifdef _WIN32 +#ifndef USE_THREADS +#define USE_THREADS +#endif +#endif + +#if defined(USE_THREADS) +#define _TLS __thread +#else +#define _TLS +#endif + +#define GUID_STRING_LENGTH 36 + +#if defined(_WIN32) +#include +//#include + +typedef char* sockopt_t; +/* Unknown Winsock error codes */ +#define WSAENODEV -1 + +// Map VLMCSD error codes to WSAGetLastError() and GetLastError() codes +// Add more if you need them +#define SOCKET_EADDRINUSE WSAEADDRINUSE +#define SOCKET_ENODEV WSAENODEV +#define SOCKET_EADDRNOTAVAIL WSAEADDRNOTAVAIL +#define SOCKET_EACCES WSAEACCES +#define SOCKET_EINVAL WSAEINVAL +#define SOCKET_ENOTSOCK WSAENOTSOCK +#define SOCKET_EINTR WSAEINTR +#define SOCKET_EINPROGRESS WSAEINPROGRESS +#define SOCKET_ECONNABORTED WSAECONNABORTED +#define SOCKET_EALREADY WSAEALREADY + +#define VLMCSD_EACCES ERROR_ACCESS_DENIED +#define VLMCSD_EINVAL ERROR_INVALID_PARAMETER +#define VLMCSD_ENOMEM ERROR_OUTOFMEMORY +#define VLMCSD_EPERM ERROR_CAN_NOT_COMPLETE + + +#define socket_errno WSAGetLastError() +#define socketclose(x) (closesocket(x)) +#define vlmcsd_strerror(x) win_strerror(x) +#define VLMCSD_SHUT_RD SD_RECEIVE +#define VLMCSD_SHUT_WR SD_SEND +#define VLMCSD_SHUT_RDWR SD_BOTH + +#elif defined(__CYGWIN__) +#include + + +// Resolve conflicts between OpenSSL and MS Crypto API +#ifdef _CRYPTO_OPENSSL +#undef OCSP_RESPONSE +#undef X509_NAME +#endif + +#else +typedef uint32_t DWORD; +typedef uint16_t WORD; +typedef uint8_t BYTE; +typedef uint16_t WCHAR; +typedef int32_t BOOL; +typedef int32_t HRESULT; +#define SUCCEEDED(hr) (((HRESULT)(hr)) >= 0) +#define FAILED(hr) (((HRESULT)(hr)) < 0) +#define S_OK ((HRESULT)0) + + +#define FALSE 0 +#define TRUE !0 + +typedef struct { + DWORD Data1; + WORD Data2; + WORD Data3; + BYTE Data4[8]; +} /*__packed*/ GUID; + +typedef struct { + DWORD dwLowDateTime; + DWORD dwHighDateTime; +} /*__packed*/ FILETIME; + +#endif // defined(__CYGWIN__) + +#ifndef _WIN32 +// Map VLMCSD error codes to POSIX codes +// Add more if you need them +#define SOCKET_EADDRINUSE EADDRINUSE +#define SOCKET_ENODEV ENODEV +#define SOCKET_EADDRNOTAVAIL EADDRNOTAVAIL +#define SOCKET_EACCES EACCES +#define SOCKET_EINVAL EINVAL +#define SOCKET_ENOTSOCK ENOTSOCK +#define SOCKET_EINTR EINTR +#define SOCKET_EINPROGRESS EINPROGRESS +#define SOCKET_ECONNABORTED ECONNABORTED +#define SOCKET_EALREADY EALREADY + +#define VLMCSD_EACCES EACCES +#define VLMCSD_EINVAL EINVAL +#define VLMCSD_EINTR EINTR +#define VLMCSD_ENOMEM ENOMEM +#define VLMCSD_EPERM EPERM + +typedef void* sockopt_t; +#define _countof(x) ( sizeof(x) / sizeof(x[0]) ) +#define SOCKET int +#define INVALID_SOCKET -1 +#define socket_errno errno +#define socketclose(x) (close(x)) +#define vlmcsd_strerror strerror +#define VLMCSD_SHUT_RD SHUT_RD +#define VLMCSD_SHUT_WR SHUT_WR +#define VLMCSD_SHUT_RDWR SHUT_RDWR + +#endif // __MINGW__ +#define INVALID_UID ((uid_t)~0) +#define INVALID_GID ((gid_t)~0) + +#undef IsEqualGUID +#define IsEqualGUID(a, b) ( !memcmp(a, b, sizeof(GUID)) ) + +#if !defined(__stdcall) && !_MSC_VER +#define __stdcall +#endif + +#if !defined(__cdecl) && !_MSC_VER +#define __cdecl +#endif + +typedef const char *const * CARGV; + +typedef struct { + SOCKET socket; + DWORD RpcAssocGroup; +} CLDATA, *const PCLDATA; + + +#ifdef _MSC_VER +#define strcasecmp _stricmp +#define strncasecmp _strnicmp +#define vlmcsd_snprintf _snprintf +#define vlmcsd_vsnprintf _vsnprintf +#define vlmcsd_unlink DeleteFile +#define vlmcsd_strtoll _strtoi64 +#else // !_MSC_VER +#define vlmcsd_snprintf snprintf +#define vlmcsd_vsnprintf vsnprintf +#define vlmcsd_strtoll strtoll +#define vlmcsd_unlink unlink +#endif // !_MSC_VER + +#endif // __types_h diff --git a/vlmcsd/src/vlmcs.c b/vlmcsd/src/vlmcs.c new file mode 100644 index 0000000..e3b6cb7 --- /dev/null +++ b/vlmcsd/src/vlmcs.c @@ -0,0 +1,1443 @@ +#ifndef CONFIG +#define CONFIG "config.h" +#endif // CONFIG +#include CONFIG + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#ifndef _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include "vlmcs.h" +#if _MSC_VER +#include +#endif +#include +#include +#include +#include +#include +#if _MSC_VER +#include "wingetopt.h" +#else +#include +#endif +#include +#include +#ifndef _MSC_VER +#include +#endif +#ifndef _WIN32 +#include +#include +#else // _WIN32 +#endif // _WIN32 +#include "endian.h" +#include "shared_globals.h" +#include "output.h" +#ifndef USE_MSRPC +#include "network.h" +#include "rpc.h" +#else // USE_MSRPC +#include "msrpc-client.h" +#endif // USE_MSRPC +#include "kms.h" +#include "helpers.h" +#include "dns_srv.h" + + +#define VLMCS_OPTION_GRAB_INI 1 +#define VLMCS_OPTION_NO_GRAB_INI 2 + +#ifndef IS_LIBRARY + +// Function Prototypes +static void CreateRequestBase(REQUEST *Request); + + +// KMS Parameters +#ifndef NO_VERBOSE_LOG +static int_fast8_t verbose = FALSE; +#endif + +static int_fast8_t VMInfo = FALSE; +static int_fast8_t dnsnames = TRUE; +static int FixedRequests = 0; +static DWORD LicenseStatus = 0x02; +static const char *CMID = NULL; +static const char *CMID_prev = NULL; +static const char *WorkstationName = NULL; +static int BindingExpiration = 43200; //30 days +static const char *RemoteAddr; +static int_fast8_t ReconnectForEachRequest = FALSE; +#ifndef USE_MSRPC +static int AddressFamily = AF_UNSPEC; +#else +static int AddressFamily = 0; +#endif // USE_MSRPC +static int_fast8_t incompatibleOptions = 0; +static const char* fn_ini_client = NULL; +//static int_fast16_t kmsVersionMinor = 0; +//static const char* ePidGroup[] = { "Windows", "Office2010", "Office2013", "Office2016" }; +static int32_t ActiveProductIndex = 0; +static int32_t NCountPolicy = 0; +static GUID AppGuid, KmsGuid, SkuGuid; +static uint16_t MinorVersion = 0; +static uint16_t MajorVersion; + +#ifndef NO_DNS +static int_fast8_t NoSrvRecordPriority = FALSE; +#endif // NO_DNS + + +//typedef char iniFileEpidLines[4][256]; + +typedef struct +{ + const char* first[16]; + const char* second[16]; + const char* tld[22]; +} DnsNames; + + +// Some names for the DNS name random generator +static DnsNames ClientDnsNames = +{ + { "www", "ftp", "kms", "hack-me", "smtp", "ns1", "mx1", "ns1", "pop3", "imap", "mail", "dns", "headquarter", "we-love", "_vlmcs._tcp", "ceo-laptop" }, + { ".microsoft", ".apple", ".amazon", ".samsung", ".adobe", ".google", ".yahoo", ".facebook", ".ubuntu", ".oracle", ".borland", ".htc", ".acer", ".windows", ".linux", ".sony" }, + { ".com", ".net", ".org", ".cn", ".co.uk", ".de", ".com.tw", ".us", ".fr", ".it", ".me", ".info", ".biz", ".co.jp", ".ua", ".at", ".es", ".pro", ".by", ".ru", ".pl", ".kr" } +}; + +// Request Count Control Variables +static int RequestsToGo = 1; +static BOOL firstRequestSent = FALSE; + + +static void string2UuidOrExit(const char *const restrict input, GUID *const restrict guid) +{ + if (strlen(input) != GUID_STRING_LENGTH || !string2UuidLE(input, guid)) + { + errorout("Fatal: Command line contains an invalid GUID.\n"); + exit(VLMCSD_EINVAL); + } +} + + +#ifndef NO_HELP + +__noreturn static void clientUsage(const char* const programName) +{ + errorout( + "vlmcs %s \n\n" +# ifndef NO_DNS + "Usage: %s [options] [ [:] | . | - ] [options]\n\n" +# else // DNS + "Usage: %s [options] [[:]] [options]\n\n" +# endif // DNS + + "Options:\n\n" + +# ifndef NO_VERBOSE_LOG + " -v Be verbose\n" +# endif + " -l \n" + " -4 Force V4 protocol\n" + " -5 Force V5 protocol\n" + " -6 Force V6 protocol\n" +# ifndef USE_MSRPC + " -i Use IP protocol (4 or 6)\n" +# endif // USE_MSRPC +# ifndef NO_EXTERNAL_DATA + " -j Load external KMS data file \n" +# endif // NO_EXTERNAL_DATA + " -e Show some valid examples\n" + " -x Show valid Apps\n" + " -d no DNS names, use Netbios names (no effect if -w is used)\n" + " -V show version information and exit\n\n" + + "Advanced options:\n\n" + + " -a Use custom Application GUID\n" + " -s Use custom Activation Configuration GUID\n" + " -k Use custom KMS GUID\n" + " -c Use custom Client GUID. Default: Use random\n" + " -o Use custom Prevoius Client GUID. Default: ZeroGUID\n" + " -K Use a specific (possibly invalid) protocol version\n" + " -w Use custom workstation name. Default: Use random\n" + " -r Fake required clients\n" + " -n Fixed # of requests (Default: Enough to charge)\n" + " -m Pretend to be a virtual machine\n" + " -G Get ePID/HwId data and write to . Can't be used with -l, -4, -5, -6, -a, -s, -k, -r and -n\n" +# ifndef USE_MSRPC + " -T Use a new TCP connection for each request.\n" + " -N <0|1> disable or enable NDR64. Default: 1\n" + " -B <0|1> disable or enable RPC bind time feature negotiation. Default: 1\n" +# endif // USE_MSRPC + " -t Use specfic license status (0 <= T <= 6)\n" + " -g Use a specfic binding expiration time in minutes. Default 43200\n" +# ifndef NO_DNS + " -P Ignore priority and weight in DNS SRV records\n" +# endif // NO_DNS +# ifndef USE_MSRPC + " -p Don't use multiplexed RPC bind\n" +# endif // USE_MSRPC + "\n" + + ":\t\tTCP port name of the KMS to use. Default 1688.\n" + ":\t\thost name of the KMS to use. Default 127.0.0.1\n" +# ifndef NO_DNS + ".:\tfind KMS server in via DNS\n" +# endif // NO_DNS + ":\t\t(Type %s -x to see a list of valid apps)\n\n", + Version, programName, programName + ); + + exit(VLMCSD_EINVAL); +} + +__pure static int getLineWidth(void) +{ +#ifdef TERMINAL_FIXED_WIDTH // For Toolchains that to not have winsize + return TERMINAL_FIXED_WIDTH; +#else // Can determine width of terminal +#ifndef _WIN32 + + struct winsize w; + + if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w)) + { + return 80; // Return this if stdout is not a tty + } + + return w.ws_col; + +#else // _WIN32 + + CONSOLE_SCREEN_BUFFER_INFO csbiInfo; + HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); + + if (!GetConsoleScreenBufferInfo(hStdout, &csbiInfo)) + { + return 80; // Return this if stdout is not a Console + } + + return csbiInfo.srWindow.Right - csbiInfo.srWindow.Left; + +#endif // WIN32 + +#endif // Can determine width of terminal + +} + +__noreturn static void showProducts(PRINTFUNC p) +{ + int cols = getLineWidth(); + int itemsPerLine; + uint8_t i; + int32_t index; + + + uint_fast8_t longestString = 0; + int32_t k, items = KmsData->SkuItemCount; + + p("You may use these product names or numbers:\n\n"); + + for (index = 0; index < KmsData->SkuItemCount; index++) + { + uint_fast8_t len = (uint_fast8_t)strlen(KmsData->SkuItemList[index].Name); + if (len > longestString) longestString = len; + } + + itemsPerLine = cols / (longestString + 10); + if (!itemsPerLine) itemsPerLine = 1; + uint8_t lines = items / itemsPerLine; + if (items % itemsPerLine) lines++; + + for (i = 0; i < lines; i++) + { + for (k = 0; k < itemsPerLine; k++) + { + uint8_t j; + index = k * lines + i; + + if (index >= items) break; + + p("%3u = %s", index + 1, KmsData->SkuItemList[index].Name); + + for (j = 0; j < longestString + 4 - strlen(KmsData->SkuItemList[index].Name); j++) + { + p(" "); + } + } + + p("\n"); + } + + p("\n"); + + exit(0); +} + +__noreturn static void examples(const char* const programName) +{ + printf( + "\nRequest activation for Office 2013 using V4 protocol from 192.168.1.5:1688\n" + "\t%s -l \"Office 2013 Professional\" -4 192.168.1.5\n" + "\t%s -l \"Office 2013 Professional\" -4 192.168.1.5:1688\n\n" + + "Request activation for Windows Server 2012 using V4 protocol from localhost:1688\n" + "\t%s -4 -l \"Windows Server 2012\" -k 8665cb71-468c-4aa3-a337-cb9bc9d5eaac\n" + "\t%s -4 -l \"Windows Server 2012\"\n" + "\t%s -4 -l \"Windows Server 2012\" [::1]:1688\n" + "\t%s -4 -l \"Windows Server 2012\" 127.0.0.2:1688\n\n" + + "Send 100,000 requests to localhost:1688\n" + "\t%s -n 100000\n\n" + + "Request Activation for Windows 8 from 10.0.0.1:4711 and pretend to be Steve Ballmer\n" + "\t%s -l \"Windows 8 Professional\" -w steveb1.redmond.microsoft.com 10.0.0.1:4711\n\n", + programName, programName, programName, programName, programName, programName, programName, programName + ); + + exit(0); +} + +#else // NO_HELP + + +__noreturn static void clientUsage(const char* const programName) +{ + errorout("Incorrect parameter specified.\n"); + exit(VLMCSD_EINVAL); +} + + +#endif // NO_HELP + + +static void parseProtocolVersion(void) +{ + char *endptr_major, *endptr_minor, *period = strchr(optarg, (int)'.'); + + if (!period) + { + errorout("Fatal: Protocol version must be in the format #.#\n"); + exit(VLMCSD_EINVAL); + } + + long major = strtol(optarg, &endptr_major, 10); + long minor = strtol(period + 1, &endptr_minor, 10); + + if ((*endptr_major && *endptr_major != '.') || *endptr_minor || *optarg == '.' || !period[1]) + { + errorout("Fatal: Protocol version must be in the format #.#\n"); + exit(VLMCSD_EINVAL); + } + + if (major < 0 || major > 0xffff || minor < 0 || minor > 0xffff) + { + errorout("Fatal: Major and minor protocol version number must be between 0 and 65535\n"); + exit(VLMCSD_EINVAL); + } + + MajorVersion = (uint16_t)major; + MinorVersion = (uint16_t)minor; +} + + +static int32_t findLicensePackByName(const char* const name) +{ + int32_t i; + + for (i = KmsData->SkuItemCount - 1; i >= 0; i--) + { + if (!strcasecmp(name, KmsData->SkuItemList[i].Name)) return i; + } + + return i; +} + +static const char* const client_optstring = "+N:B:i:j:l:a:s:k:c:w:r:n:t:g:G:o:K:pPTv456mexdV"; + + +//We handle only "-j". Many other options do not run without a loaded database +static void parseCommandLinePass0(const int argc, CARGV argv) +{ + int o; + optReset(); + + for (opterr = 0; (o = getopt(argc, (char* const*)argv, client_optstring)) > 0; ) switch (o) + { +# ifndef NO_EXTERNAL_DATA + case 'j': // Set "License Pack" and protocol version (e.g. Windows8, Office2013v5, ...) + fn_data = optarg; +# ifndef NO_INTERNAL_DATA + ExplicitDataLoad = TRUE; +# endif // NO_INTERNAL_DATA + break; +# endif // NO_EXTERNAL_DATA + + default: + break; + } +} + +//First pass. We handle only "-l". Since -a -k -s -4 -5 and -6 are exceptions to -l, we process -l first +static void parseCommandLinePass1(const int argc, CARGV argv) +{ + int o; + optReset(); + + for (opterr = 0; (o = getopt(argc, (char* const*)argv, client_optstring)) > 0; ) switch (o) + { + case 'l': // Set "License Pack" and protocol version (e.g. Windows8, Office2013v5, ...) + if (stringToInt(optarg, 1, KmsData->SkuItemCount, (unsigned int*)&ActiveProductIndex)) + { + ActiveProductIndex--; + break; + } + + ActiveProductIndex = findLicensePackByName(optarg); + if (ActiveProductIndex < 0) + { + errorout("Invalid client application. \"%s\" is not valid for -l.\n\n", optarg); +#ifndef NO_HELP + showProducts(&errorout); +#endif // !NO_HELP + } + + break; + + default: + break; + } + + int32_t kmsIndex = KmsData->SkuItemList[ActiveProductIndex].KmsIndex; + int32_t appIndex = KmsData->SkuItemList[ActiveProductIndex].AppIndex; + + MajorVersion = (uint16_t)KmsData->SkuItemList[ActiveProductIndex].ProtocolVersion; + NCountPolicy = (uint32_t)KmsData->SkuItemList[ActiveProductIndex].NCountPolicy; + memcpy(&SkuGuid, &KmsData->SkuItemList[ActiveProductIndex].Guid, sizeof(GUID)); + memcpy(&KmsGuid, &KmsData->KmsItemList[kmsIndex].Guid, sizeof(GUID)); + memcpy(&AppGuid, &KmsData->AppItemList[appIndex].Guid, sizeof(GUID)); +} + + +// Second Pass. Handle all options except "-l" +static void parseCommandLinePass2(const char *const programName, const int argc, CARGV argv) +{ + int o; + optReset(); + + for (opterr = 0; (o = getopt(argc, (char* const*)argv, client_optstring)) > 0; ) switch (o) + { +#ifndef NO_HELP + + case 'j': + break; + + case 'e': // Show examples + + examples(programName); + + case 'x': // Show Apps + + showProducts(&printf); + +#endif // NO_HELP + +# ifndef NO_DNS + + case 'P': + + NoSrvRecordPriority = TRUE; + break; + +# endif // NO_DNS + + case 'G': + + incompatibleOptions |= VLMCS_OPTION_GRAB_INI; + fn_ini_client = optarg; + break; + +# ifndef USE_MSRPC + + case 'N': + if (!getArgumentBool(&UseClientRpcNDR64, optarg)) clientUsage(programName); + break; + + case 'B': + if (!getArgumentBool(&UseClientRpcBTFN, optarg)) clientUsage(programName); + break; + + case 'i': + + switch (getOptionArgumentInt((char)o, 4, 6)) + { + case 4: + AddressFamily = AF_INET; + break; + case 6: + AddressFamily = AF_INET6; + break; + default: + errorout("IPv5 does not exist.\n"); + exit(VLMCSD_EINVAL); + } + + break; + + case 'p': // Multiplexed RPC + + UseMultiplexedRpc = FALSE; + break; + +# endif // USE_MSRPC + + case 'n': // Fixed number of Requests (regardless, whether they are required) + + incompatibleOptions |= VLMCS_OPTION_NO_GRAB_INI; + FixedRequests = getOptionArgumentInt((char)o, 1, INT_MAX); + break; + + case 'r': // Fake minimum required client count + + incompatibleOptions |= VLMCS_OPTION_NO_GRAB_INI; + NCountPolicy = getOptionArgumentInt((char)o, 0, INT_MAX); + break; + + case 'c': // use a specific client GUID + + // If using a constant Client ID, send only one request unless /N= explicitly specified + if (!FixedRequests) FixedRequests = 1; + + CMID = optarg; + break; + + case 'o': // use a specific previous client GUID + + CMID_prev = optarg; + break; + + case 'a': // Set specific App Id + + incompatibleOptions |= VLMCS_OPTION_NO_GRAB_INI; + string2UuidOrExit(optarg, &AppGuid); + break; + + case 'g': // Set custom "grace" time in minutes (default 30 days) + + BindingExpiration = getOptionArgumentInt((char)o, 0, INT_MAX); + break; + + case 's': // Set specfic SKU ID + + incompatibleOptions |= VLMCS_OPTION_NO_GRAB_INI; + string2UuidOrExit(optarg, &SkuGuid); + break; + + case 'k': // Set specific KMS ID + + incompatibleOptions |= VLMCS_OPTION_NO_GRAB_INI; + string2UuidOrExit(optarg, &KmsGuid); + break; + + case '4': // Force V4 protocol + case '5': // Force V5 protocol + case '6': // Force V5 protocol + + incompatibleOptions |= VLMCS_OPTION_NO_GRAB_INI; + MajorVersion = o - 0x30; + MinorVersion = 0; + break; + + case 'K': // Use specific protocol (may be invalid) + + parseProtocolVersion(); + break; + + case 'd': // Don't use DNS names + + dnsnames = FALSE; + break; + +# ifndef NO_VERBOSE_LOG + + case 'v': // Be verbose + + verbose = TRUE; + break; + +# endif // NO_VERBOSE_LOG + + case 'm': // Pretend to be a virtual machine + + VMInfo = TRUE; + break; + + case 'w': // WorkstationName (max. 63 chars) + + WorkstationName = optarg; + + if (strlen(WorkstationName) > 63) + { + errorout("\007WARNING! Truncating workstation name to 63 characters (%s).\n", WorkstationName); + } + + break; + + case 't': + + LicenseStatus = getOptionArgumentInt((char)o, 0, 0x7fffffff); + if ((unsigned int)LicenseStatus > 6) errorout("Warning: Correct license status is 0 <= license status <= 6.\n"); + break; + +# ifndef USE_MSRPC + + case 'T': + + ReconnectForEachRequest = TRUE; + break; + +# endif // USE_MSRPC + + case 'l': + incompatibleOptions |= VLMCS_OPTION_NO_GRAB_INI; + break; + +# ifndef NO_VERSION_INFORMATION + + case 'V': +# if defined(__s390__) && !defined(__zarch__) && !defined(__s390x__) + printf("vlmcs %s %i-bit\n", Version, sizeof(void*) == 4 ? 31 : (int)sizeof(void*) << 3); +# else + printf("vlmcs %s %i-bit\n", Version, (int)sizeof(void*) << 3); +# endif // defined(__s390__) && !defined(__zarch__) && !defined(__s390x__) + printPlatform(); + printCommonFlags(); + printClientFlags(); + exit(0); + +# endif // NO_VERSION_INFORMATION + + default: + clientUsage(programName); + } + if ((incompatibleOptions & (VLMCS_OPTION_NO_GRAB_INI | VLMCS_OPTION_GRAB_INI)) == (VLMCS_OPTION_NO_GRAB_INI | VLMCS_OPTION_GRAB_INI)) + clientUsage(programName); +} + + +///* +// * Compares 2 GUIDs where one is host-endian and the other is little-endian (network byte order) +// */ +//int_fast8_t IsEqualGuidLEHE(const GUID* const guid1, const GUID* const guid2) +//{ +// GUID tempGuid; +// LEGUID(&tempGuid, guid2); +// return IsEqualGUID(guid1, &tempGuid); +//} + + +#ifndef USE_MSRPC +static void checkRpcLevel(const REQUEST* request, RESPONSE* response) +{ + if (!RpcFlags.HasNDR32) + errorout("\nWARNING: Server's RPC protocol does not support NDR32.\n"); + + if (UseClientRpcBTFN && UseClientRpcNDR64 && RpcFlags.HasNDR64 && !RpcFlags.HasBTFN) + errorout("\nWARNING: Server's RPC protocol has NDR64 but no BTFN.\n"); + + //# ifndef NO_BASIC_PRODUCT_LIST + // if (!IsEqualGuidLEHE(&request->KMSID, &ProductList[15].guid) && UseClientRpcBTFN && !RpcFlags.HasBTFN) + // errorout("\nWARNING: A server with pre-Vista RPC activated a product other than Office 2010.\n"); + //# endif // NO_BASIC_PRODUCT_LIST +} +#endif // USE_MSRPC + + +static void displayResponse(const RESPONSE_RESULT result, const REQUEST* request, RESPONSE* response, BYTE *hwid) +{ + fflush(stdout); + + if (!result.RpcOK) errorout("\n\007ERROR: Non-Zero RPC result code.\n"); + if (!result.DecryptSuccess) errorout("\n\007ERROR: Decryption of V5/V6 response failed.\n"); + if (!result.IVsOK) errorout("\n\007ERROR: AES CBC initialization vectors (IVs) of request and response do not match.\n"); + if (!result.PidLengthOK) errorout("\n\007ERROR: The length of the PID is not valid.\n"); + if (!result.HashOK) errorout("\n\007ERROR: Computed hash does not match hash in response.\n"); + if (!result.ClientMachineIDOK) errorout("\n\007ERROR: Client machine GUIDs of request and response do not match.\n"); + if (!result.TimeStampOK) errorout("\n\007ERROR: Time stamps of request and response do not match.\n"); + if (!result.VersionOK) errorout("\n\007ERROR: Protocol versions of request and response do not match.\n"); + if (!result.HmacSha256OK) errorout("\n\007ERROR: Keyed-Hash Message Authentication Code (HMAC) is incorrect.\n"); + if (!result.IVnotSuspicious) errorout("\nWARNING: The KMS server is an emulator because the response uses an IV following KMSv5 rules in KMSv6 protocol.\n"); + + if (result.effectiveResponseSize != result.correctResponseSize) + { + errorout("\n\007WARNING: Size of RPC payload (KMS Message) should be %u but is %u.", result.correctResponseSize, result.effectiveResponseSize); + } + +# ifndef USE_MSRPC + checkRpcLevel(request, response); +# endif // USE_MSRPC + + if (!result.DecryptSuccess) return; // Makes no sense to display anything + + char ePID[3 * PID_BUFFER_SIZE]; + if (!ucs2_to_utf8(response->KmsPID, ePID, PID_BUFFER_SIZE, 3 * PID_BUFFER_SIZE)) + { + memset(ePID + 3 * PID_BUFFER_SIZE - 3, 0, 3); + } + + // Read KMSPID from Response +# ifndef NO_VERBOSE_LOG + if (!verbose) +# endif // NO_VERBOSE_LOG + { + printf(" -> %s", ePID); + + if (LE16(response->MajorVer) > 5) + { +# ifndef _WIN32 + printf(" (%016llX)", (unsigned long long)BE64(*(uint64_t*)hwid)); +# else // _WIN32 + printf(" (%016I64X)", (unsigned long long)BE64(*(uint64_t*)hwid)); +# endif // _WIN32 + } + + printf("\n"); + } +# ifndef NO_VERBOSE_LOG + else + { + printf( + "\n\nResponse from KMS server\n========================\n\n" + "Size of KMS Response : %u (0x%x)\n", result.effectiveResponseSize, result.effectiveResponseSize + ); + + logResponseVerbose(ePID, hwid, response, &printf); + printf("\n"); + } +# endif // NO_VERBOSE_LOG +} + + +static void connectRpc(RpcCtx *s) +{ +# ifdef NO_DNS + + RpcDiag_t rpcDiag; + + *s = connectToAddress(RemoteAddr, AddressFamily, FALSE); + if (*s == INVALID_RPCCTX) + { + errorout("Fatal: Could not connect to %s\n", RemoteAddr); + exit(SOCKET_ECONNABORTED); + } + + if (verbose) + printf("\nPerforming RPC bind ...\n"); + + RpcStatus status; + if ((status = rpcBindClient(*s, verbose, &rpcDiag))) + { + errorout("Fatal: Could not bind RPC\n"); + exit(status); + } + + if (verbose) printf("... successful\n"); + +# else // DNS + + static kms_server_dns_ptr* serverlist = NULL; + static int numServers = 0; + //static int_fast8_t ServerListAlreadyPrinted = FALSE; + int i; + + if (!strcmp(RemoteAddr, "-") || *RemoteAddr == '.') // Get KMS server via DNS SRV record + { + if (!serverlist) + numServers = getKmsServerList(&serverlist, RemoteAddr); + + if (numServers < 1) + { + errorout("Fatal: No KMS servers found\n"); + exit(SOCKET_ECONNABORTED); + } + + if (!NoSrvRecordPriority) sortSrvRecords(serverlist, numServers); + +# ifndef NO_VERBOSE_LOG + if (verbose /*&& !ServerListAlreadyPrinted*/) + { + for (i = 0; i < numServers; i++) + { + printf( + "Found %-40s (priority: %hu, weight: %hu, randomized weight: %i)\n", + serverlist[i]->serverName, + serverlist[i]->priority, serverlist[i]->weight, + NoSrvRecordPriority ? 0 : serverlist[i]->random_weight + ); + } + + printf("\n"); + //ServerListAlreadyPrinted = TRUE; + } +# endif // NO_VERBOSE_LOG + } + else // Just use the server supplied on the command line + { + if (!serverlist) + { + serverlist = (kms_server_dns_ptr*)vlmcsd_malloc(sizeof(kms_server_dns_ptr)); + *serverlist = (kms_server_dns_ptr)vlmcsd_malloc(sizeof(kms_server_dns_t)); + + numServers = 1; + strncpy((*serverlist)->serverName, RemoteAddr, sizeof((*serverlist)->serverName)); + } + } + + for (i = 0; i < numServers; i++) + { + *s = connectToAddress(serverlist[i]->serverName, AddressFamily, (*RemoteAddr == '.' || *RemoteAddr == '-')); + + if (*s == INVALID_RPCCTX) continue; + RpcDiag_t rpcDiag; + +# ifndef NO_VERBOSE_LOG + if (verbose) printf("\nPerforming RPC bind ...\n"); + + if (rpcBindClient(*s, verbose, &rpcDiag)) +# else + if (rpcBindClient(*s, FALSE, &rpcDiag)) +# endif + { + errorout("Warning: Could not bind RPC\n"); + continue; + } + +# ifndef NO_VERBOSE_LOG + if (verbose) printf("... successful\n"); +# endif + + return; + } + + errorout("Fatal: Could not connect to any KMS server\n"); + exit(SOCKET_ECONNABORTED); + +# endif // DNS +} + +#endif // IS_LIBRARY + +int SendActivationRequest(const RpcCtx sock, RESPONSE *baseResponse, REQUEST *baseRequest, RESPONSE_RESULT *result, BYTE *const hwid) +{ + size_t requestSize, responseSize; + BYTE *request, *response; + int status; + + result->mask = 0; + + if (LE16(baseRequest->MajorVer) < 5) + request = CreateRequestV4(&requestSize, baseRequest); + else + request = CreateRequestV6(&requestSize, baseRequest); + + if (!((status = rpcSendRequest(sock, request, requestSize, &response, &responseSize)))) + { + if (LE16(((RESPONSE*)(response))->MajorVer) == 4) + { + RESPONSE_V4 response_v4; + *result = DecryptResponseV4(&response_v4, (const int)responseSize, response, request); + memcpy(baseResponse, &response_v4.ResponseBase, sizeof(RESPONSE)); + } + else + { + RESPONSE_V6 response_v6; + *result = DecryptResponseV6(&response_v6, (int)responseSize, response, request, hwid); + memcpy(baseResponse, &response_v6.ResponseBase, sizeof(RESPONSE)); + } + + result->RpcOK = TRUE; + } + + if (response) free(response); + free(request); + return status; +} + +#ifndef IS_LIBRARY + +static int sendRequest(RpcCtx *const s, REQUEST *const request, RESPONSE *const response, hwid_t hwid, RESPONSE_RESULT *const result) +{ + CreateRequestBase(request); + + if (*s == INVALID_RPCCTX) + connectRpc(s); + else + { + // Check for lame KMS emulators that close the socket after each request + int_fast8_t disconnected = isDisconnected(*s); + + if (disconnected) + errorout("\nWarning: Server closed RPC connection (probably non-multitasked KMS emulator)\n"); + + if (ReconnectForEachRequest || disconnected) + { + closeRpc(*s); + connectRpc(s); + } + } + + printf("Sending activation request (KMS V%u) ", MajorVersion); + fflush(stdout); + + return SendActivationRequest(*s, response, request, result, hwid); +} + + +static void displayRequestError(RpcCtx *const s, const int status, const int currentRequest, const int totalRequests) +{ + errorout("\nError 0x%08X while sending request %u of %u\n", status, currentRequest, RequestsToGo + totalRequests); + + switch (status) + { + case 0xC004F042: // not licensed + errorout("The KMS server has declined to activate the requested product\n"); + break; + + case 0x8007000D: // e.g. v6 protocol on a v5 server + errorout("The KMS host you are using is unable to handle your product. It only supports legacy versions\n"); + break; + + case 0xC004F06C: + errorout("The time stamp differs too much from the KMS server time\n"); + break; + + case 0xC004D104: + errorout("The security processor reported that invalid data was used\n"); + break; + + case 1: + errorout("An RPC protocol error has occured\n"); + closeRpc(*s); + connectRpc(s); + break; + + default: +# if _WIN32 + errorout("%s\n", win_strerror(status)); +# endif // _WIN32 + break; + } +} + +static void newIniBackupFile(const char* const restrict fname) +{ + FILE *restrict f = fopen(fname, "wb"); + + if (!f) + { + int error = errno; + errorout("Fatal: Cannot create %s: %s\n", fname, strerror(error)); + exit(error); + } + + if (fclose(f)) + { + int error = errno; + errorout("Fatal: Cannot write to %s: %s\n", fname, strerror(error)); + vlmcsd_unlink(fname); + exit(error); + } +} + + +static void updateIniFile(char*** restrict lines) +{ + int_fast8_t* lineWritten = (int_fast8_t*)malloc(KmsData->CsvlkCount * sizeof(int_fast8_t)); +# if !_MSC_VER + struct stat statbuf; +# endif + uint_fast8_t i; + int_fast8_t iniFileExistedBefore = TRUE; + unsigned int lineNumber; + + memset(lineWritten, FALSE, KmsData->CsvlkCount * sizeof(int_fast8_t)); + + char* restrict fn_bak = (char*)vlmcsd_malloc(strlen(fn_ini_client) + 2); + + strcpy(fn_bak, fn_ini_client); + strcat(fn_bak, "~"); + +# if _MSC_VER + if (!PathFileExists(fn_ini_client)) + { + iniFileExistedBefore = FALSE; + newIniBackupFile(fn_bak); + } +# else + if (stat(fn_ini_client, &statbuf)) + { + if (errno != ENOENT) + { + int error = errno; + errorout("Fatal: %s: %s\n", fn_ini_client, strerror(error)); + exit(error); + } + else + { + iniFileExistedBefore = FALSE; + newIniBackupFile(fn_bak); + } + } +# endif + else + { + vlmcsd_unlink(fn_bak); // Required for Windows. Most Unix systems don't need it. + if (rename(fn_ini_client, fn_bak)) + { + const int error = errno; + errorout("Fatal: Cannot create %s: %s\n", fn_bak, strerror(error)); + exit(error); + } + } + + printf("\n%s file %s\n", iniFileExistedBefore ? "Updating" : "Creating", fn_ini_client); + + FILE *restrict in, *restrict out; + + in = fopen(fn_bak, "rb"); + + if (!in) + { + const int error = errno; + errorout("Fatal: Cannot open %s: %s\n", fn_bak, strerror(error)); + exit(error); + } + + out = fopen(fn_ini_client, "wb"); + + if (!out) + { + const int error = errno; + errorout("Fatal: Cannot create %s: %s\n", fn_ini_client, strerror(error)); + exit(error); + } + + char sourceLine[256]; + + for (lineNumber = 1; fgets(sourceLine, sizeof(sourceLine), in); lineNumber++) + { + for (i = 0; i < KmsData->CsvlkCount; i++) + { + if (*(*lines)[i] && !strncasecmp(sourceLine, (*lines)[i], strlen(getNextString((KmsData->CsvlkData[i].EPid))))) + { + if (lineWritten[i]) break; + + fprintf(out, "%s", (*lines)[i]); + printf("line %2i: %s", lineNumber, (*lines)[i]); + lineWritten[i] = TRUE; + break; + } + } + + if (i >= KmsData->CsvlkCount) + { + fprintf(out, "%s", sourceLine); + } + } + + if (ferror(in)) + { + int error = errno; + errorout("Fatal: Cannot read from %s: %s\n", fn_bak, strerror(error)); + exit(error); + } + + fclose(in); + + for (i = 0; i < KmsData->CsvlkCount; i++) + { + if (!lineWritten[i] && *(*lines)[i]) + { + fprintf(out, "%s", (*lines)[i]); + printf("line %2i: %s", lineNumber + i, (*lines)[i]); + } + } + + if (fclose(out)) + { + const int error = errno; + errorout("Fatal: Cannot write to %s: %s\n", fn_ini_client, strerror(error)); + exit(error); + } + + if (!iniFileExistedBefore) vlmcsd_unlink(fn_bak); + + free(fn_bak); +} + + +static void grabServerData() +{ + RpcCtx s = INVALID_RPCCTX; + WORD MajorVer = 6; + int32_t i; + int32_t j; + + char** lines = (char**)vlmcsd_malloc(KmsData->CsvlkCount * sizeof(char*)); + GUID* kmsGuids = (GUID*)vlmcsd_malloc(KmsData->CsvlkCount * sizeof(GUID)); + + for (i = 0; i < KmsData->CsvlkCount; i++) + { + lines[i] = (char*)vlmcsd_malloc(256); + *lines[i] = 0; + + for (j = 0; j < KmsData->KmsItemCount; j++) + { + if (KmsData->KmsItemList[j].EPidIndex == i) + { + kmsGuids[i] = KmsData->KmsItemList[j].Guid; + break; + } + } + } + + RESPONSE response; + RESPONSE_RESULT result; + REQUEST request; + hwid_t hwid; + int status; + size_t len; + + for (i = 0; i < KmsData->CsvlkCount && MajorVer > 3; i++) + { + const int32_t kmsIndex = getProductIndex(&kmsGuids[i], KmsData->KmsItemList, KmsData->KmsItemCount, NULL, NULL); + + if (kmsIndex < 0) + { + errorout("Warning: KMS GUID not in database.\n"); + continue; + } + + ActiveProductIndex = ~0; + + for (j = KmsData->SkuItemCount - 1; j >= 0; j--) + { + if (KmsData->SkuItemList[j].KmsIndex == kmsIndex) + { + ActiveProductIndex = j; + break; + } + } + + if (ActiveProductIndex == ~0) + { + errorout("Warning: KMS GUID not in database.\n"); + continue; + } + + const int32_t appIndex = KmsData->SkuItemList[ActiveProductIndex].AppIndex; + + NCountPolicy = (uint32_t)KmsData->SkuItemList[ActiveProductIndex].NCountPolicy; + memcpy(&SkuGuid, &KmsData->SkuItemList[ActiveProductIndex].Guid, sizeof(GUID)); + memcpy(&KmsGuid, &KmsData->KmsItemList[kmsIndex].Guid, sizeof(GUID)); + memcpy(&AppGuid, &KmsData->AppItemList[appIndex].Guid, sizeof(GUID)); + MajorVersion = (uint16_t)MajorVer; + + status = sendRequest(&s, &request, &response, hwid, &result); + printf("%-11s", getNextString(KmsData->CsvlkData[i].EPid)); + + if (status) + { + displayRequestError(&s, status, i + 7 - MajorVer, 9 - MajorVer); + + if (status == 1) break; + + if ((status & 0xF0000000) == 0x80000000) + { + MajorVer--; + i--; + } + + continue; + } + + printf("%i of %i", (int)(i + 7 - MajorVer), (int)(KmsData->CsvlkCount + 6 - MajorVer)); + displayResponse(result, &request, &response, hwid); + + char ePID[3 * PID_BUFFER_SIZE]; + + if (!ucs2_to_utf8(response.KmsPID, ePID, PID_BUFFER_SIZE, 3 * PID_BUFFER_SIZE)) + { + memset(ePID + 3 * PID_BUFFER_SIZE - 3, 0, 3); + } + + vlmcsd_snprintf(lines[i], 255 - strlen(lines[i]), "%s = %s", getNextString(KmsData->CsvlkData[i].EPid), ePID); + + if (response.MajorVer > 5) + { + len = strlen(lines[i]); + vlmcsd_snprintf(lines[i] + len, 255 - len, " / %02X %02X %02X %02X %02X %02X %02X %02X", hwid[0], hwid[1], hwid[2], hwid[3], hwid[4], hwid[5], hwid[6], hwid[7]); + } + + len = strlen(lines[i]); + vlmcsd_snprintf(lines[i] + len, 255 - len, "\n"); + + } + + if (strcmp(fn_ini_client, "-")) + { + updateIniFile(&lines); + } + else + { + printf("\n"); + for (i = 0; i < KmsData->CsvlkCount; i++) printf("%s", lines[i]); + } +} + + +int client_main(int argc, CARGV argv) +{ +#if defined(_WIN32) && !defined(USE_MSRPC) + + // Windows Sockets must be initialized + + WSADATA wsaData; + int error; + + if ((error = WSAStartup(0x0202, &wsaData))) + { + errorout("Fatal: Could not initialize Windows sockets (Error: %d).\n", error); + return error; + } + +#endif // _WIN32 + +#ifdef _NTSERVICE + + // We are not a service + IsNTService = FALSE; + +#endif // _NTSERVICE + + randomNumberInit(); + + //# ifndef NO_EXTERNAL_DATA + // ExplicitDataLoad = TRUE; + //# endif // NO_EXTERNAL_DATA + + parseCommandLinePass0(argc, argv); + + int_fast8_t useDefaultHost = FALSE; + + if (optind < argc) + RemoteAddr = argv[optind]; + else + useDefaultHost = TRUE; + + const int hostportarg = optind; + + if (optind < argc - 1) + { + parseCommandLinePass0(argc - hostportarg, argv + hostportarg); + + if (optind < argc - hostportarg) + clientUsage(argv[0]); + } + + loadKmsData(); + + if (!KmsData->AppItemCount || !KmsData->SkuItemCount || !KmsData->KmsItemCount) + { + errorout("Fatal: Incomplete KMS data file\n"); + exit(VLMCSD_EINVAL); + } + + parseCommandLinePass1(argc, argv); + + if (optind < argc - 1) + { + parseCommandLinePass1(argc - hostportarg, argv + hostportarg); + } + + parseCommandLinePass2(argv[0], argc, argv); + + if (optind < argc - 1) + parseCommandLinePass2(argv[0], argc - hostportarg, argv + hostportarg); + + if (useDefaultHost) + { +# ifndef USE_MSRPC + RemoteAddr = AddressFamily == AF_INET6 ? "::1" : "127.0.0.1"; +# else + RemoteAddr = "127.0.0.1"; +# endif + } + + if (fn_ini_client != NULL) + grabServerData(); + else + { + int requests; + RpcCtx s = INVALID_RPCCTX; + + for (requests = 0, RequestsToGo = NCountPolicy == 1 ? 1 : NCountPolicy - 1; RequestsToGo; requests++) + { + RESPONSE response; + REQUEST request; + RESPONSE_RESULT result; + hwid_t hwid; + + int status = sendRequest(&s, &request, &response, hwid, &result); + + if (FixedRequests) RequestsToGo = FixedRequests - requests - 1; + + if (status) + { + displayRequestError(&s, status, requests + 1, RequestsToGo + requests + 1); + if (!FixedRequests) RequestsToGo = 0; + } + else + { + if (!FixedRequests) + { + if (firstRequestSent && NCountPolicy - (int)response.Count >= RequestsToGo) + { + errorout("\nThe KMS server does not increment it's active clients. Aborting...\n"); + RequestsToGo = 0; + } + else + { + RequestsToGo = NCountPolicy - response.Count; + if (RequestsToGo < 0) RequestsToGo = 0; + } + } + + fflush(stderr); + printf("%i of %i ", requests + 1, RequestsToGo + requests + 1); + displayResponse(result, &request, &response, hwid); + firstRequestSent = TRUE; + } + } + } + + return 0; +} + + +// Create Base KMS Client Request +static void CreateRequestBase(REQUEST *Request) +{ + Request->MinorVer = LE16(MinorVersion); + Request->MajorVer = LE16(MajorVersion); + Request->VMInfo = LE32(VMInfo); + Request->LicenseStatus = LE32(LicenseStatus); + Request->BindingExpiration = LE32(BindingExpiration); + Request->N_Policy = LE32(NCountPolicy); + + memcpy(&Request->ActID, &SkuGuid, sizeof(GUID)); + memcpy(&Request->KMSID, &KmsGuid, sizeof(GUID)); + memcpy(&Request->AppID, &AppGuid, sizeof(GUID)); + + getUnixTimeAsFileTime(&Request->ClientTime); + + { + if (CMID) + { + string2UuidOrExit(CMID, &Request->CMID); + } + else + { + get16RandomBytes(&Request->CMID); + + // Set reserved UUID bits + Request->CMID.Data4[0] &= 0x3F; + Request->CMID.Data4[0] |= 0x80; + + // Set UUID type 4 (random UUID) + Request->CMID.Data3 &= LE16(0xfff); + Request->CMID.Data3 |= LE16(0x4000); + } + + if (CMID_prev) + { + string2UuidOrExit(CMID_prev, &Request->CMID_prev); + } + else + { + memset(&Request->CMID_prev, 0, sizeof(Request->CMID_prev)); + } + } + + static const char alphanum[] = "0123456789" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" /*"abcdefghijklmnopqrstuvwxyz" */; + + if (WorkstationName) + { + utf8_to_ucs2(Request->WorkstationName, WorkstationName, WORKSTATION_NAME_BUFFER, WORKSTATION_NAME_BUFFER * 3); + } + else if (dnsnames) + { + int len, len2; + unsigned int index = rand() % vlmcsd_countof(ClientDnsNames.first); + len = (int)utf8_to_ucs2(Request->WorkstationName, ClientDnsNames.first[index], WORKSTATION_NAME_BUFFER, WORKSTATION_NAME_BUFFER * 3); + + index = rand() % vlmcsd_countof(ClientDnsNames.second); + len2 = (int)utf8_to_ucs2(Request->WorkstationName + len, ClientDnsNames.second[index], WORKSTATION_NAME_BUFFER, WORKSTATION_NAME_BUFFER * 3); + + index = rand() % vlmcsd_countof(ClientDnsNames.tld); + utf8_to_ucs2(Request->WorkstationName + len + len2, ClientDnsNames.tld[index], WORKSTATION_NAME_BUFFER, WORKSTATION_NAME_BUFFER * 3); + } + else + { + unsigned int size = (rand() % 14) + 1; + const unsigned char *dummy; + unsigned int i; + + for (i = 0; i < size; i++) + { + Request->WorkstationName[i] = utf8_to_ucs2_char((unsigned char*)alphanum + (rand() % (sizeof(alphanum) - 1)), &dummy); + } + + Request->WorkstationName[size] = 0; + } + +# ifndef NO_VERBOSE_LOG + if (verbose) + { + printf("\nRequest Parameters\n==================\n\n"); + logRequestVerbose(Request, &printf); + printf("\n"); + } +# endif // NO_VERBOSE_LOG +} + +#if _MSC_VER && !defined(_DEBUG)&& !MULTI_CALL_BINARY +int __stdcall WinStartUp(void) +{ + WCHAR **szArgList; + int argc; + szArgList = CommandLineToArgvW(GetCommandLineW(), &argc); + + int i; + char **argv = (char**)vlmcsd_malloc(sizeof(char*)*argc); + + for (i = 0; i < argc; i++) + { + int size = WideCharToMultiByte(CP_UTF8, 0, szArgList[i], -1, argv[i], 0, NULL, NULL); + argv[i] = (char*)vlmcsd_malloc(size); + WideCharToMultiByte(CP_UTF8, 0, szArgList[i], -1, argv[i], size, NULL, NULL); + } + + exit(client_main(argc, argv)); +} +#endif // _MSC_VER && !defined(_DEBUG)&& !MULTI_CALL_BINARY + + +#endif // IS_LIBRARY diff --git a/vlmcsd/src/vlmcs.h b/vlmcsd/src/vlmcs.h new file mode 100644 index 0000000..dce2ba3 --- /dev/null +++ b/vlmcsd/src/vlmcs.h @@ -0,0 +1,29 @@ +#ifndef VLMCS_H_ +#define VLMCS_H_ + +#ifndef CONFIG +#define CONFIG "config.h" +#endif // CONFIG +#include CONFIG + +#if !defined(USE_MSRPC) && defined(_WIN32) +#include +#endif // defined(USE_MSRPC) && defined(_WIN32) +#include "types.h" +#ifndef USE_MSRPC +#include "rpc.h" +#else // USE_MSRPC +#include "msrpc-client.h" +#endif // USE_MSRPC +#include "kms.h" + +#if MULTI_CALL_BINARY < 1 +#define client_main main +#else +int client_main(int argc, CARGV argv); +#endif + +int SendActivationRequest(const RpcCtx sock, RESPONSE *baseResponse, REQUEST *baseRequest, RESPONSE_RESULT *result, BYTE *const hwid); + +#endif /* VLMCS_H_ */ + diff --git a/vlmcsd/src/vlmcsd.c b/vlmcsd/src/vlmcsd.c new file mode 100644 index 0000000..efa75b1 --- /dev/null +++ b/vlmcsd/src/vlmcsd.c @@ -0,0 +1,1976 @@ +#ifndef _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#endif + +#ifndef CONFIG +#define CONFIG "config.h" +#endif // CONFIG +#include CONFIG + +#if defined(USE_MSRPC) && !defined(_WIN32) && !defined(__CYGWIN__) +#error Microsoft RPC is only available on Windows and Cygwin +#endif + +#if defined(USE_MSRPC) && defined(SIMPLE_SOCKETS) +#error You can only define either USE_MSRPC or SIMPLE_SOCKETS but not both +#endif + +#if defined(NO_SOCKETS) && defined(USE_MSRPC) +#error Cannot use inetd mode with Microsoft RPC +#endif + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include +#include +#include + +#if _MSC_VER +#include "wingetopt.h" +#endif + +#ifndef _WIN32 +#include +#include +#include + +#if !defined(NO_LIMIT) && !__minix__ +#include +#if !__ANDROID__ +#include +#endif // !__ANDROID__ +#endif // !defined(NO_LIMIT) && !__minix__ + +#include +#include +#include +#include +#ifndef NO_LIMIT +#include +#endif // NO_LIMIT +#endif // !_WIN32 + +#if __APPLE__ +#include +#endif // __APPLE__ + +#if __linux__ && defined(USE_AUXV) +#include +#endif + +#if __FreeBSD__ +#include +#endif + +#include "vlmcsd.h" +// ReSharper disable CppUnusedIncludeDirective +#include "endian.h" +// ReSharper restore CppUnusedIncludeDirective +#include "shared_globals.h" +#include "output.h" +#ifndef USE_MSRPC +#include "network.h" +#else // USE_MSRPC +#include "msrpc-server.h" +#endif // USE_MSRPC +#include "ntservice.h" +#include "helpers.h" + +#ifndef NO_TAP +#include "wintap.h" +#endif + +static const char* const optstring = "a:N:B:m:t:A:R:u:g:L:p:i:H:P:l:r:U:W:C:c:F:O:o:x:T:K:E:M:j:SseDdVvqkZ"; + +#if !defined(NO_SOCKETS) && !defined(USE_MSRPC) && !defined(SIMPLE_SOCKETS) +static uint_fast8_t maxsockets = 0; + +#endif // !defined(NO_SOCKETS) && !defined(USE_MSRPC) && !defined(SIMPLE_SOCKETS) + +#ifdef _NTSERVICE +static int_fast8_t installService = 0; +static const char* restrict ServiceUser = NULL; +static const char* restrict ServicePassword = ""; +#endif + +#ifndef NO_PID_FILE +static const char* fn_pid = NULL; +#endif + +#if !defined(NO_INI_FILE) || !defined(NO_CL_PIDS) + +#ifndef NO_INI_FILE +#ifdef INI_FILE +static const char* fn_ini = INI_FILE; +#else // !INI_FILE +static const char* fn_ini = NULL; +#endif // !INI_FILE +#endif // NO_INI_FILE + +#ifndef NO_TAP +char* tapArgument = NULL; +#endif // NO_TAP + +static const char* IniFileErrorMessage = ""; +char* IniFileErrorBuffer = NULL; +#define INIFILE_ERROR_BUFFERSIZE 256 + +static IniFileParameter_t IniFileParameterList[] = +{ +# ifndef NO_SOCKETS + { "ExitLevel", INI_PARAM_EXIT_LEVEL }, +# endif // NO_SOCKETS +# ifndef NO_TAP + { "VPN", INI_PARAM_VPN }, +# endif // NO_TAP +# ifndef NO_EXTERNAL_DATA + { "KmsData", INI_PARAM_DATA_FILE }, +# endif // NO_EXTERNAL_DATA +# ifndef NO_STRICT_MODES + { "WhiteListingLevel", INI_PARAM_WHITELISTING_LEVEL }, + { "CheckClientTime", INI_PARAM_CHECK_CLIENT_TIME }, +# ifndef NO_CLIENT_LIST + { "StartEmpty", INI_PARAM_START_EMPTY }, + { "MaintainClients", INI_PARAM_MAINTAIN_CLIENTS }, +# endif // NO_CLIENT_LIST +# endif // NO_STRICT_MODES +# ifndef NO_RANDOM_EPID + { "RandomizationLevel", INI_PARAM_RANDOMIZATION_LEVEL }, + { "LCID", INI_PARAM_LCID }, + { "HostBuild", INI_PARAM_HOST_BUILD }, +# endif // NO_RANDOM_EPID +# if !defined(NO_SOCKETS) && (defined(USE_MSRPC) || defined(SIMPLE_SOCKETS) || defined(HAVE_GETIFADDR)) + { "Port", INI_PARAM_PORT }, +# endif // defined(USE_MSRPC) || defined(SIMPLE_SOCKETS) +# if !defined(NO_SOCKETS) && !defined(USE_MSRPC) +# ifndef SIMPLE_SOCKETS + { "Listen", INI_PARAM_LISTEN }, +# endif // SIMPLE_SOCKETS +# if HAVE_FREEBIND + { "FreeBind", INI_PARAM_FREEBIND }, +# endif // HAVE_FREEBIND +# if !defined(NO_LIMIT) && !__minix__ + { "MaxWorkers", INI_PARAM_MAX_WORKERS }, +# endif // !defined(NO_LIMIT) && !__minix__ +# endif // !defined(NO_SOCKETS) && !defined(USE_MSRPC) +# if !defined(NO_TIMEOUT) && !__minix__ && !defined(USE_MSRPC) & !defined(USE_MSRPC) + { "ConnectionTimeout", INI_PARAM_CONNECTION_TIMEOUT }, +# endif // !defined(NO_TIMEOUT) && !__minix__ && !defined(USE_MSRPC) & !defined(USE_MSRPC) +# ifndef USE_MSRPC + { "DisconnectClientsImmediately", INI_PARAM_DISCONNECT_IMMEDIATELY }, +# ifndef SIMPLE_RPC + { "UseNDR64", INI_PARAM_RPC_NDR64 }, + { "UseBTFN", INI_PARAM_RPC_BTFN }, +# endif // !SIMPLE_RPC +# endif // USE_MSRPC +# ifndef NO_PID_FILE + { "PIDFile", INI_PARAM_PID_FILE }, +# endif // NO_PID_FILE +# ifndef NO_LOG + { "LogDateAndTime", INI_PARAM_LOG_DATE_AND_TIME }, + { "LogFile", INI_PARAM_LOG_FILE }, +# ifndef NO_VERBOSE_LOG + { "LogVerbose", INI_PARAM_LOG_VERBOSE }, +# endif // NO_VERBOSE_LOG +# endif // NO_LOG +# ifndef NO_CUSTOM_INTERVALS + {"ActivationInterval", INI_PARAM_ACTIVATION_INTERVAL }, + {"RenewalInterval", INI_PARAM_RENEWAL_INTERVAL }, +# endif // NO_CUSTOM_INTERVALS +# if !defined(NO_USER_SWITCH) && !defined(_WIN32) + { "user", INI_PARAM_UID }, + { "group", INI_PARAM_GID}, +# endif // !defined(NO_USER_SWITCH) && !defined(_WIN32) +# if !defined(NO_PRIVATE_IP_DETECT) + {"PublicIPProtectionLevel", INI_PARAM_PUBLIC_IP_PROTECTION_LEVEL }, +# endif +}; + +#endif // NO_INI_FILE + + +#if !defined(NO_LIMIT) && !defined (NO_SOCKETS) && !__minix__ + +#if !defined(USE_THREADS) && !defined(CYGWIN) && !defined(USE_MSRPC) +static int shmid = -1; +#endif + + +#endif // !defined(NO_LIMIT) && !defined (NO_SOCKETS) && !__minix__ + +#ifndef NO_USER_SWITCH +#ifndef _WIN32 + +static const char* uname = NULL, * gname = NULL; +static gid_t gid = INVALID_GID; +static uid_t uid = INVALID_UID; + +// Get Numeric id of user/group +static char GetNumericId(gid_t* restrict id, const char* const c) +{ + char* endptr; + gid_t temp; + + temp = (gid_t)strtoll(c, &endptr, 10); + if (!*endptr) *id = temp; + if (*endptr || temp == (gid_t)-1) errno = EINVAL; + + return *endptr || *id == (gid_t)-1; +} + + +// Get group id from option argument +static char GetGid() +{ + struct group* g; + + if ((g = getgrnam(optarg))) + gid = g->gr_gid; + else + return GetNumericId(&gid, optarg); + + return 0; +} + + +// Get user id from option argument +static char GetUid() +{ + struct passwd* u; + + ////PORTABILITY: Assumes uid_t and gid_t are of same size (shouldn't be a problem) + if ((u = getpwnam(optarg))) + uid = u->pw_uid; + else + return GetNumericId((gid_t*)&uid, optarg); + + return 0; +} +#endif // _WIN32 +#endif //NO_USER_SWITCH + +#ifdef NO_HELP +static __noreturn void usage() +{ + printerrorf("Incorrect parameters\n\n"); + exit(VLMCSD_EINVAL); +} +#else // HELP + + +static __noreturn void usage() +{ + printerrorf("vlmcsd %s\n" + "\nUsage:\n" + " %s [ options ]\n\n" + "Where:\n" +# if !defined(_WIN32) && !defined(NO_USER_SWITCH) + " -u \t\tset uid to \n" + " -g \t\tset gid to \n" +# endif // !defined(_WIN32) && !defined(NO_USER_SWITCH) +# ifndef NO_CL_PIDS + " -a =\tuse for \n" +# endif // NO_CL_PIDS +# ifndef NO_RANDOM_EPID + " -r 0|1|2\t\tset ePID randomization level (default 1)\n" + " -C \t\tuse fixed in random ePIDs\n" + " -H \t\tuse fixed number in random ePIDs\n" +# endif // NO_RANDOM_EPID +# if !defined(NO_PRIVATE_IP_DETECT) +# if HAVE_GETIFADDR + " -o 0|1|2|3\t\tset protection level against clients with public IP addresses (default 0)\n" +# else // !HAVE_GETIFADDR +# ifndef USE_MSRPC + " -o 0|2\t\tset protection level against clients with public IP addresses (default 0)\n" +# else // USE_MSRPC + " -o 0|2\t\tset protection level against clients with public IP addresses (default 0). Limited use with MS RPC\n" +# endif // USE_MSRPC +# endif // !HAVE_GETIFADDR +# endif // !defined(NO_PRIVATE_IP_DETECT) +# ifndef NO_TAP + " -O [=][/]\tuse VPN adapter with IPv4 address and CIDR \n" +# endif +# ifndef NO_SOCKETS + " -x \t\texit if warning reached (default 0)\n" +# if !defined(USE_MSRPC) && !defined(SIMPLE_SOCKETS) + " -L
[:]\tlisten on IP address
with optional \n" + " -P \t\tset TCP port for subsequent -L statements (default 1688)\n" +# if HAVE_FREEBIND + " -F0, -F1\t\tdisable/enable binding to foreign IP addresses\n" +# endif // HAVE_FREEBIND +# else // defined(USE_MSRPC) || defined(SIMPLE_SOCKETS) + " -P \t\tuse TCP port (default 1688)\n" +# endif // defined(USE_MSRPC) || defined(SIMPLE_SOCKETS) +# if !defined(NO_LIMIT) && !__minix__ + " -m \t\tHandle max. simultaneously (default no limit)\n" +# endif // !defined(NO_LIMIT) && !__minix__ +# ifdef _NTSERVICE + " -s\t\t\tinstall vlmcsd as an NT service. Ignores -e" +# ifndef _WIN32 + ", -f and -D" +# endif // _WIN32 + "\n" + " -S\t\t\tremove vlmcsd service. Ignores all other options\n" + " -U \t\trun NT service as . Must be used with -s\n" + " -W \t\toptional for -U. Must be used with -s\n" +# endif // _NTSERVICE +# ifndef NO_LOG + " -e\t\t\tlog to stdout\n" +# endif // NO_LOG +# ifndef _WIN32 // + " -D\t\t\trun in foreground\n" +# else // _WIN32 + " -D\t\t\tdoes nothing. Provided for compatibility with POSIX versions only\n" +# endif // _WIN32 +# endif // NO_SOCKETS +# ifndef NO_STRICT_MODES + " -K 0|1|2|3\t\tset white-listing level for KMS IDs (default -K0)\n" + " -c0, -c1\t\tdisable/enable client time checking (default -c0)\n" +# ifndef NO_CLIENT_LIST + " -M0, -M1\t\tdisable/enable maintaining clients (default -M0)\n" + " -E0, -E1\t\tdisable/enable start with empty client list (default -E0, ignored if -M0)\n" +# endif // !NO_CLIENT_LIST +# endif // !NO_STRICT_MODES +# ifndef USE_MSRPC +# if !defined(NO_TIMEOUT) && !__minix__ + " -t \t\tdisconnect clients after of inactivity (default 30)\n" +# endif // !defined(NO_TIMEOUT) && !__minix__ + " -d\t\t\tdisconnect clients after each request\n" + " -k\t\t\tdon't disconnect clients after each request (default)\n" +# ifndef SIMPLE_RPC + " -N0, -N1\t\tdisable/enable NDR64\n" + " -B0, -B1\t\tdisable/enable bind time feature negotiation\n" +# endif // !SIMPLE_RPC +# endif // USE_MSRPC +# ifndef NO_PID_FILE + " -p \t\twrite pid to \n" +# endif // NO_PID_FILE +# ifndef NO_INI_FILE + " -i \t\tuse config file \n" +# endif // NO_INI_FILE +# ifndef NO_EXTERNAL_DATA + " -j \t\tuse KMS data file \n" +# endif // !NO_EXTERNAL_DATA +# ifndef NO_CUSTOM_INTERVALS + " -R \t\trenew activation every (default 1w)\n" + " -A \t\tretry activation every (default 2h)\n" +# endif // NO_CUSTOM_INTERVALS +# ifndef NO_LOG +# ifndef _WIN32 + " -l syslog log to syslog\n" +# endif // _WIN32 + " -l \t\tlog to \n" + " -T0, -T1\t\tdisable/enable logging with time and date (default -T1)\n" +# ifndef NO_VERBOSE_LOG + " -v\t\t\tlog verbose\n" + " -q\t\t\tdon't log verbose (default)\n" +# endif // NO_VERBOSE_LOG +# endif // NO_LOG +# ifndef NO_VERSION_INFORMATION + " -V\t\t\tdisplay version information and exit\n" +# endif // NO_VERSION_INFORMATION + , + Version, global_argv[0]); + + exit(VLMCSD_EINVAL); +} +#endif // HELP + + +#ifndef NO_CUSTOM_INTERVALS +#if !defined(NO_INI_FILE) + +__pure static BOOL getTimeSpanFromIniFile(DWORD* result, const char* const restrict argument) +{ + const DWORD val = timeSpanString2Minutes(argument); + + if (!val) + { + IniFileErrorMessage = "Incorrect time span."; + return FALSE; + } + + *result = val; + return TRUE; +} + +#endif // !defined(NO_INI_FILE) + + +__pure static DWORD getTimeSpanFromCommandLine(const char* const restrict arg, const char optchar) +{ + const DWORD val = timeSpanString2Minutes(arg); + + if (!val) + { + printerrorf("Fatal: No valid time span specified in option -%c.\n", optchar); + exit(VLMCSD_EINVAL); + } + + return val; +} + +#endif // NO_CUSTOM_INTERVALS + + +#if !defined(NO_INI_FILE) || !defined (NO_CL_PIDS) +static __pure int isControlCharOrSlash(const char c) +{ + if ((unsigned char)c < '!') return TRUE; + if (c == '/') return TRUE; + return FALSE; +} + + +static void iniFileLineNextWord(const char** s) +{ + while (**s && isspace((int)**s)) (*s)++; +} + + +static BOOL setHwIdFromIniFileLine(const char** s, const uint32_t index, const uint8_t overwrite) +{ + iniFileLineNextWord(s); + + if (**s == '/') + { + if (!overwrite && KmsResponseParameters[index].HwId) return TRUE; + + BYTE* HwId = (BYTE*)vlmcsd_malloc(sizeof(((RESPONSE_V6*)0)->HwId)); + hex2bin(HwId, *s + 1, sizeof(((RESPONSE_V6*)0)->HwId)); + KmsResponseParameters[index].HwId = HwId; + } + + return TRUE; +} + + +static BOOL setEpidFromIniFileLine(const char** s, const uint32_t index, const char* ePidSource, const uint8_t overwrite) +{ + iniFileLineNextWord(s); + const char* savedPosition = *s; + uint_fast16_t i; + + for (i = 0; !isControlCharOrSlash(**s); i++) + { + if (utf8_to_ucs2_char((const unsigned char*)*s, (const unsigned char**)s) == (WCHAR)~0) + { + return FALSE; + } + } + + if (i < 1 || i >= PID_BUFFER_SIZE) return FALSE; + if (!overwrite && KmsResponseParameters[index].Epid) return TRUE; + + const size_t size = *s - savedPosition + 1; + + char* epidbuffer = (char*)vlmcsd_malloc(size); + memcpy(epidbuffer, savedPosition, size - 1); + epidbuffer[size - 1] = 0; + + KmsResponseParameters[index].Epid = epidbuffer; + +#ifndef NO_LOG + KmsResponseParameters[index].EpidSource = ePidSource; +#endif //NO_LOG + + return TRUE; +} + +#ifndef NO_INI_FILE +static BOOL getIniFileArgumentBool(int_fast8_t* result, const char* const argument) +{ + IniFileErrorMessage = "Argument must be true/on/yes/1 or false/off/no/0"; + return getArgumentBool(result, argument); +} + + +static BOOL getIniFileArgumentInt(unsigned int* result, const char* const argument, const unsigned int min, const unsigned int max) +{ + unsigned int tempResult; + + if (!stringToInt(argument, min, max, &tempResult)) + { + vlmcsd_snprintf(IniFileErrorBuffer, INIFILE_ERROR_BUFFERSIZE, "Must be integer between %u and %u", min, max); + IniFileErrorMessage = IniFileErrorBuffer; + return FALSE; + } + + *result = tempResult; + return TRUE; +} + + +static BOOL setIniFileParameter(uint_fast8_t id, const char* const iniarg) +{ + unsigned int result; + BOOL success = TRUE; + switch (id) + { +# ifndef NO_TAP + + case INI_PARAM_VPN: + tapArgument = (char*)vlmcsd_strdup(iniarg); + break; + +# endif // NO_TAP + +# if !defined(NO_USER_SWITCH) && !_WIN32 + + case INI_PARAM_GID: + { + struct group* g; + IniFileErrorMessage = "Invalid group id or name"; + if (!(gname = vlmcsd_strdup(iniarg))) return FALSE; + + if ((g = getgrnam(iniarg))) + gid = g->gr_gid; + else + success = !GetNumericId(&gid, iniarg); + break; + } + + case INI_PARAM_UID: + { + struct passwd* p; + IniFileErrorMessage = "Invalid user id or name"; + if (!(uname = vlmcsd_strdup(iniarg))) return FALSE; + + if ((p = getpwnam(iniarg))) + uid = p->pw_uid; + else + success = !GetNumericId(&uid, iniarg); + break; + } + +# endif // !defined(NO_USER_SWITCH) && !defined(_WIN32) + +# ifndef NO_RANDOM_EPID + + case INI_PARAM_LCID: + success = getIniFileArgumentInt(&result, iniarg, 0, 32767); + if (success) Lcid = (uint16_t)result; + break; + + case INI_PARAM_RANDOMIZATION_LEVEL: + success = getIniFileArgumentInt(&result, iniarg, 0, 2); + if (success) RandomizationLevel = (int_fast8_t)result; + break; + + case INI_PARAM_HOST_BUILD: + success = getIniFileArgumentInt(&result, iniarg, 0, 65535); + if (success) HostBuild = (uint16_t)result; + break; + +# endif // NO_RANDOM_EPID + +# if (defined(USE_MSRPC) || defined(SIMPLE_SOCKETS) || defined(HAVE_GETIFADDR)) && !defined(NO_SOCKETS) + + case INI_PARAM_PORT: + defaultport = vlmcsd_strdup(iniarg); + break; + +# endif // (defined(USE_MSRPC) || defined(SIMPLE_SOCKETS) || defined(HAVE_GETIFADDR)) && !defined(NO_SOCKETS) + +# if !defined(NO_SOCKETS) && !defined(USE_MSRPC) && !defined(SIMPLE_SOCKETS) + + case INI_PARAM_LISTEN: + maxsockets++; + return TRUE; + +# endif // !defined(NO_SOCKETS) && !defined(USE_MSRPC) && !defined(SIMPLE_SOCKETS) +# if !defined(NO_LIMIT) && !defined(NO_SOCKETS) && !__minix__ + + case INI_PARAM_MAX_WORKERS: +# ifdef USE_MSRPC + success = getIniFileArgumentInt(&MaxTasks, iniarg, 1, RPC_C_LISTEN_MAX_CALLS_DEFAULT); +# else // !USE_MSRPC + success = getIniFileArgumentInt(&MaxTasks, iniarg, 1, SEM_VALUE_MAX); +# endif // !USE_MSRPC + break; + +# endif // !defined(NO_LIMIT) && !defined(NO_SOCKETS) && !__minix__ + +# ifndef NO_PID_FILE + + case INI_PARAM_PID_FILE: + fn_pid = vlmcsd_strdup(iniarg); + break; + +# endif // NO_PID_FILE + +# ifndef NO_EXTERNAL_DATA + + case INI_PARAM_DATA_FILE: + fn_data = vlmcsd_strdup(iniarg); +# ifndef NO_INTERNAL_DATA + ExplicitDataLoad = TRUE; +# endif // NO_INTERNAL_DATA + break; + +# endif // NO_EXTERNAL_DATA + +# ifndef NO_STRICT_MODES + + case INI_PARAM_WHITELISTING_LEVEL: + success = getIniFileArgumentInt(&WhitelistingLevel, iniarg, 0, 3); + break; + + case INI_PARAM_CHECK_CLIENT_TIME: + success = getIniFileArgumentBool(&CheckClientTime, iniarg); + break; + +# ifndef NO_CLIENT_LIST + case INI_PARAM_MAINTAIN_CLIENTS: + success = getIniFileArgumentBool(&MaintainClients, iniarg); + break; + + case INI_PARAM_START_EMPTY: + success = getIniFileArgumentBool(&StartEmpty, iniarg); + break; + +# endif // NO_CLIENT_LIST +# endif // !NO_STRICT_MODES + + +# ifndef NO_LOG + + case INI_PARAM_LOG_FILE: + fn_log = vlmcsd_strdup(iniarg); + break; + + case INI_PARAM_LOG_DATE_AND_TIME: + success = getIniFileArgumentBool(&LogDateAndTime, iniarg); + break; + +# ifndef NO_VERBOSE_LOG + case INI_PARAM_LOG_VERBOSE: + success = getIniFileArgumentBool(&logverbose, iniarg); + break; + +# endif // NO_VERBOSE_LOG +# endif // NO_LOG + +# ifndef NO_CUSTOM_INTERVALS + + case INI_PARAM_ACTIVATION_INTERVAL: + success = getTimeSpanFromIniFile(&VLActivationInterval, iniarg); + break; + + case INI_PARAM_RENEWAL_INTERVAL: + success = getTimeSpanFromIniFile(&VLRenewalInterval, iniarg); + break; + +# endif // NO_CUSTOM_INTERVALS + +# ifndef USE_MSRPC + +# if !defined(NO_TIMEOUT) && !__minix__ + + case INI_PARAM_CONNECTION_TIMEOUT: + success = getIniFileArgumentInt(&result, iniarg, 1, 600); + if (success) ServerTimeout = (DWORD)result; + break; + +# endif // !defined(NO_TIMEOUT) && !__minix__ + + case INI_PARAM_DISCONNECT_IMMEDIATELY: + success = getIniFileArgumentBool(&DisconnectImmediately, iniarg); + break; + + case INI_PARAM_RPC_NDR64: + success = getIniFileArgumentBool(&UseServerRpcNDR64, iniarg); + if (success) IsNDR64Defined = TRUE; + break; + + case INI_PARAM_RPC_BTFN: + success = getIniFileArgumentBool(&UseServerRpcBTFN, iniarg); + break; + +# endif // USE_MSRPC + +# ifndef NO_SOCKETS + + case INI_PARAM_EXIT_LEVEL: + success = getIniFileArgumentInt(&result, iniarg, 0, 1); + if (success) ExitLevel = (int_fast8_t)result; + break; + +# endif // NO_SOCKETS + +# if HAVE_FREEBIND + + case INI_PARAM_FREEBIND: + success = getIniFileArgumentBool(&freebind, iniarg); + break; + +# endif // HAVE_FREEBIND + +# if !defined(NO_PRIVATE_IP_DETECT) + + case INI_PARAM_PUBLIC_IP_PROTECTION_LEVEL: + success = getIniFileArgumentInt(&PublicIPProtectionLevel, iniarg, 0, 3); + +# if !HAVE_GETIFADDR + if (PublicIPProtectionLevel & 1) + { + IniFileErrorMessage = "Must be 0 or 2"; + success = FALSE; + } +# endif // !HAVE_GETIFADDR + + break; + +# endif // !defined(NO_PRIVATE_IP_DETECT) + + default: + return FALSE; + } + + return success; +} +#endif // !NO_INI_FILE + + + +static BOOL getIniFileArgument(const char** s) +{ + while (!isspace((int)**s) && **s != '=' && **s) (*s)++; + iniFileLineNextWord(s); + + if (*((*s)++) != '=') + { + IniFileErrorMessage = "'=' required after keyword."; + return FALSE; + } + + iniFileLineNextWord(s); + + if (!**s) + { + IniFileErrorMessage = "missing argument after '='."; + return FALSE; + } + + return TRUE; +} + + +static int8_t GetCsvlkIndexFromName(const char* s) +{ + int8_t i; + + for (i = 0; i < KmsData->CsvlkCount; i++) + { + const char* csvlkName = getNextString(KmsData->CsvlkData[i].EPid); + + if (!strncasecmp(csvlkName, s, strlen(csvlkName))) + { + return i; + } + } + + return -1; +} + +static BOOL handleIniFileEpidParameter(const char* s, uint8_t allowIniFileDirectives, const char* ePidSource) +{ + int_fast16_t i; + + if (allowIniFileDirectives) + { + for (i = 0; i < (int_fast16_t)vlmcsd_countof(IniFileParameterList); i++) + { + if (!strncasecmp(IniFileParameterList[i].Name, s, strlen(IniFileParameterList[i].Name))) + { + return TRUE; + } + } + } + + i = GetCsvlkIndexFromName(s); + + if (i >= 0) + { + if (!getIniFileArgument(&s)) return FALSE; + if (!setEpidFromIniFileLine(&s, i, ePidSource, !allowIniFileDirectives)) return FALSE; + if (!setHwIdFromIniFileLine(&s, i, !allowIniFileDirectives)) return FALSE; + return TRUE; + } + + IniFileErrorMessage = "Unknown keyword."; + return FALSE; +} + +#endif // !defined(NO_INI_FILE) || !defined (NO_CL_PIDS) + +#ifndef NO_INI_FILE +static void ignoreIniFileParameter(uint_fast8_t iniFileParameterId) +{ + uint_fast8_t i; + + for (i = 0; i < vlmcsd_countof(IniFileParameterList); i++) + { + if (IniFileParameterList[i].Id != iniFileParameterId) continue; + IniFileParameterList[i].Id = 0; + break; + } +} +#else // NO_INI_FILE +#define ignoreIniFileParameter(x) +#endif // NO_INI_FILE + +#ifndef NO_INI_FILE +static BOOL handleIniFileParameter(const char* s) +{ + uint_fast8_t i; + + for (i = 0; i < vlmcsd_countof(IniFileParameterList); i++) + { + if (strncasecmp(IniFileParameterList[i].Name, s, strlen(IniFileParameterList[i].Name))) continue; + if (!IniFileParameterList[i].Id) return TRUE; + if (!getIniFileArgument(&s)) return FALSE; + + return setIniFileParameter(IniFileParameterList[i].Id, s); + } + + IniFileErrorMessage = NULL; + return TRUE; +} + + +#if !defined(NO_SOCKETS) && !defined(SIMPLE_SOCKETS) && !defined(USE_MSRPC) +static BOOL setupListeningSocketsFromIniFile(const char* s) +{ + if (!maxsockets) return TRUE; + if (strncasecmp("Listen", s, 6)) return TRUE; + if (!getIniFileArgument(&s)) return TRUE; + + vlmcsd_snprintf(IniFileErrorBuffer, INIFILE_ERROR_BUFFERSIZE, "Cannot listen on %s.", s); + IniFileErrorMessage = IniFileErrorBuffer; + return addListeningSocket(s); +} +#endif // !defined(NO_SOCKETS) && !defined(SIMPLE_SOCKETS) && !defined(USE_MSRPC) + + +static BOOL readIniFile(const uint_fast8_t pass) +{ + char line[256]; + const char* s; + unsigned int lineNumber; + uint_fast8_t lineParseError; + + FILE* restrict f; + BOOL result = TRUE; + + IniFileErrorBuffer = (char*)vlmcsd_malloc(INIFILE_ERROR_BUFFERSIZE); + + if (!((f = fopen(fn_ini, "r")))) return FALSE; + + for (lineNumber = 1; (s = fgets(line, sizeof(line), f)); lineNumber++) + { + size_t i; + + for (i = strlen(line); i > 0; i--) + { + if (line[i - 1] != 0xd && line[i - 1] != 0xa) + { + break; + } + } + + line[i] = 0; + + iniFileLineNextWord(&s); + if (*s == ';' || *s == '#' || !*s) continue; + + if (pass == INI_FILE_PASS_1) + { + if (handleIniFileParameter(s)) continue; + lineParseError = TRUE; + } + else if (pass == INI_FILE_PASS_2) + { + if (handleIniFileEpidParameter(s, TRUE, fn_ini)) continue; + lineParseError = TRUE; + } +# if !defined(NO_SOCKETS) && !defined(SIMPLE_SOCKETS) && !defined(USE_MSRPC) + else if (pass == INI_FILE_PASS_3) + { + lineParseError = !setupListeningSocketsFromIniFile(s); + } + else + { + return FALSE; + } +# endif // !defined(NO_SOCKETS) && && !defined(SIMPLE_SOCKETS) && !defined(USE_MSRPC) + + if (lineParseError) + { + printerrorf("Warning: %s line %u: \"%s\". %s\n", fn_ini, lineNumber, line, IniFileErrorMessage); + continue; + } + } + + if (ferror(f)) result = FALSE; + + free(IniFileErrorBuffer); + fclose(f); + +# if !defined(NO_SOCKETS) && !defined(NO_LOG) + + if (pass == INI_FILE_PASS_1 && !InetdMode && result) + { +# ifdef _NTSERVICE + if (!installService) +# endif // _NTSERVICE + logger("Read ini file %s\n", fn_ini); + } + +# endif // !defined(NO_SOCKETS) && !defined(NO_LOG) + + return result; +} +#endif // NO_INI_FILE + + +#if !defined(NO_SOCKETS) +#if !defined(_WIN32) +#if !defined(NO_SIGHUP) +static void exec_self(char** argv) +{ + getExeName(); + + if (fn_exe != NULL) + { + execv(fn_exe, argv); + } + else + { + execvp(argv[0], argv); + } +} + + +__noreturn static void HangupHandler(const int signal_unused) +{ + int i; + int_fast8_t daemonize_protection = TRUE; + CARGV argv_in = multi_argv == NULL ? global_argv : multi_argv; + int argc_in = multi_argc == 0 ? global_argc : multi_argc; + const char** argv_out = (const char**)vlmcsd_malloc((argc_in + 2) * sizeof(char**)); + + for (i = 0; i < argc_in; i++) + { + if (!strcmp(argv_in[i], "-Z")) daemonize_protection = FALSE; + argv_out[i] = argv_in[i]; + } + + argv_out[argc_in] = argv_out[argc_in + 1] = NULL; + if (daemonize_protection) argv_out[argc_in] = (char*)"-Z"; + + exec_self((char**)argv_out); + int error = errno; + +# ifndef NO_LOG + logger("Fatal: Unable to restart on SIGHUP: %s\n", strerror(error)); +# endif + +# ifndef NO_PID_FILE + if (fn_pid) unlink(fn_pid); +# endif // NO_PID_FILE + exit(error); +} +#endif // NO_SIGHUP + + +__noreturn static void terminationHandler(const int signal_unused) +{ + cleanup(); + exit(0); +} + + +#if defined(CHILD_HANDLER) || __minix__ +static void childHandler(const int signal) +{ + waitpid(-1, NULL, WNOHANG); +} +#endif // defined(CHILD_HANDLER) || __minix__ + + +static int daemonizeAndSetSignalAction() +{ + struct sigaction sa; + sigemptyset(&sa.sa_mask); + +# ifndef NO_LOG + if (!nodaemon) if (daemon(!0, logstdout)) +# else // NO_LOG + if (!nodaemon) if (daemon(!0, 0)) +# endif // NO_LOG + { + printerrorf("Fatal: Could not daemonize to background.\n"); + return(errno); + } + + if (!InetdMode) + { +# ifndef USE_THREADS + +# if defined(CHILD_HANDLER) || __minix__ + sa.sa_handler = childHandler; +# else // !(defined(CHILD_HANDLER) || __minix__) + sa.sa_handler = SIG_IGN; +# endif // !(defined(CHILD_HANDLER) || __minix__) + sa.sa_flags = SA_NOCLDWAIT; + + if (sigaction(SIGCHLD, &sa, NULL)) + return(errno); + +# endif // !USE_THREADS + + sa.sa_handler = terminationHandler; + sa.sa_flags = 0; + + sigaction(SIGINT, &sa, NULL); + sigaction(SIGTERM, &sa, NULL); + +# ifndef NO_SIGHUP + sa.sa_handler = HangupHandler; + sa.sa_flags = SA_NODEFER; + sigaction(SIGHUP, &sa, NULL); +# endif // NO_SIGHUP + } + + return 0; +} + + +#else // _WIN32 + +static BOOL __stdcall terminationHandler(const DWORD fdwCtrlType) +{ + // What a lame substitute for Unix signal handling + switch (fdwCtrlType) + { + case CTRL_C_EVENT: + case CTRL_CLOSE_EVENT: + case CTRL_BREAK_EVENT: + case CTRL_LOGOFF_EVENT: + case CTRL_SHUTDOWN_EVENT: + cleanup(); + exit(0); + default: + return FALSE; + } +} + + +static DWORD daemonizeAndSetSignalAction() +{ + if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE)terminationHandler, TRUE)) + { +#ifndef NO_LOG + const DWORD rc = GetLastError(); + logger("Warning: Could not register Windows signal handler: Error %u\n", rc); +#endif // NO_LOG + } + + return ERROR_SUCCESS; +} +#endif // _WIN32 +#endif // !defined(NO_SOCKETS) + + +// Workaround for Cygwin fork problem (only affects cygwin processes that are Windows services) +// Best is to compile for Cygwin with threads. fork() is slow and unreliable on Cygwin +#if !defined(NO_INI_FILE) || !defined(NO_LOG) || !defined(NO_CL_PIDS) || !defined(NO_EXTERNAL_DATA) +__pure static char* getCommandLineArg(char* const restrict arg) +{ +# if !__CYGWIN__ || defined(USE_THREADS) || defined(NO_SOCKETS) + return arg; +# else + if (!IsNTService) return arg; + + return vlmcsd_strdup(arg); +# endif +} +#endif // !defined(NO_INI_FILE) || !defined(NO_LOG) || !defined(NO_CL_PIDS) || !defined(NO_EXTERNAL_DATA) + + +static void parseGeneralArguments() { + int o; + + for (opterr = 0; (o = getopt(global_argc, (char* const*)global_argv, (const char*)optstring)) > 0; ) switch (o) + { +# if !defined(NO_SOCKETS) && !defined(NO_SIGHUP) && !defined(_WIN32) + case 'Z': + IsRestarted = TRUE; + nodaemon = TRUE; + break; +# endif // !defined(NO_SOCKETS) && !defined(NO_SIGHUP) && !defined(_WIN32) + +# ifndef NO_TAP + + case 'O': + ignoreIniFileParameter(INI_PARAM_VPN); + tapArgument = getCommandLineArg(optarg); + break; + +# endif // NO_TAP + +# ifndef NO_CL_PIDS + + case 'a': + break; + +# endif // NO_CL_PIDS + +# ifndef NO_EXTERNAL_DATA + + case 'j': + ignoreIniFileParameter(INI_PARAM_DATA_FILE); + fn_data = getCommandLineArg(optarg); +# ifndef NO_INTERNAL_DATA + ExplicitDataLoad = TRUE; +# endif // NO_INTERNAL_DATA + break; + +# endif // NO_EXTERNAL_DATA + +# ifndef NO_SOCKETS + + case 'x': + ignoreIniFileParameter(INI_PARAM_EXIT_LEVEL); + ExitLevel = (int_fast8_t)getOptionArgumentInt((char)o, 0, 1); + break; + + case 'P': + ignoreIniFileParameter(INI_PARAM_PORT); +# if !defined(SIMPLE_SOCKETS) && !defined(USE_MSRPC) + ignoreIniFileParameter(INI_PARAM_LISTEN); +# else + defaultport = optarg; +# endif // !SIMPLE_SOCKETS + break; + +# if !defined(NO_LIMIT) && !__minix__ + + case 'm': +# ifdef USE_MSRPC + MaxTasks = getOptionArgumentInt(o, 1, RPC_C_LISTEN_MAX_CALLS_DEFAULT); +# else // !USE_MSRPC + MaxTasks = getOptionArgumentInt((char)o, 1, SEM_VALUE_MAX); +# endif // !USE_MSRPC + ignoreIniFileParameter(INI_PARAM_MAX_WORKERS); + break; + +# endif // !defined(NO_LIMIT) && !__minix__ +# endif // NO_SOCKETS + +# if !defined(NO_TIMEOUT) && !__minix__ && !defined(USE_MSRPC) + case 't': + ServerTimeout = getOptionArgumentInt((char)o, 1, 600); + ignoreIniFileParameter(INI_PARAM_CONNECTION_TIMEOUT); + break; +# endif // !defined(NO_TIMEOUT) && !__minix__ && !defined(USE_MSRPC) + +# ifndef NO_PID_FILE + case 'p': + fn_pid = getCommandLineArg(optarg); + ignoreIniFileParameter(INI_PARAM_PID_FILE); + break; +# endif + +# ifndef NO_INI_FILE + case 'i': + fn_ini = getCommandLineArg(optarg); + if (!strcmp(fn_ini, "-")) fn_ini = NULL; + break; +# endif + +# ifndef NO_LOG + + case 'T': + if (!getArgumentBool(&LogDateAndTime, optarg)) usage(); + ignoreIniFileParameter(INI_PARAM_LOG_DATE_AND_TIME); + break; + + case 'l': + fn_log = getCommandLineArg(optarg); + ignoreIniFileParameter(INI_PARAM_LOG_FILE); + break; + +# ifndef NO_VERBOSE_LOG + case 'v': + case 'q': + logverbose = o == 'v'; + ignoreIniFileParameter(INI_PARAM_LOG_VERBOSE); + break; + +# endif // NO_VERBOSE_LOG +# endif // NO_LOG + +# if !defined(NO_PRIVATE_IP_DETECT) + case 'o': + ignoreIniFileParameter(INI_PARAM_PUBLIC_IP_PROTECTION_LEVEL); + PublicIPProtectionLevel = getOptionArgumentInt((char)o, 0, 3); + +# if !HAVE_GETIFADDR + if (PublicIPProtectionLevel & 1) usage(); +# endif // !HAVE_GETIFADDR + + break; +# endif // !defined(NO_PRIVATE_IP_DETECT) + +# ifndef NO_SOCKETS +# if !defined(USE_MSRPC) && !defined(SIMPLE_SOCKETS) + case 'L': + maxsockets++; + ignoreIniFileParameter(INI_PARAM_LISTEN); + break; +# if HAVE_FREEBIND + case 'F': + if (!getArgumentBool(&freebind, optarg)) usage(); + ignoreIniFileParameter(INI_PARAM_FREEBIND); + break; +# endif // HAVE_FREEBIND +# endif // !defined(USE_MSRPC) && !defined(SIMPLE_SOCKETS) + +# ifdef _NTSERVICE + case 'U': + ServiceUser = optarg; + break; + + case 'W': + ServicePassword = optarg; + break; + + case 's': +# ifndef USE_MSRPC + if (InetdMode) usage(); +# endif // USE_MSRPC + if (!IsNTService) installService = 1; // Install + break; + + case 'S': + if (!IsNTService) installService = 2; // Remove + break; +# endif // _NTSERVICE + +# ifndef NO_STRICT_MODES + + case 'K': + WhitelistingLevel = (int_fast8_t)getOptionArgumentInt((char)o, 0, 3); + ignoreIniFileParameter(INI_PARAM_WHITELISTING_LEVEL); + break; + + case 'c': + if (!getArgumentBool(&CheckClientTime, optarg)) usage(); + ignoreIniFileParameter(INI_PARAM_CHECK_CLIENT_TIME); + break; + +# ifndef NO_CLIENT_LIST + case 'E': + if (!getArgumentBool(&StartEmpty, optarg)) usage(); + ignoreIniFileParameter(INI_PARAM_START_EMPTY); + break; + + case 'M': + if (!getArgumentBool(&MaintainClients, optarg)) usage(); + ignoreIniFileParameter(INI_PARAM_MAINTAIN_CLIENTS); + break; + +# endif // !NO_CLIENT_LIST +# endif // !NO_STRICT_MODES + + case 'D': +# ifndef _WIN32 + nodaemon = 1; +# else // _WIN32 +# ifdef _PEDANTIC + printerrorf("Warning: Option -D has no effect in the Windows version of vlmcsd.\n"); +# endif // _PEDANTIC +# endif // _WIN32 + break; + +# ifndef NO_LOG + + case 'e': + logstdout = 1; + break; + +# endif // NO_LOG +# endif // NO_SOCKETS + +# ifndef NO_RANDOM_EPID + case 'r': + RandomizationLevel = (int_fast8_t)getOptionArgumentInt((char)o, 0, 2); + ignoreIniFileParameter(INI_PARAM_RANDOMIZATION_LEVEL); + break; + + case 'C': + Lcid = (uint16_t)getOptionArgumentInt((char)o, 0, 32767); + + ignoreIniFileParameter(INI_PARAM_LCID); + +# ifdef _PEDANTIC + if (!IsValidLcid(Lcid)) + { + printerrorf("Warning: %s is not a valid LCID.\n", optarg); + } +# endif // _PEDANTIC + + break; + + case 'H': + HostBuild = (uint16_t)getOptionArgumentInt((char)o, 0, 0xffff); + ignoreIniFileParameter(INI_PARAM_HOST_BUILD); + break; +# endif // NO_RANDOM_PID + +# if !defined(NO_USER_SWITCH) && !defined(_WIN32) + case 'g': + gname = optarg; + ignoreIniFileParameter(INI_PARAM_GID); +# ifndef NO_SIGHUP + if (!IsRestarted) +# endif // NO_SIGHUP + if (GetGid()) + { + printerrorf("Fatal: %s for %s failed: %s\n", "setgid", gname, strerror(errno)); + exit(errno); + } + break; + + case 'u': + uname = optarg; + ignoreIniFileParameter(INI_PARAM_UID); +# ifndef NO_SIGHUP + if (!IsRestarted) +# endif // NO_SIGHUP + if (GetUid()) + { + printerrorf("Fatal: %s for %s failed: %s\n", "setuid", uname, strerror(errno)); + exit(errno); + } + break; +# endif // NO_USER_SWITCH && !_WIN32 + +# ifndef NO_CUSTOM_INTERVALS + case 'R': + VLRenewalInterval = getTimeSpanFromCommandLine(optarg, (char)o); + ignoreIniFileParameter(INI_PARAM_RENEWAL_INTERVAL); + break; + + case 'A': + VLActivationInterval = getTimeSpanFromCommandLine(optarg, (char)o); + ignoreIniFileParameter(INI_PARAM_ACTIVATION_INTERVAL); + break; +# endif // NO_CUSTOM_INTERVALS + +# ifndef USE_MSRPC + case 'd': + case 'k': + DisconnectImmediately = o == 'd'; + ignoreIniFileParameter(INI_PARAM_DISCONNECT_IMMEDIATELY); + break; + +# ifndef SIMPLE_RPC + case 'N': + if (!getArgumentBool(&UseServerRpcNDR64, optarg)) usage(); + IsNDR64Defined = TRUE; + ignoreIniFileParameter(INI_PARAM_RPC_NDR64); + break; + + case 'B': + if (!getArgumentBool(&UseServerRpcBTFN, optarg)) usage(); + ignoreIniFileParameter(INI_PARAM_RPC_BTFN); + break; +# endif // !SIMPLE_RPC +# endif // !USE_MSRPC + +# ifndef NO_VERSION_INFORMATION + case 'V': +# ifdef _NTSERVICE + if (IsNTService) break; +# endif +# if defined(__s390__) && !defined(__zarch__) && !defined(__s390x__) + printf("vlmcsd %s %i-bit\n", Version, sizeof(void*) == 4 ? 31 : (int)sizeof(void*) << 3); +# else + printf("vlmcsd %s %i-bit\n", Version, (int)sizeof(void*) << 3); +# endif // defined(__s390__) && !defined(__zarch__) && !defined(__s390x__) + printPlatform(); + printCommonFlags(); + printServerFlags(); + exit(0); +# endif // NO_VERSION_INFORMATION + + default: + usage(); + } + + // Do not allow non-option arguments + if (optind != global_argc) + usage(); + +# ifdef _NTSERVICE + // -U and -W must be used with -s + if ((ServiceUser || *ServicePassword) && installService != 1) usage(); +# endif // _NTSERVICE +} + + +#if !defined(NO_PID_FILE) +static void writePidFile() +{ +# ifndef NO_SIGHUP + if (IsRestarted) return; +# endif // NO_SIGHUP + + if (fn_pid && !InetdMode) + { + FILE* file = fopen(fn_pid, "w"); + + if (file) + { +# if _MSC_VER + fprintf(file, "%u", (unsigned int)GetCurrentProcessId()); +# else + fprintf(file, "%u", (unsigned int)getpid()); +# endif + fclose(file); + } + +# ifndef NO_LOG + else + { + logger("Warning: Cannot write pid file '%s'. %s.\n", fn_pid, strerror(errno)); + } +# endif // NO_LOG + } +} +#else +#define writePidFile() +#endif // !defined(NO_PID_FILE) + +#if !defined(NO_SOCKETS) && !defined(USE_MSRPC) + +void cleanup() +{ + if (!InetdMode) + { +# ifndef NO_CLIENT_LIST + if (MaintainClients) CleanUpClientLists(); +# endif // !NO_CLIENT_LIST + +# ifndef NO_PID_FILE + if (fn_pid) vlmcsd_unlink(fn_pid); +# endif // NO_PID_FILE + closeAllListeningSockets(); + +# if !defined(NO_LIMIT) && !defined(NO_SOCKETS) && !defined(_WIN32) && !__minix__ + sem_unlink("/vlmcsd"); +# if !defined(USE_THREADS) && !defined(CYGWIN) + if (shmid >= 0) + { + if (MaxTaskSemaphore != (sem_t*)-1) shmdt(MaxTaskSemaphore); + shmctl(shmid, IPC_RMID, NULL); + } +# endif // !defined(USE_THREADS) && !defined(CYGWIN) +# endif // !defined(NO_LIMIT) && !defined(NO_SOCKETS) && !defined(_WIN32) && !__minix__ + +# ifndef NO_LOG + logger("vlmcsd %s was shutdown\n", Version); +# endif // NO_LOG + } +} + +#elif defined(USE_MSRPC) + +void cleanup() +{ +# ifndef NO_PID_FILE + if (fn_pid) unlink(fn_pid); +# endif // NO_PID_FILE + +# ifndef NO_LOG + logger("vlmcsd %s was shutdown\n", Version); +# endif // NO_LOG +} + +#else // Neither Sockets nor RPC + +__pure void cleanup() {} + +#endif // Neither Sockets nor RPC + + +#if !defined(USE_MSRPC) && !defined(NO_LIMIT) && !defined(NO_SOCKETS) && !__minix__ +// Get a semaphore for limiting the maximum concurrent tasks +static void allocateSemaphore(void) +{ +# ifdef USE_THREADS +# define sharemode 0 +# else +# define sharemode 1 +# endif + +# ifndef _WIN32 + sem_unlink("/vlmcsd"); +# endif + + if (MaxTasks < SEM_VALUE_MAX && !InetdMode) + { +# ifndef _WIN32 + +# if !defined(USE_THREADS) && !defined(CYGWIN) + + if ((MaxTaskSemaphore = sem_open("/vlmcsd", O_CREAT /*| O_EXCL*/, 0700, MaxTasks)) == SEM_FAILED) // fails on many systems + { + // We didn't get a named Semaphore (/dev/shm on Linux) so let's try our own shared page + + if ( + (shmid = shmget(IPC_PRIVATE, sizeof(sem_t), IPC_CREAT | 0600)) < 0 || + (MaxTaskSemaphore = (sem_t*)shmat(shmid, NULL, 0)) == (sem_t*)-1 || + sem_init(MaxTaskSemaphore, 1, MaxTasks) < 0 + ) + { + int errno_save = errno; + if (MaxTaskSemaphore != (sem_t*)-1) shmdt(MaxTaskSemaphore); + if (shmid >= 0) shmctl(shmid, IPC_RMID, NULL); + printerrorf("Warning: Could not create semaphore: %s\n", vlmcsd_strerror(errno_save)); + MaxTasks = SEM_VALUE_MAX; + } + } + +# else // THREADS or CYGWIN + + MaxTaskSemaphore = (sem_t*)vlmcsd_malloc(sizeof(sem_t)); + + if (sem_init(MaxTaskSemaphore, sharemode, MaxTasks) < 0) // sem_init is not implemented on Darwin (returns ENOSYS) + { + free(MaxTaskSemaphore); + + if ((MaxTaskSemaphore = sem_open("/vlmcsd", O_CREAT /*| O_EXCL*/, 0700, MaxTasks)) == SEM_FAILED) + { + printerrorf("Warning: Could not create semaphore: %s\n", vlmcsd_strerror(errno)); + MaxTasks = SEM_VALUE_MAX; + } + } + +# endif // THREADS or CYGWIN + +# else // _WIN32 + + if (!((MaxTaskSemaphore = CreateSemaphoreA(NULL, MaxTasks, MaxTasks, NULL)))) + { + printerrorf("Warning: Could not create semaphore: %s\n", vlmcsd_strerror(GetLastError())); + MaxTasks = SEM_VALUE_MAX; + } + +# endif // _WIN32 + } +} +#endif // !defined(NO_LIMIT) && !defined(NO_SOCKETS) && !__minix__ + + +#if !defined(NO_SOCKETS) && !defined(USE_MSRPC) && !defined(SIMPLE_SOCKETS) +int setupListeningSockets() +{ + int o; +# if HAVE_GETIFADDR + char** privateIPList = NULL; + int numPrivateIPs = 0; + if (PublicIPProtectionLevel & 1) getPrivateIPAddresses(&numPrivateIPs, &privateIPList); + const uint_fast8_t allocsockets = (uint_fast8_t)(maxsockets ? (maxsockets + numPrivateIPs) : ((PublicIPProtectionLevel & 1) ? numPrivateIPs : 2)); +# else // !HAVE_GETIFADDR + uint_fast8_t allocsockets = maxsockets ? maxsockets : 2; +# endif // !HAVE_GETIFADDR + + SocketList = (SOCKET*)vlmcsd_malloc((size_t)allocsockets * sizeof(SOCKET)); + + const int_fast8_t haveIPv4Stack = checkProtocolStack(AF_INET); + const int_fast8_t haveIPv6Stack = checkProtocolStack(AF_INET6); + + // Reset getopt since we've alread used it + optReset(); + + for (opterr = 0; (o = getopt(global_argc, (char* const*)global_argv, (const char*)optstring)) > 0; ) switch (o) + { + case 'P': + defaultport = optarg; + break; + + case 'L': + addListeningSocket(optarg); + break; + + default: + break; + } + + +# ifndef NO_INI_FILE + if (maxsockets && !numsockets) + { + if (fn_ini && !readIniFile(INI_FILE_PASS_3)) + { +# ifdef INI_FILE + if (strcmp(fn_ini, INI_FILE)) +# endif // INI_FILE + printerrorf("Warning: Can't read %s: %s\n", fn_ini, strerror(errno)); + } + } +# endif + +# if HAVE_GETIFADDR + if (PublicIPProtectionLevel & 1) + { + int i; + for (i = 0; i < numPrivateIPs; i++) + { + addListeningSocket(privateIPList[i]); + free(privateIPList[i]); + } + + free(privateIPList); + } +# endif // HAVE_GETIFADDR + + // if -L hasn't been specified on the command line, use default sockets (all IP addresses) + // maxsocket results from first pass parsing the arguments + if (!maxsockets) + { +# if HAVE_GETIFADDR + if (!(PublicIPProtectionLevel & 1) && haveIPv6Stack) addListeningSocket("::"); + if (!(PublicIPProtectionLevel & 1) && haveIPv4Stack) addListeningSocket("0.0.0.0"); +# else // !HAVE_GETIFADDR + if (haveIPv6Stack) addListeningSocket("::"); + if (haveIPv4Stack) addListeningSocket("0.0.0.0"); +# endif // !HAVE_GETIFADDR + } + + if (!numsockets) + { + printerrorf("Fatal: Could not listen on any socket.\n"); + return(!0); + } + + return 0; +} +#endif // !defined(NO_SOCKETS) && !defined(USE_MSRPC) && !defined(SIMPLE_SOCKETS) + + +int server_main(int argc, CARGV argv) +{ + global_argc = argc; + global_argv = argv; + +# ifdef _NTSERVICE + DWORD lasterror = ERROR_SUCCESS; + + if (!StartServiceCtrlDispatcher(NTServiceDispatchTable) && (lasterror = GetLastError()) == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) + { + IsNTService = FALSE; + return newmain(); + } + + return lasterror; +# else // !_NTSERVICE + return newmain(); +# endif // !_NTSERVICE +} + + +int newmain() +{ + // Initialize thread synchronization objects for Windows and Cygwin +# ifdef USE_THREADS + +# ifndef NO_LOG +// Initialize the Critical Section for proper logging +# if _WIN32 || __CYGWIN__ + InitializeCriticalSection(&logmutex); +# endif // _WIN32 || __CYGWIN__ +# endif // NO_LOG + +# endif // USE_THREADS + +# ifdef _WIN32 + +# ifndef USE_MSRPC + WSADATA wsadata; + { + // Windows Sockets must be initialized + int error; + if ((error = WSAStartup(0x0202, &wsadata))) + { + printerrorf("Fatal: Could not initialize Windows sockets (Error: %d).\n", error); + return error; + } + } +# endif // USE_MSRPC + + // Windows can never daemonize + //nodaemon = 1; + +# else // __CYGWIN__ + + // Do not daemonize if we are a Windows service +# ifdef _NTSERVICE + if (IsNTService) nodaemon = 1; +# endif + +# endif // _WIN32 / __CYGWIN__ + + parseGeneralArguments(); // Does not return if an error occurs + +# if !defined(_WIN32) && !defined(NO_SOCKETS) && !defined(USE_MSRPC) + + struct stat statbuf; + fstat(STDIN_FILENO, &statbuf); + + if (S_ISSOCK(statbuf.st_mode)) + { + InetdMode = 1; +# ifndef NO_CLIENT_LIST + MaintainClients = FALSE; +# endif // !NO_CLIENT_LIST + nodaemon = 1; +# ifndef SIMPLE_SOCKETS + maxsockets = 0; +# endif // !SIMPLE_SOCKETS +# ifndef NO_LOG + logstdout = 0; +# endif // !NO_LOG + } + +# endif // !defined(_WIN32) && !defined(NO_SOCKETS) && !defined(USE_MSRPC) + +# ifndef NO_INI_FILE + + if (fn_ini && !readIniFile(INI_FILE_PASS_1)) + { +# ifdef INI_FILE + if (strcmp(fn_ini, INI_FILE)) +# endif // INI_FILE + printerrorf("Warning: Can't read %s: %s\n", fn_ini, strerror(errno)); + } + +# endif // NO_INI_FILE + + loadKmsData(); + +# if !defined(USE_MSRPC) && !defined(SIMPLE_RPC) + + if + ( + !IsNDR64Defined + ) + { + UseServerRpcNDR64 = !!(KmsData->Flags & KMS_OPTIONS_USENDR64); +# ifndef NO_RANDOM_EPID + if (HostBuild && RandomizationLevel) + { + UseServerRpcNDR64 = HostBuild > 7601; + } +# endif + } +# endif // !defined(USE_MSRPC) && !defined(SIMPLE_RPC) + +# if !defined(NO_RANDOM_EPID) || !defined(NO_CL_PIDS) || !defined(NO_INI_FILE) + KmsResponseParameters = (KmsResponseParam_t*)vlmcsd_malloc(sizeof(KmsResponseParam_t) * KmsData->CsvlkCount); + memset(KmsResponseParameters, 0, sizeof(KmsResponseParam_t) * KmsData->CsvlkCount); +# endif // !defined(NO_RANDOM_EPID) || !defined(NO_CL_PIDS) || !defined(NO_INI_FILE) + +#ifndef NO_CL_PIDS + optReset(); + int o; + + for (opterr = 0; (o = getopt(global_argc, (char* const*)global_argv, (const char*)optstring)) > 0; ) switch (o) + { + case 'a': + if (!handleIniFileEpidParameter(optarg, FALSE, "command line")) + { + usage(); + } + + break; + + default: + break; + } + +#endif // NO_CL_PIDS + +# ifndef NO_INI_FILE + + if (fn_ini && !readIniFile(INI_FILE_PASS_2)) + { +# ifdef INI_FILE + if (strcmp(fn_ini, INI_FILE)) +# endif // INI_FILE + printerrorf("Warning: Can't read %s: %s\n", fn_ini, strerror(errno)); + } + +# endif // NO_INI_FILE + +# ifndef NO_CLIENT_LIST + if (MaintainClients) InitializeClientLists(); +# endif // !NO_CLIENT_LIST + +# if defined(USE_MSRPC) && !defined(NO_PRIVATE_IP_DETECT) + if (PublicIPProtectionLevel) + { + printerrorf("Warning: Public IP address protection using MS RPC is poor. See vlmcsd.8\n"); + } +# endif // defined(USE_MSRPC) && !defined(NO_PRIVATE_IP_DETECT) + +# if !defined(NO_LIMIT) && !defined(NO_SOCKETS) && !__minix__ && !defined(USE_MSRPC) + allocateSemaphore(); +# endif // !defined(NO_LIMIT) && !defined(NO_SOCKETS) && __minix__ + +# ifdef _NTSERVICE + if (installService) + return NtServiceInstallation(installService, ServiceUser, ServicePassword); +# endif // _NTSERVICE + +# ifndef NO_TAP + if (tapArgument && !InetdMode) startTap(tapArgument); +# endif // NO_TAP + +# if !defined(NO_SOCKETS) && !defined(USE_MSRPC) + if (!InetdMode) + { + int error; +# ifdef SIMPLE_SOCKETS + if ((error = listenOnAllAddresses())) return error; +# else // !SIMPLE_SOCKETS + if ((error = setupListeningSockets())) return error; +# endif // !SIMPLE_SOCKETS + } +# endif // !defined(NO_SOCKETS) && !defined(USE_MSRPC) + + // After sockets have been set up, we may switch to a lower privileged user +# if !defined(_WIN32) && !defined(NO_USER_SWITCH) + +# ifndef NO_SIGHUP + if (!IsRestarted) + { +# endif // NO_SIGHUP + if (gid != INVALID_GID) + { + if (setgid(gid)) + { + printerrorf("Fatal: %s for %s failed: %s\n", "setgid", gname, strerror(errno)); + return errno; + } + + if (setgroups(1, &gid)) + { + printerrorf("Fatal: %s for %s failed: %s\n", "setgroups", gname, strerror(errno)); + return errno; + } + } + + if (uid != INVALID_UID && setuid(uid)) + { + printerrorf("Fatal: %s for %s failed: %s\n", "setuid", uname, strerror(errno)); + return errno; + } +# ifndef NO_SIGHUP + } +# endif // NO_SIGHUP + +# endif // !defined(_WIN32) && !defined(NO_USER_SWITCH) + + randomNumberInit(); + + // Randomization Level 1 means generate ePIDs at startup and use them during + // the lifetime of the process. So we generate them now +# ifndef NO_RANDOM_EPID + if (RandomizationLevel == 1) randomPidInit(); +# if !defined(NO_LOG) && !defined(NO_VERBOSE_LOG) + if (logverbose) + { + int32_t i; + + for (i = 0; i < KmsData->CsvlkCount; i++) + { + const CsvlkData_t* const csvlk = KmsData->CsvlkData + i; + const char* csvlkIniName = getNextString(csvlk->EPid); + const char* csvlkFullName = getNextString(csvlkIniName); + csvlkFullName = *csvlkFullName ? csvlkFullName : "unknown"; + const char* ePid = KmsResponseParameters[i].Epid ? KmsResponseParameters[i].Epid : RandomizationLevel == 2 ? "" : csvlk->EPid; + logger("Using CSVLK %s (%s) with %s ePID %s\n", csvlkIniName, csvlkFullName, (RandomizationLevel == 1 && KmsResponseParameters[i].IsRandom) || (RandomizationLevel == 2 && !KmsResponseParameters[i].Epid) ? "random" : "fixed", ePid); + } + } +# endif // !defined(NO_LOG) && !defined(NO_VERBOSE_LOG) +# endif + +# if !defined(NO_SOCKETS) +# ifdef _WIN32 + if (!IsNTService) + { +# endif // _WIN32 + int error; + if ((error = daemonizeAndSetSignalAction())) return error; +# ifdef _WIN32 + } +# endif // _WIN32 +# endif // !defined(NO_SOCKETS) + + writePidFile(); + +# if !defined(NO_LOG) && !defined(NO_SOCKETS) && !defined(USE_MSRPC) + if (!InetdMode) + logger("vlmcsd %s started successfully\n", Version); +# endif // !defined(NO_LOG) && !defined(NO_SOCKETS) && !defined(USE_MSRPC) + +# if defined(_NTSERVICE) && !defined(USE_MSRPC) + if (IsNTService) ReportServiceStatus(SERVICE_RUNNING, NO_ERROR, 200); +# endif // defined(_NTSERVICE) && !defined(USE_MSRPC) + + int rc; + rc = runServer(); + + // Clean up things and exit +# ifdef _NTSERVICE + if (!ServiceShutdown) +# endif + cleanup(); +# ifdef _NTSERVICE + else + ReportServiceStatus(SERVICE_STOPPED, NO_ERROR, 0); +# endif + + return rc; +} + + +#if _MSC_VER && !defined(_DEBUG)&& !MULTI_CALL_BINARY +int __stdcall WinStartUp(void) +{ + WCHAR** szArgList; + int argc; + szArgList = CommandLineToArgvW(GetCommandLineW(), &argc); + + int i; + char** argv = (char**)vlmcsd_malloc(sizeof(char*) * argc); + + for (i = 0; i < argc; i++) + { + int size = WideCharToMultiByte(CP_UTF8, 0, szArgList[i], -1, argv[i], 0, NULL, NULL); + argv[i] = (char*)vlmcsd_malloc(size); + WideCharToMultiByte(CP_UTF8, 0, szArgList[i], -1, argv[i], size, NULL, NULL); + } + + exit(server_main(argc, argv)); +} +#endif // _MSC_VER && !defined(_DEBUG)&& !MULTI_CALL_BINARY diff --git a/vlmcsd/src/vlmcsd.h b/vlmcsd/src/vlmcsd.h new file mode 100644 index 0000000..99e8497 --- /dev/null +++ b/vlmcsd/src/vlmcsd.h @@ -0,0 +1,71 @@ +#ifndef __main_h +#define __main_h + +#ifndef CONFIG +#define CONFIG "config.h" +#endif // CONFIG +#include CONFIG + +#define __T(x) #x +#define _T(x) __T(x) + +extern char *fn_log; + +#include "types.h" + +//int main(int argc, CARGV); +extern void cleanup(); + +int newmain(); + +#if MULTI_CALL_BINARY < 1 +#define server_main main +#else +int server_main(int argc, CARGV argv); +#endif + +#ifndef SA_NOCLDWAIT // required for Cygwin +#define SA_NOCLDWAIT 0 +#endif + +#if !defined(NO_INI_FILE) || !defined(NO_CL_PIDS) +#define INI_PARAM_RANDOMIZATION_LEVEL 1 +#define INI_PARAM_LCID 2 +#define INI_PARAM_LISTEN 3 +#define INI_PARAM_MAX_WORKERS 4 +#define INI_PARAM_CONNECTION_TIMEOUT 5 +#define INI_PARAM_PID_FILE 6 +#define INI_PARAM_LOG_FILE 7 +#define INI_PARAM_LOG_VERBOSE 8 +#define INI_PARAM_ACTIVATION_INTERVAL 9 +#define INI_PARAM_RENEWAL_INTERVAL 10 +#define INI_PARAM_DISCONNECT_IMMEDIATELY 11 +#define INI_PARAM_UID 12 +#define INI_PARAM_GID 13 +#define INI_PARAM_PORT 14 +#define INI_PARAM_RPC_NDR64 15 +#define INI_PARAM_RPC_BTFN 16 +#define INI_PARAM_FREEBIND 17 +#define INI_PARAM_PUBLIC_IP_PROTECTION_LEVEL 18 +#define INI_PARAM_LOG_DATE_AND_TIME 19 +#define INI_PARAM_HOST_BUILD 20 +#define INI_PARAM_WHITELISTING_LEVEL 24 +#define INI_PARAM_CHECK_CLIENT_TIME 25 +#define INI_PARAM_MAINTAIN_CLIENTS 26 +#define INI_PARAM_START_EMPTY 27 +#define INI_PARAM_DATA_FILE 28 +#define INI_PARAM_VPN 29 +#define INI_PARAM_EXIT_LEVEL 30 + +#define INI_FILE_PASS_1 1 +#define INI_FILE_PASS_2 2 +#define INI_FILE_PASS_3 3 + +typedef struct IniFileParameter +{ + const char* const Name; + uint_fast8_t Id; +} IniFileParameter_t, *PIniFileParameter_t; +#endif // NO_INI_FILE + +#endif // __main_h diff --git a/vlmcsd/src/vlmcsdmulti.c b/vlmcsd/src/vlmcsdmulti.c new file mode 100644 index 0000000..442abbb --- /dev/null +++ b/vlmcsd/src/vlmcsdmulti.c @@ -0,0 +1,121 @@ +/* Multi-Call Binary for vlmcs and vlmcsd */ + +#define _CRT_SECURE_NO_WARNINGS + +#ifndef CONFIG +#define CONFIG "config.h" +#endif // CONFIG +#include CONFIG + +#if MULTI_CALL_BINARY < 1 +#error "Please define MULTI_CALL_BINARY=1 when compiling this file." +#endif + +#include + +#if !_MSC_VER +#include +#else // _MSC_VER +#include +#include "helpers.h" +#endif // _MSC_VER + +#include "vlmcs.h" +#include "vlmcsd.h" +#include "types.h" +#include "shared_globals.h" +#include "output.h" + +#if (defined(_WIN32) || defined(__CYGWIN__)) +#define compare strcasecmp // Best for case-preserving (but otherwise case-insensitive) filesystems +#else // native Unix +#define compare strcmp // for case-sensitive filesystems +#endif // native Unix + +#if _MSC_VER +static char* basename(const char* fullname) +{ + size_t len = strlen(fullname); + char* filename = (char*)vlmcsd_malloc(len + 1); + char* extension = (char*)vlmcsd_malloc(len + 1); + static char result[64]; + + _splitpath(fullname, NULL, NULL, filename, extension); + + if (strlen(filename) + strlen(extension) > 63) + { + *result = 0; + goto finally; + } + + strcpy(result, filename); + strcat(result, extension); + + finally: + free(filename); + free(extension); + + return result; +} +#endif // _MSC_VER + +int main(int argc, CARGV argv) +{ + multi_argv = argv; + multi_argc = argc; + + if (!compare(basename((char*)*argv), "vlmcsd")) + return server_main(argc, argv); + + if (!compare(basename((char*)*argv), "vlmcs")) + return client_main(argc, argv); + +#ifdef _WIN32 + if (!compare(basename((char*)*argv), "vlmcsd.exe")) + return server_main(argc, argv); + + if (!compare(basename((char*)*argv), "vlmcs.exe")) + return client_main(argc, argv); +#endif // _WIN32 + + if (argc > 1) + { + if (!strcmp((char*)argv[1], "vlmcsd")) + return server_main(argc - 1, argv + 1); + + if (!strcmp((char*)argv[1], "vlmcs")) + return client_main(argc - 1, argv + 1); + } + + errorout( + "vlmcsdmulti %s\n\n" + "Usage:\n" + "\t%s vlmcsd []\n" + "\t%s vlmcs []\n\n", + Version, *argv, *argv + ); + + return VLMCSD_EINVAL; +} + + +#if _MSC_VER && !defined(_DEBUG) +int __stdcall WinStartUp(void) +{ + WCHAR **szArgList; + int argc; + szArgList = CommandLineToArgvW(GetCommandLineW(), &argc); + + int i; + char **argv = (char**)vlmcsd_malloc(sizeof(char*)*argc); + + for (i = 0; i < argc; i++) + { + int size = WideCharToMultiByte(CP_UTF8, 0, szArgList[i], -1, argv[i], 0, NULL, NULL); + argv[i] = (char*)vlmcsd_malloc(size); + WideCharToMultiByte(CP_UTF8, 0, szArgList[i], -1, argv[i], size, NULL, NULL); + } + + exit(main(argc, argv)); +} +#endif // _MSC_VER && !defined(_DEBUG)&& !MULTI_CALL_BINARY diff --git a/vlmcsd/src/wingetopt.c b/vlmcsd/src/wingetopt.c new file mode 100644 index 0000000..f357950 --- /dev/null +++ b/vlmcsd/src/wingetopt.c @@ -0,0 +1,78 @@ +/* +POSIX getopt for Windows + +AT&T Public License + +Code given out at the 1985 UNIFORUM conference in Dallas. +Modified for vlmcsd by Hotbird64 +*/ + +#ifdef _MSC_VER + +#include "wingetopt.h" +//#include +#include + +#define EOF (-1) +#define ERR(s, c) if(opterr){\ + char errbuf[2];\ + errbuf[0] = c; errbuf[1] = '\n';\ + fputs(argv[0], stderr);\ + fputs(s, stderr);\ + fputc(c, stderr);} +//(void) write(2, argv[0], (unsigned)strlen(argv[0]));\ + //(void) write(2, s, (unsigned)strlen(s));\ + //(void) write(2, errbuf, 2);} + +int opterr = 1; +int optind = 1; +int optopt; +char* optarg; + +int getopt(int argc, char * const argv[], const char *opts) +{ + static int sp = 1; + register int c; + register char *cp; + + if (sp == 1) + if (optind >= argc || + argv[optind][0] != '-' || argv[optind][1] == '\0') + return(EOF); + else if (strcmp(argv[optind], "--") == 0) { + optind++; + return(EOF); + } + optopt = c = argv[optind][sp]; + if (c == ':' || (cp = strchr(opts, c)) == NULL) { + //ERR(": illegal option -- ", (char)c); + if (argv[optind][++sp] == '\0') { + optind++; + sp = 1; + } + return('?'); + } + if (*++cp == ':') { + if (argv[optind][sp + 1] != '\0') + optarg = (char*)&argv[optind++][sp + 1]; + else if (++optind >= argc) { + //ERR(": option requires an argument -- ", (char)c); + sp = 1; + return('?'); + } + else + optarg = (char*)argv[optind++]; + sp = 1; + } + else { + if (argv[optind][++sp] == '\0') { + sp = 1; + optind++; + } + optarg = NULL; + } + return(c); +} + +#endif // _MSC_VER + diff --git a/vlmcsd/src/wingetopt.h b/vlmcsd/src/wingetopt.h new file mode 100644 index 0000000..2294a3a --- /dev/null +++ b/vlmcsd/src/wingetopt.h @@ -0,0 +1,31 @@ +/* +POSIX getopt for Windows + +AT&T Public License + +Code given out at the 1985 UNIFORUM conference in Dallas. +Modified for vlmcsd by Hotbird64 +*/ + +#ifndef _WINGETOPT_H_ +#define _WINGETOPT_H_ + +#ifdef _MSC_VER + + +#ifdef __cplusplus +extern "C" { +#endif + + extern int opterr; + extern int optind; + extern int optopt; + extern char *optarg; + extern int getopt(int argc, char * const argv[], const char *optstring); + +#ifdef __cplusplus +} +#endif + +#endif // _MSC_VER +#endif // __wingetopt_h diff --git a/vlmcsd/src/wintap.c b/vlmcsd/src/wintap.c new file mode 100644 index 0000000..79a94b2 --- /dev/null +++ b/vlmcsd/src/wintap.c @@ -0,0 +1,372 @@ +#ifndef _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#endif + +#ifndef CONFIG +#define CONFIG "config.h" +#endif // CONFIG +#include CONFIG +#include "helpers.h" +#include "wintap.h" + +#ifndef NO_TAP + +#include "types.h" +#include "endian.h" +#include "output.h" +#include "tap-windows.h" +#include + +#if !_WIN32 +#include +#endif // !_WIN32 + +static char* szIpAddress = "10.10.10.9"; +static char* szMask = "30"; +static char* szTapName; +static char *ActiveTapName, *AdapterClass; +static char* szLeaseDuration = "1d"; +static uint32_t IpAddress, Mask, Network, Broadcast, DhcpServer; // These are host-endian (=little-endian) for easier calculations +static uint32_t Mtu; +static uint_fast8_t Cidr; +static HANDLE TapHandle; +static TapDriverVersion_t DriverVersion; +static IpPacket_t* IpPacket; +static uint32_t DhcpLeaseDuration; + + +static BOOL isAddressAssigned() +{ + PMIB_IPADDRTABLE pIPAddrTable; + DWORD dwSize = 0; + BOOL result = FALSE; + + pIPAddrTable = (PMIB_IPADDRTABLE)vlmcsd_malloc(sizeof(MIB_IPADDRTABLE)); + const DWORD status = GetIpAddrTable(pIPAddrTable, &dwSize, 0); + free(pIPAddrTable); + + if (status != ERROR_INSUFFICIENT_BUFFER) return FALSE; + pIPAddrTable = (MIB_IPADDRTABLE *)vlmcsd_malloc(dwSize); + + if (GetIpAddrTable(pIPAddrTable, &dwSize, 0)) + { + free(pIPAddrTable); + return FALSE; + } + + PMIB_IPADDRROW row; + for (row = pIPAddrTable->table; row < pIPAddrTable->table + pIPAddrTable->dwNumEntries; row++) + { + if ( + row->dwAddr == BE32(IpAddress) && + !(row->wType & (MIB_IPADDR_DELETED | MIB_IPADDR_DISCONNECTED | MIB_IPADDR_TRANSIENT)) + ) + { + result = TRUE; + break; + } + } + + free(pIPAddrTable); + return result; +} + + +static void parseTapArgument(char* argument) +{ + char* equalSignPosition = strchr(argument, (int)'='); + char* slashPosition = strchr(argument, (int)'/'); + char* colonPosition = strchr(argument, (int)':'); + + szTapName = argument; + + if (equalSignPosition) + { + *equalSignPosition = 0; + szIpAddress = equalSignPosition + 1; + } + + if (slashPosition) + { + *slashPosition = 0; + szMask = slashPosition + 1; + } + + if (colonPosition) + { + *colonPosition = 0; + szLeaseDuration = colonPosition + 1; + } + + IpAddress = BE32(inet_addr(szIpAddress)); + + if (IpAddress == BE32(INADDR_NONE)) + { + printerrorf("Fatal: %s is not a valid IPv4 address\n", szIpAddress); + exit(VLMCSD_EINVAL); + } + + char* next; + Cidr = (uint8_t)strtol(szMask, &next, 10); + + if (*next || Cidr < 8 || Cidr > 30) + { + printerrorf("Fatal: /%s is not a valid CIDR mask between /8 and /30\n", szMask); + exit(VLMCSD_EINVAL); + } + + if (!((DhcpLeaseDuration = timeSpanString2Seconds(szLeaseDuration)))) + { + printerrorf("Fatal: No valid time span specified in option -%c.\n", 'O'); + exit(VLMCSD_EINVAL); + } + + Mask = (uint32_t)~(0xffffffff >> Cidr); + Network = IpAddress & Mask; + Broadcast = IpAddress | ~Mask; + DhcpServer = IpAddress + 1; + + if (IpAddress <= Network || IpAddress + 1 >= Broadcast) + { + uint32_t lowerIpBE = BE32(Network + 1); + uint32_t upperIpBE = BE32(Broadcast - 2); + const char* szLower = vlmcsd_strdup(inet_ntoa(*(struct in_addr*)&lowerIpBE)); + const char* szUpper = vlmcsd_strdup(inet_ntoa(*(struct in_addr*)&upperIpBE)); + + printerrorf("Fatal: For this subnet the IPv4 address must be "); + + if (lowerIpBE == upperIpBE) + { + printerrorf("%s\n", szLower); + } + else + { + printerrorf("between %s and %s\n", szLower, szUpper); + } + + exit(VLMCSD_EINVAL); + } +} + + +__noreturn static void WinErrorExit(DWORD error) +{ + printerrorf("Registry read error: %s\n", win_strerror((int)error)); + exit(error); +} + + +static HANDLE OpenTapHandle() +{ + HANDLE handle = INVALID_HANDLE_VALUE; + HKEY regAdapterKey; + DWORD regResult; + if ((regResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, ADAPTER_KEY, 0, KEY_READ | KEY_WOW64_64KEY, ®AdapterKey)) != ERROR_SUCCESS) + { + WinErrorExit(regResult); + } + + char subKeyName[TAP_REGISTRY_DATA_SIZE]; + DWORD i, subKeySize = sizeof(subKeyName); + + for (i = 0; (regResult = RegEnumKeyEx(regAdapterKey, i, subKeyName, &subKeySize, NULL, NULL, NULL, NULL)) != ERROR_NO_MORE_ITEMS; i++) + { + HKEY regSubKey; + DWORD type, regDataSize; + char regData[TAP_REGISTRY_DATA_SIZE]; + + if (regResult) WinErrorExit(regResult); + + if ((regResult = RegOpenKeyEx(regAdapterKey, subKeyName, 0, KEY_READ | KEY_WOW64_64KEY, ®SubKey)) == ERROR_SUCCESS) + { + regDataSize = sizeof(regData); + + if (RegQueryValueEx(regSubKey, "ComponentId", NULL, &type, (LPBYTE)regData, ®DataSize) == ERROR_SUCCESS) + { + if ( + type == REG_SZ && + ( + !strncmp(regData, "tap0801", sizeof(regData)) || + !strncmp(regData, "tap0901", sizeof(regData)) || + !strncmp(regData, "TEAMVIEWERVPN", sizeof(regData)) + ) + ) + { + AdapterClass = vlmcsd_strdup(regData); + regDataSize = sizeof(regData); + + if (RegQueryValueEx(regSubKey, "NetCfgInstanceId", NULL, &type, (LPBYTE)regData, ®DataSize) == ERROR_SUCCESS && type == REG_SZ) + { + HKEY connectionKey; + char connectionKeyName[TAP_REGISTRY_DATA_SIZE]; + + strncpy(connectionKeyName, NETWORK_CONNECTIONS_KEY "\\", sizeof(connectionKeyName)); + strncat(connectionKeyName, regData, sizeof(connectionKeyName) - strlen(connectionKeyName) - 1); + strncat(connectionKeyName, "\\Connection", sizeof(connectionKeyName) - strlen(connectionKeyName) - 1); + + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, connectionKeyName, 0, KEY_READ | KEY_WOW64_64KEY, &connectionKey) == ERROR_SUCCESS) + { + char deviceName[TAP_REGISTRY_DATA_SIZE]; + regDataSize = sizeof(deviceName); + + if (RegQueryValueEx(connectionKey, "Name", NULL, &type, (LPBYTE)deviceName, ®DataSize) == ERROR_SUCCESS && type == REG_SZ) + { + if (!strcmp(szTapName, ".") || !strncasecmp(szTapName, deviceName, sizeof(deviceName))) + { + ActiveTapName = vlmcsd_strdup(deviceName); + strncpy(deviceName, USERMODEDEVICEDIR, sizeof(deviceName)); + strncat(deviceName, regData, sizeof(deviceName) - strlen(deviceName) - 1); + strncat(deviceName, strcmp(AdapterClass, "TEAMVIEWERVPN") ? TAP_WIN_SUFFIX : ".dgt", sizeof(deviceName) - strlen(deviceName) - 1); + handle = CreateFile(deviceName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, NULL); + } + } + } + + RegCloseKey(connectionKey); + } + + if (handle == INVALID_HANDLE_VALUE) free(AdapterClass); + } + } + } + + RegCloseKey(regSubKey); + subKeySize = sizeof(subKeyName); + if (handle != INVALID_HANDLE_VALUE) break; + } + + RegCloseKey(regAdapterKey); + + if (handle == INVALID_HANDLE_VALUE) + { + printerrorf("Fatal: No compatible VPN adapter"); + + if (!strcmp(szTapName, ".")) + { + printerrorf("s"); + } + else + { + printerrorf(" with name \"%s\"", szTapName); + } + + printerrorf(" available for use\n"); + exit(ERROR_DEVICE_NOT_AVAILABLE); + } + + return handle; +} + + +static int DevCtl(DWORD code, void* data, DWORD len) +{ + if (!DeviceIoControl(TapHandle, code, data, len, data, len, &len, NULL)) + { + const DWORD error = GetLastError(); + printerrorf("Fatal: VPN adapter error: %s\n", win_strerror(error)); + exit(error); + } + + return len; +} + + +static DWORD WINAPI TapMirror(LPVOID data_unused) +{ + while (TRUE) + { + DWORD bytesRead, bytesWritten; + if (!ReadFile(TapHandle, IpPacket, Mtu, &bytesRead, NULL)) break; + + const uint32_t temp = IpPacket->ip_src; + IpPacket->ip_src = IpPacket->ip_dst; + IpPacket->ip_dst = temp; + + if (!WriteFile(TapHandle, IpPacket, bytesRead, &bytesWritten, NULL)) break; + +# if !defined(NO_LOG) && defined(_PEDANTIC) + if (bytesRead != bytesWritten) logger("Warning: VPN device \"%s\": %u bytes could not be written\n", ActiveTapName, bytesRead - bytesWritten); +# endif // !defined(NO_LOG) && defined(_PEDANTIC) + } + + const DWORD error = GetLastError(); + +# ifndef NO_LOG + logger("Warning: VPN thread for device \"%s\" exiting: %s\n", ActiveTapName, win_strerror(error)); +# endif // NO_LOG + + free(ActiveTapName); + CloseHandle(TapHandle); + exitOnWarningLevel(1); + return error; +} + + +void startTap(char* const argument) +{ + if (!strcmp(argument, "-")) return; + parseTapArgument(argument); + + TapHandle = OpenTapHandle(); + + // Get MTU and driver version + DevCtl(TAP_WIN_IOCTL_GET_MTU, &Mtu, sizeof(Mtu)); + DevCtl(TAP_WIN_IOCTL_GET_VERSION, &DriverVersion, sizeof(DriverVersion)); + + // Configure TUN mode + TapConfigTun_t tapTunCfg; + tapTunCfg.Address.s_addr = BE32(IpAddress); + tapTunCfg.Network.s_addr = BE32(Network); + tapTunCfg.Mask.s_addr = BE32(Mask); + DevCtl(TAP_WIN_IOCTL_CONFIG_TUN, &tapTunCfg, sizeof(tapTunCfg)); + + // Setup the drivers internal DHCP server + TapConfigDhcp_t tapDhcpCfg; + tapDhcpCfg.Address.s_addr = BE32(IpAddress); + tapDhcpCfg.Mask.s_addr = BE32(Mask); + tapDhcpCfg.DhcpServer.s_addr = BE32(IpAddress + 1); + tapDhcpCfg.LeaseDuration = DhcpLeaseDuration; + DevCtl(TAP_WIN_IOCTL_CONFIG_DHCP_MASQ, &tapDhcpCfg, sizeof(tapDhcpCfg)); + + // Connect the virtual network cable + BOOL isCableConnected = TRUE; + DevCtl(TAP_WIN_IOCTL_SET_MEDIA_STATUS, &isCableConnected, sizeof(isCableConnected)); + + // Allocate buffer and start mirror thread + IpPacket = (IpPacket_t*)vlmcsd_malloc(Mtu); + HANDLE threadHandle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)TapMirror, NULL, 0, NULL); + + if (!threadHandle) + { + DWORD error = GetLastError(); + printerrorf("Fatal: Unable to start VPN thread: %s\n", win_strerror(error)); + exit(error); + } + + CloseHandle(threadHandle); + +# ifndef NO_LOG + logger("%s %u.%u.%u device \"%s\" started\n", AdapterClass, DriverVersion.Major, DriverVersion.Minor, DriverVersion.Build, ActiveTapName); +# endif // NO_LOG + + DWORD i; + BOOL isAssigned; + + // Wait up to 4 seconds until the IP address is up and running + // so vlmcsd can actually bind to and listen on it + for (i = 0; !((isAssigned = isAddressAssigned())) && i < 20; i++) Sleep(200); + + if (!isAssigned) + { + printerrorf("Warning: IPv4 address %s not assigned\n", szIpAddress); + } + else + { +# ifndef NO_LOG + logger("IPv4 address %s assigned\n", szIpAddress); +# endif // NO_LOG + } +} + +#endif // NO_TAP + diff --git a/vlmcsd/src/wintap.h b/vlmcsd/src/wintap.h new file mode 100644 index 0000000..27b4f95 --- /dev/null +++ b/vlmcsd/src/wintap.h @@ -0,0 +1,50 @@ +#ifndef __WINTAP_H +#define __WINTAP_H + +#define TAP_REGISTRY_DATA_SIZE 256 + +// Network-Endian (= Big-Endian) +typedef struct TapConfigTun +{ + struct in_addr Address; + struct in_addr Network; + struct in_addr Mask; +} TapConfigTun_t, *PTapConfigTun_t; + +// Network-Endian (= Big-Endian), except LeaseDuration +typedef struct TapConfigDhcp +{ + struct in_addr Address; + struct in_addr Mask; + struct in_addr DhcpServer; + uint32_t LeaseDuration; // Host-Endian (=Little-Endian). Anything else is Big-Endian +} TapConfigDhcp_t, *PTapConfigDhcp_t; + +typedef struct TapDriverVersion +{ + uint32_t Major; + uint32_t Minor; + uint32_t Build; + uint32_t Revision; +} TapDriverVersion_t, *PTapDriverVersion_t; + +// Network-Endian (= Big-Endian) +typedef struct IpPacket { + uint8_t ip_hl : 4, /* header length */ + ip_v : 4; /* version */ + uint8_t ip_tos; /* type of service */ + int16_t ip_len; /* total length */ + uint16_t ip_id; /* identification */ + int16_t ip_off; /* fragment offset field */ + uint8_t ip_ttl; /* time to live */ + uint8_t ip_p; /* protocol */ + uint16_t ip_sum; /* checksum */ + uint32_t ip_src, ip_dst; /* source and dest address */ + uint8_t payload[0]; +} IpPacket_t, *PIpPacket_t; + +void startTap(char* const argument); + +#endif //__WINTAP_H + + diff --git a/zip/Makefile b/zip/Makefile new file mode 100644 index 0000000..35a1724 --- /dev/null +++ b/zip/Makefile @@ -0,0 +1,73 @@ +# +# Copyright (C) 2007-2016 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=zip +PKG_REV:=30 +PKG_VERSION:=3.0 +PKG_RELEASE:=4 + +PKG_SOURCE:=$(PKG_NAME)$(PKG_REV).tar.gz +PKG_SOURCE_URL:=@SF/infozip +PKG_HASH:=f0e8bb1f9b7eb0b01285495a2699df3a4b766784c1765a8f1aeedf63c0806369 +PKG_MAINTAINER:=Álvaro Fernández Rojas + +PKG_LICENSE:=BSD-4-Clause +PKG_LICENSE_FILES:=LICENSE + +PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)/zip$(PKG_REV) +HOST_BUILD_DIR:=$(BUILD_DIR_HOST)/$(PKG_NAME)-$(PKG_VERSION)/zip$(PKG_REV) +PKG_CHECK_FORMAT_SECURITY:=0 + +include $(INCLUDE_DIR)/host-build.mk +include $(INCLUDE_DIR)/package.mk + +define Package/zip + SECTION:=utils + CATEGORY:=Utilities + DEPENDS:= + TITLE:=Archiver for .zip files + URL:=http://infozip.sourceforge.net/Zip.html + SUBMENU:=Compression +endef + +define Package/zip/description + This is InfoZIP's zip program. It produces files that are fully + compatible with the popular PKZIP program; however, the command line + options are not identical. In other words, the end result is the same, + but the methods differ. +endef + +define Build/Configure +endef + +define Build/Compile + $(MAKE) -C $(PKG_BUILD_DIR) -f unix/Makefile generic \ + prefix="$(PKG_INSTALL_DIR)/usr" \ + CFLAGS="$(TARGET_CFLAGS)" \ + CC="$(TARGET_CC) $(TARGET_CFLAGS) -O $(TARGET_CPPFLAGS) -I. -DUNIX $(TARGET_LDFLAGS) -Wno-incompatible-pointer-types" \ + IZ_BZIP2="no" \ + install +endef + +define Package/zip/install + $(INSTALL_DIR) $(1)/usr/bin/ + $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/* $(1)/usr/bin/ +endef + +define Host/Compile + +$(HOST_MAKE_VARS) $(MAKE) $(HOST_JOBS) -C $(HOST_BUILD_DIR) -I. -f unix/Makefile generic +endef + +define Host/Install + $(INSTALL_DIR) $(STAGING_DIR_HOSTPKG)/bin/ + $(INSTALL_BIN) $(HOST_BUILD_DIR)/zip $(STAGING_DIR_HOSTPKG)/bin/ +endef + +$(eval $(call HostBuild)) +$(eval $(call BuildPackage,zip)) diff --git a/zip/patches/001-unix-configure-borrow-the-LFS-test-from-autotools.patch b/zip/patches/001-unix-configure-borrow-the-LFS-test-from-autotools.patch new file mode 100644 index 0000000..892540b --- /dev/null +++ b/zip/patches/001-unix-configure-borrow-the-LFS-test-from-autotools.patch @@ -0,0 +1,90 @@ +From fc392c939b9a18959482f588aff0afc29dd6d30a Mon Sep 17 00:00:00 2001 +From: Romain Naour +Date: Fri, 23 Jan 2015 22:20:18 +0100 +Subject: [PATCH 6/6] unix/configure: borrow the LFS test from autotools. + +Infozip's LFS check can't work for cross-compilation +since it try to run a target's binary on the host system. + +Instead, use to LFS test used by autotools which is a +compilation test. +(see autotools/lib/autoconf/specific.m4) + +Reported-by: Richard Genoud +Signed-off-by: Romain Naour +--- + configure | 46 +++++++++++++++------------------------------- + 1 file changed, 15 insertions(+), 31 deletions(-) + +diff --rupN a/unix/configure b/unix/configure +--- a/unix/configure ++++ b/unix/configure +@@ -399,9 +399,8 @@ else + fi + + +-# Now we set the 64-bit file environment and check the size of off_t +-# Added 11/4/2003 EG +-# Revised 8/12/2004 EG ++# LFS check borrowed from autotools sources ++# lib/autoconf/specific.m4 + + echo Check for Large File Support + cat > conftest.c << _EOF_ +@@ -410,23 +409,19 @@ cat > conftest.c << _EOF_ + # define _FILE_OFFSET_BITS 64 /* select default interface as 64 bit */ + # define _LARGE_FILES /* some OSes need this for 64-bit off_t */ + #include +-#include +-#include +-#include ++ ++ /* Check that off_t can represent 2**63 - 1 correctly. ++ We can't simply define LARGE_OFF_T to be 9223372036854775807, ++ since some C++ compilers masquerading as C compilers ++ incorrectly reject 9223372036854775807. */ ++#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) ++ int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 ++ && LARGE_OFF_T % 2147483647 == 1) ++ ? 1 : -1]; ++ + int main() + { +- off_t offset; +- struct stat s; +- /* see if have 64-bit off_t */ +- if (sizeof(offset) < 8) +- return 1; +- printf(" off_t is %d bytes\n", sizeof(off_t)); +- /* see if have 64-bit stat */ +- if (sizeof(s.st_size) < 8) { +- printf(" s.st_size is %d bytes\n", sizeof(s.st_size)); +- return 2; +- } +- return 3; ++ return 0; + } + _EOF_ + # compile it +@@ -434,19 +429,8 @@ $CC -o conftest conftest.c >/dev/null 2> + if [ $? -ne 0 ]; then + echo -- no Large File Support + else +-# run it +- ./conftest +- r=$? +- if [ $r -eq 1 ]; then +- echo -- no Large File Support - no 64-bit off_t +- elif [ $r -eq 2 ]; then +- echo -- no Large File Support - no 64-bit stat +- elif [ $r -eq 3 ]; then +- echo -- yes we have Large File Support! +- CFLAGS="${CFLAGS} -DLARGE_FILE_SUPPORT" +- else +- echo -- no Large File Support - conftest returned $r +- fi ++ echo -- yes we have Large File Support! ++ CFLAGS="${CFLAGS} -DLARGE_FILE_SUPPORT" + fi + + diff --git a/zip/patches/010-remove-build-date.patch b/zip/patches/010-remove-build-date.patch new file mode 100644 index 0000000..d7165cd --- /dev/null +++ b/zip/patches/010-remove-build-date.patch @@ -0,0 +1,15 @@ +From: Santiago Vila +Subject: Remove (optional) build date to make the build reproducible +Bug-Debian: http://bugs.debian.org/779042 + +--- a/unix/unix.c ++++ b/unix/unix.c +@@ -1020,7 +1020,7 @@ + + + /* Define the compile date string */ +-#ifdef __DATE__ ++#if 0 + # define COMPILE_DATE " on " __DATE__ + #else + # define COMPILE_DATE "" diff --git a/zip/patches/200-fix-build-for-gcc-14.patch b/zip/patches/200-fix-build-for-gcc-14.patch new file mode 100644 index 0000000..7168c62 --- /dev/null +++ b/zip/patches/200-fix-build-for-gcc-14.patch @@ -0,0 +1,31 @@ +--- a/timezone.c ++++ b/timezone.c +@@ -41,6 +41,7 @@ + #include "timezone.h" + #include + #include ++#include + + #ifdef IZTZ_DEFINESTDGLOBALS + long timezone = 0; +--- a/unix/configure ++++ b/unix/configure +@@ -505,7 +505,7 @@ done + echo Check for memset + echo "int main(){ char k; memset(&k,0,0); return 0; }" > conftest.c + $CC -o conftest conftest.c >/dev/null 2>/dev/null +-[ $? -ne 0 ] && CFLAGS="${CFLAGS} -DZMEM" ++[ $? -ne 0 ] && CFLAGS="${CFLAGS}" + + + echo Check for memmove +--- a/unix/unix.c ++++ b/unix/unix.c +@@ -67,7 +67,6 @@ local char *readd OF((DIR *)); + #ifndef dirent + # define dirent direct + #endif +-typedef FILE DIR; + /* + ** Apparently originally by Rich Salz. + ** Cleaned up and modified by James W. Birdsall.