# -*- coding: utf-8 -*-
from setuphelpers import *
import codecs
# Documentation : https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-xp/bb490698(v=technet.10)?redirectedfrom=MSDN
forcelogoff = "no"
minpwlen = 14
maxpwage = 365
minpwage = 1
uniquepw = 24
lockout_threshold = 5
lockout_duration = 15
reset_lockout_count = 15
set_complexity = True
clear_store_pw = False
admin_account_lockout = True
def decode_file(src_file:None,dest_file:None):
encoded_text = open(src_file, 'rb').read() #you should read in binary mode to get the BOM correctly
bom = codecs.BOM_UTF16_LE #print dir(codecs) for other encodings
assert encoded_text.startswith(bom) #make sure the encoding is what you expect, otherwise you'll get wrong data
encoded_text = encoded_text[len(bom):] #strip away the BOM
decoded_text = encoded_text.decode('utf-16le')
f = open(dest_file, 'wb')
f.write(decoded_text.encode('utf-8'))
f.close()
def encode_file(src_file,dest_file):
encoded_text = open(src_file, 'rb').read() #you should read in binary mode to get the BOM correctly
decoded_text = encoded_text.decode('utf-8')
f = open(dest_file, 'wb')
f.write(decoded_text.encode('utf-16le'))
f.close()
def install():
print(f"Set local password policy")
run(f"net accounts /forcelogoff:{forcelogoff} /minpwlen:{minpwlen} /maxpwage:{maxpwage} /minpwage:{minpwage} /uniquepw:{uniquepw} \
/lockoutthreshold:{lockout_threshold} /lockoutwindow:{reset_lockout_count} /lockoutduration:{lockout_duration}")
run(r'C:\Windows\system32\secedit.exe /export /cfg secconfig.ini /areas SECURITYPOLICY')
decoded_file = "decoded_secconfig.ini"
decode_file("secconfig.ini", decoded_file)
print('Set complexity password')
if set_complexity:
if inifile_hasoption(decoded_file,"System Access","PasswordComplexity"):
if inifile_readstring(decoded_file,"System Access","PasswordComplexity") == "0":
inifile_writestring(decoded_file,"System Access","PasswordComplexity", "1")
if not clear_store_pw:
if inifile_hasoption(decoded_file,"System Access","ClearTextPassword"):
if inifile_readstring(decoded_file,"System Access","ClearTextPassword") == "1":
inifile_writestring(decoded_file,"System Access","ClearTextPassword","0")
if admin_account_lockout:
if inifile_hasoption(decoded_file,"System Access","AllowAdministratorLockout"):
if inifile_readstring(decoded_file,"System Access","AllowAdministratorLockout") == "0":
inifile_writestring(decoded_file,"System Access","AllowAdministratorLockout","1")
encoded_file = "encoded_secconfig.ini"
encode_file(decoded_file, encoded_file)
run(rf'C:\Windows\system32\secedit.exe /import /cfg {encoded_file} /overwrite /areas SECURITYPOLICY /db wapt_secconfig /quiet')
run(r'C:\Windows\system32\secedit.exe /configure /db wapt_secconfig /overwrite /areas SECURITYPOLICY /quiet')
registry_set(HKEY_LOCAL_MACHINE,r'SYSTEM\CurrentControlSet\Control\SAM', 'RelaxMinimumPasswordLengthLimits', 1)
def uninstall():
uninstall_dir = makepath('C:','Windows','Temp','secedit_dir')
mkdirs(uninstall_dir)
run("net accounts /forcelogoff:no /minpwlen:0 /maxpwage:UNLIMITED /minpwage:0 /uniquepw:0 \
/lockoutthreshold:0 /lockoutwindow:30 /lockoutduration:30")
run(r'C:\Windows\system32\secedit.exe /export /cfg C:\Windows\Temp\secconfig.ini /areas SECURITYPOLICY')
decoded_file = makepath(uninstall_dir,"decoded_secconfig.ini")
decode_file("C:\Windows\Temp\secconfig.ini",decoded_file)
print('Unset complexity password')
inifile_writestring(decoded_file,"System Access","PasswordComplexity", "0")
inifile_writestring(decoded_file,"System Access","ClearTextPassword","0")
inifile_writestring(decoded_file,"System Access","AllowAdministratorLockout","1")
encoded_file = makepath(uninstall_dir,'encode_decoded_secconfig.ini')
encode_file(decoded_file, encoded_file)
run(rf'C:\Windows\system32\secedit.exe /import /cfg {encoded_file} /overwrite /areas SECURITYPOLICY /db wapt_secconfig /quiet')
run(r'C:\Windows\system32\secedit.exe /configure /db wapt_secconfig /overwrite /areas SECURITYPOLICY /quiet')
remove_tree(uninstall_dir)
registry_set(HKEY_LOCAL_MACHINE,r'SYSTEM\CurrentControlSet\Control\SAM', 'RelaxMinimumPasswordLengthLimits', 0)
def audit():
audit_dir = makepath('C:','Windows','Temp','secconfig_audit')
mkdirs(audit_dir)
audit_file = makepath(audit_dir,"secconfig.ini")
run(rf'C:\Windows\system32\secedit.exe /export /cfg {audit_file} /areas SECURITYPOLICY')
decoded_file = makepath(audit_dir,'decoded_secconfig.ini')
decode_file(audit_file, decoded_file)
parameter_in_fault = []
error = False
params = {"ForceLogoffWhenHourExpire ":forcelogoff},{'MinimumPasswordAge':minpwage},{'MaximumPasswordAge':maxpwage},{'MinimumPasswordLength':minpwlen}, \
{"PasswordHistorySize":uniquepw},{"LockoutBadCount":lockout_threshold},{"LockoutDuration":lockout_duration},{"ResetLockoutCount":reset_lockout_count}, \
{'PasswordComplexity':set_complexity},{"ClearTextPassword":clear_store_pw},{"AllowAdministratorLockout":admin_account_lockout}
for option in params:
for i in option:
if inifile_hasoption(decoded_file,"System Access",i):
if inifile_readstring(decoded_file,"System Access",i) == str(option[i]):
print(f"{i} is in correct value : {option[i]}")
elif str(option[i]) == "True":
if inifile_readstring(decoded_file,"System Access",i) == "1":
print(f"{i} is in correct value : {option[i]}")
else:
print(f'{i} isn\'t in correct value : {inifile_readstring(decoded_file,"System Access",i)} expected {option[i]}')
parameter_in_fault.append(i)
error = True
elif str(option[i]) == "False":
if inifile_readstring(decoded_file,"System Access",i) == "0":
print(f"{i} is in correct value : {option[i]}")
else:
print(f'{i} isn\'t in correct value : {inifile_readstring(decoded_file,"System Access",i)} expected {option[i]}')
parameter_in_fault.append(i)
error = True
else:
print(f'{i} isn\'t in correct value : {inifile_readstring(decoded_file,"System Access",i)} expected {option[i]}')
parameter_in_fault.append(i)
error = True
remove_tree(audit_dir)
if error:
WAPT.write_audit_data_if_changed("Windows password policy", 'Parameters in fault', parameter_in_fault, keep_days=365)
return "ERROR"
else:
WAPT.write_audit_data_if_changed("Windows password policy", 'Parameters in fault', "OK", keep_days=365)
return "OK"