Database keeps different AppId (#50), restyling minimal info logging

This commit is contained in:
Matteo ℱan 2020-09-07 23:44:10 +02:00
parent 33cedce48c
commit 016a4c367f
No known key found for this signature in database
GPG Key ID: 3C30A05BC133D9B6
9 changed files with 101 additions and 83 deletions

View File

@ -166,7 +166,7 @@ The following are just some brief notes about parameters handling. For a more de
- 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`.
- To change your logfile path use `-F` option, for example: `python3 pykms_Server.py -F /path/to/your/logfile.log -V DEBUG`.
- To view a minimal set of logging information use `-V MINI` option, for example: `python3 pykms_Server.py -F /path/to/your/logfile.log -V MINI`.
- To view a minimal set of logging information use `-V MININFO` option, for example: `python3 pykms_Server.py -F /path/to/your/logfile.log -V MININFO`.
- To redirect logging on stdout use `-F STDOUT` option, for example: `python3 pykms_Server.py -F STDOUT -V DEBUG`.
- You can create logfile and view logging information on stdout at the same time with `-F FILESTDOUT` option, for example: `python3 pykms_Server.py -F FILESTDOUT /path/to/your/logfile.log -V DEBUG`.
- With `-F STDOUTOFF` you disable all stdout messages (but a logfile will be created), for example: `python3 pykms_Server.py -F STDOUTOFF /path/to/your/logfile.log -V DEBUG`.

View File

@ -66,7 +66,7 @@ Default setting is serve forever (no timeout).
the overhead involved becomes more expensive, so using this option you enable printing (pretty / logging) messages
asynchronously reducing time-consuming. Deactivated by default.
-V or --loglevel <{CRITICAL, ERROR, WARNING, INFO, DEBUG, MINI}>
-V or --loglevel <{CRITICAL, ERROR, WARNING, INFO, DEBUG, MININFO}>
> Use this flag to set a logging loglevel. The default is _ERROR_.
example:
```
@ -162,7 +162,7 @@ You can also put further parameters as defined below:
-m or --mode <{WindowsVista, Windows7, Windows8, Windows8.1, Windows10, Office2010, Office2013, Office2016, Office2019}>
> Use this flag to manually specify a Microsoft _PRODUCTNAME_ for testing the KMS server. Default is Windows8.1.
-c or --cmid <CMID>
-c or --cmid <CMID>
> Use this flag to manually specify a CMID to use. If no CMID is specified, a random one will be generated.
The Microsoft KMS host machine identifies KMS clients with a unique Client Machine ID
(CMID, example: ae3a27d1-b73a-4734-9878-70c949815218). For a KMS client to successfully activate, the KMS server
@ -179,7 +179,7 @@ activate regardless of CMID being unique for a subset of specific machines or no
-y or --async-msg
> Prints pretty / logging messages asynchronously. Deactivated by default.
-V or --loglevel <{CRITICAL, ERROR, WARNING, INFO, DEBUG, MINI}>
-V or --loglevel <{CRITICAL, ERROR, WARNING, INFO, DEBUG, MININFO}>
> Use this flag to set a logging loglevel. The default is _ERROR_.
-F or --logfile <LOGFILE>

View File

@ -107,9 +107,6 @@ class kmsBase:
return 4 + (((~bodyLength & 3) + 1) & 3)
def serverLogic(self, kmsRequest):
if self.srv_config['sqlite']:
sql_initialize(self.srv_config['sqlite'])
pretty_printer(num_text = 15, where = "srv")
kmsRequest = byterize(kmsRequest)
loggersrv.debug("KMS Request Bytes: \n%s\n" % justify(deco(binascii.b2a_hex(enco(str(kmsRequest), 'latin-1')), 'latin-1')))
@ -205,17 +202,18 @@ could be detected as not genuine !{end}" %currentClientCount)
loggersrv.info("License Status: %s" % infoDict["licenseStatus"])
loggersrv.info("Request Time: %s" % local_dt.strftime('%Y-%m-%d %H:%M:%S %Z (UTC%z)'))
if self.srv_config['loglevel'] == 'MINI':
loggersrv.mini("", extra = {'host': socket.gethostname() + " [" + self.srv_config["ip"] + "]",
'status' : infoDict["licenseStatus"],
'product' : infoDict["skuId"]})
if self.srv_config['loglevel'] == 'MININFO':
loggersrv.mininfo("", extra = {'host': str(self.srv_config['raddr']),
'status' : infoDict["licenseStatus"],
'product' : infoDict["skuId"]})
# Create database.
if self.srv_config['sqlite']:
sql_initialize(self.srv_config['sqlite'])
sql_update(self.srv_config['sqlite'], infoDict)
return self.createKmsResponse(kmsRequest, currentClientCount)
return self.createKmsResponse(kmsRequest, currentClientCount, appName)
def createKmsResponse(self, kmsRequest, currentClientCount):
def createKmsResponse(self, kmsRequest, currentClientCount, appName):
response = self.kmsResponseStruct()
response['versionMinor'] = kmsRequest['versionMinor']
response['versionMajor'] = kmsRequest['versionMajor']
@ -227,14 +225,15 @@ could be detected as not genuine !{end}" %currentClientCount)
response["kmsEpid"] = self.srv_config["epid"].encode('utf-16le')
response['clientMachineId'] = kmsRequest['clientMachineId']
# rule: timeserver - 4h <= timeclient <= timeserver + 4h, check if is satisfied.
# rule: timeserver - 4h <= timeclient <= timeserver + 4h, check if is satisfied (TODO).
response['responseTime'] = kmsRequest['requestTime']
response['currentClientCount'] = currentClientCount
response['vLActivationInterval'] = self.srv_config["activation"]
response['vLRenewalInterval'] = self.srv_config["renewal"]
# Update database epid.
if self.srv_config['sqlite']:
response = sql_update_epid(self.srv_config['sqlite'], kmsRequest, response)
sql_update_epid(self.srv_config['sqlite'], kmsRequest, response, appName)
loggersrv.info("Server ePID: %s" % response["kmsEpid"].decode('utf-16le'))

View File

@ -62,7 +62,7 @@ will be generated.', 'def' : None, 'des' : "machine"},
'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"]},
'choi' : ["CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG", "MININFO"]},
'lfile' : {'help' : 'Use this option to set an output log file. The default is \"pykms_logclient.log\". \
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.',
@ -168,7 +168,7 @@ def client_update():
def client_create():
loggerclt.info("Connecting to %s on port %d..." % (clt_config['ip'], clt_config['port']))
try:
s = socket.create_connection((clt_config['ip'], clt_config['port']))
clt_sock = socket.create_connection((clt_config['ip'], clt_config['port']))
loggerclt.info("Connection successful !")
except (socket.gaierror, socket.error) as e:
pretty_printer(log_obj = loggerclt.error, to_exit = True, where = "clt",
@ -181,12 +181,12 @@ def client_create():
try:
loggerclt.info("Sending RPC bind request...")
pretty_printer(num_text = [-1, 1], where = "clt")
s.send(RPC_Bind)
clt_sock.send(RPC_Bind)
except socket.error as e:
pretty_printer(log_obj = loggerclt.error, to_exit = True, where = "clt",
put_text = "{reverse}{red}{bold}While sending: %s{end}" %str(e))
try:
bindResponse = s.recv(1024)
bindResponse = clt_sock.recv(1024)
if bindResponse == '' or not bindResponse:
pretty_printer(log_obj = loggerclt.warning, to_exit = True, where = "clt",
put_text = "{reverse}{yellow}{bold}No data received.{end}")
@ -206,12 +206,12 @@ def client_create():
loggerclt.info("Sending RPC activation request...")
RPC_Actv = enco(str(requester.generateRequest()), 'latin-1')
pretty_printer(num_text = [-1, 12], where = "clt")
s.send(RPC_Actv)
clt_sock.send(RPC_Actv)
except socket.error as e:
pretty_printer(log_obj = loggerclt.error, to_exit = True, where = "clt",
put_text = "{reverse}{red}{bold}While sending: %s{end}" %str(e))
try:
response = s.recv(1024)
response = clt_sock.recv(1024)
pretty_printer(num_text = [-4, 20], where = "clt")
except socket.error as e:
pretty_printer(log_obj = loggerclt.error, to_exit = True, where = "clt",
@ -232,10 +232,10 @@ def client_create():
loggerclt.info("KMS VL Activation Interval: %s" % kmsResp['vLActivationInterval'])
loggerclt.info("KMS VL Renewal Interval: %s" % kmsResp['vLRenewalInterval'])
if clt_config['loglevel'] == 'MINI':
loggerclt.mini("", extra = {'host': socket.gethostname() + " [" + clt_config["ip"] + "]",
'status' : "Activated",
'product' : clt_config["mode"]})
if clt_config['loglevel'] == 'MININFO':
loggerclt.mininfo("", extra = {'host': str(clt_sock.getpeername()),
'status' : kmsBase.licenseStates[requester.srv_config['KMSClientLicenseStatus']],
'product' : clt_config["mode"]})
pretty_printer(num_text = 21, where = "clt")

View File

@ -54,14 +54,15 @@ def justify(astring, indent = 35, break_every = 100):
return justy
##----------------------------------------------------------------------------------------------------------------------------------------------------
ColorMap = {'gray' : '\x1b[90m',
ColorMap = {'black' : '\x1b[90m',
'red' : '\x1b[91m',
'green' : '\x1b[92m',
'green' : '\x1b[38;2;0;238;118m', # '\x1b[92m'
'yellow' : '\x1b[93m',
'blue' : '\x1b[94m',
'magenta' : '\x1b[95m',
'magenta' : '\x1b[38;2;205;0;205m', # '\x1b[95m'
'cyan' : '\x1b[96m',
'white' : '\x1b[97m'
'white' : '\x1b[97m',
'orange' : '\x1b[38;2;255;165;0m'
}
ExtraMap = {'end' : '\x1b[0m',

View File

@ -80,9 +80,9 @@ class KmsGui(tk.Tk):
self.customcolors = { 'black' : '#000000',
'white' : '#FFFFFF',
'green' : '#90EE90',
'green' : '#00EE76',
'yellow' : '#FFFF00',
'magenta' : '#DA70D6',
'magenta' : '#CD00CD',
'orange' : '#FFA500',
'red' : '#FF4500',
'blue' : '#1E90FF',

View File

@ -66,8 +66,8 @@ class LevelFormatter(logging.Formatter):
self.formatters[loglevel] = logging.Formatter(formats[loglevel], datefmt = self.dfmt)
def colorize(self, formats, loglevel):
if loglevel == logging.MINI:
frmt = '{gray}' + formats[loglevel] + '{end}'
if loglevel == logging.MININFO:
frmt = '{orange}' + formats[loglevel] + '{end}'
elif loglevel == logging.CRITICAL:
frmt = '{magenta}{bold}' + formats[loglevel] + '{end}'
elif loglevel == logging.ERROR:
@ -153,7 +153,8 @@ class MultiProcessingLogHandler(logging.Handler):
def logger_create(log_obj, config, mode = 'a'):
# Create new level.
add_logging_level('MINI', logging.CRITICAL + 10)
num_lvl_mininfo = 25
add_logging_level('MININFO', num_lvl_mininfo)
log_handlers = []
# Configure visualization.
@ -188,13 +189,19 @@ def logger_create(log_obj, config, mode = 'a'):
levelnum = [k for k in levelnames if k != 0]
frmt_gen = '%(asctime)s %(levelname)-8s %(message)s'
frmt_std = '%(name)s %(asctime)s %(levelname)-8s %(message)s'
frmt_min = '[%(asctime)s] [%(levelname)-8s] %(host)s %(status)s %(product)s %(message)s'
frmt_std = '%(asctime)s %(levelname)-8s %(message)s'
frmt_min = '%(asctime)s %(levelname)-8s %(host)s %(status)s %(product)s %(message)s'
frmt_name = '%(name)s '
from pykms_Server import serverthread
if serverthread.with_gui:
frmt_std = frmt_name + frmt_std
frmt_min = frmt_name + frmt_min
def apply_formatter(levelnum, formats, handler, color = False):
levelformdict = {}
for num in levelnum:
if num != logging.CRITICAL + 10:
if num != num_lvl_mininfo:
levelformdict[num] = formats[0]
else:
levelformdict[num] = formats[1]
@ -220,25 +227,32 @@ def logger_create(log_obj, config, mode = 'a'):
log_obj.setLevel(config['loglevel'])
#------------------------------------------------------------------------------------------------------------------------------------------------------------
def check_dir(path, where, log_obj = None, argument = '-F/--logfile', typefile = '.log'):
filename = os.path.basename(path)
pathname = os.path.dirname(path)
extension = os.path.splitext(filename)[1]
if pathname == os.sep:
pathname += filename
msg_dir = "{reverse}{red}{bold}argument `%s`: invalid directory: '%s'. Exiting...{end}"
msg_fil = "{reverse}{red}{bold}argument `%s`: not a %s file, invalid extension: '%s'. Exiting...{end}"
if not os.path.isdir(pathname):
if path.count('/') == 0:
pathname = filename
pretty_printer(log_obj = log_obj, where = where, to_exit = True,
put_text = msg_dir %(argument, pathname))
elif not extension.lower() == typefile:
pretty_printer(log_obj = log_obj, where = where, to_exit = True,
put_text = msg_fil %(argument, typefile, extension))
def check_logfile(optionlog, defaultlog, where):
if not isinstance(optionlog, list):
optionlog = [optionlog]
lenopt = len(optionlog)
msg_dir = "{reverse}{red}{bold}argument `-F/--logfile`: invalid directory: '%s'. Exiting...{end}"
msg_long = "{reverse}{red}{bold}argument `-F/--logfile`: too much arguments. Exiting...{end}"
msg_log = "{reverse}{red}{bold}argument `-F/--logfile`: not a log file, invalid extension: '%s'. Exiting...{end}"
def checkdir(path):
filename = os.path.basename(path)
pathname = os.path.dirname(path)
if not os.path.isdir(pathname):
if path.count('/') == 0:
pathname = filename
pretty_printer(put_text = msg_dir %pathname, where = where, to_exit = True)
elif not filename.lower().endswith('.log'):
pretty_printer(put_text = msg_log %filename, where = where, to_exit = True)
if lenopt > 2:
pretty_printer(put_text = msg_long, where = where, to_exit = True)
@ -249,13 +263,13 @@ def check_logfile(optionlog, defaultlog, where):
optionlog.append(defaultlog)
elif lenopt == 2:
# check directory path.
checkdir(optionlog[1])
check_dir(optionlog[1], where)
else:
if lenopt == 2:
pretty_printer(put_text = msg_long, where = where, to_exit = True)
elif lenopt == 1 and (any(opt not in ['STDOUT', 'FILEOFF'] for opt in optionlog)):
# check directory path.
checkdir(optionlog[0])
check_dir(optionlog[0], where)
return optionlog

View File

@ -19,7 +19,7 @@ import ipaddress
import pykms_RpcBind, pykms_RpcRequest
from pykms_RpcBase import rpcBase
from pykms_Dcerpc import MSRPCHeader
from pykms_Misc import check_setup, check_lcid
from pykms_Misc import check_setup, check_lcid, check_dir
from pykms_Misc import KmsParser, KmsParserException, KmsParserHelp
from pykms_Misc import kms_parser_get, kms_parser_check_optionals, kms_parser_check_positionals
from pykms_Format import enco, deco, pretty_printer
@ -198,7 +198,7 @@ The default is \"364F463A8863D35F\" or type \"RANDOM\" to auto generate the HWID
'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"]},
'choi' : ["CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG", "MININFO"]},
'lfile' : {'help' : 'Use this option to set an output log file. The default is \"pykms_logserver.log\". \
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.',
@ -395,16 +395,16 @@ def server_check():
# Check sqlite.
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}")
if isinstance(srv_config['sqlite'], str):
check_dir(srv_config['sqlite'], 'srv', log_obj = loggersrv.error, argument = '-s/--sqlite', typefile = '.db')
elif srv_config['sqlite'] is True:
srv_config['sqlite'] = os.path.join('.', 'pykms_database.db')
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}")
put_text = "{reverse}{yellow}{bold}Module 'sqlite3' not installed, database support disabled.{end}")
srv_config['sqlite'] = False
# Check other specific server options.
@ -498,6 +498,7 @@ def server_main_no_terminal():
class kmsServerHandler(socketserver.BaseRequestHandler):
def setup(self):
loggersrv.info("Connection accepted: %s:%d" %(self.client_address[0], self.client_address[1]))
srv_config['raddr'] = self.client_address
def handle(self):
while True:

View File

@ -27,7 +27,7 @@ licenseStatus TEXT, lastRequestTime INTEGER, kmsEpid TEXT, requestCount INTEGER)
except sqlite3.Error as e:
pretty_printer(log_obj = loggersrv.error, to_exit = True,
put_text = "{reverse}{red}{bold}%s. Exiting...{end}" %str(e))
put_text = "{reverse}{red}{bold}Sqlite Error: %s. Exiting...{end}" %str(e))
finally:
if con:
con.commit()
@ -38,7 +38,7 @@ def sql_update(dbName, infoDict):
try:
con = sqlite3.connect(dbName)
cur = con.cursor()
cur.execute("SELECT * FROM clients WHERE clientMachineId=:clientMachineId;", infoDict)
cur.execute("SELECT * FROM clients WHERE clientMachineId=:clientMachineId AND applicationId=:appId;", infoDict)
try:
data = cur.fetchone()
if not data:
@ -48,51 +48,54 @@ skuId, licenseStatus, lastRequestTime, requestCount) VALUES (:clientMachineId, :
else:
# Update data.
if data[1] != infoDict["machineName"]:
cur.execute("UPDATE clients SET machineName=:machineName WHERE clientMachineId=:clientMachineId;", infoDict)
cur.execute("UPDATE clients SET machineName=:machineName WHERE \
clientMachineId=:clientMachineId AND applicationId=:appId;", infoDict)
if data[2] != infoDict["appId"]:
cur.execute("UPDATE clients SET applicationId=:appId WHERE clientMachineId=:clientMachineId;", infoDict)
cur.execute("UPDATE clients SET applicationId=:appId WHERE \
clientMachineId=:clientMachineId AND applicationId=:appId;", infoDict)
if data[3] != infoDict["skuId"]:
cur.execute("UPDATE clients SET skuId=:skuId WHERE clientMachineId=:clientMachineId;", infoDict)
cur.execute("UPDATE clients SET skuId=:skuId WHERE \
clientMachineId=:clientMachineId AND applicationId=:appId;", infoDict)
if data[4] != infoDict["licenseStatus"]:
cur.execute("UPDATE clients SET licenseStatus=:licenseStatus WHERE clientMachineId=:clientMachineId;", infoDict)
cur.execute("UPDATE clients SET licenseStatus=:licenseStatus WHERE \
clientMachineId=:clientMachineId AND applicationId=:appId;", infoDict)
if data[5] != infoDict["requestTime"]:
cur.execute("UPDATE clients SET lastRequestTime=:requestTime WHERE clientMachineId=:clientMachineId;", infoDict)
cur.execute("UPDATE clients SET lastRequestTime=:requestTime WHERE \
clientMachineId=:clientMachineId AND applicationId=:appId;", infoDict)
# Increment requestCount
cur.execute("UPDATE clients SET requestCount=requestCount+1 WHERE clientMachineId=:clientMachineId;", infoDict)
cur.execute("UPDATE clients SET requestCount=requestCount+1 WHERE \
clientMachineId=:clientMachineId AND applicationId=:appId;", infoDict)
except sqlite3.Error as e:
pretty_printer(log_obj = loggersrv.error, to_exit = True,
put_text = "{reverse}{red}{bold}%s. Exiting...{end}" %str(e))
put_text = "{reverse}{red}{bold}Sqlite Error: %s. Exiting...{end}" %str(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))
put_text = "{reverse}{red}{bold}Sqlite Error: %s. Exiting...{end}" %str(e))
finally:
if con:
con.commit()
con.close()
def sql_update_epid(dbName, kmsRequest, response):
def sql_update_epid(dbName, kmsRequest, response, appName):
cmid = str(kmsRequest['clientMachineId'].get())
con = None
try:
con = sqlite3.connect(dbName)
cur = con.cursor()
cur.execute("SELECT * FROM clients WHERE clientMachineId=?;", [cmid])
cur.execute("SELECT * FROM clients WHERE clientMachineId=? AND applicationId=?;", (cmid, appName))
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))
cur.execute("UPDATE clients SET kmsEpid=? WHERE \
clientMachineId=? AND applicationId=?;", (str(response["kmsEpid"].decode('utf-16le')), cmid, appName))
except sqlite3.Error as e:
pretty_printer(log_obj = loggersrv.error, to_exit = True,
put_text = "{reverse}{red}{bold}%s. Exiting...{end}" %str(e))
put_text = "{reverse}{red}{bold}Sqlite Error: %s. Exiting...{end}" %str(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))
put_text = "{reverse}{red}{bold}Sqlite Error: %s. Exiting...{end}" %str(e))
finally:
if con:
con.commit()
con.close()
return response