import select
import signal
import socket
-import hashlib
import subprocess
import configparser
The configuration.
_co (private)
The connection object (socket).
- _db (private)
- The password database.
- _db_file_name (private)
- The (fully qualified) file name of the password database.
Methods:
__init__
self._cfg = configparser.ConfigParser()
self._cfg.read('/etc/pds.conf')
- self._db_file_name = self._cfg['server']['database']
- db_file = open(self._db_file_name, 'rb')
- self._db = pickle.load(db_file)
- db_file.close()
-
self._co = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self._co.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
password_b64 = base64.b16decode(password_b16)
password_bytes = base64.b64decode(password_b64)
password_string = password_bytes.decode('utf-8')
- password_dict = {}
- targets_cfg = self._cfg['targets']
- target_count = targets_cfg.getint('count')
- for target_serial in range(target_count):
- target_section = 'target.{}'.format(target_serial + 1)
- target_cfg = self._cfg[target_section]
- target_format = target_cfg.get('format')
- if target_format != 'htdigest':
- reason = 'Invalid format {}.'.format(target_format)
- return {'success': False, 'reason': reason}
- target_realm = target_cfg.get('htdigest realm')
- source_string = '{}:{}:{}'.format(login_name,
- target_realm,
- password_string)
- source_bytes = source_string.encode('utf-8')
- htdigest = hashlib.md5(source_bytes).hexdigest()
- password_dict[(target_format, target_realm)] = htdigest
- #md5_digest = hashlib.md5(password_bytes).hexdigest()
- #sha1_digest = hashlib.sha1(password_bytes).hexdigest()
- #sha224_digest = hashlib.sha224(password_bytes).hexdigest()
- #sha256_digest = hashlib.sha256(password_bytes).hexdigest()
- #sha384_digest = hashlib.sha384(password_bytes).hexdigest()
- #sha512_digest = hashlib.sha512(password_bytes).hexdigest()
- #result = subprocess.run(['mkpasswd',
- # '--method=md5crypt',
- # password_bytes],
- # capture_output=True)
- #salted_md5_digest = result.stdout.decode().strip()
- #result = subprocess.run(['mkpasswd',
- # '--method=sha256crypt',
- # password_bytes],
- # capture_output=True)
- #salted_sha256_digest = result.stdout.decode().strip()
- #result = subprocess.run(['mkpasswd',
- # '--method=sha512crypt',
- # password_bytes],
- # capture_output=True)
- #salted_sha512_digest = result.stdout.decode().strip()
- #result = subprocess.run(['mkpasswd',
- # '--method=yescrypt',
- # password_bytes],
- # capture_output=True)
- #yescrypt_digest = result.stdout.decode().strip()
-
- self._db[login_name] = password_dict
- success = self._save_db()
- if not success:
- reason = 'Could not save password database.'
- return {'success': False, 'reason': reason}
- success = self._notifytargets()
- if not success:
- reason = 'Could not notify all targets.'
+ smbpasswd_command = 'echo -e "{}\n{}" | smbpasswd -a -s {}'
+ smbpasswd_command = smbpasswd_command.format(password_string,
+ password_string,
+ login_name)
+ command_list = ['ssh', 'store', '--', smbpasswd_command]
+ completed_process = subprocess.run(command_list, capture_output=True)
+ if completed_process.returncode != 0:
+ reason = completed_process.stderr.decode('utf-8')
return {'success': False, 'reason': reason}
return {'success': True}
"""
login_name = request_dict['login name']
- if login_name in self._db:
- del self._db[login_name]
- success = self._save_db()
- if not success:
- reason = 'Could not save password database.'
- return {'success': False, 'reason': reason}
- success = self._notifytargets()
- if not success:
- reason = 'Could not notify all targets.'
+ smbpasswd_command = 'smbpasswd -d -s {}'.format(login_name)
+ command_list = ['ssh', 'store', '--', smbpasswd_command]
+ completed_process = subprocess.run(command_list, capture_output=True)
+ if completed_process.returncode != 0:
+ reason = completed_process.stderr.decode('utf-8')
return {'success': False, 'reason': reason}
return {'success': True}
- def _notifytargets(self):
- """Notify targets of the changed/expired passwords.
-
- Parameters:
- None
-
- Return value:
- None
-
- """
- success = True
- targets_cfg = self._cfg['targets']
- target_count = targets_cfg.getint('count')
- for target_serial in range(target_count):
- target_section = 'target.{}'.format(target_serial + 1)
- target_cfg = self._cfg[target_section]
- target_format = target_cfg.get('format')
- target_method = target_cfg.get('method')
- if (target_format, target_method) != ('htdigest', 'rsync'):
- success = False
- continue
- target_realm = target_cfg.get('htdigest realm')
- db_key = (target_format, target_realm)
- target_host = target_cfg.get('rsync host')
- target_module = target_cfg.get('rsync module')
- target_file = target_cfg.get('rsync file')
- local_file_name = os.path.join('/tmp', target_file)
- local_file = open(local_file_name, 'wt')
- digest_lines = []
- for login_name in sorted(self._db.keys()):
- if db_key not in self._db[login_name]:
- success = False
- continue
- htdigest = self._db[login_name][db_key]
- digest_line = '{}:{}:{}{}'.format(login_name,
- target_realm,
- htdigest,
- os.linesep)
- digest_lines.append(digest_line)
- local_file.writelines(digest_lines)
- local_file.close()
- rsync_target = '{}::{}'.format(target_host, target_module)
- result = subprocess.run(['rsync',
- '--archive',
- local_file_name,
- rsync_target])
- if result.returncode != 0:
- success = False
- return success
-
def _respond(self, client_co, response_dict):
"""Respond to a client.
response_bytes = pickle.dumps(response_dict)
client_co.sendall(response_bytes)
- def _save_db(self):
- """Save the password database.
-
- Parameters:
- None
-
- Return value:
- success
-
- """
- db_file = open(self._db_file_name, 'wb')
- pickle.dump(self._db, db_file)
- db_file.close()
- return True
-
def _shutdown(self):
"""Shut down the pds.