From a480f1ab8ae086c2fec382c83fe4401d2bc0e50c Mon Sep 17 00:00:00 2001 From: =?utf8?q?Zolt=C3=A1n=20Felleg?= Date: Fri, 2 Jun 2023 23:42:51 +0200 Subject: [PATCH] Updated fdc.in (implemented password distribution server). --- .../c3d/firstboot/scripts/90_setupservices.sh | 4 + sources/fdc.in/c3d/mode.txt | 4 +- sources/fdc.in/c3d/owner.txt | 1 - .../install-data/etc/httpd/conf.d/fdc.80.conf | 8 +- .../c3d/postinstall/install-data/etc/pds.conf | 23 ++ .../postinstall/install-data/etc/rsyncd.conf | 9 + .../etc/systemd/system/pds.service | 11 + .../usr/local/bin/mailpwdexpiration.py | 60 ++- .../install-data/usr/local/bin/pds | 369 ++++++++++++++++++ .../var/www/htdocs.80/index.xhtml | 18 +- .../install-data/var/www/htdocs.80/main.css | 4 + .../var/www/htdocs.80/wsgi/epilogue.xhtml | 2 - .../www/htdocs.80/wsgi/passwordchange.wsgi | 101 ----- .../var/www/htdocs.80/wsgi/prologue.xhtml | 9 - .../var/www/wsgi/passwordchange.wsgi | 156 ++++++++ .../postinstall/scripts/10_setupservices.sh | 2 + .../c3d/preinstall/scripts/01_rsyncpdsdb.sh | 13 + sources/fdc.in/envvars | 1 + 18 files changed, 646 insertions(+), 149 deletions(-) create mode 100644 sources/fdc.in/c3d/postinstall/install-data/etc/pds.conf create mode 100644 sources/fdc.in/c3d/postinstall/install-data/etc/rsyncd.conf create mode 100644 sources/fdc.in/c3d/postinstall/install-data/etc/systemd/system/pds.service create mode 100755 sources/fdc.in/c3d/postinstall/install-data/usr/local/bin/pds delete mode 100644 sources/fdc.in/c3d/postinstall/install-data/var/www/htdocs.80/wsgi/epilogue.xhtml delete mode 100644 sources/fdc.in/c3d/postinstall/install-data/var/www/htdocs.80/wsgi/passwordchange.wsgi delete mode 100644 sources/fdc.in/c3d/postinstall/install-data/var/www/htdocs.80/wsgi/prologue.xhtml create mode 100644 sources/fdc.in/c3d/postinstall/install-data/var/www/wsgi/passwordchange.wsgi create mode 100755 sources/fdc.in/c3d/preinstall/scripts/01_rsyncpdsdb.sh diff --git a/sources/fdc.in/c3d/firstboot/scripts/90_setupservices.sh b/sources/fdc.in/c3d/firstboot/scripts/90_setupservices.sh index d22ac19..d8706ee 100755 --- a/sources/fdc.in/c3d/firstboot/scripts/90_setupservices.sh +++ b/sources/fdc.in/c3d/firstboot/scripts/90_setupservices.sh @@ -5,8 +5,12 @@ systemctl enable httpd.service systemctl start httpd.service systemctl enable oddjobd.service systemctl start oddjobd.service +systemctl enable pds.service +systemctl start pds.service systemctl enable postfix.service systemctl start postfix.service +systemctl enable rsyncd.service +systemctl start rsyncd.service systemctl enable sssd.service systemctl start sssd.service diff --git a/sources/fdc.in/c3d/mode.txt b/sources/fdc.in/c3d/mode.txt index 396fc87..4b91e7b 100644 --- a/sources/fdc.in/c3d/mode.txt +++ b/sources/fdc.in/c3d/mode.txt @@ -4,6 +4,6 @@ 444 postinstall/install-data/etc/ssh/ssh_host_*_key.pub 600 postinstall/install-data/etc/ssh/sshd_config.d/*.conf 600 postinstall/install-data/etc/sssd/sssd.conf -755 postinstall/install-data/usr/local/bin/*.py -755 postinstall/install-data/usr/local/bin/*.sh +755 postinstall/install-data/usr/local/bin/* 755 postinstall/scripts/*.sh +755 preinstall/scripts/*.sh diff --git a/sources/fdc.in/c3d/owner.txt b/sources/fdc.in/c3d/owner.txt index 1bb5c6e..49158bf 100644 --- a/sources/fdc.in/c3d/owner.txt +++ b/sources/fdc.in/c3d/owner.txt @@ -1,2 +1 @@ # owner file (relative to /c3d) -root:ssh_keys postinstall/install-data/etc/ssh/ssh_host_*_key diff --git a/sources/fdc.in/c3d/postinstall/install-data/etc/httpd/conf.d/fdc.80.conf b/sources/fdc.in/c3d/postinstall/install-data/etc/httpd/conf.d/fdc.80.conf index 53f7397..f5b2622 100644 --- a/sources/fdc.in/c3d/postinstall/install-data/etc/httpd/conf.d/fdc.80.conf +++ b/sources/fdc.in/c3d/postinstall/install-data/etc/httpd/conf.d/fdc.80.conf @@ -1,5 +1,3 @@ -WSGISocketPrefix run/wsgi - ServerName fdc.in.useribm.hu ServerAdmin siteadmin@useribm.hu @@ -10,7 +8,7 @@ WSGISocketPrefix run/wsgi Require all granted - WSGIDaemonProcess was.80 processes=1 threads=1 maximum-requests=10000 shutdown-timeout=5 - WSGIProcessGroup was.80 - WSGIScriptAlias /passwordchange /var/www/htdocs.80/wsgi/passwordchange.wsgi + WSGIDaemonProcess fdc.80 + WSGIProcessGroup fdc.80 + WSGIScriptAlias /passwordchange /var/www/wsgi/passwordchange.wsgi diff --git a/sources/fdc.in/c3d/postinstall/install-data/etc/pds.conf b/sources/fdc.in/c3d/postinstall/install-data/etc/pds.conf new file mode 100644 index 0000000..2c257a2 --- /dev/null +++ b/sources/fdc.in/c3d/postinstall/install-data/etc/pds.conf @@ -0,0 +1,23 @@ +[server] +address = +port = 1420 +database = /var/lib/pds/db + +[targets] +count = 2 + +[target.1] +format = htdigest +htdigest realm = webdrive +method = rsync +rsync host = store.in.useribm.hu +rsync module = httpdauth +rsync file = webdrive.digest + +[target.2] +format = htdigest +htdigest realm = ceges +method = rsync +rsync host = store.in.useribm.hu +rsync module = httpdauth +rsync file = ceges.digest diff --git a/sources/fdc.in/c3d/postinstall/install-data/etc/rsyncd.conf b/sources/fdc.in/c3d/postinstall/install-data/etc/rsyncd.conf new file mode 100644 index 0000000..a1546d2 --- /dev/null +++ b/sources/fdc.in/c3d/postinstall/install-data/etc/rsyncd.conf @@ -0,0 +1,9 @@ +transfer logging = yes +use chroot = no +uid = root +gid = root + +[pdsdb] + path = /var/lib/pds + read only = true + hosts allow = 10.228.0.0/16, 2001:1aa1:000a:0424::/64 diff --git a/sources/fdc.in/c3d/postinstall/install-data/etc/systemd/system/pds.service b/sources/fdc.in/c3d/postinstall/install-data/etc/systemd/system/pds.service new file mode 100644 index 0000000..4a5c50e --- /dev/null +++ b/sources/fdc.in/c3d/postinstall/install-data/etc/systemd/system/pds.service @@ -0,0 +1,11 @@ +[Unit] +Description=Password Distribution Server +After=NetworkManager.service +Wants=NetworkManager.service + +[Service] +Type=simple +ExecStart=/usr/local/bin/pds + +[Install] +WantedBy=multi-user.target diff --git a/sources/fdc.in/c3d/postinstall/install-data/usr/local/bin/mailpwdexpiration.py b/sources/fdc.in/c3d/postinstall/install-data/usr/local/bin/mailpwdexpiration.py index b8396ac..e5193ac 100755 --- a/sources/fdc.in/c3d/postinstall/install-data/usr/local/bin/mailpwdexpiration.py +++ b/sources/fdc.in/c3d/postinstall/install-data/usr/local/bin/mailpwdexpiration.py @@ -1,14 +1,17 @@ #!/usr/bin/env python +import os import ldap import time -import email +import pickle import smtplib +import email.policy +import email.message -LDAP_URI='ldaps://fds.useribm.hu' -USERS_BASE='ou=people,dc=user,dc=hu' +LDAP_URI = 'ldaps://fds.useribm.hu' +USERS_BASE = 'ou=people,dc=user,dc=hu' PWD_MAX_AGE = 365 * 24 * 60 * 60 @@ -19,38 +22,45 @@ PWD_WARNING_SUBJECT = 'Jelszavad {} nap múlva lejár' PWD_WARNING_MESSAGE = '''Tisztelt {}! A jelszavad a céges címtárban (például a fájlszerver eléréshez) le fog járni {} nap múlva. -Kérlek adj meg új jelszót (a régi megadása után) a https://www.useribm.hu/passwordchange oldalon +Kérlek adj meg új jelszót (a régi megadása után) a https://www.useribm.hu/passwordchange oldalon. -Üdvözlettel, Címtár''' +Üdvözlettel, +USER Címtár''' PWD_ERROR_SUBJECT = 'Jelszavad lejárt' PWD_ERROR_MESSAGE = '''Tisztelt {}! A jelszavad a céges címtárban (például a fájlszerver eléréshez) lejárt. -Kérlek adj meg új jelszót (a régi megadása után) a https://www.useribm.hu/passwordchange oldalon +Kérlek adj meg új jelszót (a régi megadása után) a https://www.useribm.hu/passwordchange oldalon. -Üdvözlettel, Címtár''' +Üdvözlettel, +USER Címtár''' def send_mail(mail_type, expiration_days, uid, email_address): - msg = email.message.EmailMessage() + msg = email.message.EmailMessage(email.policy.SMTP) if mail_type == 'WARNING': - msg.set_content(PWD_WARNING_MESSAGE.format(uid, expiration_days)) - msg['Subject'] = PWD_WARNING_SUBJECT.format(expiration_days) + msg.set_content(PWD_WARNING_MESSAGE.format(uid, + expiration_days)) + msg.add_header('Subject', + PWD_WARNING_SUBJECT.format(expiration_days)) elif mail_type == 'ERROR': msg.set_content(PWD_ERROR_MESSAGE.format(uid)) - msg['Subject'] = PWD_ERROR_SUBJECT + msg.add_header('Subject', PWD_ERROR_SUBJECT) elif mail_type == 'CRITICAL': msg.set_content(PWD_ERROR_MESSAGE.format(uid)) - msg['Subject'] = PWD_ERROR_SUBJECT + msg.add_header('Subject', PWD_ERROR_SUBJECT) else: msg.set_content('Invalid mail_type value: {}'.format(mail_type)) - msg['Subject'] = 'Invalid mail_type value: {}'.format(mail_type) + msg.add_header('Subject', + 'Invalid mail_type value: {}'.format(mail_type)) email_address = 'zoltan.felleg@userrendszerhaz.hu' - msg['From'] = 'dirsrv@useribm.hu' - msg['To'] = email_address + msg.add_header('From', '"USER Címtár" ') + msg.add_header('To', email_address) + msg.add_header('Date', time.asctime(time.gmtime())) srv = smtplib.SMTP() - srv.connect('mx.in.useribm.hu') + srv.connect('mx.in.useribm.hu', 587) + srv.ehlo() srv.send_message(msg) srv.quit() @@ -66,18 +76,28 @@ if __name__ == '__main__': 'pwdUpdateTime']) (search_result_type, search_result_data) = ldap_object.result() - current_timestamp = time.mktime(time.gmtime()) + current_ts = time.mktime(time.gmtime()) + valid_users = [] for item in search_result_data: (dn, values) = item if ('mail' in values) and ('pwdUpdateTime' in values): uid = values['uid'][0].decode('utf-8') email_address = values['mail'][0].decode('utf-8') pwd_update_time = values['pwdUpdateTime'][0].decode('utf-8') - pwd_update_timestamp = time.mktime(time.strptime(pwd_update_time, '%Y%m%d%H%M%S%z')) - expiration_seconds = PWD_MAX_AGE - (current_timestamp - pwd_update_timestamp) + pwd_update_ts = time.mktime(time.strptime(pwd_update_time, + '%Y%m%d%H%M%S%z')) + expiration_seconds = PWD_MAX_AGE - (current_ts - pwd_update_ts) expiration_days = expiration_seconds / (24 * 60 * 60) - rounded_expiration_days = int(expiration_days + 0.5) + if expiration_days < 0: + rounded_expiration_days = int(expiration_days - 0.5) + else: + rounded_expiration_days = int(expiration_days + 0.5) + valid_users.append(uid) + #print(uid, rounded_expiration_days) + #continue if rounded_expiration_days in PWD_EXPIRED_DAYS: send_mail('ERROR', rounded_expiration_days, uid, email_address) elif rounded_expiration_days in PWD_EXPIRING_DAYS: send_mail('WARNING', rounded_expiration_days, uid, email_address) + #elif uid == 'zfelleg': + # send_mail('CRITICAL', rounded_expiration_days, uid, email_address) diff --git a/sources/fdc.in/c3d/postinstall/install-data/usr/local/bin/pds b/sources/fdc.in/c3d/postinstall/install-data/usr/local/bin/pds new file mode 100755 index 0000000..9f8d3d1 --- /dev/null +++ b/sources/fdc.in/c3d/postinstall/install-data/usr/local/bin/pds @@ -0,0 +1,369 @@ +#!/usr/bin/env python + + +import os +import sys +import base64 +import pickle +import select +import signal +import socket +import hashlib +import subprocess +import configparser + + +class ossh: + + """Operating System Signal Handler. + + Class attributes: + None + + Instance attributes: + _cfg (private) + The configuration. + + Methods: + __init__ + Create an ossh. + _shutdown_server (private) + Shut down the server. + + """ + + def __init__(self): + """Create an ossh. + + Parameters: + None + + Return value: + An ossh. + + Exceptions: + all/any + + """ + self._cfg = configparser.ConfigParser() + self._cfg.read('/etc/pds.conf') + + server_cfg = self._cfg['server'] + self._server_address = server_cfg.get('address', 'localhost') + self._server_port = server_cfg.getint('port') + + signal.signal(signal.SIGINT, self._shutdown_server) + signal.signal(signal.SIGTERM, self._shutdown_server) + + def _shutdown_server(self, *args): + """Shut down the server. + + Parameters: + None + + Return value: + None + + Exceptions: + all/any + + """ + request_dict = {'request': 'shutdown'} + request_bytes = pickle.dumps(request_dict) + co = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + co.connect((self._server_address, self._server_port)) + co.sendall(request_bytes) + co.shutdown(socket.SHUT_RDWR) + co.close() + +class pds(): + + """Password Distribution Server. + + Class attributes: + None + + Instance attributes: + _cfg (private) + 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__ + Create a pds. + _shutdown (private) + Shut down the pds. + run + Run the pds. + + """ + + def __init__(self): + """Create a pds. + + Parameters: + None + + Return value: + a pds. + + """ + 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) + + self._signal_handler = ossh() + + def _change_password(self, request_dict): + """Change the password of a user. + + Parameters: + request_dict + The request. + + Return value: + The response. + + """ + login_name = request_dict['login name'] + password_b16 = request_dict['password'] + 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.' + return {'success': False, 'reason': reason} + return {'success': True} + + def _expire_password(self, request_dict): + """Expire the password of a user. + + Parameters: + request_dict + The request. + + Return value: + None + + """ + 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.' + 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. + + Parameters: + client_co + The connection object (socket) of the client. + response_dict + The response. + + Return value: + None + + """ + 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. + + Parameters: + None + + Return value: + None + + """ + self._co.shutdown(socket.SHUT_RDWR) + self._co.close() + sys.exit() + + def run(self): + """Run the pds. + + Parameters: + None + + Return value: + None + + """ + server_cfg = self._cfg['server'] + server_address = server_cfg.get('address') + server_port = server_cfg.getint('port') + self._co.bind((server_address, server_port)) + self._co.listen(5) + while True: + (rfr, rfw, rfx) = select.select([self._co], [], [], 900) + if rfr == []: + print('no client') + sys.stdout.flush() + continue + + (client_co, client_address) = self._co.accept() + print('Connected by {}'.format(client_address)) + sys.stdout.flush() + request_bytes = client_co.recv(4096) + if not request_bytes: + print('Disconnected by {}'.format(client_address)) + sys.stdout.flush() + client_co.close() + continue + request_dict = pickle.loads(request_bytes) + print('Received: {}'.format(request_dict)) + sys.stdout.flush() + request = request_dict['request'] + if request == 'change password': + response_dict = self._change_password(request_dict) + elif request == 'expire password': + response_dict = self._expire_password(request_dict) + elif request == 'shutdown': + client_co.shutdown(socket.SHUT_RDWR) + client_co.close() + self._shutdown() + self._respond(client_co, response_dict) + client_co.shutdown(socket.SHUT_RDWR) + client_co.close() + + +if __name__ == '__main__': + server = pds() + server.run() diff --git a/sources/fdc.in/c3d/postinstall/install-data/var/www/htdocs.80/index.xhtml b/sources/fdc.in/c3d/postinstall/install-data/var/www/htdocs.80/index.xhtml index fde0847..ac9eef7 100644 --- a/sources/fdc.in/c3d/postinstall/install-data/var/www/htdocs.80/index.xhtml +++ b/sources/fdc.in/c3d/postinstall/install-data/var/www/htdocs.80/index.xhtml @@ -8,16 +8,16 @@
-

Login Name:

-

-

Old Password:

-

+

Felhaszálónév:

+

+

Régi jelszó:

+


-

New Password:

-

-

New Password Again:

-

-

+

Új jelszó:

+

+

Új jelszó mégegyszer:

+

+

diff --git a/sources/fdc.in/c3d/postinstall/install-data/var/www/htdocs.80/main.css b/sources/fdc.in/c3d/postinstall/install-data/var/www/htdocs.80/main.css index ec079d7..e98b637 100644 --- a/sources/fdc.in/c3d/postinstall/install-data/var/www/htdocs.80/main.css +++ b/sources/fdc.in/c3d/postinstall/install-data/var/www/htdocs.80/main.css @@ -2,3 +2,7 @@ h1, p { /* Center horizontally*/ text-align: center; } + +hr { + width: 25%; +} diff --git a/sources/fdc.in/c3d/postinstall/install-data/var/www/htdocs.80/wsgi/epilogue.xhtml b/sources/fdc.in/c3d/postinstall/install-data/var/www/htdocs.80/wsgi/epilogue.xhtml deleted file mode 100644 index b605728..0000000 --- a/sources/fdc.in/c3d/postinstall/install-data/var/www/htdocs.80/wsgi/epilogue.xhtml +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/sources/fdc.in/c3d/postinstall/install-data/var/www/htdocs.80/wsgi/passwordchange.wsgi b/sources/fdc.in/c3d/postinstall/install-data/var/www/htdocs.80/wsgi/passwordchange.wsgi deleted file mode 100644 index d8f1047..0000000 --- a/sources/fdc.in/c3d/postinstall/install-data/var/www/htdocs.80/wsgi/passwordchange.wsgi +++ /dev/null @@ -1,101 +0,0 @@ -import os -import cgi -import sys -import ldap -import traceback - - -LDAP_URI='ldaps://fds.useribm.hu' -USERS_BASE='ou=people,dc=user,dc=hu' - - -def password_change_app(environ, start_response): - - error_occured = False - - field_storage = cgi.FieldStorage(fp=environ['wsgi.input'], - environ=environ, - keep_blank_values=True) - - uid = field_storage['login_name'].value - old_password = field_storage['old_password'].value - new_password = field_storage['new_password'].value - new_password_again = field_storage['new_password_again'].value - - if new_password != new_password_again: - formatted_traceback = ['NEW_PASSWORD_MISMATCH'] - error_occured = True - - if not error_occured: - try: - ldap_object = ldap.initialize(LDAP_URI) - #ldap_object.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER) - #ldap_object.set_option(ldap.OPT_X_TLS_NEWCTX, 0) - except: - (exc_type, exc_value, exc_traceback) = sys.exc_info() - formatted_traceback = traceback.format_exception(exc_type, - exc_value, - exc_traceback) - error_occured = True - - if not error_occured: - user_dn=','.join(['uid={}'.format(uid), USERS_BASE]) - try: - bind_id = ldap_object.simple_bind(user_dn, old_password) - (bind_result_type, bind_result_data) = ldap_object.result() - except: - (exc_type, exc_value, exc_traceback) = sys.exc_info() - formatted_traceback = traceback.format_exception(exc_type, - exc_value, - exc_traceback) - error_occured = True - - if not error_occured: - try: - password_change_id = ldap_object.passwd(user_dn, - old_password, - new_password) - (pwd_result_type, pwd_result_data) = ldap_object.result() - except: - (exc_type, exc_value, exc_traceback) = sys.exc_info() - formatted_traceback = traceback.format_exception(exc_type, - exc_value, - exc_traceback) - error_occured = True - - prologue_file = open('/var/www/htdocs.80/wsgi/prologue.xhtml', 'r') - response_prologue = prologue_file.read() - prologue_file.close() - response_epilogue = '' - if not error_occured: - success_text = '

Woohoo, you have successfully changed your password!

' - response_texts = [response_prologue, - success_text, - response_epilogue] - else: - response_texts = [response_prologue, '
']
-        response_texts.extend(formatted_traceback)
-        response_texts.append('
') - response_texts.append('

') - response_texts.append(response_epilogue) - response_body = bytes(os.linesep.join(response_texts), 'utf-8') - - # HTTP response code and message - status = '200 OK' - - # HTTP headers expected by the client - # They must be wrapped as a list of tupled pairs: - # [(Header name, Header value)]. - response_headers = [ - ('Content-Type', 'text/html'), - ('Content-Length', str(len(response_body))) - ] - - # Send them to the server using the supplied function - start_response(status, response_headers) - - # Return the response body. Notice it is wrapped - # in a list although it could be any iterable. - return [response_body] - -application = password_change_app diff --git a/sources/fdc.in/c3d/postinstall/install-data/var/www/htdocs.80/wsgi/prologue.xhtml b/sources/fdc.in/c3d/postinstall/install-data/var/www/htdocs.80/wsgi/prologue.xhtml deleted file mode 100644 index b9f6005..0000000 --- a/sources/fdc.in/c3d/postinstall/install-data/var/www/htdocs.80/wsgi/prologue.xhtml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - Password Change - - - - diff --git a/sources/fdc.in/c3d/postinstall/install-data/var/www/wsgi/passwordchange.wsgi b/sources/fdc.in/c3d/postinstall/install-data/var/www/wsgi/passwordchange.wsgi new file mode 100644 index 0000000..3162a52 --- /dev/null +++ b/sources/fdc.in/c3d/postinstall/install-data/var/www/wsgi/passwordchange.wsgi @@ -0,0 +1,156 @@ +import os +import sys +import ldap +import base64 +import pickle +import socket +import traceback +import configparser +import urllib.parse + + +LDAP_URI='ldaps://fds.useribm.hu' +USERS_BASE='ou=people,dc=user,dc=hu' + +html_prologue = """ + + + + Password Change + + + + """ + +html_epilogue = """ +""" + +error_prologue = """

Az alábbi hiba miatt nem sikerült megváltoztatni a jelszavadat. + Ha a hibaüzenet utolsó sora mond neked valamit, + próbáld meg újra.

+

Ha nem, keresd meg zfelleget.

+

(Akinek persze az lesz az első kérdése, hogy mi volt a + hibaüzenet utolsó sora, úgyhogy azt vagy mentsd el/írd le, + vagy hagyd nyitva ezt a böngészőablakot.)

+
"""
+
+error_epilogue = """    
+

""" + +success_text = """

Jelszavadat sikeresen megváltoztattad, + az új jelszó azonnal érvényes.

""" + + +def password_change_app(environ, start_response): + + error_occured = False + + form_data_bytes = environ['wsgi.input'].read() + form_data_text = form_data_bytes.decode() + form_data_dict = urllib.parse.parse_qs(form_data_text) + #formatted_traceback = ['{}'.format(form_data_dict)] + #error_occured = True + uid = form_data_dict['login name'][0] + old_password = form_data_dict['old password'][0] + new_password = form_data_dict['new password'][0] + new_password_again = form_data_dict['new password again'][0] + + if new_password != new_password_again: + formatted_traceback = ['The (new) passwords do not match.'] + error_occured = True + + if not error_occured: + try: + ldap_object = ldap.initialize(LDAP_URI) + #ldap_object.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER) + #ldap_object.set_option(ldap.OPT_X_TLS_NEWCTX, 0) + except: + (exc_type, exc_value, exc_traceback) = sys.exc_info() + formatted_traceback = traceback.format_exception(exc_type, + exc_value, + exc_traceback) + error_occured = True + + if not error_occured: + user_dn=','.join(['uid={}'.format(uid), USERS_BASE]) + try: + bind_id = ldap_object.simple_bind(user_dn, old_password) + (bind_result_type, bind_result_data) = ldap_object.result() + except: + (exc_type, exc_value, exc_traceback) = sys.exc_info() + formatted_traceback = traceback.format_exception(exc_type, + exc_value, + exc_traceback) + error_occured = True + + if not error_occured: + try: + password_change_id = ldap_object.passwd(user_dn, + old_password, + new_password) + (pwd_result_type, pwd_result_data) = ldap_object.result() + except: + (exc_type, exc_value, exc_traceback) = sys.exc_info() + formatted_traceback = traceback.format_exception(exc_type, + exc_value, + exc_traceback) + error_occured = True + + if not error_occured: + try: + password_bytes = bytes(new_password, 'utf-8') + password_b64 = base64.b64encode(password_bytes) + password_b16 = base64.b16encode(password_b64) + cfg = configparser.ConfigParser() + cfg.read('/etc/pds.conf') + server_cfg = cfg['server'] + server_address = server_cfg.get('address', 'localhost') + server_port = server_cfg.getint('port') + request_dict = {'request': 'change password', + 'login name': uid, + 'password': password_b16} + request_bytes = pickle.dumps(request_dict) + co = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + co.settimeout(3) + co.connect((server_address, server_port)) + co.sendall(request_bytes) + response_bytes = co.recv(4096) + co.shutdown(socket.SHUT_RDWR) + co.close() + except: + (exc_type, exc_value, exc_traceback) = sys.exc_info() + formatted_traceback = traceback.format_exception(exc_type, + exc_value, + exc_traceback) + error_occured = True + + if not error_occured: + response_texts = [html_prologue, + success_text, + html_epilogue] + else: + response_texts = [html_prologue, error_prologue] + response_texts.extend(formatted_traceback) + response_texts.append(error_epilogue) + response_texts.append(html_epilogue) + response_body = bytes(os.linesep.join(response_texts), 'utf-8') + + # HTTP response code and message + status = '200 OK' + + # HTTP headers expected by the client + # They must be wrapped as a list of tupled pairs: + # [(Header name, Header value)]. + response_headers = [ + ('Content-Type', 'text/html'), + ('Content-Length', str(len(response_body))) + ] + + # Send them to the server using the supplied function + start_response(status, response_headers) + + # Return the response body. Notice it is wrapped + # in a list although it could be any iterable. + return [response_body] + +application = password_change_app diff --git a/sources/fdc.in/c3d/postinstall/scripts/10_setupservices.sh b/sources/fdc.in/c3d/postinstall/scripts/10_setupservices.sh index 0c374f3..8c41959 100755 --- a/sources/fdc.in/c3d/postinstall/scripts/10_setupservices.sh +++ b/sources/fdc.in/c3d/postinstall/scripts/10_setupservices.sh @@ -3,7 +3,9 @@ systemctl disable httpd.service systemctl disable oddjobd.service +systemctl disable pds.service systemctl disable postfix.service +systemctl disable rsyncd.service systemctl disable sssd.service systemctl disable NetworkManager-wait-online.service diff --git a/sources/fdc.in/c3d/preinstall/scripts/01_rsyncpdsdb.sh b/sources/fdc.in/c3d/preinstall/scripts/01_rsyncpdsdb.sh new file mode 100755 index 0000000..40ad8a1 --- /dev/null +++ b/sources/fdc.in/c3d/preinstall/scripts/01_rsyncpdsdb.sh @@ -0,0 +1,13 @@ +#!/bin/sh + + +. $1 + + +/usr/bin/rsync \ + --archive \ + --delete-after \ + --info=STATS \ + --mkpath \ + fdc.in.useribm.hu::pdsdb \ + $CONTAINER_BUILDROOT/c3d/postinstall/install-data/var/lib/pds diff --git a/sources/fdc.in/envvars b/sources/fdc.in/envvars index 77209a7..54292e6 100644 --- a/sources/fdc.in/envvars +++ b/sources/fdc.in/envvars @@ -3,6 +3,7 @@ DISTRIBUTION_VERSION=38 SPEC_PACKAGES="authselect \ cronie \ httpd \ + mkpasswd \ oddjob-mkhomedir \ openldap-clients \ openssh-clients \ -- 2.54.0