From 33cedce48c6866eb307acb5549f46b4af928d494 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matteo=20=E2=84=B1an?= Date: Thu, 3 Sep 2020 23:52:59 +0200 Subject: [PATCH] Implements #88, documents adjust, uniformed default values --- .gitignore | 1 + README.md | 20 ++-- docker/README.md | 6 +- docker/docker-py3-kms-minimal/Dockerfile | 4 +- docker/docker-py3-kms/Dockerfile | 6 +- docker/docker-py3-kms/run-py3-kms.sh | 4 +- docker/docker-py3-kms/start.sh | 8 +- docs/Documentation.md | 4 +- docs/Getting Started.md | 29 +++-- docs/Usage.md | 20 ++-- py-kms/pykms_Base.py | 12 +- py-kms/pykms_Client.py | 4 +- py-kms/pykms_Server.py | 35 +++--- py-kms/pykms_Sql.py | 133 +++++++++++------------ 14 files changed, 144 insertions(+), 142 deletions(-) diff --git a/.gitignore b/.gitignore index 7520c95..2b3c3ef 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ pykms_logclient.log* pykms_newlines.txt* pykms_clean_newlines.txt* pykms_config.pickle* +pykms_database.db* etrigan.log* # Byte-compiled / optimized / DLL files diff --git a/README.md b/README.md index be04a85..81d7160 100644 --- a/README.md +++ b/README.md @@ -29,23 +29,19 @@ _py-kms_ is a port of node-kms created by [cyrozap](http://forums.mydigitallife. - Microsoft Office 2013 ( Volume License ) - Microsoft Office 2016 ( Volume License ) - Microsoft Office 2019 ( Volume License ) - - It's written in Python (tested with Python 3.6.7) + - It's written in Python (tested with Python 3.6.9). - Supports execution by `Docker`, `systemd`, `Upstart` and many more... - - Includes a GUI for simlpe managing - - Uses `sqlite` for persistent data storage + - Includes a GUI for simple managing. + - Uses `sqlite` for persistent data storage. -## [Documentation](https://py-kms.readthedocs.io/en/latest/) -The documentation has been completly reworked and is now available on [readthedocs.com](https://py-kms.readthedocs.io/en/latest/Usage.html#start-parameters). It should you provide all necessary information how to get py-kms up -and running using your favourite tools - all without clumping this readme up. The documentation also houses more information about activation with _py-kms_ and to how get GVLK keys. +## Documentation +The wiki has been completly reworked and is now available on [readthedocs.com](https://py-kms.readthedocs.io/en/latest/). It should you provide all necessary information how to setup and to use _py-kms_ , all without clumping this readme. The documentation also houses more details about activation with _py-kms_ and how to get GVLK keys. -## Get it running (fast)... -- To start the server manually, execute `python3 pykms_Server.py [IPADDRESS] [PORT]`, the default `IPADDRESS` is `::` ( all ipv6-interfaces ) and the default `PORT` is `1688`. Note that both the address and port are optional. - Also note that it is recommended to use an IPv6 address - even if you are just plan to use IPv4 (the kernel maps the incoming IPv4 requests automatically to IPv6)! +## Quick start +- To start the server, execute `python3 pykms_Server.py [IPADDRESS] [PORT]`, the default _IPADDRESS_ is `0.0.0.0` ( all interfaces ) and the default _PORT_ is `1688`. Note that both the address and port are optional. It's allowed to use IPv4 and IPv6 addresses. If you have a IPv6-capable dual-stack OS, a dual-stack socket is created when using a IPv6 address. - To start the server automatically using Docker, execute `docker run -d --name py-kms --restart always -p 1688:1688 pykmsorg/py-kms`. - To show the help pages type: `python3 pykms_Server.py -h` and `python3 pykms_Client.py -h`. -- For launching py-kms GUI make the file `pykms_Server.py` executable with `chmod +x /path/to/folder/py-kms/pykms_Server.py`, then simply run `pykms_Server.py` by double-clicking. - -_If you wish to learn more about using py-kms, please refer to the documentation [here](Getting Started.md)!_ +- For launching _py-kms_ GUI make the file `pykms_Server.py` executable with `chmod +x /path/to/folder/py-kms/pykms_Server.py`, then simply run `pykms_Server.py` by double-clicking. ## License - _py-kms_ is [![Unlicense](https://img.shields.io/badge/license-unlicense-lightgray.svg)](https://github.com/SystemRage/py-kms/blob/master/LICENSE) diff --git a/docker/README.md b/docker/README.md index c9c7467..9012a65 100644 --- a/docker/README.md +++ b/docker/README.md @@ -9,17 +9,17 @@ docker run -it -d --name py3-kms \ -e HWID=RANDOM \ -e LOGLEVEL=INFO \ -e LOGSIZE=2 \ - -e LOGFILE=/var/log/py3-kms.log \ + -e LOGFILE=/var/log/pykms_logserver.log \ -v /etc/localtime:/etc/localtime:ro \ -v /var/log:/var/log:rw \ --restart unless-stopped pykmsorg/py-kms:[TAG] ``` -_Make sure to insert at `[TAG]` your wanted edition! The default is `latest`, which does not include SQLLite support. For all available tag check [this](https://hub.docker.com/r/pykmsorg/py-kms/tags) out._ +_Make sure to insert at `[TAG]` your wanted edition! The default is `latest`, which does not include SQLite support. For all available tag check [this](https://hub.docker.com/r/pykmsorg/py-kms/tags)._ Therefore you can omit the `-e SQLITE=...` and `-p 8080:8080` option if you plan to use the `minimal` or `latest` image. # Sqlite-web A web-based SQLite database browser written in Python. -Start on http://example.com:8080/ in read-only mode for clients.db. +Start on http://example.com:8080/ in read-only mode for _pykms_database.db_. # Options ``` diff --git a/docker/docker-py3-kms-minimal/Dockerfile b/docker/docker-py3-kms-minimal/Dockerfile index e34ebf7..d54ece5 100644 --- a/docker/docker-py3-kms-minimal/Dockerfile +++ b/docker/docker-py3-kms-minimal/Dockerfile @@ -1,8 +1,8 @@ -# This is a minimized version from docker/docker-py3-kms/Dockerfile without SQLLite support to further reduce image size +# This is a minimized version from docker/docker-py3-kms/Dockerfile without SQLite support to further reduce image size FROM alpine:3.8 -ENV IP :: +ENV IP 0.0.0.0 ENV PORT 1688 ENV EPID "" ENV LCID 1033 diff --git a/docker/docker-py3-kms/Dockerfile b/docker/docker-py3-kms/Dockerfile index 138003f..8d1bb4b 100644 --- a/docker/docker-py3-kms/Dockerfile +++ b/docker/docker-py3-kms/Dockerfile @@ -9,8 +9,8 @@ FROM alpine:3.8 # EN: IP-address # RU: IP-адрес -ENV IP :: -# The IP address to listen on. The default is "::" (all interfaces). +ENV IP 0.0.0.0 +# The IP address to listen on. The default is "0.0.0.0" (all interfaces). # EN: TCP-port # RU: TCP-порт @@ -68,7 +68,7 @@ ENV LOGFILE /var/log/pykms_logserver.log # EN: log file size in MB # RU: Максимальный размер Лог-файл в мегабайтах ENV LOGSIZE "" -# Use this flag to set a maximum size (in MB) to the output log file. Desactivated by default. +# Use this flag to set a maximum size (in MB) to the output log file. Deactivated by default. # EN: Startup script # RU: Скрипт автозапуска diff --git a/docker/docker-py3-kms/run-py3-kms.sh b/docker/docker-py3-kms/run-py3-kms.sh index c96bcdc..a98e5d4 100755 --- a/docker/docker-py3-kms/run-py3-kms.sh +++ b/docker/docker-py3-kms/run-py3-kms.sh @@ -9,8 +9,8 @@ docker run -d --name py3-kms \ -e SQLITE=true \ -e HWID=RANDOM \ -e LOGLEVEL=INFO \ - -e LOGFILE=/var/log/py3-kms.log \ + -e LOGFILE=/var/log/pykms_logserver.log \ -e LOGSIZE=2 \ -v /etc/localtime:/etc/localtime:ro \ -v /var/log:/var/log:rw \ - --restart unless-stopped pykms/pykms:py3-kms \ No newline at end of file + --restart unless-stopped pykmsorg/py-kms:python3 diff --git a/docker/docker-py3-kms/start.sh b/docker/docker-py3-kms/start.sh index 2180747..e4c845c 100644 --- a/docker/docker-py3-kms/start.sh +++ b/docker/docker-py3-kms/start.sh @@ -28,12 +28,12 @@ else /bin/bash -c "/usr/bin/python3 pykms_Server.py ${IP} ${PORT} -l ${LCID} -c ${CLIENT_COUNT} -a ${ACTIVATION_INTERVAL} -r ${RENEWAL_INTERVAL} -s -w ${HWID} -V ${LOGLEVEL} -F ${LOGFILE} &" sleep 5 /usr/bin/python3 pykms_Client.py ${IP} ${PORT} -m Windows10 & - /usr/bin/python3 /home/sqlite_web/sqlite_web.py -H ${IP} -x ${PWD}/clients.db --read-only + /usr/bin/python3 /home/sqlite_web/sqlite_web.py -H ${IP} -x ${PWD}/pykms_database.db --read-only else /bin/bash -c "/usr/bin/python3 pykms_Server.py ${IP} ${PORT} -l ${LCID} -c ${CLIENT_COUNT} -a ${ACTIVATION_INTERVAL} -r ${RENEWAL_INTERVAL} -s -w ${HWID} -V ${LOGLEVEL} -F ${LOGFILE} -S ${LOGSIZE} &" sleep 5 /usr/bin/python3 pykms_Client.py ${IP} ${PORT} -m Windows10 & - /usr/bin/python3 /home/sqlite_web/sqlite_web.py -H ${IP} -x ${PWD}/clients.db --read-only + /usr/bin/python3 /home/sqlite_web/sqlite_web.py -H ${IP} -x ${PWD}/pykms_database.db --read-only fi else if [ "$LOGSIZE" == "" ]; @@ -41,12 +41,12 @@ else /bin/bash -c "/usr/bin/python3 pykms_Server.py ${IP} ${PORT} -e ${EPID} -l ${LCID} -c ${CLIENT_COUNT} -a ${ACTIVATION_INTERVAL} -r ${RENEWAL_INTERVAL} -s -w ${HWID} -V ${LOGLEVEL} -F ${LOGFILE} &" sleep 5 /usr/bin/python3 pykms_Client.py ${IP} ${PORT} -m Windows10 & - /usr/bin/python3 /home/sqlite_web/sqlite_web.py -H ${IP} -x ${PWD}/clients.db --read-only + /usr/bin/python3 /home/sqlite_web/sqlite_web.py -H ${IP} -x ${PWD}/pykms_database.db --read-only else /bin/sh -c "/usr/bin/python3 pykms_Server.py ${IP} ${PORT} -e ${EPID} -l ${LCID} -c ${CLIENT_COUNT} -a ${ACTIVATION_INTERVAL} -r ${RENEWAL_INTERVAL} -s -w ${HWID} -V ${LOGLEVEL} -F ${LOGFILE} -S ${LOGSIZE} &" sleep 5 /usr/bin/python3 pykms_Client.py ${IP} ${PORT} -m Windows10 & - /usr/bin/python3 /home/sqlite_web/sqlite_web.py -H ${IP} -x ${PWD}/clients.db --read-only + /usr/bin/python3 /home/sqlite_web/sqlite_web.py -H ${IP} -x ${PWD}/pykms_database.db --read-only fi fi fi diff --git a/docs/Documentation.md b/docs/Documentation.md index 5e8b389..037087f 100644 --- a/docs/Documentation.md +++ b/docs/Documentation.md @@ -1,5 +1,5 @@ # Documentation -What follows are some detailed explanations how some parts work. +What follows are some detailed explanations how the KMS infrastructure works. ## Understanding Key Management Service KMS activates Microsoft products on a local network, eliminating the need for individual computers to connect to Microsoft. To do this, KMS uses a client–server topology. A KMS client locates a KMS server by using DNS or a static @@ -324,7 +324,7 @@ Where command line options are: -## Further references +## Further References * [1] https://forums.mydigitallife.net/threads/emulated-kms-servers-on-non-windows-platforms.50234 * [2] https://forums.mydigitallife.net/threads/discussion-microsoft-office-2019.75232 * [3] https://forums.mydigitallife.net/threads/miscellaneous-kms-related-developments.52594 diff --git a/docs/Getting Started.md b/docs/Getting Started.md index 0fca055..826e8b6 100644 --- a/docs/Getting Started.md +++ b/docs/Getting Started.md @@ -1,10 +1,9 @@ # Getting Started -What follows are some guides how to start the `pykms_Server.py` script, which provides the server. +What follows are some guides how to start the `pykms_Server.py` script, which provides the emulated server. ## Running as a service *** - -You can simply manage a daemon that runs as a background process. This can be achieved by using any of the guides below or by writing your own solution. +You can simply manage a daemon that runs as a background process. This can be achieved by using any of the notes below or by writing your own solution. ### Docker ![docker-auto](https://img.shields.io/docker/cloud/automated/pykmsorg/py-kms) @@ -12,19 +11,20 @@ You can simply manage a daemon that runs as a background process. This can be ac ![docker-pulls](https://img.shields.io/docker/pulls/pykmsorg/py-kms) ![docker-size](https://img.shields.io/docker/image-size/pykmsorg/py-kms) -If you wish to get _py-kms_ just up and running without installing any dependencies or writing own scripts: Just use Docker! Docker also solves problems regarding the explicit IPv4 and IPv6 usage: It just supports both. The following +If you wish to get _py-kms_ just up and running without installing any dependencies or writing own scripts: Just use Docker ! +Docker also solves problems regarding the explicit IPv4 and IPv6 usage (it just supports both). The following command will download, "install" and start _py-kms_ and also keep it alive after any service disruption. ```bash docker run -d --name py-kms --restart always -p 1688:1688 pykmsorg/py-kms ``` There are currently three tags of the image available (select one just by appending `:` to the image from above): -* `latest`, currently the same like minimal... -* `minimal`, wich is based on the python3 minimal configuration of py-kms. _This tag does NOT include `sqlite` support!_ +* `latest`, currently the same like `minimal`. +* `minimal`, which is based on the python3 minimal configuration of py-kms. _This tag does NOT include `sqlite` support !_ * `python3`, which is fully configurable and equipped with `sqlite` support and a web interface for management. If you just want to use the image and don't want to build them yourself, you can always use the official image at the [Docker Hub](https://hub.docker.com/r/pykmsorg/py-kms) (`pykmsorg/py-kms`). To ensure that you are using always the -latest version you should check something like [watchtower](https://github.com/containrrr/watchtower) out! +latest version you should check something like [watchtower](https://github.com/containrrr/watchtower) out ! ### Systemd If you are running a Linux distro using `systemd`, create the file: `sudo nano /etc/systemd/system/py3-kms.service`, then add the following (change it where needed) and save: @@ -114,14 +114,19 @@ if __name__ == '__main__': Now in a command prompt type `C:\Windows\Python27\python.exe kms-winservice.py install` to install the service. Display all the services with `services.msc` and find the service associated with _py-kms_, change the startup type from `manual` to `auto`. Finally `Start` the service. If this approach fails, you can try to use [Non-Sucking Service Manager](https://nssm.cc/) or Task Scheduler as described [here](https://blogs.esri.com/esri/arcgis/2013/07/30/scheduling-a-scrip/). -## Manual execution +### Other Platforms +They might be useful to you: +- [FreeNAS](https://github.com/SystemRage/py-kms/issues/56) +- [FreeBSD](https://github.com/SystemRage/py-kms/issues/89) + +## Manual Execution *** ### Dependencies - Python 3.x. - Tkinter module (for the GUI). - If the `tzlocal` module is installed, the "Request Time" in the verbose output will be converted into local time. Otherwise, it will be in UTC. -- It can use the `sqlite3` module so you can use the database function, storing activation data so it can be recalled again. +- It can use the `sqlite3` module, storing activation data in a database so it can be recalled again. - Installation example on Ubuntu / Mint: - `sudo apt-get update` - `sudo apt-get install python3-tk python3-pip` @@ -146,7 +151,7 @@ user@host ~ $ ip addr inet6 ****::****:****:****:****/64 scope link noprefixroute valid_lft forever preferred_lft forever ``` -In the example above is `192.168.1.102` the ip we want to listen on, so it is this command (**note you can omit the ip AND port specification if you just wish to listen on all interfaces**): +In the example above is `192.168.1.102` the ip we want to listen on, so it is this command (**note you can omit the ip AND port specification if you just wish to listen on all interfaces with port 1688**): ``` user@host ~/path/to/folder/py-kms $ python3 pykms_Server.py 192.168.1.102 1688 @@ -155,8 +160,8 @@ user@host ~/path/to/folder/py-kms $ python3 pykms_Server.py 192.168.1.102 1688 To stop `pykms_Server.py`, in the same bash window where code running, simply press `CTRL+C`. Alternatively, in a new bash window, use `kill ` command (you can type `ps aux` first and have the process ) or `killall `. -#### Notes -The following are just some quick notes - for a more detailed list of parameters see [here](Usage.md). +### Quick Guide +The following are just some brief notes about parameters handling. For a more detailed description see [here](Usage.md). - To generate a random HWID use `-w` option: `python3 pykms_Server.py -w RANDOM`. - To get the HWID from any server use the client, for example type: `python3 pykms_Client.py :: 1688 -m Windows8.1 -V INFO`. diff --git a/docs/Usage.md b/docs/Usage.md index 6465c41..05e259e 100644 --- a/docs/Usage.md +++ b/docs/Usage.md @@ -54,7 +54,8 @@ e.g. because it could not reach the server. The default is 120 minutes (2 hours) > Instructs clients to renew activation every _RENEWALINTERVAL_ minutes. The default is 10080 minutes (7 days). -s or --sqlite -> Use this option to store request information from unique clients in an SQLite database. +> Use this option to store request information from unique clients in an SQLite database. Deactivated by default. +If enabled the default database file is _pykms_database.db_. You can also provide a specific location. -t0 or --timeout-idle > Maximum inactivity time (in seconds) after which the connection with the client is closed. @@ -63,7 +64,7 @@ Default setting is serve forever (no timeout). -y or --async-msg > With high levels of logging (e.g hundreds of log statements), in a traditional synchronous log model, the overhead involved becomes more expensive, so using this option you enable printing (pretty / logging) messages -asynchronously reducing time-consuming. Desactivated by default. +asynchronously reducing time-consuming. Deactivated by default. -V or --loglevel <{CRITICAL, ERROR, WARNING, INFO, DEBUG, MINI}> > Use this flag to set a logging loglevel. The default is _ERROR_. @@ -81,7 +82,7 @@ Mon, 12 Jun 2017 22:09:00 INFO HWID: 364F463A8863D35F > Creates a _LOGFILE.log_ logging file. The default is named _pykms_logserver.log_. example: ``` -user@user ~/path/to/folder/py-kms $ python3 pykms_Server.py 192.168.1.102 8080 -F ~/path/to/folder/py-kms/newlogfile.log -V INFO -w RANDOM +user@host ~/path/to/folder/py-kms $ python3 pykms_Server.py 192.168.1.102 8080 -F ~/path/to/folder/py-kms/newlogfile.log -V INFO -w RANDOM ``` creates _newlogfile.log_ with these initial messages: ``` @@ -134,7 +135,7 @@ You can also enable other suboptions of `-F` doing what is reported in the follo -S or --logsize -> Use this flag to set a maximum size (in MB) to the output log file. Desactivated by default. +> Use this flag to set a maximum size (in MB) to the output log file. Deactivated by default. ### pykms_Client.py If _py-kms_ server doesn't works correctly, you can test it with the KMS client `pykms_Client.py`, running on the same machine where you started `pykms_Server.py`. @@ -142,7 +143,7 @@ If _py-kms_ server doesn't works correctly, you can test it with the KMS client For example (in separated bash windows) run these commands: ``` user@host ~/path/to/folder/py-kms $ python3 pykms_Server.py -V DEBUG -user@host ~/path/to/folder/py-kms $ python3 pykms_Client.py 0.0.0.0 1688 -V DEBUG +user@host ~/path/to/folder/py-kms $ python3 pykms_Client.py -V DEBUG ``` Or if you want better specify: @@ -176,7 +177,7 @@ activate regardless of CMID being unique for a subset of specific machines or no > Use this flag to manually specify an ASCII _MACHINENAME_ to use. If no _MACHINENAME_ is specified a random one will be generated. -y or --async-msg -> Prints pretty / logging messages asynchronously. Desactivated by default. +> Prints pretty / logging messages asynchronously. Deactivated by default. -V or --loglevel <{CRITICAL, ERROR, WARNING, INFO, DEBUG, MINI}> > Use this flag to set a logging loglevel. The default is _ERROR_. @@ -186,11 +187,10 @@ activate regardless of CMID being unique for a subset of specific machines or no You can enable same _pykms_Server.py_ suboptions of `-F`. -S or --logsize -> Use this flag to set a maximum size (in MB) to the output log file. Desactivated by default. +> Use this flag to set a maximum size (in MB) to the output log file. Deactivated by default. ## Activation Procedure -Briefly the product asks for a key during installation, so it needs you to enter the GVLK. Then the user can set connection parameters, while KMS server must already be running on server machine. Finally with specific -commands activation occurs automatically and can be extended later every time for another 180 (or 30 or 45) days. +The product asks for a key during installation, so it needs you to enter the GVLK. Then the user can set connection parameters, while KMS server must already be running on server machine. Finally with specific commands, activation occurs automatically and can be extended later every time for another 180 (or 30 or 45) days. ### Windows *** @@ -203,7 +203,7 @@ The `//nologo` option of `cscript` was used only to hide the startup logo. 0. Run a Command Prompt as Administrator (you are directly in `C:\Windows\System32` path). 1. This is optional, it's for unistalling any existing product key. 2. Then put in your product's GVLK. -3. Set connection parameters... +3. Set connection parameters. 4. Try online activation, but... if that fails with error `0xC004F074` you’ll most likely have to configure your firewall that it accepts incoming connections on TCP port 1688. So for Linux users (server-side with `pykms_Server.py` running): `sudo ufw allow 1688` (to remove this rule `sudo ufw delete allow 1688`) 5. Attempt online activation (now with traffic on 1688 enabled). diff --git a/py-kms/pykms_Base.py b/py-kms/pykms_Base.py index a20edb0..b08aff4 100644 --- a/py-kms/pykms_Base.py +++ b/py-kms/pykms_Base.py @@ -107,8 +107,8 @@ class kmsBase: return 4 + (((~bodyLength & 3) + 1) & 3) def serverLogic(self, kmsRequest): - if self.srv_config['sqlite'] and self.srv_config['dbSupport']: - self.dbName = sql_initialize() + if self.srv_config['sqlite']: + sql_initialize(self.srv_config['sqlite']) pretty_printer(num_text = 15, where = "srv") kmsRequest = byterize(kmsRequest) @@ -210,8 +210,8 @@ could be detected as not genuine !{end}" %currentClientCount) 'status' : infoDict["licenseStatus"], 'product' : infoDict["skuId"]}) - if self.srv_config['sqlite'] and self.srv_config['dbSupport']: - sql_update(self.dbName, infoDict) + if self.srv_config['sqlite']: + sql_update(self.srv_config['sqlite'], infoDict) return self.createKmsResponse(kmsRequest, currentClientCount) @@ -233,8 +233,8 @@ could be detected as not genuine !{end}" %currentClientCount) response['vLActivationInterval'] = self.srv_config["activation"] response['vLRenewalInterval'] = self.srv_config["renewal"] - if self.srv_config['sqlite'] and self.srv_config['dbSupport']: - response = sql_update_epid(self.dbName, kmsRequest, response) + if self.srv_config['sqlite']: + response = sql_update_epid(self.srv_config['sqlite'], kmsRequest, response) loggersrv.info("Server ePID: %s" % response["kmsEpid"].decode('utf-16le')) diff --git a/py-kms/pykms_Client.py b/py-kms/pykms_Client.py index 4e96e70..eee5efc 100644 --- a/py-kms/pykms_Client.py +++ b/py-kms/pykms_Client.py @@ -59,7 +59,7 @@ clt_options = { 'def' : None, 'des' : "cmid"}, 'name' : {'help' : 'Use this flag to manually specify an ASCII machine name to use. If no machine name is specified a random one \ will be generated.', 'def' : None, 'des' : "machine"}, - 'asyncmsg' : {'help' : 'Prints pretty / logging messages asynchronously. Desactivated by default.', + 'asyncmsg' : {'help' : 'Prints pretty / logging messages asynchronously. Deactivated by default.', 'def' : False, 'des' : "asyncmsg"}, 'llevel' : {'help' : 'Use this option to set a log level. The default is \"ERROR\".', 'def' : "ERROR", 'des' : "loglevel", 'choi' : ["CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG", "MINI"]}, @@ -67,7 +67,7 @@ will be generated.', 'def' : None, 'des' : "machine"}, Type \"STDOUT\" to view log info on stdout. Type \"FILESTDOUT\" to combine previous actions. \ Use \"STDOUTOFF\" to disable stdout messages. Use \"FILEOFF\" if you not want to create logfile.', 'def' : os.path.join('.', 'pykms_logclient.log'), 'des' : "logfile"}, - 'lsize' : {'help' : 'Use this flag to set a maximum size (in MB) to the output log file. Desactivated by default.', 'def' : 0, 'des': "logsize"}, + 'lsize' : {'help' : 'Use this flag to set a maximum size (in MB) to the output log file. Deactivated by default.', 'def' : 0, 'des': "logsize"}, } def client_options(): diff --git a/py-kms/pykms_Server.py b/py-kms/pykms_Server.py index 298a0f7..9863e94 100755 --- a/py-kms/pykms_Server.py +++ b/py-kms/pykms_Server.py @@ -188,13 +188,14 @@ for server OSes and Office >=5', 'def' : None, 'des' : "clientcount"}, 'def' : 120, 'des': "activation"}, 'renewal' : {'help' : 'Use this option to specify the renewal interval (in minutes). Default is \"10080\" minutes (7 days).', 'def' : 1440 * 7, 'des' : "renewal"}, - 'sql' : {'help' : 'Use this option to store request information from unique clients in an SQLite database. Desactivated by default.', + 'sql' : {'help' : 'Use this option to store request information from unique clients in an SQLite database. Deactivated by default. \ +If enabled the default .db file is \"pykms_database.db\". You can also provide a specific location.', 'def' : False, 'des' : "sqlite"}, 'hwid' : {'help' : 'Use this option to specify a HWID. The HWID must be an 16-character string of hex characters. \ The default is \"364F463A8863D35F\" or type \"RANDOM\" to auto generate the HWID.', 'def' : "364F463A8863D35F", 'des' : "hwid"}, 'time0' : {'help' : 'Maximum inactivity time (in seconds) after which the connection with the client is closed. If \"None\" (default) serve forever.', 'def' : None, 'des' : "timeoutidle"}, - 'asyncmsg' : {'help' : 'Prints pretty / logging messages asynchronously. Desactivated by default.', + 'asyncmsg' : {'help' : 'Prints pretty / logging messages asynchronously. Deactivated by default.', 'def' : False, 'des' : "asyncmsg"}, 'llevel' : {'help' : 'Use this option to set a log level. The default is \"ERROR\".', 'def' : "ERROR", 'des' : "loglevel", 'choi' : ["CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG", "MINI"]}, @@ -202,7 +203,7 @@ The default is \"364F463A8863D35F\" or type \"RANDOM\" to auto generate the HWID Type \"STDOUT\" to view log info on stdout. Type \"FILESTDOUT\" to combine previous actions. \ Use \"STDOUTOFF\" to disable stdout messages. Use \"FILEOFF\" if you not want to create logfile.', 'def' : os.path.join('.', 'pykms_logserver.log'), 'des' : "logfile"}, - 'lsize' : {'help' : 'Use this flag to set a maximum size (in MB) to the output log file. Desactivated by default.', 'def' : 0, 'des': "logsize"}, + 'lsize' : {'help' : 'Use this flag to set a maximum size (in MB) to the output log file. Deactivated by default.', 'def' : 0, 'des': "logsize"}, } def server_options(): @@ -219,8 +220,8 @@ def server_options(): default = srv_options['activation']['def'], help = srv_options['activation']['help'], type = int) server_parser.add_argument("-r", "--renewal-interval", action = "store", dest = srv_options['renewal']['des'], default = srv_options['renewal']['def'], help = srv_options['renewal']['help'], type = int) - server_parser.add_argument("-s", "--sqlite", action = "store_true", dest = srv_options['sql']['des'], - default = srv_options['sql']['def'], help = srv_options['sql']['help']) + server_parser.add_argument("-s", "--sqlite", nargs = "?", dest = srv_options['sql']['des'], const = True, + default = srv_options['sql']['def'], help = srv_options['sql']['help'], type = str) server_parser.add_argument("-w", "--hwid", action = "store", dest = srv_options['hwid']['des'], default = srv_options['hwid']['def'], help = srv_options['hwid']['help'], type = str) server_parser.add_argument("-t0", "--timeout-idle", action = "store", dest = srv_options['time0']['des'], default = srv_options['time0']['def'], @@ -298,7 +299,6 @@ def server_options(): except KmsParserException as e: pretty_printer(put_text = "{reverse}{red}{bold}%s. Exiting...{end}" %str(e), to_exit = True) - class Etrigan_Check(Etrigan_check): def emit_opt_err(self, msg): pretty_printer(put_text = "{reverse}{red}{bold}%s{end}" %msg, to_exit = True) @@ -316,7 +316,7 @@ class Etrigan(Etrigan): def server_daemon(): if 'etrigan' in srv_config.values(): - path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'pykms_config.pickle') + path = os.path.join('.', 'pykms_config.pickle') if srv_config['operation'] in ['stop', 'restart', 'status'] and len(sys.argv[1:]) > 2: pretty_printer(put_text = "{reverse}{red}{bold}too much arguments with etrigan '%s'. Exiting...{end}" %srv_config['operation'], @@ -394,15 +394,18 @@ def server_check(): srv_config['lcid'] = check_lcid(srv_config['lcid'], loggersrv.warning) # Check sqlite. - try: - import sqlite3 - except: - pretty_printer(log_obj = loggersrv.warning, - put_text = "{reverse}{yellow}{bold}Module 'sqlite3' is not installed, database support disabled.{end}") - srv_config['dbSupport'] = False - else: - srv_config['dbSupport'] = True - + if srv_config['sqlite']: + if (isinstance(srv_config['sqlite'], str)) and (not srv_config['sqlite'].lower().endswith('.db')): + pretty_printer(log_obj = loggersrv.error, to_exit = True, + put_text = "{reverse}{red}{bold}Not a sqlite file (.db).{end}") + try: + import sqlite3 + if isinstance(srv_config['sqlite'], bool): + srv_config['sqlite'] = os.path.join('.', 'pykms_database.db') + except ImportError: + pretty_printer(log_obj = loggersrv.warning, + put_text = "{reverse}{yellow}{bold}Module 'sqlite3' is not installed, database support disabled.{end}") + srv_config['sqlite'] = False # Check other specific server options. list_dest = ['clientcount', 'timeoutidle'] diff --git a/py-kms/pykms_Sql.py b/py-kms/pykms_Sql.py index d5b7910..a09164a 100644 --- a/py-kms/pykms_Sql.py +++ b/py-kms/pykms_Sql.py @@ -5,9 +5,9 @@ import logging # sqlite3 is optional. try: - import sqlite3 + import sqlite3 except ImportError: - pass + pass from pykms_Format import pretty_printer @@ -15,87 +15,84 @@ from pykms_Format import pretty_printer loggersrv = logging.getLogger('logsrv') -def sql_initialize(): - dbName = 'clients.db' - if not os.path.isfile(dbName): - # Initialize the database. - con = None - try: - con = sqlite3.connect(dbName) - cur = con.cursor() - cur.execute("CREATE TABLE clients(clientMachineId TEXT, machineName TEXT, applicationId TEXT, skuId TEXT, \ +def sql_initialize(dbName): + if not os.path.isfile(dbName): + # Initialize the database. + con = None + try: + con = sqlite3.connect(dbName) + cur = con.cursor() + cur.execute("CREATE TABLE clients(clientMachineId TEXT, machineName TEXT, applicationId TEXT, skuId TEXT, \ licenseStatus TEXT, lastRequestTime INTEGER, kmsEpid TEXT, requestCount INTEGER)") - except sqlite3.Error as e: + except sqlite3.Error as e: pretty_printer(log_obj = loggersrv.error, to_exit = True, put_text = "{reverse}{red}{bold}%s. Exiting...{end}" %str(e)) - finally: - if con: - con.commit() - con.close() - return dbName - + finally: + if con: + con.commit() + con.close() def sql_update(dbName, infoDict): - con = None - try: - con = sqlite3.connect(dbName) - cur = con.cursor() - cur.execute("SELECT * FROM clients WHERE clientMachineId=:clientMachineId;", infoDict) - try: - data = cur.fetchone() - if not data: - # Insert row. - cur.execute("INSERT INTO clients (clientMachineId, machineName, applicationId, \ + con = None + try: + con = sqlite3.connect(dbName) + cur = con.cursor() + cur.execute("SELECT * FROM clients WHERE clientMachineId=:clientMachineId;", infoDict) + try: + data = cur.fetchone() + if not data: + # Insert row. + cur.execute("INSERT INTO clients (clientMachineId, machineName, applicationId, \ skuId, licenseStatus, lastRequestTime, requestCount) VALUES (:clientMachineId, :machineName, :appId, :skuId, :licenseStatus, :requestTime, 1);", infoDict) - else: - # Update data. - if data[1] != infoDict["machineName"]: - cur.execute("UPDATE clients SET machineName=:machineName WHERE clientMachineId=:clientMachineId;", infoDict) - if data[2] != infoDict["appId"]: - cur.execute("UPDATE clients SET applicationId=:appId WHERE clientMachineId=:clientMachineId;", infoDict) - if data[3] != infoDict["skuId"]: - cur.execute("UPDATE clients SET skuId=:skuId WHERE clientMachineId=:clientMachineId;", infoDict) - if data[4] != infoDict["licenseStatus"]: - cur.execute("UPDATE clients SET licenseStatus=:licenseStatus WHERE clientMachineId=:clientMachineId;", infoDict) - if data[5] != infoDict["requestTime"]: - cur.execute("UPDATE clients SET lastRequestTime=:requestTime WHERE clientMachineId=:clientMachineId;", infoDict) - # Increment requestCount - cur.execute("UPDATE clients SET requestCount=requestCount+1 WHERE clientMachineId=:clientMachineId;", infoDict) + else: + # Update data. + if data[1] != infoDict["machineName"]: + cur.execute("UPDATE clients SET machineName=:machineName WHERE clientMachineId=:clientMachineId;", infoDict) + if data[2] != infoDict["appId"]: + cur.execute("UPDATE clients SET applicationId=:appId WHERE clientMachineId=:clientMachineId;", infoDict) + if data[3] != infoDict["skuId"]: + cur.execute("UPDATE clients SET skuId=:skuId WHERE clientMachineId=:clientMachineId;", infoDict) + if data[4] != infoDict["licenseStatus"]: + cur.execute("UPDATE clients SET licenseStatus=:licenseStatus WHERE clientMachineId=:clientMachineId;", infoDict) + if data[5] != infoDict["requestTime"]: + cur.execute("UPDATE clients SET lastRequestTime=:requestTime WHERE clientMachineId=:clientMachineId;", infoDict) + # Increment requestCount + cur.execute("UPDATE clients SET requestCount=requestCount+1 WHERE clientMachineId=:clientMachineId;", infoDict) - except sqlite3.Error as e: + except sqlite3.Error as e: pretty_printer(log_obj = loggersrv.error, to_exit = True, put_text = "{reverse}{red}{bold}%s. Exiting...{end}" %str(e)) - except sqlite3.Error as e: + except sqlite3.Error as e: pretty_printer(log_obj = loggersrv.error, to_exit = True, put_text = "{reverse}{red}{bold}%s. Exiting...{end}" %str(e)) - finally: - if con: - con.commit() - con.close() + finally: + if con: + con.commit() + con.close() def sql_update_epid(dbName, kmsRequest, response): - cmid = str(kmsRequest['clientMachineId'].get()) - con = None - try: - con = sqlite3.connect(dbName) - cur = con.cursor() - cur.execute("SELECT * FROM clients WHERE clientMachineId=?;", [cmid]) - try: - data = cur.fetchone() - if data[6]: - response["kmsEpid"] = data[6].encode('utf-16le') - else: - cur.execute("UPDATE clients SET kmsEpid=? WHERE clientMachineId=?;", (str(response["kmsEpid"].decode('utf-16le')), - cmid)) - except sqlite3.Error as e: + cmid = str(kmsRequest['clientMachineId'].get()) + con = None + try: + con = sqlite3.connect(dbName) + cur = con.cursor() + cur.execute("SELECT * FROM clients WHERE clientMachineId=?;", [cmid]) + try: + data = cur.fetchone() + if data[6]: + response["kmsEpid"] = data[6].encode('utf-16le') + else: + cur.execute("UPDATE clients SET kmsEpid=? WHERE clientMachineId=?;", (str(response["kmsEpid"].decode('utf-16le')), + cmid)) + except sqlite3.Error as e: pretty_printer(log_obj = loggersrv.error, to_exit = True, put_text = "{reverse}{red}{bold}%s. Exiting...{end}" %str(e)) - except sqlite3.Error as e: + except sqlite3.Error as e: pretty_printer(log_obj = loggersrv.error, to_exit = True, put_text = "{reverse}{red}{bold}%s. Exiting...{end}" %str(e)) - finally: - if con: - con.commit() - con.close() - return response + finally: + if con: + con.commit() + con.close() + return response