Updated fdc.in (added samba password synchronization).
authorZoltán Felleg <zoltan.felleg@userrendszerhaz.hu>
Mon, 9 Sep 2024 12:07:11 +0000 (14:07 +0200)
committerZoltán Felleg <zoltan.felleg@userrendszerhaz.hu>
Mon, 9 Sep 2024 12:07:11 +0000 (14:07 +0200)
sources/fdc.in/c3d/mode.txt
sources/fdc.in/c3d/postinstall/install-data/etc/pds.conf
sources/fdc.in/c3d/postinstall/install-data/etc/ssh/ssh_host_ed25519_key-cert.pub
sources/fdc.in/c3d/postinstall/install-data/etc/ssh/ssh_known_hosts [new file with mode: 0644]
sources/fdc.in/c3d/postinstall/install-data/root/.ssh/config [new file with mode: 0644]
sources/fdc.in/c3d/postinstall/install-data/root/.ssh/scripts [new file with mode: 0644]
sources/fdc.in/c3d/postinstall/install-data/root/.ssh/scripts-cert-perpetual.pub [new file with mode: 0644]
sources/fdc.in/c3d/postinstall/install-data/root/.ssh/scripts.pub [new file with mode: 0644]
sources/fdc.in/c3d/postinstall/install-data/usr/local/bin/mailpwdexpiration.py
sources/fdc.in/c3d/postinstall/install-data/usr/local/bin/pds
sources/fdc.in/c3d/postinstall/install-data/var/www/wsgi/passwordchange.wsgi

index 4b91e7b39335fe7f30bf922afc60fadab43fa1c1..845a89f0711d87c6ee505cc4c293ea76347fcce7 100644 (file)
@@ -4,6 +4,8 @@
 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
+700 postinstall/install-data/root/.ssh
+600 postinstall/install-data/root/.ssh/scripts
 755 postinstall/install-data/usr/local/bin/*
 755 postinstall/scripts/*.sh
 755 preinstall/scripts/*.sh
index 2c257a27159032d0633d1f805fb63159cd27ceed..7f18598fed21ee8e847ed65c3335446566d7bb80 100644 (file)
@@ -4,9 +4,14 @@ port = 1420
 database = /var/lib/pds/db
 
 [targets]
-count = 2
+count = 3
 
 [target.1]
+format = cleartext
+method = ssh smbpasswd
+ssh host = store
+
+[target.2]
 format = htdigest
 htdigest realm = webdrive
 method = rsync
@@ -14,7 +19,7 @@ rsync host = store.in.useribm.hu
 rsync module = httpdauth
 rsync file = webdrive.digest
 
-[target.2]
+[target.3]
 format = htdigest
 htdigest realm = ceges
 method = rsync
index 890580871d60ca7d2065c86086a299e3acfd4cb0..76be8cad801725e7891815cd09ecddbe1daba793 100644 (file)
@@ -1 +1 @@
-ssh-ed25519-cert-v01@openssh.com AAAAIHNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAIDKU1Qv0xVQsBXFkQ7BLNDz41lny8emxGrAhdTvAWt/tAAAAIB70M2gk+Ew23Vkcr1exHW705JPkUBygcv0xVdqsQOjfAAAAAAAAAAAAAAACAAAADmZkYy51c2VyaWJtLmh1AAAAEgAAAA5mZGMudXNlcmlibS5odQAAAAAAAAAA//////////8AAAAAAAAAAAAAAAAAAAAzAAAAC3NzaC1lZDI1NTE5AAAAIEXYIIzrUSx8/BQ6/ttkSr5oEyB5F5Yg4bp1DOkqDON9AAAAUwAAAAtzc2gtZWQyNTUxOQAAAEDPGYtr8L8QZkualco2Bhh2oT8QpU9IDvAdnSBp5kEpdpksiL2j/8YUUZ/E1fys2Tk/Q/eoyb31K6peYuiOjAAK ssh_host_ed25519_key.pub
+ssh-ed25519-cert-v01@openssh.com AAAAIHNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAIJlu3dQ4lI01w8aNXw4EnUaiSkGjnjTlz3RzGur0fWfoAAAAIB70M2gk+Ew23Vkcr1exHW705JPkUBygcv0xVdqsQOjfAAAAAAAAAAAAAAACAAAAEWZkYy5pbi51c2VyaWJtLmh1AAAAAAAAAAAAAAAA//////////8AAAAAAAAAAAAAAAAAAAAzAAAAC3NzaC1lZDI1NTE5AAAAIEXYIIzrUSx8/BQ6/ttkSr5oEyB5F5Yg4bp1DOkqDON9AAAAUwAAAAtzc2gtZWQyNTUxOQAAAECeArHKF8nQwbVLxF3DnPzAAbo1VlhZzGlgFU/Vi/T5wRPzlH4a1llV0omQWoy8Momvg1MLa3iSW1K5Tn+odo0G ssh_host_ed25519_key.pub
diff --git a/sources/fdc.in/c3d/postinstall/install-data/etc/ssh/ssh_known_hosts b/sources/fdc.in/c3d/postinstall/install-data/etc/ssh/ssh_known_hosts
new file mode 100644 (file)
index 0000000..b1e530e
--- /dev/null
@@ -0,0 +1 @@
+@cert-authority *.in.useribm.hu ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEXYIIzrUSx8/BQ6/ttkSr5oEyB5F5Yg4bp1DOkqDON9 host-CA
diff --git a/sources/fdc.in/c3d/postinstall/install-data/root/.ssh/config b/sources/fdc.in/c3d/postinstall/install-data/root/.ssh/config
new file mode 100644 (file)
index 0000000..36b798d
--- /dev/null
@@ -0,0 +1,4 @@
+Host store
+  HostName store.in.useribm.hu
+  IdentityFile ~/.ssh/scripts
+  CertificateFile ~/.ssh/scripts-cert-perpetual.pub
diff --git a/sources/fdc.in/c3d/postinstall/install-data/root/.ssh/scripts b/sources/fdc.in/c3d/postinstall/install-data/root/.ssh/scripts
new file mode 100644 (file)
index 0000000..8b28294
--- /dev/null
@@ -0,0 +1,7 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
+QyNTUxOQAAACCov7UxRarXY9DYCnXN3p9V9dIA+cdgE01zDt2Ib7skaAAAAJDhnXcI4Z13
+CAAAAAtzc2gtZWQyNTUxOQAAACCov7UxRarXY9DYCnXN3p9V9dIA+cdgE01zDt2Ib7skaA
+AAAEDur/ftds6sV1ODzHgaE9Zopp9q81/cpZ28oeJx0kBqs6i/tTFFqtdj0NgKdc3en1X1
+0gD5x2ATTXMO3YhvuyRoAAAAB3NjcmlwdHMBAgMEBQY=
+-----END OPENSSH PRIVATE KEY-----
diff --git a/sources/fdc.in/c3d/postinstall/install-data/root/.ssh/scripts-cert-perpetual.pub b/sources/fdc.in/c3d/postinstall/install-data/root/.ssh/scripts-cert-perpetual.pub
new file mode 100644 (file)
index 0000000..ad5a767
--- /dev/null
@@ -0,0 +1 @@
+ssh-ed25519-cert-v01@openssh.com AAAAIHNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAIKS44C/sAOymRuRk+hakczneUKQgOvzHOK2f0PscogULAAAAIKi/tTFFqtdj0NgKdc3en1X10gD5x2ATTXMO3YhvuyRoAAAAAAAAAAAAAAABAAAAB3NjcmlwdHMAAAAIAAAABHJvb3QAAAAAAAAAAP//////////AAAAAAAAAIIAAAAVcGVybWl0LVgxMS1mb3J3YXJkaW5nAAAAAAAAABdwZXJtaXQtYWdlbnQtZm9yd2FyZGluZwAAAAAAAAAWcGVybWl0LXBvcnQtZm9yd2FyZGluZwAAAAAAAAAKcGVybWl0LXB0eQAAAAAAAAAOcGVybWl0LXVzZXItcmMAAAAAAAAAAAAAADMAAAALc3NoLWVkMjU1MTkAAAAgJx/9ddTx01W1u94abBt2dEl9ggi3PEqaBGTOWnSTqvkAAABTAAAAC3NzaC1lZDI1NTE5AAAAQBUb0cL1SmwE3WT68ketXa5R4+6+itQPeiTHiCPsDeQQE5uITh+8b9qGHTn/aNJtm3WyFgLtWu6GxO0m3IMvNQs= scripts
diff --git a/sources/fdc.in/c3d/postinstall/install-data/root/.ssh/scripts.pub b/sources/fdc.in/c3d/postinstall/install-data/root/.ssh/scripts.pub
new file mode 100644 (file)
index 0000000..c84db94
--- /dev/null
@@ -0,0 +1 @@
+ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKi/tTFFqtdj0NgKdc3en1X10gD5x2ATTXMO3YhvuyRo scripts
index 974627c33a757bb312786e418832ccd29e8f74e2..a90fb4ba9f025e82a59997c0e47adf55d3111f72 100755 (executable)
@@ -79,7 +79,6 @@ if __name__ == '__main__':
     (search_result_type, search_result_data) = ldap_object.result()
 
     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):
@@ -94,7 +93,6 @@ if __name__ == '__main__':
                 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:
index 9f8d3d11c0eae163b7f92120c79fd28ebbae2649..dafafb0e4946dbdc62a95fa06df09b47b80bee3f 100755 (executable)
@@ -8,7 +8,6 @@ import pickle
 import select
 import signal
 import socket
-import hashlib
 import subprocess
 import configparser
 
@@ -88,10 +87,6 @@ class pds():
             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__
@@ -116,11 +111,6 @@ class 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)
 
@@ -142,58 +132,14 @@ class pds():
         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}
 
@@ -209,68 +155,14 @@ class pds():
 
         """
         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.
 
@@ -287,21 +179,6 @@ class pds():
         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.
 
index 3162a52ae5b89465574284b1634182ba88b40db9..4d642cb3d01df34e6bbba233bc9c4bef424c4f48 100644 (file)
@@ -56,7 +56,7 @@ def password_change_app(environ, start_response):
     new_password_again = form_data_dict['new password again'][0]
 
     if new_password != new_password_again:
-        formatted_traceback = ['The (new) passwords do not match.']
+        formatted_traceback = ['Az új jelszavak nem egyeznek meg.']
         error_occured = True
 
     if not error_occured: