From 9f0e32eab4bad7018df10f14fbf04825d71a0cfb Mon Sep 17 00:00:00 2001 From: Scott Little Date: Wed, 1 Aug 2018 15:39:37 -0400 Subject: [PATCH] Relocate python-keyring to stx-integ/security/python-keyring Move content from stx-gplv3 into stx-integ Packages will be relocated to stx-integ: base/ anaconda crontabs dnsmasq rsync database/ python-psycopg2 filesystem/ parted grub/ grub2 security/ python-keyring Change-Id: I17163dbff41222985a29228a8b42c919a86d1e67 Story: 2002801 Task: 22687 Signed-off-by: Scott Little --- centos_pkg_dirs | 1 + security/python-keyring/PKG-INFO | 16 ++ .../python-keyring/centos/build_srpm.data | 2 + ...01-move-package-from-tarball-to-srpm.patch | 78 ++++++ ...-buildrequires-python-setuptools_scm.patch | 20 ++ .../centos/meta_patches/PATCH_ORDER | 2 + security/python-keyring/centos/srpm_path | 1 + .../python-keyring/chmod_keyringlock2.patch | 37 +++ .../chown_keyringlock_file.patch | 12 + .../fix_keyring_lockfile_location.patch | 113 ++++++++ .../python-keyring/keyring_path_change.patch | 24 ++ .../python-keyring/lock_keyring_file.patch | 45 ++++ .../python-keyring/lock_keyring_file2.patch | 42 +++ .../python-keyring/no_keyring_password.patch | 70 +++++ .../python-keyring/remove-reader-lock.patch | 136 ++++++++++ ...move_others_perms_on_keyringcfg_file.patch | 15 ++ .../python-keyring/use_new_lock.patch | 243 ++++++++++++++++++ .../python-keyring/use_temporary_file.patch | 162 ++++++++++++ 18 files changed, 1019 insertions(+) create mode 100644 security/python-keyring/PKG-INFO create mode 100644 security/python-keyring/centos/build_srpm.data create mode 100644 security/python-keyring/centos/meta_patches/0001-move-package-from-tarball-to-srpm.patch create mode 100644 security/python-keyring/centos/meta_patches/0002-meta-buildrequires-python-setuptools_scm.patch create mode 100644 security/python-keyring/centos/meta_patches/PATCH_ORDER create mode 100644 security/python-keyring/centos/srpm_path create mode 100644 security/python-keyring/python-keyring/chmod_keyringlock2.patch create mode 100644 security/python-keyring/python-keyring/chown_keyringlock_file.patch create mode 100644 security/python-keyring/python-keyring/fix_keyring_lockfile_location.patch create mode 100644 security/python-keyring/python-keyring/keyring_path_change.patch create mode 100644 security/python-keyring/python-keyring/lock_keyring_file.patch create mode 100644 security/python-keyring/python-keyring/lock_keyring_file2.patch create mode 100644 security/python-keyring/python-keyring/no_keyring_password.patch create mode 100644 security/python-keyring/python-keyring/remove-reader-lock.patch create mode 100644 security/python-keyring/python-keyring/remove_others_perms_on_keyringcfg_file.patch create mode 100644 security/python-keyring/python-keyring/use_new_lock.patch create mode 100644 security/python-keyring/python-keyring/use_temporary_file.patch diff --git a/centos_pkg_dirs b/centos_pkg_dirs index bf9468238..6b825a952 100644 --- a/centos_pkg_dirs +++ b/centos_pkg_dirs @@ -144,3 +144,4 @@ base/crontabs base/dnsmasq base/rsync filesystem/parted +security/python-keyring diff --git a/security/python-keyring/PKG-INFO b/security/python-keyring/PKG-INFO new file mode 100644 index 000000000..6ee15e95d --- /dev/null +++ b/security/python-keyring/PKG-INFO @@ -0,0 +1,16 @@ +Metadata-Version: 1.1 +Name: python-keyring +Version: 5.7 +Summary: Python 2 library to store and access passwords safely +Home-page: https://github.com/jaraco/keyring +Author: +Author-email: +License: MIT and Python + +Description: +The Python keyring lib provides a easy way to access the system keyring +service from python. It can be used in any application that needs safe +password storage. + + +Platform: UNKNOWN diff --git a/security/python-keyring/centos/build_srpm.data b/security/python-keyring/centos/build_srpm.data new file mode 100644 index 000000000..3ffb50847 --- /dev/null +++ b/security/python-keyring/centos/build_srpm.data @@ -0,0 +1,2 @@ +COPY_LIST="python-keyring/*" +TIS_PATCH_VER=2 diff --git a/security/python-keyring/centos/meta_patches/0001-move-package-from-tarball-to-srpm.patch b/security/python-keyring/centos/meta_patches/0001-move-package-from-tarball-to-srpm.patch new file mode 100644 index 000000000..151ad3d73 --- /dev/null +++ b/security/python-keyring/centos/meta_patches/0001-move-package-from-tarball-to-srpm.patch @@ -0,0 +1,78 @@ +From d7f5646de9ec990ed81489cc12d7942654bc017d Mon Sep 17 00:00:00 2001 +From: Kam Nasim +Date: Fri, 23 Dec 2016 14:30:17 -0500 +Subject: [PATCH] first meta patch to move python-keyring package from download + tarball to srpm. Also updated to add tis patch versioning + +--- + SPECS/python-keyring.spec | 30 +++++++++++++++++++++++++++--- + 1 file changed, 27 insertions(+), 3 deletions(-) + +diff --git a/SPECS/python-keyring.spec b/SPECS/python-keyring.spec +index 14e4e93..60d05ee 100644 +--- a/SPECS/python-keyring.spec ++++ b/SPECS/python-keyring.spec +@@ -2,7 +2,7 @@ + + Name: python-keyring + Version: 5.7.1 +-Release: 1%{?dist} ++Release: 1%{?_tis_dist}.%{tis_patch_ver} + Summary: Python 2 library to store and access passwords safely + License: MIT and Python + URL: http://bitbucket.org/kang/python-keyring-lib/ +@@ -10,10 +10,21 @@ Source0: https://pypi.io/packages/source/k/keyring/keyring-%{version}.tar + BuildArch: noarch + BuildRequires: python2-devel + BuildRequires: python-setuptools +-BuildRequires: python-setuptools_scm + Obsoletes: %{name}-kwallet < %{version}-%{release} + Obsoletes: %{name}-gnome < %{version}-%{release} + ++Patch0: no_keyring_password.patch ++Patch1: lock_keyring_file.patch ++Patch2: lock_keyring_file2.patch ++Patch3: use_new_lock.patch ++Patch4: fix_keyring_lockfile_location.patch ++Patch5: use_temporary_file.patch ++Patch6: chown_keyringlock_file.patch ++Patch7: chmod_keyringlock2.patch ++Patch8: keyring_path_change.patch ++Patch9: remove-reader-lock.patch ++Patch10: remove_others_perms_on_keyringcfg_file.patch ++ + %description + The Python keyring lib provides a easy way to access the system keyring + service from python. It can be used in any application that needs safe +@@ -39,7 +50,6 @@ Python keyring lib also provides following build-in keyrings. + Summary: Python 3 library to access the system keyring service + BuildRequires: python3-devel + BuildRequires: python3-setuptools +-BuildRequires: python3-setuptools_scm + + %description -n python3-keyring + The Python keyring lib provides a easy way to access the system keyring +@@ -64,6 +74,20 @@ Python keyring lib also provides following build-in keyrings. + + %prep + %setup -qn keyring-%{version} ++ ++# WRS ++%patch0 -p1 ++%patch1 -p1 ++%patch2 -p1 ++%patch3 -p1 ++%patch4 -p1 ++%patch5 -p1 ++%patch6 -p1 ++%patch7 -p1 ++%patch8 -p1 ++%patch9 -p1 ++%patch10 -p1 ++ + rm -frv keyring.egg-info + # Drop redundant shebangs. + sed -i '1{\@^#!/usr/bin/env python@d}' keyring/cli.py +-- +1.8.3.1 + diff --git a/security/python-keyring/centos/meta_patches/0002-meta-buildrequires-python-setuptools_scm.patch b/security/python-keyring/centos/meta_patches/0002-meta-buildrequires-python-setuptools_scm.patch new file mode 100644 index 000000000..28c9e490e --- /dev/null +++ b/security/python-keyring/centos/meta_patches/0002-meta-buildrequires-python-setuptools_scm.patch @@ -0,0 +1,20 @@ +diff --git a/SPECS/python-keyring.spec b/SPECS/python-keyring.spec +index 60d05ee..a41f849 100644 +--- a/SPECS/python-keyring.spec ++++ b/SPECS/python-keyring.spec +@@ -10,6 +10,7 @@ Source0: https://pypi.io/packages/source/k/keyring/keyring-%{version}.tar + BuildArch: noarch + BuildRequires: python2-devel + BuildRequires: python-setuptools ++BuildRequires: python2-setuptools_scm + Obsoletes: %{name}-kwallet < %{version}-%{release} + Obsoletes: %{name}-gnome < %{version}-%{release} + +@@ -50,6 +51,7 @@ Python keyring lib also provides following build-in keyrings. + Summary: Python 3 library to access the system keyring service + BuildRequires: python3-devel + BuildRequires: python3-setuptools ++BuildRequires: python3-setuptools_scm + + %description -n python3-keyring + The Python keyring lib provides a easy way to access the system keyring diff --git a/security/python-keyring/centos/meta_patches/PATCH_ORDER b/security/python-keyring/centos/meta_patches/PATCH_ORDER new file mode 100644 index 000000000..d6a71099d --- /dev/null +++ b/security/python-keyring/centos/meta_patches/PATCH_ORDER @@ -0,0 +1,2 @@ +0001-move-package-from-tarball-to-srpm.patch +0002-meta-buildrequires-python-setuptools_scm.patch diff --git a/security/python-keyring/centos/srpm_path b/security/python-keyring/centos/srpm_path new file mode 100644 index 000000000..1dce7079a --- /dev/null +++ b/security/python-keyring/centos/srpm_path @@ -0,0 +1 @@ +mirror:Source/python-keyring-5.7.1-1.el7.src.rpm diff --git a/security/python-keyring/python-keyring/chmod_keyringlock2.patch b/security/python-keyring/python-keyring/chmod_keyringlock2.patch new file mode 100644 index 000000000..f95be88f7 --- /dev/null +++ b/security/python-keyring/python-keyring/chmod_keyringlock2.patch @@ -0,0 +1,37 @@ +Index: keyring-5.3/keyring/backends/file.py +=================================================================== +--- keyring-5.3.orig/keyring/backends/file.py ++++ keyring-5.3/keyring/backends/file.py +@@ -68,6 +68,9 @@ class BaseKeyring(FileBacked, KeyringBac + service = escape_for_ini(service) + username = escape_for_ini(username) + ++ # ensure the file exists ++ self._ensure_file_path() ++ + # load the passwords from the file + config = configparser.RawConfigParser() + if os.path.exists(self.file_path): +@@ -146,12 +149,16 @@ class BaseKeyring(FileBacked, KeyringBac + user_read_write = 0o644 + os.chmod(self.file_path, user_read_write) + if not os.path.isfile(lockdir + "/" + lockfile): +- import stat +- with open(lockdir + "/" + lockfile, 'w'): +- pass +- # must have the lock file with the correct group permissisions g+rw +- os.chmod(lockdir + "/" + lockfile, stat.S_IRWXG | stat.S_IRWXU) +- os.chown(lockdir + "/" + lockfile,-1,345) ++ with open(lockdir + "/" + lockfile, 'w'): ++ pass ++ if os.path.isfile(lockdir + "/" + lockfile): ++ import stat ++ import grp ++ if oct(stat.S_IMODE(os.stat(lockdir + "/" + lockfile).st_mode)) != '0770': ++ # Must have the lock file with the correct group and permissisions g+rw ++ os.chmod(lockdir + "/" + lockfile, stat.S_IRWXG | stat.S_IRWXU) ++ groupinfo = grp.getgrnam('wrs_protected') ++ os.chown(lockdir + "/" + lockfile,-1,groupinfo.gr_gid) + + + def delete_password(self, service, username): diff --git a/security/python-keyring/python-keyring/chown_keyringlock_file.patch b/security/python-keyring/python-keyring/chown_keyringlock_file.patch new file mode 100644 index 000000000..28c56bc67 --- /dev/null +++ b/security/python-keyring/python-keyring/chown_keyringlock_file.patch @@ -0,0 +1,12 @@ +Index: keyring-5.3/keyring/backends/file.py +=================================================================== +--- keyring-5.3.orig/keyring/backends/file.py ++++ keyring-5.3/keyring/backends/file.py +@@ -151,6 +151,7 @@ class BaseKeyring(FileBacked, KeyringBac + pass + # must have the lock file with the correct group permissisions g+rw + os.chmod(lockdir + "/" + lockfile, stat.S_IRWXG | stat.S_IRWXU) ++ os.chown(lockdir + "/" + lockfile,-1,345) + + + def delete_password(self, service, username): diff --git a/security/python-keyring/python-keyring/fix_keyring_lockfile_location.patch b/security/python-keyring/python-keyring/fix_keyring_lockfile_location.patch new file mode 100644 index 000000000..4287256b6 --- /dev/null +++ b/security/python-keyring/python-keyring/fix_keyring_lockfile_location.patch @@ -0,0 +1,113 @@ +Index: keyring-5.3/keyring/backends/file.py +=================================================================== +--- keyring-5.3.orig/keyring/backends/file.py ++++ keyring-5.3/keyring/backends/file.py +@@ -19,6 +19,8 @@ from ..util.escape import escape as esca + from oslo_concurrency import lockutils + + ++lockfile = "keyringlock" ++ + class FileBacked(object): + @abc.abstractproperty + def filename(self): +@@ -104,16 +106,18 @@ class BaseKeyring(FileBacked, KeyringBac + service = escape_for_ini(service) + username = escape_for_ini(username) + ++ # ensure the file exists ++ self._ensure_file_path() ++ + # encrypt the password + password_encrypted = self.encrypt(password.encode('utf-8')) + # encode with base64 + password_base64 = base64.encodestring(password_encrypted).decode() + ++ lockdir = os.path.dirname(self.file_path) + +- with lockutils.lock("keyringlock",external=True,lock_path="/tmp"): ++ with lockutils.lock(lockfile,external=True,lock_path=lockdir): + +- # ensure the file exists +- self._ensure_file_path() + + config = None + try: +@@ -159,14 +163,13 @@ class BaseKeyring(FileBacked, KeyringBac + + + +- +- + def _ensure_file_path(self): + """ + Ensure the storage path exists. + If it doesn't, create it with "go-rwx" permissions. + """ + storage_root = os.path.dirname(self.file_path) ++ lockdir = storage_root + if storage_root and not os.path.isdir(storage_root): + os.makedirs(storage_root) + if not os.path.isfile(self.file_path): +@@ -175,13 +178,22 @@ class BaseKeyring(FileBacked, KeyringBac + pass + user_read_write = 0o644 + os.chmod(self.file_path, user_read_write) ++ if not os.path.isfile(lockdir + "/" + lockfile): ++ import stat ++ with open(lockdir + "/" + lockfile, 'w'): ++ pass ++ # must have the lock file with the correct group permissisions g+rw ++ os.chmod(lockdir + "/" + lockfile, stat.S_IRWXG | stat.S_IRWXU) ++ + + def delete_password(self, service, username): + """Delete the password for the username of the service. + """ + service = escape_for_ini(service) + username = escape_for_ini(username) +- with lockutils.lock("keyringlock",external=True,lock_path="/tmp"): ++ ++ lockdir = os.path.dirname(self.file_path) ++ with lockutils.lock(lockfile,external=True,lock_path=lockdir): + config = configparser.RawConfigParser() + if os.path.exists(self.file_path): + config.read(self.file_path) +@@ -290,17 +302,6 @@ class EncryptedKeyring(Encrypted, BaseKe + # set a reference password, used to check that the password provided + # matches for subsequent checks. + +- # try to pre-create the /tmp/keyringlock if it doesn't exist +- lockfile = "/tmp/keyringlock" +- if os.geteuid() == 0 and (not os.path.exists(lockfile)): +- from pwd import getpwnam +- import stat +- nonrootuser = "wrsroot" +- with open(lockfile, 'w'): +- pass +- # must have the lock file with the correct group permissisions g+rw +- os.chmod(lockfile, stat.S_IRWXG | stat.S_IRWXU) +- + + self.set_password('keyring-setting', 'password reference', + 'password reference value') +@@ -313,9 +314,10 @@ class EncryptedKeyring(Encrypted, BaseKe + return False + self._migrate() + ++ lockdir = os.path.dirname(self.file_path) + # lock access to the file_path here, make sure it's not being written + # to while while we're checking for keyring-setting +- with lockutils.lock("keyringlock",external=True,lock_path="/tmp"): ++ with lockutils.lock(lockfile,external=True,lock_path=lockdir): + config = configparser.RawConfigParser() + config.read(self.file_path) + try: +@@ -325,7 +327,6 @@ class EncryptedKeyring(Encrypted, BaseKe + ) + except (configparser.NoSectionError, configparser.NoOptionError): + # The current file doesn't have the keyring-setting, check the backup +- logging.warning("_check_file: The current file doesn't have the keyring-setting, check the backup") + if os.path.exists(self.backup_file_path): + config = configparser.RawConfigParser() + config.read(self.backup_file_path) diff --git a/security/python-keyring/python-keyring/keyring_path_change.patch b/security/python-keyring/python-keyring/keyring_path_change.patch new file mode 100644 index 000000000..46aa23527 --- /dev/null +++ b/security/python-keyring/python-keyring/keyring_path_change.patch @@ -0,0 +1,24 @@ +--- + keyring/util/platform_.py | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/keyring/util/platform_.py ++++ b/keyring/util/platform_.py +@@ -2,6 +2,7 @@ from __future__ import absolute_import + + import os + import platform ++from tsconfig.tsconfig import SW_VERSION + + def _settings_root_XP(): + return os.path.join(os.environ['USERPROFILE'], 'Local Settings') +@@ -19,7 +20,8 @@ def _data_root_Linux(): + Use freedesktop.org Base Dir Specfication to determine storage + location. + """ +- fallback = os.path.expanduser('/opt/platform/.keyring/') ++ keyring_dir = os.path.join('/opt/platform/.keyring', SW_VERSION) ++ fallback = os.path.expanduser(keyring_dir) + root = os.environ.get('XDG_DATA_HOME', None) or fallback + return os.path.join(root, 'python_keyring') + diff --git a/security/python-keyring/python-keyring/lock_keyring_file.patch b/security/python-keyring/python-keyring/lock_keyring_file.patch new file mode 100644 index 000000000..dab72486d --- /dev/null +++ b/security/python-keyring/python-keyring/lock_keyring_file.patch @@ -0,0 +1,45 @@ +Index: keyring-5.3/keyring/backends/file.py +=================================================================== +--- keyring-5.3.orig/keyring/backends/file.py ++++ keyring-5.3/keyring/backends/file.py +@@ -6,6 +6,7 @@ import base64 + import sys + import json + import abc ++import time + + from ..py27compat import configparser + +@@ -95,14 +96,29 @@ class BaseKeyring(FileBacked, KeyringBac + config = configparser.RawConfigParser() + config.read(self.file_path) + ++ # obtain lock for the keyring file ++ lock = '' ++ i = 60 ++ while i: ++ if not os.path.isfile('/tmp/.keyringlock'): ++ lock = open('/tmp/.keyringlock', 'w') ++ break ++ else: ++ time.sleep(0.500) ++ i=i-1 ++ + # update the keyring with the password + if not config.has_section(service): + config.add_section(service) + config.set(service, username, password_base64) + +- # save the keyring back to the file +- with open(self.file_path, 'w') as config_file: +- config.write(config_file) ++ if i: ++ # save the keyring back to the file ++ with open(self.file_path, 'w') as config_file: ++ config.write(config_file) ++ lock.close() ++ os.remove('/tmp/.keyringlock') ++ + + def _ensure_file_path(self): + """ diff --git a/security/python-keyring/python-keyring/lock_keyring_file2.patch b/security/python-keyring/python-keyring/lock_keyring_file2.patch new file mode 100644 index 000000000..7633b5eac --- /dev/null +++ b/security/python-keyring/python-keyring/lock_keyring_file2.patch @@ -0,0 +1,42 @@ +Index: keyring-5.3/keyring/backends/file.py +=================================================================== +--- keyring-5.3.orig/keyring/backends/file.py ++++ keyring-5.3/keyring/backends/file.py +@@ -92,10 +92,6 @@ class BaseKeyring(FileBacked, KeyringBac + # ensure the file exists + self._ensure_file_path() + +- # load the keyring from the disk +- config = configparser.RawConfigParser() +- config.read(self.file_path) +- + # obtain lock for the keyring file + lock = '' + i = 60 +@@ -107,15 +103,21 @@ class BaseKeyring(FileBacked, KeyringBac + time.sleep(0.500) + i=i-1 + +- # update the keyring with the password +- if not config.has_section(service): +- config.add_section(service) +- config.set(service, username, password_base64) + + if i: +- # save the keyring back to the file ++ # Load the keyring from the disk ++ config = configparser.RawConfigParser() ++ config.read(self.file_path) ++ ++ # Update the keyring with the password ++ if not config.has_section(service): ++ config.add_section(service) ++ config.set(service, username, password_base64) ++ ++ # Save the keyring back to the file + with open(self.file_path, 'w') as config_file: + config.write(config_file) ++ + lock.close() + os.remove('/tmp/.keyringlock') + diff --git a/security/python-keyring/python-keyring/no_keyring_password.patch b/security/python-keyring/python-keyring/no_keyring_password.patch new file mode 100644 index 000000000..6ea22fd34 --- /dev/null +++ b/security/python-keyring/python-keyring/no_keyring_password.patch @@ -0,0 +1,70 @@ +Index: keyring-3.2/keyring/backends/file.py +=================================================================== +--- keyring-3.2.orig/keyring/backends/file.py ++++ keyring-3.2/keyring/backends/file.py +@@ -114,7 +114,7 @@ class BaseKeyring(KeyringBackend): + # create the file without group/world permissions + with open(self.file_path, 'w'): + pass +- user_read_write = 0o600 ++ user_read_write = 0o644 + os.chmod(self.file_path, user_read_write) + + def delete_password(self, service, username): +@@ -188,12 +188,19 @@ class EncryptedKeyring(BaseKeyring): + + def _get_new_password(self): + while True: +- password = getpass.getpass( +- "Please set a password for your new keyring: ") +- confirm = getpass.getpass('Please confirm the password: ') +- if password != confirm: +- sys.stderr.write("Error: Your passwords didn't match\n") +- continue ++#**************************************************************** ++# Forging the Keyring password to allow automation and still keep ++# the password encoded. TODO to be revisited when Barbican keyring ++# Will be used with the complete PKI solution ++#**************************************************************** ++# password = getpass.getpass( ++# "Please set a password for your new keyring: ") ++# confirm = getpass.getpass('Please confirm the password: ') ++# if password != confirm: ++# sys.stderr.write("Error: Your passwords didn't match\n") ++# continue ++ password = "Please set a password for your new keyring: " ++ + if '' == password.strip(): + # forbid the blank password + sys.stderr.write("Error: blank passwords aren't allowed.\n") +@@ -233,8 +240,15 @@ class EncryptedKeyring(BaseKeyring): + Unlock this keyring by getting the password for the keyring from the + user. + """ +- self.keyring_key = getpass.getpass( +- 'Please enter password for encrypted keyring: ') ++#**************************************************************** ++# Forging the Keyring password to allow automation and still keep ++# the password encoded. TODO to be revisited when Barbican keyring ++# Will be used with the complete PKI solution ++#**************************************************************** ++# self.keyring_key = getpass.getpass( ++# 'Please enter password for encrypted keyring: ') ++ self.keyring_key = "Please set a password for your new keyring: " ++ + try: + ref_pw = self.get_password('keyring-setting', 'password reference') + assert ref_pw == 'password reference value' +Index: keyring-3.2/keyring/util/platform_.py +=================================================================== +--- keyring-3.2.orig/keyring/util/platform_.py ++++ keyring-3.2/keyring/util/platform_.py +@@ -16,7 +16,7 @@ def _data_root_Linux(): + Use freedesktop.org Base Dir Specfication to determine storage + location. + """ +- fallback = os.path.expanduser('~/.local/share') ++ fallback = os.path.expanduser('/opt/platform/.keyring/') + root = os.environ.get('XDG_DATA_HOME', None) or fallback + return os.path.join(root, 'python_keyring') + diff --git a/security/python-keyring/python-keyring/remove-reader-lock.patch b/security/python-keyring/python-keyring/remove-reader-lock.patch new file mode 100644 index 000000000..137805db6 --- /dev/null +++ b/security/python-keyring/python-keyring/remove-reader-lock.patch @@ -0,0 +1,136 @@ +--- + keyring/backends/file.py | 85 ++++++++++++++++++++++------------------------- + 1 file changed, 41 insertions(+), 44 deletions(-) + +--- a/keyring/backends/file.py ++++ b/keyring/backends/file.py +@@ -18,6 +18,7 @@ from ..backend import KeyringBackend + from ..util import platform_, properties + from ..util.escape import escape as escape_for_ini + from oslo_concurrency import lockutils ++from tempfile import mkstemp + + + lockfile = "keyringlock" +@@ -102,11 +103,9 @@ class BaseKeyring(FileBacked, KeyringBac + # encode with base64 + password_base64 = base64.encodestring(password_encrypted).decode() + +- lockdir = os.path.dirname(self.file_path) +- +- with lockutils.lock(lockfile,external=True,lock_path=lockdir): +- ++ keyringdir = os.path.dirname(self.file_path) + ++ with lockutils.lock(lockfile, external=True, lock_path=keyringdir): + config = None + try: + # Load the keyring from the disk +@@ -121,16 +120,20 @@ class BaseKeyring(FileBacked, KeyringBac + config.add_section(service) + config.set(service, username, password_base64) + +- # Save the keyring back to the file +- storage_root = os.path.dirname(self.file_path) +- tmpfile = "tmpfile.%s" % os.getpid() +- with open(storage_root + "/" + tmpfile, 'w') as config_file: +- config.write(config_file) +- # copy will overwrite but move will not +- shutil.copy(storage_root + "/" + tmpfile,self.file_path) +- # wipe out tmpfile here +- os.remove(storage_root + "/" + tmpfile) ++ # remove any residual temporary files here ++ try: ++ for tmpfile in glob.glob("%s/tmp*" % keyringdir): ++ os.remove(tmpfile) ++ except: ++ logging.warning("_check_file: tmpfile removal failed") + ++ # Write the keyring to a temp file, then move the new file ++ # to avoid overwriting the existing inode ++ (fd, fname) = mkstemp(dir=keyringdir) ++ with os.fdopen(fd, "w") as config_file: ++ config.write(config_file) ++ os.chmod(fname, os.stat(self.file_path).st_mode) ++ shutil.move(fname, self.file_path) + + + def _ensure_file_path(self): +@@ -167,8 +170,8 @@ class BaseKeyring(FileBacked, KeyringBac + service = escape_for_ini(service) + username = escape_for_ini(username) + +- lockdir = os.path.dirname(self.file_path) +- with lockutils.lock(lockfile,external=True,lock_path=lockdir): ++ keyringdir = os.path.dirname(self.file_path) ++ with lockutils.lock(lockfile, external=True, lock_path=keyringdir): + config = configparser.RawConfigParser() + if os.path.exists(self.file_path): + config.read(self.file_path) +@@ -177,15 +180,21 @@ class BaseKeyring(FileBacked, KeyringBac + raise PasswordDeleteError("Password not found") + except configparser.NoSectionError: + raise PasswordDeleteError("Password not found") +- # update the file +- storage_root = os.path.dirname(self.file_path) +- tmpfile = "tmpfile.%s" % os.getpid() +- with open(storage_root + "/" + tmpfile, 'w') as config_file: ++ ++ # remove any residual temporary files here ++ try: ++ for tmpfile in glob.glob("%s/tmp*" % keyringdir): ++ os.remove(tmpfile) ++ except: ++ logging.warning("_check_file: tmpfile removal failed") ++ ++ # Write the keyring to a temp file, then move the new file ++ # to avoid overwriting the existing inode ++ (fd, fname) = mkstemp(dir=keyringdir) ++ with os.fdopen(fd, "w") as config_file: + config.write(config_file) +- # copy will overwrite but move will not +- shutil.copy(storage_root + "/" + tmpfile,self.file_path) +- # wipe out tmpfile +- os.remove(storage_root + "/" + tmpfile) ++ os.chmod(fname, os.stat(self.file_path).st_mode) ++ shutil.move(fname, self.file_path) + + + class PlaintextKeyring(BaseKeyring): +@@ -294,27 +303,15 @@ class EncryptedKeyring(Encrypted, BaseKe + return False + self._migrate() + +- lockdir = os.path.dirname(self.file_path) +- # lock access to the file_path here, make sure it's not being written +- # to while while we're checking for keyring-setting +- with lockutils.lock(lockfile,external=True,lock_path=lockdir): +- config = configparser.RawConfigParser() +- config.read(self.file_path) +- try: +- config.get( +- escape_for_ini('keyring-setting'), +- escape_for_ini('password reference'), +- ) +- except (configparser.NoSectionError, configparser.NoOptionError): +- return False +- +- # remove any residual temporary files here +- try: +- for tmpfile in glob.glob(os.path.dirname(self.file_path) + "/" + "tmpfile.*"): +- os.remove(tmpfile) +- except: +- logging.warning("_check_file: tmpfile removal failed") +- ++ config = configparser.RawConfigParser() ++ config.read(self.file_path) ++ try: ++ config.get( ++ escape_for_ini('keyring-setting'), ++ escape_for_ini('password reference'), ++ ) ++ except (configparser.NoSectionError, configparser.NoOptionError): ++ return False + + return True + diff --git a/security/python-keyring/python-keyring/remove_others_perms_on_keyringcfg_file.patch b/security/python-keyring/python-keyring/remove_others_perms_on_keyringcfg_file.patch new file mode 100644 index 000000000..dcc4c2e05 --- /dev/null +++ b/security/python-keyring/python-keyring/remove_others_perms_on_keyringcfg_file.patch @@ -0,0 +1,15 @@ +--- + keyring/backends/file.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/keyring/backends/file.py ++++ b/keyring/backends/file.py +@@ -149,7 +149,7 @@ class BaseKeyring(FileBacked, KeyringBac + # create the file without group/world permissions + with open(self.file_path, 'w'): + pass +- user_read_write = 0o644 ++ user_read_write = 0o640 + os.chmod(self.file_path, user_read_write) + if not os.path.isfile(lockdir + "/" + lockfile): + with open(lockdir + "/" + lockfile, 'w'): diff --git a/security/python-keyring/python-keyring/use_new_lock.patch b/security/python-keyring/python-keyring/use_new_lock.patch new file mode 100644 index 000000000..d1b483d8f --- /dev/null +++ b/security/python-keyring/python-keyring/use_new_lock.patch @@ -0,0 +1,243 @@ +Index: keyring-5.3/keyring/backends/file.py +=================================================================== +--- keyring-5.3.orig/keyring/backends/file.py ++++ keyring-5.3/keyring/backends/file.py +@@ -7,6 +7,8 @@ import sys + import json + import abc + import time ++import logging ++import shutil + + from ..py27compat import configparser + +@@ -14,6 +16,7 @@ from ..errors import PasswordDeleteError + from ..backend import KeyringBackend + from ..util import platform_, properties + from ..util.escape import escape as escape_for_ini ++from oslo_concurrency import lockutils + + + class FileBacked(object): +@@ -31,6 +34,13 @@ class FileBacked(object): + """ + return os.path.join(platform_.data_root(), self.filename) + ++ @properties.NonDataProperty ++ def backup_file_path(self): ++ """ ++ The path to the file where passwords are stored. This property ++ may be overridden by the subclass or at the instance level. ++ """ ++ return os.path.join(platform_.data_root(), self.backup_filename) + + class BaseKeyring(FileBacked, KeyringBackend): + """ +@@ -78,6 +88,16 @@ class BaseKeyring(FileBacked, KeyringBac + password = None + return password + ++ ++ def filecopy(self,src,dest): ++ """copy file src to dest with default buffer size ++ """ ++ with open(src, 'r') as f1: ++ with open(dest, 'w') as f2: ++ shutil.copyfileobj(f1,f2) ++ f2.flush() ++ ++ + def set_password(self, service, username, password): + """Write the password in the file. + """ +@@ -89,37 +109,56 @@ class BaseKeyring(FileBacked, KeyringBac + # encode with base64 + password_base64 = base64.encodestring(password_encrypted).decode() + +- # ensure the file exists +- self._ensure_file_path() + +- # obtain lock for the keyring file +- lock = '' +- i = 60 +- while i: +- if not os.path.isfile('/tmp/.keyringlock'): +- lock = open('/tmp/.keyringlock', 'w') +- break +- else: +- time.sleep(0.500) +- i=i-1 ++ with lockutils.lock("keyringlock",external=True,lock_path="/tmp"): + ++ # ensure the file exists ++ self._ensure_file_path() ++ ++ config = None ++ try: ++ # Load the keyring from the disk ++ config = configparser.RawConfigParser() ++ config.read(self.file_path) ++ except configparser.ParsingError as e: ++ logging.warning("set_password: keyring file corrupted, Reverting to Backup") ++ # Revert to the backup file (copy backup over current file) ++ try: ++ src = self.backup_file_path ++ dest = self.file_path ++ self.filecopy(src,dest) ++ except shutil.Error as e: ++ logging.warning("set_password: Revert from Backup failed. Error: %s" % e) ++ raise ++ # Load the keyring from the disk, if this fails exception is raised ++ try: ++ config = configparser.RawConfigParser() ++ config.read(self.file_path) ++ except: ++ e = sys.exc_info()[0] ++ logging.warning("set_password: Both keyring files are non useable. Error: %s" % e) ++ raise + +- if i: +- # Load the keyring from the disk +- config = configparser.RawConfigParser() +- config.read(self.file_path) + + # Update the keyring with the password + if not config.has_section(service): + config.add_section(service) + config.set(service, username, password_base64) + ++ # Make a back up of the keyring file here ++ try: ++ src = self.file_path ++ dest = self.backup_file_path ++ self.filecopy(src,dest) ++ except shutil.Error as e: ++ logging.warning("set_password: Backup failed. Error: %s" % e) ++ + # Save the keyring back to the file + with open(self.file_path, 'w') as config_file: + config.write(config_file) + +- lock.close() +- os.remove('/tmp/.keyringlock') ++ ++ + + + def _ensure_file_path(self): +@@ -142,17 +181,18 @@ class BaseKeyring(FileBacked, KeyringBac + """ + service = escape_for_ini(service) + username = escape_for_ini(username) +- config = configparser.RawConfigParser() +- if os.path.exists(self.file_path): +- config.read(self.file_path) +- try: +- if not config.remove_option(service, username): ++ with lockutils.lock("keyringlock",external=True,lock_path="/tmp"): ++ config = configparser.RawConfigParser() ++ if os.path.exists(self.file_path): ++ config.read(self.file_path) ++ try: ++ if not config.remove_option(service, username): ++ raise PasswordDeleteError("Password not found") ++ except configparser.NoSectionError: + raise PasswordDeleteError("Password not found") +- except configparser.NoSectionError: +- raise PasswordDeleteError("Password not found") +- # update the file +- with open(self.file_path, 'w') as config_file: +- config.write(config_file) ++ # update the file ++ with open(self.file_path, 'w') as config_file: ++ config.write(config_file) + + class PlaintextKeyring(BaseKeyring): + """Simple File Keyring with no encryption""" +@@ -161,6 +201,7 @@ class PlaintextKeyring(BaseKeyring): + "Applicable for all platforms, but not recommended" + + filename = 'keyring_pass.cfg' ++ backup_filename = 'crypted_pass_backup.cfg' + + def encrypt(self, password): + """Directly return the password itself. +@@ -214,6 +255,7 @@ class EncryptedKeyring(Encrypted, BaseKe + """PyCrypto File Keyring""" + + filename = 'crypted_pass.cfg' ++ backup_filename = 'crypted_pass_backup.cfg' + pw_prefix = 'pw:'.encode() + + @properties.ClassProperty +@@ -247,6 +289,19 @@ class EncryptedKeyring(Encrypted, BaseKe + self.keyring_key = self._get_new_password() + # set a reference password, used to check that the password provided + # matches for subsequent checks. ++ ++ # try to pre-create the /tmp/keyringlock if it doesn't exist ++ lockfile = "/tmp/keyringlock" ++ if os.geteuid() == 0 and (not os.path.exists(lockfile)): ++ from pwd import getpwnam ++ import stat ++ nonrootuser = "wrsroot" ++ with open(lockfile, 'w'): ++ pass ++ # must have the lock file with the correct group permissisions g+rw ++ os.chmod(lockfile, stat.S_IRWXG | stat.S_IRWXU) ++ ++ + self.set_password('keyring-setting', 'password reference', + 'password reference value') + +@@ -257,15 +312,41 @@ class EncryptedKeyring(Encrypted, BaseKe + if not os.path.exists(self.file_path): + return False + self._migrate() +- config = configparser.RawConfigParser() +- config.read(self.file_path) +- try: +- config.get( +- escape_for_ini('keyring-setting'), +- escape_for_ini('password reference'), +- ) +- except (configparser.NoSectionError, configparser.NoOptionError): +- return False ++ ++ # lock access to the file_path here, make sure it's not being written ++ # to while while we're checking for keyring-setting ++ with lockutils.lock("keyringlock",external=True,lock_path="/tmp"): ++ config = configparser.RawConfigParser() ++ config.read(self.file_path) ++ try: ++ config.get( ++ escape_for_ini('keyring-setting'), ++ escape_for_ini('password reference'), ++ ) ++ except (configparser.NoSectionError, configparser.NoOptionError): ++ # The current file doesn't have the keyring-setting, check the backup ++ logging.warning("_check_file: The current file doesn't have the keyring-setting, check the backup") ++ if os.path.exists(self.backup_file_path): ++ config = configparser.RawConfigParser() ++ config.read(self.backup_file_path) ++ try: ++ config.get( ++ escape_for_ini('keyring-setting'), ++ escape_for_ini('password reference'), ++ ) ++ except (configparser.NoSectionError, configparser.NoOptionError): ++ return False ++ # backup file has it, let's use it ++ try: ++ src = self.backup_file_path ++ dest = self.file_path ++ shutil.copy(src,dest) ++ except shutil.Error as e: ++ logging.warning("Revert from Backup failed. Error: %s" % e) ++ return False ++ else: ++ return False ++ + return True + + def _unlock(self): diff --git a/security/python-keyring/python-keyring/use_temporary_file.patch b/security/python-keyring/python-keyring/use_temporary_file.patch new file mode 100644 index 000000000..faa968d5f --- /dev/null +++ b/security/python-keyring/python-keyring/use_temporary_file.patch @@ -0,0 +1,162 @@ +Index: keyring-5.3/keyring/backends/file.py +=================================================================== +--- keyring-5.3.orig/keyring/backends/file.py ++++ keyring-5.3/keyring/backends/file.py +@@ -9,6 +9,7 @@ import abc + import time + import logging + import shutil ++import glob + + from ..py27compat import configparser + +@@ -36,13 +37,6 @@ class FileBacked(object): + """ + return os.path.join(platform_.data_root(), self.filename) + +- @properties.NonDataProperty +- def backup_file_path(self): +- """ +- The path to the file where passwords are stored. This property +- may be overridden by the subclass or at the instance level. +- """ +- return os.path.join(platform_.data_root(), self.backup_filename) + + class BaseKeyring(FileBacked, KeyringBackend): + """ +@@ -91,15 +85,6 @@ class BaseKeyring(FileBacked, KeyringBac + return password + + +- def filecopy(self,src,dest): +- """copy file src to dest with default buffer size +- """ +- with open(src, 'r') as f1: +- with open(dest, 'w') as f2: +- shutil.copyfileobj(f1,f2) +- f2.flush() +- +- + def set_password(self, service, username, password): + """Write the password in the file. + """ +@@ -125,23 +110,7 @@ class BaseKeyring(FileBacked, KeyringBac + config = configparser.RawConfigParser() + config.read(self.file_path) + except configparser.ParsingError as e: +- logging.warning("set_password: keyring file corrupted, Reverting to Backup") +- # Revert to the backup file (copy backup over current file) +- try: +- src = self.backup_file_path +- dest = self.file_path +- self.filecopy(src,dest) +- except shutil.Error as e: +- logging.warning("set_password: Revert from Backup failed. Error: %s" % e) +- raise +- # Load the keyring from the disk, if this fails exception is raised +- try: +- config = configparser.RawConfigParser() +- config.read(self.file_path) +- except: +- e = sys.exc_info()[0] +- logging.warning("set_password: Both keyring files are non useable. Error: %s" % e) +- raise ++ logging.warning("set_password: keyring file corrupted") + + + # Update the keyring with the password +@@ -149,17 +118,15 @@ class BaseKeyring(FileBacked, KeyringBac + config.add_section(service) + config.set(service, username, password_base64) + +- # Make a back up of the keyring file here +- try: +- src = self.file_path +- dest = self.backup_file_path +- self.filecopy(src,dest) +- except shutil.Error as e: +- logging.warning("set_password: Backup failed. Error: %s" % e) +- + # Save the keyring back to the file +- with open(self.file_path, 'w') as config_file: ++ storage_root = os.path.dirname(self.file_path) ++ tmpfile = "tmpfile.%s" % os.getpid() ++ with open(storage_root + "/" + tmpfile, 'w') as config_file: + config.write(config_file) ++ # copy will overwrite but move will not ++ shutil.copy(storage_root + "/" + tmpfile,self.file_path) ++ # wipe out tmpfile here ++ os.remove(storage_root + "/" + tmpfile) + + + +@@ -203,8 +170,15 @@ class BaseKeyring(FileBacked, KeyringBac + except configparser.NoSectionError: + raise PasswordDeleteError("Password not found") + # update the file +- with open(self.file_path, 'w') as config_file: ++ storage_root = os.path.dirname(self.file_path) ++ tmpfile = "tmpfile.%s" % os.getpid() ++ with open(storage_root + "/" + tmpfile, 'w') as config_file: + config.write(config_file) ++ # copy will overwrite but move will not ++ shutil.copy(storage_root + "/" + tmpfile,self.file_path) ++ # wipe out tmpfile ++ os.remove(storage_root + "/" + tmpfile) ++ + + class PlaintextKeyring(BaseKeyring): + """Simple File Keyring with no encryption""" +@@ -213,7 +187,6 @@ class PlaintextKeyring(BaseKeyring): + "Applicable for all platforms, but not recommended" + + filename = 'keyring_pass.cfg' +- backup_filename = 'crypted_pass_backup.cfg' + + def encrypt(self, password): + """Directly return the password itself. +@@ -267,7 +240,6 @@ class EncryptedKeyring(Encrypted, BaseKe + """PyCrypto File Keyring""" + + filename = 'crypted_pass.cfg' +- backup_filename = 'crypted_pass_backup.cfg' + pw_prefix = 'pw:'.encode() + + @properties.ClassProperty +@@ -326,27 +298,15 @@ class EncryptedKeyring(Encrypted, BaseKe + escape_for_ini('password reference'), + ) + except (configparser.NoSectionError, configparser.NoOptionError): +- # The current file doesn't have the keyring-setting, check the backup +- if os.path.exists(self.backup_file_path): +- config = configparser.RawConfigParser() +- config.read(self.backup_file_path) +- try: +- config.get( +- escape_for_ini('keyring-setting'), +- escape_for_ini('password reference'), +- ) +- except (configparser.NoSectionError, configparser.NoOptionError): +- return False +- # backup file has it, let's use it +- try: +- src = self.backup_file_path +- dest = self.file_path +- shutil.copy(src,dest) +- except shutil.Error as e: +- logging.warning("Revert from Backup failed. Error: %s" % e) +- return False +- else: +- return False ++ return False ++ ++ # remove any residual temporary files here ++ try: ++ for tmpfile in glob.glob(os.path.dirname(self.file_path) + "/" + "tmpfile.*"): ++ os.remove(tmpfile) ++ except: ++ logging.warning("_check_file: tmpfile removal failed") ++ + + return True +