diff --git a/WAPT/control b/WAPT/control index a341ea5..a55886d 100644 --- a/WAPT/control +++ b/WAPT/control @@ -1,11 +1,11 @@ package : fws-backuppc-agent -version : 1.3.4-4 +version : 1.3.4-18 architecture : all section : base priority : optional maintainer : Daniel Berteaud description : BackupPC Agent -depends : fws-openssh +depends : fws-openssh,fws-sysinternals-suite conflicts : maturity : DEV locale : all diff --git a/deploy_keys.bat.j2 b/deploy_keys.bat.j2 new file mode 100644 index 0000000..03bafaa --- /dev/null +++ b/deploy_keys.bat.j2 @@ -0,0 +1,7 @@ +@echo off + +IF NOT EXIST "%USERPROFILE%\.ssh" mkdir "%USERPROFILE%\.ssh" +IF EXIST "%USERPROFILE%\.ssh\authorized_keys" del /q "%USERPROFILE%\.ssh\authorized_keys" +{% for key in ssh_keys %} +echo {{ key }} >> "%USERPROFILE%\.ssh\authorized_keys" +{% endfor %} \ No newline at end of file diff --git a/setup.py b/setup.py index aa0e611..c705aa6 100644 --- a/setup.py +++ b/setup.py @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- from setuphelpers import * from cryptography.fernet import Fernet -import json -import os +import json, os, random, string, time +from jinja2 import Environment, FileSystemLoader uninstallkey = [] @@ -18,7 +18,12 @@ if isfile(makepath(programfiles32,'wapt','private','symetric.txt')) and isfile(m f = Fernet(open(makepath(programfiles32,'wapt','private','symetric.txt'),'r').read()) variables.update(json.loads(f.decrypt(open(makepath(programfiles32,'wapt','private','variables.txt'),'r').read()))) +# Create a random pass for the local backup account if not defined +if not 'backup_pass' in variables: + variables['backup_pass'] = ''.join(random.sample(string.lowercase+string.uppercase+string.digits,60)) + overrides = ['rsyncd.conf', 'rsync.cmd', 'pre-exec.cmd', 'vsrsync.cmd', 'cygiconv-2.dll', 'cygwin1.dll', 'cygz.dll', 'rsync.exe'] +install_dir = makepath(os.getenv('SYSTEMDRIVE','C:\\'),'BackupPC') def install(): print('Installing BackupPC Agent') @@ -31,11 +36,11 @@ def install(): print('Overriding scripts and binaries') for file in overrides: print('Copying %s' % file) - filecopyto(file,makepath(os.getenv('SYSTEMDRIVE','C:\\'),'BackupPC')) + filecopyto(file, install_dir) # We write credential file print('Writing credential file') - open(makepath(os.getenv('SYSTEMDRIVE','C:\\'),'BackupPC','rsyncd.secrets'),'w').write('backup:%s' % variables['backup_rsync_pass']) + open(r'%s\rsyncd.secrets' % install_dir,'w').write('backup:%s' % variables['backup_rsync_pass']) # The default behaviour is to add a firewall rule allowing local network. We'll remove this rule to create a more restrictive one print('Removing uneeded firewall rules') @@ -44,31 +49,48 @@ def install(): # Create the backup account print('Create a local account and add it to the admin group') run('net user lbkp /add', accept_returncodes=[0,2]) - if 'backup_pass' in variables : - run('net user lbkp %s' % variables['backup_pass']) + run('net user lbkp %s' % variables['backup_pass']) run('net localgroup Administrateurs lbkp /add', accept_returncodes=[0,2]) - print('Writing SSH Keys for the backup account') - mkdirs(makepath(os.getenv('SYSTEMDRIVE','C:\\'),'Users','lbkp','.ssh')) - open(makepath(os.getenv('SYSTEMDRIVE','C:\\'),'Users','lbkp','.ssh','authorized_keys'),'w').write("\n".join(variables['backup_ssh_keys'])) - run(r'icacls.exe "%s" /inheritance:d' % makepath(os.getenv('SYSTEMDRIVE','C:\\'),'Users','lbkp','.ssh','authorized_keys')) - run(r'icacls.exe "%s" /remove:g "*S-1-5-32-545" /t /c /q' % makepath(os.getenv('SYSTEMDRIVE','C:\\'),'Users','lbkp','.ssh','authorized_keys')) - run(r'icacls.exe "%s" /remove:g "*S-1-5-11" /t /c /q' % makepath(os.getenv('SYSTEMDRIVE','C:\\'),'Users','lbkp','.ssh','authorized_keys')) - run(r'icacls.exe "%s" /grant "NT SERVICE\sshd":(R)' % makepath(os.getenv('SYSTEMDRIVE','C:\\'),'Users','lbkp','.ssh','authorized_keys')) + + print('Restricting permissions on private files') + run(r'icacls.exe "%s" /inheritance:d' % install_dir) + run(r'icacls.exe "%s" /remove:g "*S-1-5-32-545" /t /c /q' % install_dir) + run(r'icacls.exe "%s" /remove:g "*S-1-5-11" /t /c /q' % install_dir) + run(r'icacls.exe "%s" /remove:g "*S-1-5-1" /t /c /q' % install_dir) + run(r'icacls.exe "%s" /remove:g "*S-1-1-0" /t /c /q' % install_dir) + + print('Creating the deploy_keys.bat') + jinja2 = Environment( + loader=FileSystemLoader('.'), + trim_blocks=True + ) + open(r'%s\deploy_keys.bat' % install_dir,'w').write( + jinja2.get_template('deploy_keys.bat.j2').render( + ssh_keys = variables['backup_ssh_keys'] + ) + ) + # We need to create lbkp profile dir and put it's .ssh.authorized_keys file. + # We can't use runas, we can't use psexec either as waptservice runs as SYSTEM. So we create a one-time task running as user lbkp + # This task just creates .ssh and populate .ssh/authorized_keys + print('Deploying ssh keys through a scheduled task') + run(r'schtasks /Create /SC ONCE /TN "deploy_backup_ssh_keys" /TR "%s\deploy_keys.bat" /ST "%s" /RU lbkp /RP %s /F /V1 /Z' % (install_dir, time.strftime('%H:%M:%S',time.localtime(time.time() + 120)), variables['backup_pass'])) + run_task('deploy_backup_ssh_keys') + delete_task('deploy_backup_ssh_keys') def uninstall(): print('Removing BackupPC Agent') - print('Removing lbkp from Admin group') - run('net localgroup Administrateurs lbkp /delete', accept_returncodes=[0,2]) + print('Removing lbkp account') + delete_user('lbkp') print('Removing files') for file in overrides: - path = makepath(os.getenv('SYSTEMDRIVE','C:\\'),'BackupPC',file) + path = makepath(install_dir, file) if isfile(path): os.unlink(path) def audit(): for file in overrides + ['rsyncd.secrets','part.cmd' ]: - if not isfile(makepath(os.getenv('SYSTEMDRIVE','C:\\'),'BackupPC',file)): - print('%s is missing' % makepath(os.getenv('SYSTEMDRIVE','C:\\'),'BackupPC',file)) + if not isfile(makepath(install_dir, file)): + print('%s is missing' % makepath(install_dir, file)) return "ERROR" return "OK" \ No newline at end of file