././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1724253560.1211357 oslo.privsep-3.4.0/0000775000175000017500000000000000000000000014204 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/.coveragerc0000664000175000017500000000014500000000000016325 0ustar00zuulzuul00000000000000[run] branch = True source = oslo_privsep omit = oslo_privsep/tests/* [report] ignore_errors = True ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/.mailmap0000664000175000017500000000013100000000000015620 0ustar00zuulzuul00000000000000# Format is: # # ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/.pre-commit-config.yaml0000664000175000017500000000252300000000000020467 0ustar00zuulzuul00000000000000# We from the Oslo project decided to pin repos based on the # commit hash instead of the version tag to prevend arbitrary # code from running in developer's machines. To update to a # newer version, run `pre-commit autoupdate` and then replace # the newer versions with their commit hash. default_language_version: python: python3 repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: 9136088a246768144165fcc3ecc3d31bb686920a # v3.3.0 hooks: - id: trailing-whitespace # Replaces or checks mixed line ending - id: mixed-line-ending args: ['--fix', 'lf'] exclude: '.*\.(svg)$' # Forbid files which have a UTF-8 byte-order marker - id: check-byte-order-marker # Checks that non-binary executables have a proper shebang - id: check-executables-have-shebangs # Check for files that contain merge conflict strings. - id: check-merge-conflict # Check for debugger imports and py37+ breakpoint() # calls in python source - id: debug-statements - id: check-yaml files: .*\.(yaml|yml)$ - repo: local hooks: - id: flake8 name: flake8 additional_dependencies: - hacking>=6.1.0,<6.2.0 language: python entry: flake8 files: '^.*\.py$' exclude: '^(doc|releasenotes|tools)/.*$' ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/.stestr.conf0000664000175000017500000000010600000000000016452 0ustar00zuulzuul00000000000000[DEFAULT] test_path=${OS_TEST_PATH:-./oslo_privsep/tests} top_path=./ ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/.zuul.yaml0000664000175000017500000000033300000000000016144 0ustar00zuulzuul00000000000000- project: templates: - check-requirements - lib-forward-testing-python3 - openstack-python3-jobs - periodic-stable-jobs - publish-openstack-docs-pti - release-notes-jobs-python3 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253559.0 oslo.privsep-3.4.0/AUTHORS0000664000175000017500000000504000000000000015253 0ustar00zuulzuul00000000000000Alexander Tsamutali Andreas Jaeger Angus Lees Ben Nemec Bogdan Teleaga ChangBo Guo(gcb) Chuck Short Claudiu Belu Corey Bryant Cédric Jeanneret Daniel Bengtsson Darragh O'Reilly Davanum Srinivas Dirk Mueller Doug Hellmann Eric Brown Eric Fried Eric Harney Flavio Percoco Ghanshyam Ghanshyam Mann Gorka Eguileor Hervé Beraud Hongbin Lu Javier Pena John Garbutt Joshua Harlow Joshua Harlow Kirill Bespalov Max Lamprecht Mohammed Naser Moisés Guimarães de Medeiros OpenStack Release Bot Pavlo Shchelokovskyy Pierre Riteau Rodolfo Alonso Rodolfo Alonso Hernandez Sam Wan Sean McGinnis Stephen Finucane Sven Kieske Swapnil Kulkarni (coolsvap) Takashi Kajinami Takashi Kajinami Thierry Carrez TommyLike Tony Breeds Vieri <15050873171@163.com> Vu Cong Tuan Walter A. Boring IV Zhihai Song ZhijunWei ZhongShengping avnish caoyuan elajkat jacky06 liangcui loooosy melissaml pengyuesheng ricolin shupeng <15050873171@163.com> songwenping sonu.kumar wangqi wu.shiming xgwang5843 yangyawei zhangboye ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/CONTRIBUTING.rst0000664000175000017500000000152600000000000016651 0ustar00zuulzuul00000000000000If you would like to contribute to the development of oslo's libraries, first you must take a look to this page: https://specs.openstack.org/openstack/oslo-specs/specs/policy/contributing.html If you would like to contribute to the development of OpenStack, you must follow the steps in this page: http://docs.openstack.org/infra/manual/developers.html If you already have a good understanding of how the system works and your OpenStack accounts are set up, you can skip to the development workflow section of this documentation to learn how changes to OpenStack should be submitted for review via the Gerrit tool: http://docs.openstack.org/infra/manual/developers.html#development-workflow Pull requests submitted through GitHub will be ignored. Bugs should be filed on Launchpad, not GitHub: https://bugs.launchpad.net/oslo.privsep ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253559.0 oslo.privsep-3.4.0/ChangeLog0000664000175000017500000002427100000000000015764 0ustar00zuulzuul00000000000000CHANGES ======= 3.4.0 ----- * reno: Update master for unmaintained/zed * Remove old excludes * Update master for stable/2024.1 * reno: Update master for unmaintained/xena * reno: Update master for unmaintained/wallaby * reno: Update master for unmaintained/victoria 3.3.0 ----- * Display coverage report * reno: Update master for unmaintained/yoga * Bump hacking * Update python classifier in setup.cfg * add new kernel capabilities * Fix wrong path in coveragerc * fix broken links in readme * Update master for stable/2023.2 3.2.0 ----- * Imported Translations from Zanata * Bump bandit * Revert "Moves supported python runtimes from version 3.8 to 3.10" * Moves supported python runtimes from version 3.8 to 3.10 * setgid should be called before setuid * Update master for stable/2023.1 3.1.0 ----- * Setup logging without fixing evenlet logging * Add Python3 antelope unit tests * Update master for stable/zed 3.0.1 ----- * Remove logic for Python < 3.8 3.0.0 ----- * Drop python3.6/3.7 support in testing runtime 2.8.0 ----- * Remove unnecessary unicode prefixes * Add note explaining max\_buffer\_size value * Fix formatting of release list * Add Python3 zed unit tests * Update master for stable/yoga 2.7.0 ----- * Remove six * Bump max\_buffer\_size for Deserializer * Add Python3 yoga unit tests * Update master for stable/xena 2.6.2 ----- 2.6.1 ----- * Add except path with exception debug to send\_recv 2.6.0 ----- * Add timeout to PrivContext and entrypoint\_with\_timeout decorator * Changed minversion in tox to 3.18.0 * Upgrade the pre-commit-hooks version * setup.cfg: Replace dashes with underscores * Allow finer grained log levels * Add Python3 xena unit tests * Update master for stable/wallaby * Fix requirements issues * Use TOX\_CONSTRAINTS\_FILE * Use py3 as the default runtime for tox 2.5.0 ----- * Add Python3 wallaby unit tests * Update master for stable/victoria * Adding pre-commit 2.4.0 ----- * [goal] Migrate testing to ubuntu focal * Bump bandit version 2.3.0 ----- * Undo the eventlet monkey patch for the privileged daemon 2.2.1 ----- * Replace assertItemsEqual with assertCountEqual * Fix pygments style 2.2.0 ----- * Fix hacking min version to 3.0.1 * Switch to newer openstackdocstheme and reno versions * Remove the unused coding style modules * Remove translation sections from setup.cfg * Align contributing doc with oslo's policy * Bump default tox env from py37 to py38 * Add py38 package metadata * Add release notes links to doc index * Add Python3 victoria unit tests * Update master for stable/ussuri 2.1.1 ----- * Update hacking for Python3 * Use unittest.mock instead of third party mock 2.1.0 ----- * Make compatible with msgpack 1.0.0 * Bring sanity to lower-constraints * Disable logger validation during unit testing * Add lock around channel creation * trivial: Cleanup Sphinx config file, setup.cfg * tox: Add missing 'deps' for releasenotes testenv 2.0.0 ----- * remove outdated header * [ussuri][goal] Drop python 2.7 support and testing 1.34.0 ------ * tox: Trivial cleanup * Add functional tests * Bump the openstackdocstheme extension to 1.20 * tox: Keeping going with docs * Switch to Ussuri jobs * Update the constraints url * Update master for stable/train 1.33.3 ------ * Reno for SIGHUP fix 1.33.2 ------ * Self-resetting PrivContext * Add Python 3 Train unit tests * Move doc related modules to doc/requirements.txt 1.33.1 ------ * Pass correct arguments to six.reraise * Cap Bandit below 1.6.0 and update Sphinx requirement * Replace git.openstack.org URLs with opendev.org URLs 1.33.0 ------ * OpenDev Migration Patch * Add more usage documentation * Convert dict keys received in \_ClientChannel from byte to str * Update master for stable/stein * Add sample\_default for thread\_pool\_size Opt 1.32.1 ------ * add python 3.7 unit test job * Update hacking version 1.32.0 ------ 1.31.1 ------ * Expose privsep options for config-generator 1.31.0 ------ * Use template for lower-constraints * Set unicode\_errors handler to 'surrogateescape' in msgpack * Add futures as a requirement for Python 2 * Update mailinglist from dev to discuss * Use threads to process target function * Clean up .gitignore references to personal tools * Don't quote {posargs} in tox.ini 1.30.1 ------ * Replace assertRaisesRegexp with assertRaisesRegex * Avoids calling ffi.dlopen(None) on Windows * add lib-forward-testing-python3 test job * add python 3.6 unit test job * Remove PyPI downloads * import zuul job settings from project-config * Add that 'Release Notes' in README * Update reno for stable/rocky * Switch to stestr * fix tox python3 overrides * Added example blogposts * Trivial: Update pypi url to new url 1.29.0 ------ * set default python to python3 * fix lower constraints and uncap eventlet * Skip unit tests in bandit scan * add lower-constraints job * Updated from global requirements 1.28.0 ------ * Updated from global requirements * Imported Translations from Zanata * Update links in README * Imported Translations from Zanata * Update reno for stable/queens * Updated from global requirements * Updated from global requirements * Updated from global requirements * msgpack-python has been renamed to msgpack 1.26.0 ------ * Updated from global requirements 1.25.0 ------ * Expose caps values/names as int enum * add bandit to pep8 job 1.24.0 ------ * Remove -U from pip install * Avoid tox\_install.sh for constraints support * Updated from global requirements * Remove setting of version/release from releasenotes * Updated from global requirements * Updated from global requirements * Imported Translations from Zanata * Updated from global requirements * Updated from global requirements 1.23.0 ------ * Updated from global requirements * Imported Translations from Zanata * Updated from global requirements * Update reno for stable/pike * Updated from global requirements * Update capabilities from current kernel source 1.22.0 ------ * Updated from global requirements * Update URLs in documents according to document migration * add sphinx instructions to build API reference docs * switch from oslosphinx to openstackdocstheme * rearrange existing documentation to follow the new standard layout 1.21.1 ------ * Enable some off-by-default checks 1.21.0 ------ * Updated from global requirements * Updated from global requirements * Remove pbr warnerrors in favor of sphinx check * Updated from global requirements * Using assertIsNone(xxx) instead of assertEqual(None, xxx) * Updated from global requirements * Updated from global requirements * Updated from global requirements 1.20.0 ------ * Updated from global requirements * Add test to verify log record can be formatted * Updated from global requirements 1.19.0 ------ * Remove log translations 1.18.0 ------ * Use iterable object for 'args' in log record * Updated from global requirements 1.17.0 ------ * Updated from global requirements * [Fix gate]Update test requirement * Updated from global requirements * pbr.version.VersionInfo needs package name (oslo.xyz and not oslo\_xyz) * Update reno for stable/ocata * Remove references to Python 3.4 1.16.0 ------ * Add Constraints support * Show team and repo badges on README 1.15.0 ------ * Updated from global requirements * Don't use deprecated method logger.warn * Updated from global requirements * Imported Translations from Zanata * Updated from global requirements 1.14.0 ------ * Enable release notes translation * Updated from global requirements * Updated from global requirements * modify the home-page info with the developer documentation * Ignore timeout error when receiving message from sockect * Update reno for stable/newton * Deal with CONF.config\_dir correctly * Preserve all LogRecord fields from privileged side 1.13.0 ------ * Report underlying integer for unknown capabilities * Updated from global requirements 1.12.0 ------ * Add Python 3.5 classifier and venv * Fixes unit tests on Windows * More sophisticated logging on privileged side 1.11.0 ------ * Updated from global requirements * Use default value for undefined caps in fmt\_caps 1.10.0 ------ * Updated from global requirements * Add reno for release notes management * Updated from global requirements * Updated from global requirements 1.9.0 ----- * Provide way to "initialise" oslo.privsep * PrivContext: Sets client\_mode to False on Windows * Imported Translations from Zanata 1.8.0 ----- * Updated from global requirements * Drop python3.3 support in classifier 1.7.0 ----- 1.6.0 ----- * Imported Translations from Zanata * Remove unused py27 socketpair/makefile workaround * Remove direct dependency on babel * Updated from global requirements 1.5.0 ----- * Updated from global requirements * Updated from global requirements * Switch to msgpack for serialization * Updated from global requirements 1.3.0 ----- * Updated from global requirements 1.2.0 ----- * Updated from global requirements * fdopen: Use better "is using eventlet" test * Ensure fdopen uses greenio object under eventlet 1.1.0 ----- * UnprivilegedPrivsepFixture: Clear capabilities config * Change name of privsep\_helper to match code 1.0.0 ----- * Ignore --config-dir when value is None * Add version and download badges to README * Update translation setup * Updated from global requirements * Updated from global requirements * Updated from global requirements * Imported Translations from Zanata * Updated from global requirements * Update/make better the README.rst long description 0.3.0 ----- * Improve \`helper\_command' config default * Updated from global requirements * Replace deprecated LOG.warn with LOG.warning * Updated from global requirements * Use logging intead of oslo\_log * Remove unused file openstack-common.conf * remove python 2.6 trove classifier 0.2.0 ----- * Updated from global requirements * Updated from global requirements * Removes MANIFEST.in as it is not needed explicitely by PBR * Remove python 2.6 and tox.ini cleanup * Don't fail badly on windows 0.1.0 ----- * Updated from global requirements * Updated from global requirements * Imported Translations from Zanata * Add support for Linux capabilities * Enable translations * Initial basic privsep functionality * Tell git to ignore /.eggs dir too * Updated from global requirements * oslo.i18n boilerplate * Initial cookiecutter project * Added .gitreview ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/HACKING.rst0000664000175000017500000000025100000000000016000 0ustar00zuulzuul00000000000000oslo.privsep Style Commandments ====================================================== Read the OpenStack Style Commandments https://docs.openstack.org/hacking/latest/ ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/LICENSE0000664000175000017500000002363700000000000015224 0ustar00zuulzuul00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1724253560.1251357 oslo.privsep-3.4.0/PKG-INFO0000664000175000017500000000476500000000000015315 0ustar00zuulzuul00000000000000Metadata-Version: 1.2 Name: oslo.privsep Version: 3.4.0 Summary: OpenStack library for privilege separation Home-page: https://docs.openstack.org/oslo.privsep/latest/ Author: OpenStack Author-email: openstack-discuss@lists.openstack.org License: UNKNOWN Description: ======================== Team and repository tags ======================== .. image:: https://governance.openstack.org/tc/badges/oslo.privsep.svg :target: https://governance.openstack.org/tc/reference/tags/index.html .. Change things from this point on ============ oslo.privsep ============ .. image:: https://img.shields.io/pypi/v/oslo.privsep.svg :target: https://pypi.org/project/oslo.privsep/ :alt: Latest Version OpenStack library for privilege separation This library helps applications perform actions which require more or less privileges than they were started with in a safe, easy to code and easy to use manner. For more information on why this is generally a good idea please read over the `principle of least privilege`_ and the `specification`_ which created this library. * Free software: Apache license * Documentation: https://docs.openstack.org/oslo.privsep/latest/ * Source: https://opendev.org/openstack/oslo.privsep * Bugs: https://bugs.launchpad.net/oslo.privsep * Release Notes: https://docs.openstack.org/releasenotes/oslo.privsep .. _principle of least privilege: https://en.wikipedia.org/wiki/Principle_of_least_privilege .. _specification: https://specs.openstack.org/openstack/oslo-specs/specs/liberty/privsep.html Platform: UNKNOWN Classifier: Environment :: OpenStack Classifier: Intended Audience :: Information Technology Classifier: Intended Audience :: System Administrators Classifier: License :: OSI Approved :: Apache Software License Classifier: Operating System :: POSIX :: Linux Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.8 Classifier: Programming Language :: Python :: 3.9 Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: Python :: 3.11 Classifier: Programming Language :: Python :: 3 :: Only Classifier: Programming Language :: Python :: Implementation :: CPython Requires-Python: >=3.8 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/README.rst0000664000175000017500000000237000000000000015675 0ustar00zuulzuul00000000000000======================== Team and repository tags ======================== .. image:: https://governance.openstack.org/tc/badges/oslo.privsep.svg :target: https://governance.openstack.org/tc/reference/tags/index.html .. Change things from this point on ============ oslo.privsep ============ .. image:: https://img.shields.io/pypi/v/oslo.privsep.svg :target: https://pypi.org/project/oslo.privsep/ :alt: Latest Version OpenStack library for privilege separation This library helps applications perform actions which require more or less privileges than they were started with in a safe, easy to code and easy to use manner. For more information on why this is generally a good idea please read over the `principle of least privilege`_ and the `specification`_ which created this library. * Free software: Apache license * Documentation: https://docs.openstack.org/oslo.privsep/latest/ * Source: https://opendev.org/openstack/oslo.privsep * Bugs: https://bugs.launchpad.net/oslo.privsep * Release Notes: https://docs.openstack.org/releasenotes/oslo.privsep .. _principle of least privilege: https://en.wikipedia.org/wiki/Principle_of_least_privilege .. _specification: https://specs.openstack.org/openstack/oslo-specs/specs/liberty/privsep.html ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1724253560.1091354 oslo.privsep-3.4.0/doc/0000775000175000017500000000000000000000000014751 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/doc/requirements.txt0000664000175000017500000000016700000000000020241 0ustar00zuulzuul00000000000000openstackdocstheme>=2.2.0 # Apache-2.0 sphinx>=2.0.0 # BSD reno>=3.1.0 # Apache-2.0 sphinxcontrib-apidoc>=0.2.0 # BSD ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1724253560.1091354 oslo.privsep-3.4.0/doc/source/0000775000175000017500000000000000000000000016251 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/doc/source/conf.py0000664000175000017500000000377300000000000017562 0ustar00zuulzuul00000000000000# -*- coding: utf-8 -*- # Copyright (C) 2020 Red Hat, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. # See the License for the specific language governing permissions and # limitations under the License. # -- General configuration ---------------------------------------------------- # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = [ 'sphinx.ext.autodoc', 'sphinxcontrib.apidoc', 'openstackdocstheme', ] # openstackdocstheme options openstackdocs_repo_name = 'openstack/oslo.privsep' openstackdocs_bug_project = 'oslo.privsep' openstackdocs_bug_tag = '' # The suffix of source filenames. source_suffix = '.rst' # The master toctree document. master_doc = 'index' # General information about the project. copyright = '2014, OpenStack Foundation' # If true, '()' will be appended to :func: etc. cross-reference text. add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). add_module_names = True # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'native' # -- Options for HTML output -------------------------------------------------- # The theme to use for HTML and HTML Help pages. Major themes that come with # Sphinx are currently 'default' and 'sphinxdoc'. html_theme = 'openstackdocs' # -- sphinxcontrib.apidoc configuration -------------------------------------- apidoc_module_dir = '../../oslo_privsep' apidoc_output_dir = 'reference/api' apidoc_excluded_paths = [ 'tests', ] ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1724253560.1131353 oslo.privsep-3.4.0/doc/source/contributor/0000775000175000017500000000000000000000000020623 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/doc/source/contributor/contributing.rst0000664000175000017500000000012400000000000024061 0ustar00zuulzuul00000000000000============== Contributing ============== .. include:: ../../../CONTRIBUTING.rst ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/doc/source/contributor/history.rst0000664000175000017500000000004000000000000023050 0ustar00zuulzuul00000000000000.. include:: ../../../ChangeLog ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/doc/source/contributor/index.rst0000664000175000017500000000016500000000000022466 0ustar00zuulzuul00000000000000=================== Contributor Guide =================== .. toctree:: :maxdepth: 2 contributing history ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/doc/source/index.rst0000664000175000017500000000170000000000000020110 0ustar00zuulzuul00000000000000============== oslo.privsep ============== oslo.privsep is an OpenStack library for privilege separation. It helps applications perform actions which require more or less privileges than they were started with in a safe, easy to code and easy to use manner. For more information on why this is generally a good idea please read over the `principle of least privilege`_ and the `specification`_ which created this library. .. _principle of least privilege: https://en.wikipedia.org/wiki/Principle_of_least_privilege .. _specification: https://specs.openstack.org/openstack/oslo-specs/specs/liberty/privsep.html Contents ======== .. toctree:: :maxdepth: 2 install/index user/index contributor/index reference/index Release Notes ============= Read also the `oslo.privsep Release Notes `_. Indices and tables ================== * :ref:`genindex` * :ref:`modindex` * :ref:`search` ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1724253560.1131353 oslo.privsep-3.4.0/doc/source/install/0000775000175000017500000000000000000000000017717 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/doc/source/install/index.rst0000664000175000017500000000014300000000000021556 0ustar00zuulzuul00000000000000============== Installation ============== At the command line:: $ pip install oslo.privsep ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1724253560.1131353 oslo.privsep-3.4.0/doc/source/reference/0000775000175000017500000000000000000000000020207 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/doc/source/reference/index.rst0000664000175000017500000000007700000000000022054 0ustar00zuulzuul00000000000000===== API ===== .. toctree:: :maxdepth: 2 api/modules ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1724253560.1131353 oslo.privsep-3.4.0/doc/source/user/0000775000175000017500000000000000000000000017227 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/doc/source/user/index.rst0000664000175000017500000001354500000000000021100 0ustar00zuulzuul00000000000000======= Usage ======= oslo.privsep lets you define in your code specific functions that will run in predefined privilege contexts. This lets you run functions with more (or less) privileges than the rest of the code. Privsep functions live in a specific ``privsep`` submodule (for example, ``nova.privsep`` for nova). Defining a context ================== Contexts are defined in the ``privsep/__init__.py`` file. For example, this defines a sys_admin_pctxt with ``CAP_CHOWN``, ``CAP_DAC_OVERRIDE``, ``CAP_DAC_READ_SEARCH``, ``CAP_FOWNER``, ``CAP_NET_ADMIN``, and ``CAP_SYS_ADMIN`` rights (equivalent to ``sudo`` rights):: from oslo_privsep import capabilities from oslo_privsep import priv_context sys_admin_pctxt = priv_context.PrivContext( 'nova', cfg_section='nova_sys_admin', pypath=__name__ + '.sys_admin_pctxt', capabilities=[capabilities.CAP_CHOWN, capabilities.CAP_DAC_OVERRIDE, capabilities.CAP_DAC_READ_SEARCH, capabilities.CAP_FOWNER, capabilities.CAP_NET_ADMIN, capabilities.CAP_SYS_ADMIN], ) Defining a context with timeout ------------------------------- It is possible to initialize PrivContext with timeout:: from oslo_privsep import capabilities from oslo_privsep import priv_context dhcp_release_cmd = priv_context.PrivContext( __name__, cfg_section='privsep_dhcp_release', pypath=__name__ + '.dhcp_release_cmd', capabilities=[caps.CAP_SYS_ADMIN, caps.CAP_NET_ADMIN], timeout=5 ) ``PrivsepTimeout`` is raised if timeout is reached. .. warning:: The daemon (the root process) task won't stop when timeout is reached. That means we'll have less available threads if the related thread never finishes. Defining a privileged function ============================== Functions are defined in files under the ``privsep/`` subdirectory, for example in a ``privsep/motd.py`` file for functions touching the MOTD file. They make use of a decorator pointing to the context we defined above:: import nova.privsep @nova.privsep.sys_admin_pctxt.entrypoint def update_motd(message): with open('/etc/motd', 'w') as f: f.write(message) Privileged functions must be as simple, specialized and narrow as possible, so as to prevent further escalation. In this example, ``update_motd(message)`` is narrow: it only allows the service to overwrite the MOTD file. If a more generic ``update_file(filename, content)`` was created, it could be used to overwrite any file in the filesystem, allowing easy escalation to root rights. That would defeat the whole purpose of oslo.privsep. Defining a privileged function with timeout ------------------------------------------- It is possible to use ``entrypoint_with_timeout`` decorator:: from oslo_privsep import daemon from neutron import privileged @privileged.default.entrypoint_with_timeout(timeout=5) def get_link_devices(namespace, **kwargs): try: with get_iproute(namespace) as ip: return make_serializable(ip.get_links(**kwargs)) except OSError as e: if e.errno == errno.ENOENT: raise NetworkNamespaceNotFound(netns_name=namespace) raise except daemon.FailedToDropPrivileges: raise except daemon.PrivsepTimeout: raise ``PrivsepTimeout`` is raised if timeout is reached. .. warning:: The daemon (the root process) task won't stop when timeout is reached. That means we'll have less available threads if the related thread never finishes. Using a privileged function =========================== To use the privileged function in the regular code, you can just call it:: import nova.privsep.motd ... nova.privsep.motd.update_motd('This node is currently idle') It is better to import the complete path (``import nova.privsep.motd``) rather than the motd name (``from nova.privsep import motd``) so that it is easier to spot that the function runs in a different privileged context. For more details, you can read the following blog post: * `How to make a privileged call with oslo privsep`_ .. _How to make a privileged call with oslo privsep: https://www.madebymikal.com/how-to-make-a-privileged-call-with-oslo-privsep/ Converting from rootwrap to privsep =================================== oslo.rootwrap is a precursor of oslo.privsep to allow code to run commands under sudo if they match a predefined filter. For example, you could define a filter that would allow you to run chmod as root using the following filter:: chmod: CommandFilter, chmod, root Beyond the bad performance of calling full commands in order to accomplish simple tasks, rootwrap also led to bad security: it was difficult to filter commands in a way that would not easily allow privilege escalation. Replacing rootwrap filters with privsep functions is easy. The chmod filter above can be replaced with a function that calls ``os.chmod()``. However a straight 1:1 filter:function replacement generally results in functions that are still too broad for good security. It is better to replace each chmod rootwrap *call* with a narrow privsep function that will limit it to specific files. Sometimes it is necessary to refactor the calling code: the rootwrap design discouraged the creation of new filters and therefore often resulted in the creation of overly-broad calling functions. As an example, this `patch series`_ is work-in-progress to transition Nova from rootwrap to privsep. For more details, you can read the following blog post: * `Adding oslo privsep to a new project, a worked example`_ .. _patch series: https://review.openstack.org/#/q/project:openstack/nova+branch:master+topic:my-own-personal-alternative-universe .. _Adding oslo privsep to a new project, a worked example: https://www.madebymikal.com/adding-oslo-privsep-to-a-new-project-a-worked-example/ ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1724253560.1131353 oslo.privsep-3.4.0/oslo.privsep.egg-info/0000775000175000017500000000000000000000000020341 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253559.0 oslo.privsep-3.4.0/oslo.privsep.egg-info/PKG-INFO0000664000175000017500000000476500000000000021452 0ustar00zuulzuul00000000000000Metadata-Version: 1.2 Name: oslo.privsep Version: 3.4.0 Summary: OpenStack library for privilege separation Home-page: https://docs.openstack.org/oslo.privsep/latest/ Author: OpenStack Author-email: openstack-discuss@lists.openstack.org License: UNKNOWN Description: ======================== Team and repository tags ======================== .. image:: https://governance.openstack.org/tc/badges/oslo.privsep.svg :target: https://governance.openstack.org/tc/reference/tags/index.html .. Change things from this point on ============ oslo.privsep ============ .. image:: https://img.shields.io/pypi/v/oslo.privsep.svg :target: https://pypi.org/project/oslo.privsep/ :alt: Latest Version OpenStack library for privilege separation This library helps applications perform actions which require more or less privileges than they were started with in a safe, easy to code and easy to use manner. For more information on why this is generally a good idea please read over the `principle of least privilege`_ and the `specification`_ which created this library. * Free software: Apache license * Documentation: https://docs.openstack.org/oslo.privsep/latest/ * Source: https://opendev.org/openstack/oslo.privsep * Bugs: https://bugs.launchpad.net/oslo.privsep * Release Notes: https://docs.openstack.org/releasenotes/oslo.privsep .. _principle of least privilege: https://en.wikipedia.org/wiki/Principle_of_least_privilege .. _specification: https://specs.openstack.org/openstack/oslo-specs/specs/liberty/privsep.html Platform: UNKNOWN Classifier: Environment :: OpenStack Classifier: Intended Audience :: Information Technology Classifier: Intended Audience :: System Administrators Classifier: License :: OSI Approved :: Apache Software License Classifier: Operating System :: POSIX :: Linux Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.8 Classifier: Programming Language :: Python :: 3.9 Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: Python :: 3.11 Classifier: Programming Language :: Python :: 3 :: Only Classifier: Programming Language :: Python :: Implementation :: CPython Requires-Python: >=3.8 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253560.0 oslo.privsep-3.4.0/oslo.privsep.egg-info/SOURCES.txt0000664000175000017500000000512500000000000022230 0ustar00zuulzuul00000000000000.coveragerc .mailmap .pre-commit-config.yaml .stestr.conf .zuul.yaml AUTHORS CONTRIBUTING.rst ChangeLog HACKING.rst LICENSE README.rst requirements.txt setup.cfg setup.py test-requirements.txt tox.ini doc/requirements.txt doc/source/conf.py doc/source/index.rst doc/source/contributor/contributing.rst doc/source/contributor/history.rst doc/source/contributor/index.rst doc/source/install/index.rst doc/source/reference/index.rst doc/source/user/index.rst oslo.privsep.egg-info/PKG-INFO oslo.privsep.egg-info/SOURCES.txt oslo.privsep.egg-info/dependency_links.txt oslo.privsep.egg-info/entry_points.txt oslo.privsep.egg-info/not-zip-safe oslo.privsep.egg-info/pbr.json oslo.privsep.egg-info/requires.txt oslo.privsep.egg-info/top_level.txt oslo_privsep/__init__.py oslo_privsep/_i18n.py oslo_privsep/capabilities.py oslo_privsep/comm.py oslo_privsep/daemon.py oslo_privsep/priv_context.py oslo_privsep/version.py oslo_privsep/functional/__init__.py oslo_privsep/functional/test_daemon.py oslo_privsep/locale/de/LC_MESSAGES/oslo_privsep.po oslo_privsep/locale/en_GB/LC_MESSAGES/oslo_privsep.po oslo_privsep/tests/__init__.py oslo_privsep/tests/fixture.py oslo_privsep/tests/test_capabilities.py oslo_privsep/tests/test_comm.py oslo_privsep/tests/test_daemon.py oslo_privsep/tests/test_priv_context.py oslo_privsep/tests/testctx.py releasenotes/notes/add_entrypoint_with_timeout_decorator-9aab5a74153b3632.yaml releasenotes/notes/add_reno-3b4ae0789e9c45b4.yaml releasenotes/notes/add_thread_pool_size-a54e6f27ab019f96.yaml releasenotes/notes/auto-restart-client-channel-619545294557bf2b.yaml releasenotes/notes/context-logger-06b475357bebadc7.yaml releasenotes/notes/drop-python27-support-6da3028c1cf099eb.yaml releasenotes/notes/setgid-should-be-called-before-setuid-fcf01083df9d5369.yaml releasenotes/notes/un-monkey-patch-privileged-daemon-160e00296549df3d.yaml releasenotes/source/2023.1.rst releasenotes/source/2023.2.rst releasenotes/source/2024.1.rst releasenotes/source/conf.py releasenotes/source/index.rst releasenotes/source/newton.rst releasenotes/source/ocata.rst releasenotes/source/pike.rst releasenotes/source/queens.rst releasenotes/source/rocky.rst releasenotes/source/stein.rst releasenotes/source/train.rst releasenotes/source/unreleased.rst releasenotes/source/ussuri.rst releasenotes/source/victoria.rst releasenotes/source/wallaby.rst releasenotes/source/xena.rst releasenotes/source/yoga.rst releasenotes/source/zed.rst releasenotes/source/_static/.placeholder releasenotes/source/_templates/.placeholder releasenotes/source/locale/en_GB/LC_MESSAGES/releasenotes.po releasenotes/source/locale/fr/LC_MESSAGES/releasenotes.po././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253559.0 oslo.privsep-3.4.0/oslo.privsep.egg-info/dependency_links.txt0000664000175000017500000000000100000000000024407 0ustar00zuulzuul00000000000000 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253559.0 oslo.privsep-3.4.0/oslo.privsep.egg-info/entry_points.txt0000664000175000017500000000021400000000000023634 0ustar00zuulzuul00000000000000[console_scripts] privsep-helper = oslo_privsep.daemon:helper_main [oslo.config.opts] oslo.privsep = oslo_privsep.priv_context:_list_opts ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253559.0 oslo.privsep-3.4.0/oslo.privsep.egg-info/not-zip-safe0000664000175000017500000000000100000000000022567 0ustar00zuulzuul00000000000000 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253559.0 oslo.privsep-3.4.0/oslo.privsep.egg-info/pbr.json0000664000175000017500000000005600000000000022020 0ustar00zuulzuul00000000000000{"git_version": "be156e2", "is_release": true}././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253559.0 oslo.privsep-3.4.0/oslo.privsep.egg-info/requires.txt0000664000175000017500000000020700000000000022740 0ustar00zuulzuul00000000000000cffi>=1.14.0 eventlet>=0.21.0 greenlet>=0.4.14 msgpack>=0.6.0 oslo.config>=5.2.0 oslo.i18n>=3.15.3 oslo.log>=3.36.0 oslo.utils>=3.33.0 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253559.0 oslo.privsep-3.4.0/oslo.privsep.egg-info/top_level.txt0000664000175000017500000000001500000000000023067 0ustar00zuulzuul00000000000000oslo_privsep ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1724253560.1131353 oslo.privsep-3.4.0/oslo_privsep/0000775000175000017500000000000000000000000016730 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/oslo_privsep/__init__.py0000664000175000017500000000000000000000000021027 0ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/oslo_privsep/_i18n.py0000664000175000017500000000200700000000000020217 0ustar00zuulzuul00000000000000# Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. """oslo.i18n integration module. See https://docs.openstack.org/oslo.i18n/latest/user/index.html """ import oslo_i18n _translators = oslo_i18n.TranslatorFactory(domain='oslo_privsep') # The primary translation function using the well-known name "_" _ = _translators.primary # The contextual translation function using the name "_C" _C = _translators.contextual_form # The plural translation function using the name "_P" _P = _translators.plural_form ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/oslo_privsep/capabilities.py0000664000175000017500000001240400000000000021734 0ustar00zuulzuul00000000000000# Copyright 2015 Rackspace Hosting # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import enum import os import platform import sys import cffi class Capabilities(enum.IntEnum): # Generated with: # awk '/^#define CAP_[A-Z_]+[ \t]+[0-9]+/ {print $2,"=",$3}' \ # include/uapi/linux/capability.h # From the 6.6.6 kernel and the kernel git SHA:0c38b88c3323 # Will need to be refreshed as new capabilites are added to the kernel CAP_CHOWN = 0 CAP_DAC_OVERRIDE = 1 CAP_DAC_READ_SEARCH = 2 CAP_FOWNER = 3 CAP_FSETID = 4 CAP_KILL = 5 CAP_SETGID = 6 CAP_SETUID = 7 CAP_SETPCAP = 8 CAP_LINUX_IMMUTABLE = 9 CAP_NET_BIND_SERVICE = 10 CAP_NET_BROADCAST = 11 CAP_NET_ADMIN = 12 CAP_NET_RAW = 13 CAP_IPC_LOCK = 14 CAP_IPC_OWNER = 15 CAP_SYS_MODULE = 16 CAP_SYS_RAWIO = 17 CAP_SYS_CHROOT = 18 CAP_SYS_PTRACE = 19 CAP_SYS_PACCT = 20 CAP_SYS_ADMIN = 21 CAP_SYS_BOOT = 22 CAP_SYS_NICE = 23 CAP_SYS_RESOURCE = 24 CAP_SYS_TIME = 25 CAP_SYS_TTY_CONFIG = 26 CAP_MKNOD = 27 CAP_LEASE = 28 CAP_AUDIT_WRITE = 29 CAP_AUDIT_CONTROL = 30 CAP_SETFCAP = 31 CAP_MAC_OVERRIDE = 32 CAP_MAC_ADMIN = 33 CAP_SYSLOG = 34 CAP_WAKE_ALARM = 35 CAP_BLOCK_SUSPEND = 36 CAP_AUDIT_READ = 37 CAP_PERFMON = 38 CAP_BPF = 39 CAP_CHECKPOINT_RESTORE = 40 CAPS_BYNAME = {} CAPS_BYVALUE = {} module = sys.modules[__name__] # Convenience dicts for human readable values # module attributes for backwards compat/convenience for c in Capabilities: CAPS_BYNAME[c.name] = c.value CAPS_BYVALUE[c.value] = c.name setattr(module, c.name, c.value) CDEF = ''' /* Edited highlights from `echo '#include ' | gcc -E -` */ #define _LINUX_CAPABILITY_VERSION_2 0x20071026 #define _LINUX_CAPABILITY_U32S_2 2 typedef unsigned int __u32; typedef struct __user_cap_header_struct { __u32 version; int pid; } *cap_user_header_t; typedef struct __user_cap_data_struct { __u32 effective; __u32 permitted; __u32 inheritable; } *cap_user_data_t; int capset(cap_user_header_t header, const cap_user_data_t data); int capget(cap_user_header_t header, cap_user_data_t data); /* Edited highlights from `echo '#include ' | gcc -E -` */ #define PR_GET_KEEPCAPS 7 #define PR_SET_KEEPCAPS 8 int prctl (int __option, ...); ''' ffi = cffi.FFI() ffi.cdef(CDEF) if platform.system() == 'Linux': # mock.patching crt.* directly seems to upset cffi. Use an # indirection point here for easier testing. crt = ffi.dlopen(None) _prctl = crt.prctl _capget = crt.capget _capset = crt.capset else: _prctl = None _capget = None _capset = None def set_keepcaps(enable): """Set/unset thread's "keep capabilities" flag - see prctl(2)""" ret = _prctl(crt.PR_SET_KEEPCAPS, ffi.cast('unsigned long', bool(enable))) if ret != 0: errno = ffi.errno raise OSError(errno, os.strerror(errno)) def drop_all_caps_except(effective, permitted, inheritable): """Set (effective, permitted, inheritable) to provided list of caps""" eff = _caps_to_mask(effective) prm = _caps_to_mask(permitted) inh = _caps_to_mask(inheritable) header = ffi.new('cap_user_header_t', {'version': crt._LINUX_CAPABILITY_VERSION_2, 'pid': 0}) data = ffi.new('struct __user_cap_data_struct[2]') data[0].effective = eff & 0xffffffff data[1].effective = eff >> 32 data[0].permitted = prm & 0xffffffff data[1].permitted = prm >> 32 data[0].inheritable = inh & 0xffffffff data[1].inheritable = inh >> 32 ret = _capset(header, data) if ret != 0: errno = ffi.errno raise OSError(errno, os.strerror(errno)) def _mask_to_caps(mask): """Convert bitmask to list of set bit offsets""" return [i for i in range(64) if (1 << i) & mask] def _caps_to_mask(caps): """Convert list of bit offsets to bitmask""" mask = 0 for cap in caps: mask |= 1 << cap return mask def get_caps(): """Return (effective, permitted, inheritable) as lists of caps""" header = ffi.new('cap_user_header_t', {'version': crt._LINUX_CAPABILITY_VERSION_2, 'pid': 0}) data = ffi.new('struct __user_cap_data_struct[2]') ret = _capget(header, data) if ret != 0: errno = ffi.errno raise OSError(errno, os.strerror(errno)) return ( _mask_to_caps(data[0].effective | (data[1].effective << 32)), _mask_to_caps(data[0].permitted | (data[1].permitted << 32)), _mask_to_caps(data[0].inheritable | (data[1].inheritable << 32)), ) ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/oslo_privsep/comm.py0000664000175000017500000001550400000000000020242 0ustar00zuulzuul00000000000000# Copyright 2015 Rackspace Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. """Serialization/Deserialization for privsep. The wire format is a stream of msgpack objects encoding primitive python datatypes. Msgpack 'raw' is assumed to be a valid utf8 string (msgpack 2.0 'bin' type is used for bytes). Python lists are converted to tuples during serialization/deserialization. """ import datetime import enum import logging import socket import sys import threading import msgpack from oslo_privsep._i18n import _ from oslo_utils import uuidutils LOG = logging.getLogger(__name__) @enum.unique class Message(enum.IntEnum): """Types of messages sent across the communication channel""" PING = 1 PONG = 2 CALL = 3 RET = 4 ERR = 5 LOG = 6 class PrivsepTimeout(Exception): pass class Serializer(object): def __init__(self, writesock): self.writesock = writesock def send(self, msg): buf = msgpack.packb(msg, use_bin_type=True, unicode_errors='surrogateescape') self.writesock.sendall(buf) def close(self): # Hilarious. `socket._socketobject.close()` doesn't actually # call `self._sock.close()`. Oh well, we really wanted a half # close anyway. self.writesock.shutdown(socket.SHUT_WR) class Deserializer(object): def __init__(self, readsock): self.readsock = readsock self.unpacker = msgpack.Unpacker( use_list=False, raw=False, strict_map_key=False, unicode_errors='surrogateescape', # msgpack 1.0.0 set this value to 100MiB; raise it here for msgpack # < 1.0.0 max_buffer_size=100 * 1024 * 1024, ) def __iter__(self): return self def __next__(self): while True: try: return next(self.unpacker) except StopIteration: try: buf = self.readsock.recv(4096) if not buf: raise self.unpacker.feed(buf) except socket.timeout: pass class Future(object): """A very simple object to track the return of a function call""" def __init__(self, lock, timeout=None): self.condvar = threading.Condition(lock) self.error = None self.data = None self.timeout = timeout def set_result(self, data): """Must already be holding lock used in constructor""" self.data = data self.condvar.notify() def set_exception(self, exc): """Must already be holding lock used in constructor""" self.error = exc self.condvar.notify() def result(self): """Must already be holding lock used in constructor""" before = datetime.datetime.now() if not self.condvar.wait(timeout=self.timeout): now = datetime.datetime.now() LOG.warning('Timeout while executing a command, timeout: %s, ' 'time elapsed: %s', self.timeout, (now - before).total_seconds()) return (Message.ERR.value, '%s.%s' % (PrivsepTimeout.__module__, PrivsepTimeout.__name__), '') if self.error is not None: raise self.error return self.data class ClientChannel(object): def __init__(self, sock): self.running = False self.writer = Serializer(sock) self.lock = threading.Lock() self.reader_thread = threading.Thread( name='privsep_reader', target=self._reader_main, args=(Deserializer(sock),), ) self.reader_thread.daemon = True self.outstanding_msgs = {} self.reader_thread.start() def _reader_main(self, reader): """This thread owns and demuxes the read channel""" with self.lock: self.running = True for msg in reader: msgid, data = msg if msgid is None: self.out_of_band(data) else: with self.lock: if msgid not in self.outstanding_msgs: LOG.warning("msgid should be in oustanding_msgs, it is" "possible that timeout is reached!") continue self.outstanding_msgs[msgid].set_result(data) # EOF. Perhaps the privileged process exited? # Send an IOError to any oustanding waiting readers. Assuming # the write direction is also closed, any new writes should # get an immediate similar error. LOG.debug('EOF on privsep read channel') exc = IOError(_('Premature eof waiting for privileged process')) with self.lock: for mbox in self.outstanding_msgs.values(): mbox.set_exception(exc) self.running = False def out_of_band(self, msg): """Received OOB message. Subclasses might want to override this.""" pass def send_recv(self, msg, timeout=None): myid = uuidutils.generate_uuid() while myid in self.outstanding_msgs: LOG.warning("myid shoudn't be in outstanding_msgs.") myid = uuidutils.generate_uuid() future = Future(self.lock, timeout) with self.lock: self.outstanding_msgs[myid] = future try: self.writer.send((myid, msg)) reply = future.result() except Exception: LOG.warning("Unexpected error: {}".format(sys.exc_info()[0])) raise finally: del self.outstanding_msgs[myid] return reply def close(self): with self.lock: self.writer.close() self.reader_thread.join() class ServerChannel(object): """Server-side twin to ClientChannel""" def __init__(self, sock): self.rlock = threading.Lock() self.reader_iter = iter(Deserializer(sock)) self.wlock = threading.Lock() self.writer = Serializer(sock) def __iter__(self): return self def __next__(self): with self.rlock: return next(self.reader_iter) def send(self, msg): with self.wlock: self.writer.send(msg) ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/oslo_privsep/daemon.py0000664000175000017500000004726600000000000020564 0ustar00zuulzuul00000000000000# Copyright 2015 Rackspace Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. """Privilege separation ("privsep") daemon. To ease transition this supports 2 alternative methods of starting the daemon, all resulting in a helper process running with elevated privileges and open socket(s) to the original process: 1. Start via fork() Assumes process currently has all required privileges and is about to drop them (perhaps by setuid to an unprivileged user). If the the initial environment is secure and `PrivContext.start(Method.FORK)` is called early in `main()`, then this is the most secure and simplest. In particular, if the initial process is already running as non-root (but with sufficient capabilities, via eg suitable systemd service files), then no part needs to involve uid=0 or sudo. 2. Start via sudo/rootwrap This starts the privsep helper on first use via sudo and rootwrap, and communicates via a temporary Unix socket passed on the command line. The communication channel is briefly exposed in the filesystem, but is protected with file permissions and connecting to it only grants access to the unprivileged process. Requires a suitable entry in sudoers or rootwrap.conf filters. The privsep daemon exits when the communication channel is closed, (which usually occurs when the unprivileged process exits). """ from concurrent import futures import enum import errno import io import logging as pylogging import os import platform import socket import subprocess import sys import tempfile import threading import eventlet from eventlet import patcher from oslo_config import cfg from oslo_log import log as logging from oslo_utils import encodeutils from oslo_utils import importutils from oslo_privsep._i18n import _ from oslo_privsep import capabilities from oslo_privsep import comm if platform.system() == 'Linux': import fcntl import grp import pwd LOG = logging.getLogger(__name__) EVENTLET_MODULES = ('os', 'select', 'socket', 'thread', 'time', 'MySQLdb', 'builtins', 'subprocess') EVENTLET_LIBRARIES = [] def _null(): return [] for module in EVENTLET_MODULES: if hasattr(patcher, '_green_%s_modules' % module): method = getattr(patcher, '_green_%s_modules' % module) elif hasattr(patcher, '_green_%s' % module): method = getattr(patcher, '_green_%s' % module) else: method = _null() EVENTLET_LIBRARIES.append((module, method)) @enum.unique class StdioFd(enum.IntEnum): # NOTE(gus): We can't use sys.std*.fileno() here. sys.std* # objects may be random file-like objects that may not match the # true system std* fds - and indeed may not even have a file # descriptor at all (eg: test fixtures that monkey patch # fixtures.StringStream onto sys.stdout). Below we always want # the _real_ well-known 0,1,2 Unix fds during os.dup2 # manipulation. STDIN = 0 STDOUT = 1 STDERR = 2 class FailedToDropPrivileges(Exception): pass class ProtocolError(Exception): pass def set_cloexec(fd): flags = fcntl.fcntl(fd, fcntl.F_GETFD) if (flags & fcntl.FD_CLOEXEC) == 0: flags |= fcntl.FD_CLOEXEC fcntl.fcntl(fd, fcntl.F_SETFD, flags) def setuid(user_id_or_name): try: new_uid = int(user_id_or_name) except (TypeError, ValueError): new_uid = pwd.getpwnam(user_id_or_name).pw_uid if new_uid != 0: try: os.setuid(new_uid) except OSError: msg = _('Failed to set uid %s') % new_uid LOG.critical(msg) raise FailedToDropPrivileges(msg) def setgid(group_id_or_name): try: new_gid = int(group_id_or_name) except (TypeError, ValueError): new_gid = grp.getgrnam(group_id_or_name).gr_gid if new_gid != 0: try: os.setgid(new_gid) except OSError: msg = _('Failed to set gid %s') % new_gid LOG.critical(msg) raise FailedToDropPrivileges(msg) class PrivsepLogHandler(pylogging.Handler): def __init__(self, channel, processName=None): super(PrivsepLogHandler, self).__init__() self.channel = channel self.processName = processName def emit(self, record): # Vaguely based on pylogging.handlers.SocketHandler.makePickle if self.processName: record.processName = self.processName data = dict(record.__dict__) if record.exc_info: if not record.exc_text: fmt = self.formatter or pylogging.Formatter() data['exc_text'] = fmt.formatException(record.exc_info) data['exc_info'] = None # drop traceback in favor of exc_text # serialise msg now so we can drop (potentially unserialisable) args data['msg'] = record.getMessage() data['args'] = () self.channel.send((None, (comm.Message.LOG, data))) class _ClientChannel(comm.ClientChannel): """Our protocol, layered on the basic primitives in comm.ClientChannel""" def __init__(self, sock, context): self.log = logging.getLogger(context.conf.logger_name) super(_ClientChannel, self).__init__(sock) self.exchange_ping() def exchange_ping(self): try: # exchange "ready" messages reply = self.send_recv((comm.Message.PING.value,)) success = reply[0] == comm.Message.PONG except Exception as e: self.log.exception('Error while sending initial PING to privsep: ' '%s', e) success = False if not success: msg = _('Privsep daemon failed to start') self.log.critical(msg) raise FailedToDropPrivileges(msg) def remote_call(self, name, args, kwargs, timeout): result = self.send_recv((comm.Message.CALL.value, name, args, kwargs), timeout) if result[0] == comm.Message.RET: # (RET, return value) return result[1] elif result[0] == comm.Message.ERR: # (ERR, exc_type, args) # # TODO(gus): see what can be done to preserve traceback # (without leaking local values) exc_type = importutils.import_class(result[1]) raise exc_type(*result[2]) else: raise ProtocolError(_('Unexpected response: %r') % result) def out_of_band(self, msg): if msg[0] == comm.Message.LOG: # (LOG, LogRecord __dict__) message = {encodeutils.safe_decode(k): v for k, v in msg[1].items()} record = pylogging.makeLogRecord(message) if self.log.isEnabledFor(record.levelno): self.log.logger.handle(record) else: self.log.warning('Ignoring unexpected OOB message from privileged ' 'process: %r', msg) def fdopen(fd, *args, **kwargs): # NOTE(gus): We can't just use os.fdopen() here and allow the # regular (optional) monkey_patching to do its thing. Turns out # that regular file objects (as returned by os.fdopen) on python2 # are broken in lots of ways regarding blocking behaviour. We # *need* the newer io.* objects on py2 (doesn't matter on py3, # since the old file code has been replaced with io.*) if eventlet.patcher.is_monkey_patched('socket'): return eventlet.greenio.GreenPipe(fd, *args, **kwargs) else: return io.open(fd, *args, **kwargs) def _fd_logger(level=logging.WARN): """Helper that returns a file object that is asynchronously logged""" read_fd, write_fd = os.pipe() read_end = fdopen(read_fd, 'r', 1) write_end = fdopen(write_fd, 'w', 1) def logger(f): for line in f: LOG.log(level, 'privsep log: %s', line.rstrip()) t = threading.Thread( name='fd_logger', target=logger, args=(read_end,) ) t.daemon = True t.start() return write_end def replace_logging(handler, log_root=None): if log_root is None: log_root = logging.getLogger(None).logger # root logger for h in log_root.handlers: log_root.removeHandler(h) log_root.addHandler(handler) def un_monkey_patch(): for eventlet_mod_name, func_modules in EVENTLET_LIBRARIES: if not eventlet.patcher.is_monkey_patched(eventlet_mod_name): continue for name, mod in func_modules(): patched_mod = sys.modules.get(name) orig_mod = eventlet.patcher.original(name) for attr_name in mod.__patched__: patched_attr = getattr(mod, attr_name, None) unpatched_attr = getattr(orig_mod, attr_name, None) if patched_attr is not None: setattr(patched_mod, attr_name, unpatched_attr) class ForkingClientChannel(_ClientChannel): def __init__(self, context): """Start privsep daemon using fork() Assumes we already have required privileges. """ sock_a, sock_b = socket.socketpair() for s in (sock_a, sock_b): s.setblocking(True) # Important that these sockets don't get leaked set_cloexec(s) # Try to prevent any buffered output from being written by both # parent and child. for f in (sys.stdout, sys.stderr): f.flush() if os.fork() == 0: # child un_monkey_patch() channel = comm.ServerChannel(sock_b) sock_a.close() # Replace root logger early (to capture any errors during setup) replace_logging(PrivsepLogHandler(channel, processName=str(context))) Daemon(channel, context=context).run() LOG.debug('privsep daemon exiting') os._exit(0) # parent sock_b.close() super(ForkingClientChannel, self).__init__(sock_a, context) class RootwrapClientChannel(_ClientChannel): def __init__(self, context): """Start privsep daemon using exec() Uses sudo/rootwrap to gain privileges. """ listen_sock = socket.socket(socket.AF_UNIX) # Note we listen() on the unprivileged side, and connect to it # from the privileged process. This means there is no exposed # attack point on the privileged side. # NB: Permissions on sockets are not checked on some (BSD) Unices # so create socket in a private directory for safety. Privsep # daemon will (initially) be running as root, so will still be # able to connect to sock path. tmpdir = tempfile.mkdtemp() # NB: created with 0700 perms try: sockpath = os.path.join(tmpdir, 'privsep.sock') listen_sock.bind(sockpath) listen_sock.listen(1) cmd = context.helper_command(sockpath) LOG.info('Running privsep helper: %s', cmd) proc = subprocess.Popen(cmd, shell=False, stderr=_fd_logger()) if proc.wait() != 0: msg = ('privsep helper command exited non-zero (%s)' % proc.returncode) LOG.critical(msg) raise FailedToDropPrivileges(msg) LOG.info('Spawned new privsep daemon via rootwrap') sock, _addr = listen_sock.accept() LOG.debug('Accepted privsep connection to %s', sockpath) finally: # Don't need listen_sock anymore, so clean up. listen_sock.close() try: os.unlink(sockpath) except OSError as e: if e.errno != errno.ENOENT: raise os.rmdir(tmpdir) super(RootwrapClientChannel, self).__init__(sock, context) class Daemon(object): """NB: This doesn't fork() - do that yourself before calling run()""" def __init__(self, channel, context): self.channel = channel self.context = context self.user = context.conf.user self.group = context.conf.group self.caps = set(context.conf.capabilities) self.thread_pool = futures.ThreadPoolExecutor( context.conf.thread_pool_size) self.communication_error = None def run(self): """Run request loop. Sets up environment, then calls loop()""" os.chdir("/") os.umask(0) self._drop_privs() self._close_stdio() self.loop() def _close_stdio(self): with open(os.devnull, 'w+') as devnull: os.dup2(devnull.fileno(), StdioFd.STDIN) os.dup2(devnull.fileno(), StdioFd.STDOUT) # stderr is left untouched def _drop_privs(self): try: # Keep current capabilities across setuid away from root. capabilities.set_keepcaps(True) if self.group is not None: try: os.setgroups([]) except OSError: msg = _('Failed to remove supplemental groups') LOG.critical(msg) raise FailedToDropPrivileges(msg) setgid(self.group) if self.user is not None: setuid(self.user) finally: capabilities.set_keepcaps(False) LOG.info('privsep process running with uid/gid: %(uid)s/%(gid)s', {'uid': os.getuid(), 'gid': os.getgid()}) capabilities.drop_all_caps_except(self.caps, self.caps, []) def fmt_caps(capset): if not capset: return 'none' fc = [capabilities.CAPS_BYVALUE.get(c, str(c)) for c in capset] fc.sort() return '|'.join(fc) eff, prm, inh = capabilities.get_caps() LOG.info( 'privsep process running with capabilities ' '(eff/prm/inh): %(eff)s/%(prm)s/%(inh)s', { 'eff': fmt_caps(eff), 'prm': fmt_caps(prm), 'inh': fmt_caps(inh), }) def _process_cmd(self, msgid, cmd, *args): """Executes the requested command in an execution thread. This executes a call within a thread executor and returns the results of the execution. :param msgid: The message identifier. :param cmd: The `Message` type indicating the command type. :param args: The function, args, and kwargs if a Message.CALL type. :return: A tuple of the return status, optional call output, and optional error information. """ if cmd == comm.Message.PING: return (comm.Message.PONG.value,) try: if cmd != comm.Message.CALL: raise ProtocolError(_('Unknown privsep cmd: %s') % cmd) # Extract the callable and arguments name, f_args, f_kwargs = args func = importutils.import_class(name) if not self.context.is_entrypoint(func): msg = _('Invalid privsep function: %s not exported') % name raise NameError(msg) ret = func(*f_args, **f_kwargs) return (comm.Message.RET.value, ret) except Exception as e: LOG.debug( 'privsep: Exception during request[%(msgid)s]: ' '%(err)s', {'msgid': msgid, 'err': e}, exc_info=True) cls = e.__class__ cls_name = '%s.%s' % (cls.__module__, cls.__name__) return (comm.Message.ERR.value, cls_name, e.args) def _create_done_callback(self, msgid): """Creates a future callback to receive command execution results. :param msgid: The message identifier. :return: A future reply callback. """ channel = self.channel def _call_back(result): """Future execution callback. :param result: The `future` execution and its results. """ try: reply = result.result() LOG.debug('privsep: reply[%(msgid)s]: %(reply)s', {'msgid': msgid, 'reply': reply}) channel.send((msgid, reply)) except IOError: self.communication_error = sys.exc_info() except Exception as e: LOG.debug( 'privsep: Exception during request[%(msgid)s]: ' '%(err)s', {'msgid': msgid, 'err': e}, exc_info=True) cls = e.__class__ cls_name = '%s.%s' % (cls.__module__, cls.__name__) reply = (comm.Message.ERR.value, cls_name, e.args) try: channel.send((msgid, reply)) except IOError as exc: self.communication_error = exc return _call_back def loop(self): """Main body of daemon request loop""" LOG.info('privsep daemon running as pid %s', os.getpid()) # We *are* this context now - any calls through it should be # executed locally. self.context.set_client_mode(False) for msgid, msg in self.channel: error = self.communication_error if error: if error.errno == errno.EPIPE: # Write stream closed, exit loop break raise error # Submit the command for execution future = self.thread_pool.submit(self._process_cmd, msgid, *msg) future.add_done_callback(self._create_done_callback(msgid)) LOG.debug('Socket closed, shutting down privsep daemon') def helper_main(): """Start privileged process, serving requests over a Unix socket.""" cfg.CONF.register_cli_opts([ cfg.StrOpt('privsep_context', required=True), cfg.StrOpt('privsep_sock_path', required=True), ]) logging.register_options(cfg.CONF) cfg.CONF(args=sys.argv[1:], project='privsep') # note replace_logging call below try: logging.setup(cfg.CONF, 'privsep', fix_eventlet=False) except TypeError: # NOTE(ralonsoh): in case of using oslo.log<5.0.2, kwarg # "fix_eventlet" won't be defined. Remove this try clause when oslo.log # is bumped. logging.setup(cfg.CONF, 'privsep') context = importutils.import_class(cfg.CONF.privsep_context) from oslo_privsep import priv_context # Avoid circular import if not isinstance(context, priv_context.PrivContext): LOG.fatal('--privsep_context must be the (python) name of a ' 'PrivContext object') sock = socket.socket(socket.AF_UNIX) sock.connect(cfg.CONF.privsep_sock_path) set_cloexec(sock) channel = comm.ServerChannel(sock) # Channel is set up, so fork off daemon "in the background" and exit if os.fork() != 0: # parent return # child # Note we don't move into a new process group/session like a # regular daemon might, since we _want_ to remain associated with # the originating (unprivileged) process. # Channel is set up now, so move to in-band logging replace_logging(PrivsepLogHandler(channel)) LOG.info('privsep daemon starting') try: Daemon(channel, context).run() except Exception as e: LOG.exception(e) sys.exit(str(e)) LOG.debug('privsep daemon exiting') sys.exit(0) if __name__ == '__main__': helper_main() ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1724253560.1171355 oslo.privsep-3.4.0/oslo_privsep/functional/0000775000175000017500000000000000000000000021072 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/oslo_privsep/functional/__init__.py0000664000175000017500000000032600000000000023204 0ustar00zuulzuul00000000000000import os.path def load_tests(loader, tests, pattern): this_dir = os.path.dirname(__file__) new_tests = loader.discover(start_dir=this_dir, pattern=pattern) tests.addTests(new_tests) return tests ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/oslo_privsep/functional/test_daemon.py0000664000175000017500000000652100000000000023752 0ustar00zuulzuul00000000000000# Copyright 2019 Red Hat, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import logging import os import time import unittest from oslo_config import fixture as config_fixture from oslotest import base from oslo_privsep import comm from oslo_privsep import priv_context test_context = priv_context.PrivContext( __name__, cfg_section='privsep', pypath=__name__ + '.test_context', capabilities=[], ) test_context_with_timeout = priv_context.PrivContext( __name__, cfg_section='privsep', pypath=__name__ + '.test_context_with_timeout', capabilities=[], timeout=0.03 ) @test_context.entrypoint def sleep(): # We don't want the daemon to be able to handle these calls too fast. time.sleep(.001) @test_context.entrypoint_with_timeout(0.03) def sleep_with_timeout(long_timeout=0.04): time.sleep(long_timeout) return 42 @test_context_with_timeout.entrypoint def sleep_with_t_context(long_timeout=0.04): time.sleep(long_timeout) return 42 @test_context.entrypoint def one(): return 1 @test_context.entrypoint def logs(): logging.warning('foo') class TestDaemon(base.BaseTestCase): def setUp(self): super(TestDaemon, self).setUp() venv_path = os.environ['VIRTUAL_ENV'] self.cfg_fixture = self.useFixture(config_fixture.Config()) self.cfg_fixture.config( group='privsep', helper_command='sudo -E %s/bin/privsep-helper' % venv_path) priv_context.init() def test_concurrency(self): # Throw a large number of simultaneous requests at the daemon to make # sure it can can handle them. for i in range(1000): sleep() # Make sure the daemon is still working self.assertEqual(1, one()) def test_entrypoint_with_timeout(self): thread_pool_size = self.cfg_fixture.conf.privsep.thread_pool_size for _ in range(thread_pool_size + 1): self.assertRaises(comm.PrivsepTimeout, sleep_with_timeout) def test_entrypoint_with_timeout_pass(self): thread_pool_size = self.cfg_fixture.conf.privsep.thread_pool_size for _ in range(thread_pool_size + 1): res = sleep_with_timeout(0.01) self.assertEqual(42, res) def test_context_with_timeout(self): thread_pool_size = self.cfg_fixture.conf.privsep.thread_pool_size for _ in range(thread_pool_size + 1): self.assertRaises(comm.PrivsepTimeout, sleep_with_t_context) def test_context_with_timeout_pass(self): thread_pool_size = self.cfg_fixture.conf.privsep.thread_pool_size for _ in range(thread_pool_size + 1): res = sleep_with_t_context(0.01) self.assertEqual(42, res) def test_logging(self): logs() self.assertIn('foo', self.log_fixture.logger.output) if __name__ == '__main__': unittest.main() ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1724253560.1051352 oslo.privsep-3.4.0/oslo_privsep/locale/0000775000175000017500000000000000000000000020167 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1724253560.1051352 oslo.privsep-3.4.0/oslo_privsep/locale/de/0000775000175000017500000000000000000000000020557 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1724253560.1171355 oslo.privsep-3.4.0/oslo_privsep/locale/de/LC_MESSAGES/0000775000175000017500000000000000000000000022344 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/oslo_privsep/locale/de/LC_MESSAGES/oslo_privsep.po0000664000175000017500000000330400000000000025430 0ustar00zuulzuul00000000000000# Andreas Jaeger , 2016. #zanata msgid "" msgstr "" "Project-Id-Version: oslo.privsep 1.7.1.dev1\n" "Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" "POT-Creation-Date: 2016-06-10 16:43+0000\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "PO-Revision-Date: 2016-06-09 01:20+0000\n" "Last-Translator: Andreas Jaeger \n" "Language-Team: German\n" "Language: de\n" "X-Generator: Zanata 3.7.3\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" msgid "Failed to remove supplemental groups" msgstr "Fehler beim Entfernen zusätzlicher Gruppen" #, python-format msgid "Failed to set gid %s" msgstr "Fehler beim Festlegen von GID %s" #, python-format msgid "Failed to set uid %s" msgstr "Fehler beim Festlegen von Benutzer-ID %s" msgid "Group that the privsep daemon should run as." msgstr "Gruppe als die der Privsep Dämon laufen soll." #, python-format msgid "Invalid privsep function: %s not exported" msgstr "Invalide Privsep Funktion: %s ist nicht exportiert." msgid "List of Linux capabilities retained by the privsep daemon." msgstr "Liste von Linux Capabilities, die der Privsep Dämon behält." msgid "Premature eof waiting for privileged process" msgstr "Vorzeitiges Dateiende beim Warten auf den priviligierten Prozeß" msgid "Privsep daemon failed to start" msgstr "Der Privsep Dämon konnte nicht gestartet werden." #, python-format msgid "Unexpected response: %r" msgstr "Unerwartete Antwort: %r" #, python-format msgid "Unknown privsep cmd: %s" msgstr "Unbekanntes Privsep Kommando: %s" msgid "User that the privsep daemon should run as." msgstr "User als der der Privsep Dämon laufen soll." ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1724253560.1051352 oslo.privsep-3.4.0/oslo_privsep/locale/en_GB/0000775000175000017500000000000000000000000021141 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1724253560.1171355 oslo.privsep-3.4.0/oslo_privsep/locale/en_GB/LC_MESSAGES/0000775000175000017500000000000000000000000022726 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/oslo_privsep/locale/en_GB/LC_MESSAGES/oslo_privsep.po0000664000175000017500000000544000000000000026015 0ustar00zuulzuul00000000000000# Andi Chandler , 2016. #zanata # Andi Chandler , 2023. #zanata msgid "" msgstr "" "Project-Id-Version: oslo.privsep VERSION\n" "Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" "POT-Creation-Date: 2023-05-08 11:10+0000\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "PO-Revision-Date: 2023-06-21 08:58+0000\n" "Last-Translator: Andi Chandler \n" "Language-Team: English (United Kingdom)\n" "Language: en_GB\n" "X-Generator: Zanata 4.3.3\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" msgid "" "Command to invoke to start the privsep daemon if not using the \"fork\" " "method. If not specified, a default is generated using \"sudo privsep-helper" "\" and arguments designed to recreate the current configuration. This " "command must accept suitable --privsep_context and --privsep_sock_path " "arguments." msgstr "" "Command to invoke to start the privsep daemon if not using the \"fork\" " "method. If not specified, a default is generated using \"sudo privsep-helper" "\" and arguments designed to recreate the current configuration. This " "command must accept suitable --privsep_context and --privsep_sock_path " "arguments." msgid "Failed to remove supplemental groups" msgstr "Failed to remove supplemental groups" #, python-format msgid "Failed to set gid %s" msgstr "Failed to set gid %s" #, python-format msgid "Failed to set uid %s" msgstr "Failed to set uid %s" msgid "Group that the privsep daemon should run as." msgstr "Group that the privsep daemon should run as." #, python-format msgid "Invalid privsep function: %s not exported" msgstr "Invalid privsep function: %s not exported" msgid "List of Linux capabilities retained by the privsep daemon." msgstr "List of Linux capabilities retained by the privsep daemon." msgid "" "Logger name to use for this privsep context. By default all contexts log " "with oslo_privsep.daemon." msgstr "" "Logger name to use for this privsep context. By default, all contexts log " "with oslo_privsep.daemon." msgid "Premature eof waiting for privileged process" msgstr "Premature EOF waiting for privileged process" msgid "Privsep daemon failed to start" msgstr "Privsep daemon failed to start" msgid "" "The number of threads available for privsep to concurrently run processes. " "Defaults to the number of CPU cores in the system." msgstr "" "The number of threads available for privsep to concurrently run processes. " "Defaults to the number of CPU cores in the system." #, python-format msgid "Unexpected response: %r" msgstr "Unexpected response: %r" #, python-format msgid "Unknown privsep cmd: %s" msgstr "Unknown privsep cmd: %s" msgid "User that the privsep daemon should run as." msgstr "User that the privsep daemon should run as." ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/oslo_privsep/priv_context.py0000664000175000017500000002600200000000000022026 0ustar00zuulzuul00000000000000# Copyright 2015 Rackspace Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import copy import enum import functools import logging import multiprocessing import shlex import sys import threading from oslo_config import cfg from oslo_config import types from oslo_utils import importutils from oslo_privsep._i18n import _ from oslo_privsep import capabilities from oslo_privsep import daemon LOG = logging.getLogger(__name__) def CapNameOrInt(value): value = str(value).strip() try: return capabilities.CAPS_BYNAME[value] except KeyError: return int(value) OPTS = [ cfg.StrOpt('user', help=_('User that the privsep daemon should run as.')), cfg.StrOpt('group', help=_('Group that the privsep daemon should run as.')), cfg.Opt('capabilities', type=types.List(CapNameOrInt), default=[], help=_('List of Linux capabilities retained by the privsep ' 'daemon.')), cfg.IntOpt('thread_pool_size', min=1, help=_("The number of threads available for privsep to " "concurrently run processes. Defaults to the number of " "CPU cores in the system."), default=multiprocessing.cpu_count(), sample_default='multiprocessing.cpu_count()'), cfg.StrOpt('helper_command', help=_('Command to invoke to start the privsep daemon if ' 'not using the "fork" method. ' 'If not specified, a default is generated using ' '"sudo privsep-helper" and arguments designed to ' 'recreate the current configuration. ' 'This command must accept suitable --privsep_context ' 'and --privsep_sock_path arguments.')), cfg.StrOpt('logger_name', help=_('Logger name to use for this privsep context. By ' 'default all contexts log with oslo_privsep.daemon.'), default='oslo_privsep.daemon'), ] _ENTRYPOINT_ATTR = 'privsep_entrypoint' _HELPER_COMMAND_PREFIX = ['sudo'] def _list_opts(): """Returns a list of oslo.config options available in the library. The returned list includes all oslo.config options which may be registered at runtime by the library. Each element of the list is a tuple. The first element is the name of the group under which the list of elements in the second element will be registered. A group name of None corresponds to the [DEFAULT] group in config files. The purpose of this is to allow tools like the Oslo sample config file generator to discover the options exposed to users by this library. :returns: a list of (group_name, opts) tuples """ # This is the default group name, but that can be overridden by the caller group = cfg.OptGroup('privsep', title='oslo.privsep options', help='Configuration options for the oslo.privsep ' 'daemon. Note that this group name can be ' 'changed by the consuming service. Check the ' 'service\'s docs to see if this is the case.' ) return [(group, copy.deepcopy(OPTS))] @enum.unique class Method(enum.Enum): FORK = 1 ROOTWRAP = 2 def init(root_helper=None): """Initialise oslo.privsep library. This function should be called at the top of main(), after the command line is parsed, oslo.config is initialised and logging is set up, but before calling any privileged entrypoint, changing user id, forking, or anything else "odd". :param root_helper: List of command and arguments to prefix privsep-helper with, in order to run helper as root. Note, ignored if context's helper_command config option is set. """ if root_helper: global _HELPER_COMMAND_PREFIX _HELPER_COMMAND_PREFIX = root_helper class PrivContext(object): def __init__(self, prefix, cfg_section='privsep', pypath=None, capabilities=None, logger_name='oslo_privsep.daemon', timeout=None): # Note that capabilities=[] means retaining no capabilities # and leaves even uid=0 with no powers except being able to # read/write to the filesystem as uid=0. This might be what # you want, but probably isn't. # # There is intentionally no way to say "I want all the # capabilities." if capabilities is None: raise ValueError('capabilities is a required parameter') self.pypath = pypath self.prefix = prefix self.cfg_section = cfg_section # NOTE(claudiub): oslo.privsep is not currently supported on Windows, # as it uses Linux-specific functionality (os.fork, socker.AF_UNIX). # The client_mode should be set to False on Windows. self.client_mode = sys.platform != 'win32' self.channel = None self.start_lock = threading.Lock() cfg.CONF.register_opts(OPTS, group=cfg_section) cfg.CONF.set_default('capabilities', group=cfg_section, default=capabilities) cfg.CONF.set_default('logger_name', group=cfg_section, default=logger_name) self.timeout = timeout @property def conf(self): """Return the oslo.config section object as lazily as possible.""" # Need to avoid looking this up before oslo_config has been # properly initialized. return cfg.CONF[self.cfg_section] def __repr__(self): return 'PrivContext(cfg_section=%s)' % self.cfg_section def helper_command(self, sockpath): # We need to be able to reconstruct the context object in the new # python process we'll get after rootwrap/sudo. This means we # need to construct the context object and store it somewhere # globally accessible, and then use that python name to find it # again in the new python interpreter. Yes, it's all a bit # clumsy, and none of it is required when using the fork-based # alternative above. # These asserts here are just attempts to catch errors earlier. # TODO(gus): Consider replacing with setuptools entry_points. if self.pypath is None: raise AssertionError('helper_command requires priv_context ' 'pypath to be specified') if importutils.import_class(self.pypath) is not self: raise AssertionError('helper_command requires priv_context ' 'pypath for context object') # Note order is important here. Deployments will (hopefully) # have the exact arguments in sudoers/rootwrap configs and # reordering args will break configs! if self.conf.helper_command: cmd = shlex.split(self.conf.helper_command) else: cmd = _HELPER_COMMAND_PREFIX + ['privsep-helper'] try: for cfg_file in cfg.CONF.config_file: cmd.extend(['--config-file', cfg_file]) except cfg.NoSuchOptError: pass try: if cfg.CONF.config_dir is not None: for cfg_dir in cfg.CONF.config_dir: cmd.extend(['--config-dir', cfg_dir]) except cfg.NoSuchOptError: pass cmd.extend( ['--privsep_context', self.pypath, '--privsep_sock_path', sockpath]) return cmd def set_client_mode(self, enabled): if enabled and sys.platform == 'win32': raise RuntimeError( "Enabling the client_mode is not currently " "supported on Windows.") self.client_mode = enabled def entrypoint(self, func): """This is intended to be used as a decorator.""" return self._entrypoint(func) def entrypoint_with_timeout(self, timeout): """This is intended to be used as a decorator with timeout.""" def wrap(func): @functools.wraps(func) def inner(*args, **kwargs): f = self._entrypoint(func) return f(*args, _wrap_timeout=timeout, **kwargs) setattr(inner, _ENTRYPOINT_ATTR, self) return inner return wrap def _entrypoint(self, func): if not func.__module__.startswith(self.prefix): raise AssertionError('%r entrypoints must be below "%s"' % (self, self.prefix)) # Right now, we only track a single context in # _ENTRYPOINT_ATTR. This could easily be expanded into a set, # but that will increase the memory overhead. Revisit if/when # someone has a need to associate the same entrypoint with # multiple contexts. if getattr(func, _ENTRYPOINT_ATTR, None) is not None: raise AssertionError('%r is already associated with another ' 'PrivContext' % func) f = functools.partial(self._wrap, func) setattr(f, _ENTRYPOINT_ATTR, self) return f def is_entrypoint(self, func): return getattr(func, _ENTRYPOINT_ATTR, None) is self def _wrap(self, func, *args, _wrap_timeout=None, **kwargs): if self.client_mode: name = '%s.%s' % (func.__module__, func.__name__) if self.channel is not None and not self.channel.running: LOG.warning("RESTARTING PrivContext for %s", name) self.stop() if self.channel is None: self.start() r_call_timeout = _wrap_timeout or self.timeout return self.channel.remote_call(name, args, kwargs, r_call_timeout) else: return func(*args, **kwargs) def start(self, method=Method.ROOTWRAP): with self.start_lock: if self.channel is not None: LOG.warning('privsep daemon already running') return if method is Method.ROOTWRAP: channel = daemon.RootwrapClientChannel(context=self) elif method is Method.FORK: channel = daemon.ForkingClientChannel(context=self) else: raise ValueError('Unknown method: %s' % method) self.channel = channel def stop(self): if self.channel is not None: self.channel.close() self.channel = None ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1724253560.1171355 oslo.privsep-3.4.0/oslo_privsep/tests/0000775000175000017500000000000000000000000020072 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/oslo_privsep/tests/__init__.py0000664000175000017500000000000000000000000022171 0ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/oslo_privsep/tests/fixture.py0000664000175000017500000000342400000000000022135 0ustar00zuulzuul00000000000000# Copyright 2015 Rackspace Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import fixtures import logging import os import sys from oslo_config import fixture as cfg_fixture from oslo_privsep import priv_context LOG = logging.getLogger(__name__) class UnprivilegedPrivsepFixture(fixtures.Fixture): def __init__(self, context): self.context = context def setUp(self): super(UnprivilegedPrivsepFixture, self).setUp() self.conf = self.useFixture(cfg_fixture.Config()).conf self.conf.set_override('capabilities', [], group=self.context.cfg_section) for k in ('user', 'group'): self.conf.set_override( k, None, group=self.context.cfg_section) orig_pid = os.getpid() try: self.context.start(method=priv_context.Method.FORK) except Exception as e: # py3 unittest/testtools/something catches fatal # exceptions from child processes and tries to treat them # like regular non-fatal test failures. Here we attempt # to undo that. if os.getpid() == orig_pid: raise LOG.exception(e) sys.exit(1) self.addCleanup(self.context.stop) ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/oslo_privsep/tests/test_capabilities.py0000664000175000017500000000652500000000000024144 0ustar00zuulzuul00000000000000# Copyright 2015 Rackspace Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from unittest import mock from oslotest import base from oslo_privsep import capabilities class TestCapabilities(base.BaseTestCase): @mock.patch('oslo_privsep.capabilities._prctl') def test_set_keepcaps_error(self, mock_prctl): mock_prctl.return_value = -1 self.assertRaises(OSError, capabilities.set_keepcaps, True) @mock.patch('oslo_privsep.capabilities._prctl') def test_set_keepcaps(self, mock_prctl): mock_prctl.return_value = 0 capabilities.set_keepcaps(True) # Disappointingly, ffi.cast(type, 1) != ffi.cast(type, 1) # so can't just use assert_called_once_with :-( self.assertEqual(1, mock_prctl.call_count) self.assertCountEqual( [8, 1], # [PR_SET_KEEPCAPS, true] [int(x) for x in mock_prctl.call_args[0]]) @mock.patch('oslo_privsep.capabilities._capset') def test_drop_all_caps_except_error(self, mock_capset): mock_capset.return_value = -1 self.assertRaises( OSError, capabilities.drop_all_caps_except, [0], [0], [0]) @mock.patch('oslo_privsep.capabilities._capset') def test_drop_all_caps_except(self, mock_capset): mock_capset.return_value = 0 # Somewhat arbitrary bit patterns to exercise _caps_to_mask capabilities.drop_all_caps_except( (17, 24, 49), (8, 10, 35, 56), (24, 31, 40)) self.assertEqual(1, mock_capset.call_count) hdr, data = mock_capset.call_args[0] self.assertEqual(0x20071026, # _LINUX_CAPABILITY_VERSION_2 hdr.version) self.assertEqual(0x01020000, data[0].effective) self.assertEqual(0x00020000, data[1].effective) self.assertEqual(0x00000500, data[0].permitted) self.assertEqual(0x01000008, data[1].permitted) self.assertEqual(0x81000000, data[0].inheritable) self.assertEqual(0x00000100, data[1].inheritable) @mock.patch('oslo_privsep.capabilities._capget') def test_get_caps_error(self, mock_capget): mock_capget.return_value = -1 self.assertRaises(OSError, capabilities.get_caps) @mock.patch('oslo_privsep.capabilities._capget') def test_get_caps(self, mock_capget): def impl(hdr, data): # Somewhat arbitrary bit patterns to exercise _mask_to_caps data[0].effective = 0x01020000 data[1].effective = 0x00020000 data[0].permitted = 0x00000500 data[1].permitted = 0x01000008 data[0].inheritable = 0x81000000 data[1].inheritable = 0x00000100 return 0 mock_capget.side_effect = impl self.assertCountEqual( ([17, 24, 49], [8, 10, 35, 56], [24, 31, 40]), capabilities.get_caps()) ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/oslo_privsep/tests/test_comm.py0000664000175000017500000000521500000000000022441 0ustar00zuulzuul00000000000000# Copyright 2015 Rackspace Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import io from oslotest import base from oslo_privsep import comm class BufSock(object): def __init__(self): self.readpos = 0 self.buf = io.BytesIO() def recv(self, bufsize): if self.buf.closed: return b'' self.buf.seek(self.readpos, 0) data = self.buf.read(bufsize) self.readpos += len(data) return data def sendall(self, data): self.buf.seek(0, 2) self.buf.write(data) def shutdown(self, _flag): self.buf.close() class TestSerialization(base.BaseTestCase): def setUp(self): super(TestSerialization, self).setUp() sock = BufSock() self.input = comm.Serializer(sock) self.output = iter(comm.Deserializer(sock)) def send(self, data): self.input.send(data) return next(self.output) def assertSendable(self, value): self.assertEqual(value, self.send(value)) def test_none(self): self.assertSendable(None) def test_bool(self): self.assertSendable(True) self.assertSendable(False) def test_int(self): self.assertSendable(42) self.assertSendable(-84) def test_bytes(self): data = b'\x00\x01\x02\xfd\xfe\xff' self.assertSendable(data) def test_unicode(self): data = '\u4e09\u9df9\udc82' self.assertSendable(data) def test_tuple(self): self.assertSendable((1, 'foo')) def test_list(self): # NB! currently lists get converted to tuples by serialization. self.assertEqual((1, 'foo'), self.send([1, 'foo'])) def test_dict(self): self.assertSendable( { 'a': 'b', 1: 2, None: None, (1, 2): (3, 4), } ) def test_badobj(self): class UnknownClass(object): pass obj = UnknownClass() self.assertRaises(TypeError, self.send, obj) def test_eof(self): self.input.close() self.assertRaises(StopIteration, next, self.output) ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/oslo_privsep/tests/test_daemon.py0000664000175000017500000002405200000000000022751 0ustar00zuulzuul00000000000000# Copyright 2015 Rackspace Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import copy import eventlet import fixtures import functools import logging as pylogging import platform import sys import time from unittest import mock from oslo_log import formatters from oslo_log import log as logging from oslotest import base import testtools from oslo_privsep import capabilities from oslo_privsep import comm from oslo_privsep import daemon from oslo_privsep.tests import testctx LOG = logging.getLogger(__name__) def undecorated(): pass class TestException(Exception): pass def get_fake_context(conf_attrs=None, **context_attrs): conf_attrs = conf_attrs or {} context = mock.NonCallableMock() context.conf.user = 42 context.conf.group = 84 context.conf.thread_pool_size = 10 context.conf.capabilities = [ capabilities.CAP_SYS_ADMIN, capabilities.CAP_NET_ADMIN] context.conf.logger_name = 'oslo_privsep.daemon' vars(context).update(context_attrs) vars(context.conf).update(conf_attrs) return context @testctx.context.entrypoint def logme(level, msg, exc_info=False): # We want to make sure we log everything from the priv side for # the purposes of this test, so force loglevel. LOG.logger.setLevel(logging.DEBUG) if exc_info: try: raise TestException('with arg') except TestException: LOG.log(level, msg, exc_info=True) else: LOG.log(level, msg) class LogRecorder(pylogging.Formatter): def __init__(self, logs, *args, **kwargs): kwargs['validate'] = False super(LogRecorder, self).__init__(*args, **kwargs) self.logs = logs def format(self, record): self.logs.append(copy.deepcopy(record)) return super(LogRecorder, self).format(record) @testtools.skipIf(platform.system() != 'Linux', 'works only on Linux platform.') class LogTest(testctx.TestContextTestCase): def setUp(self): super(LogTest, self).setUp() def test_priv_loglevel(self): logger = self.useFixture(fixtures.FakeLogger( level=logging.INFO)) # These write to the log on the priv side logme(logging.DEBUG, 'test@DEBUG') logme(logging.WARN, 'test@WARN') time.sleep(0.1) # Hack to give logging thread a chance to run # logger.output is the resulting log on the unpriv side. # This should have been filtered based on (unpriv) loglevel. self.assertNotIn('test@DEBUG', logger.output) self.assertIn('test@WARN', logger.output) def test_record_data(self): logs = [] self.useFixture(fixtures.FakeLogger( level=logging.INFO, format='dummy', # fixtures.FakeLogger accepts only a formatter # class/function, not an instance :( formatter=functools.partial(LogRecorder, logs))) logme(logging.WARN, 'test with exc', exc_info=True) time.sleep(0.1) # Hack to give logging thread a chance to run self.assertEqual(1, len(logs)) record = logs[0] self.assertIn('test with exc', record.getMessage()) self.assertIsNone(record.exc_info) self.assertIn('TestException: with arg', record.exc_text) self.assertEqual('PrivContext(cfg_section=privsep)', record.processName) self.assertIn('test_daemon.py', record.exc_text) self.assertEqual(logging.WARN, record.levelno) self.assertEqual('logme', record.funcName) def test_format_record(self): logs = [] self.useFixture(fixtures.FakeLogger( level=logging.INFO, format='dummy', # fixtures.FakeLogger accepts only a formatter # class/function, not an instance :( formatter=functools.partial(LogRecorder, logs))) logme(logging.WARN, 'test with exc', exc_info=True) time.sleep(0.1) # Hack to give logging thread a chance to run self.assertEqual(1, len(logs)) record = logs[0] # Verify the log record can be formatted by ContextFormatter fake_config = mock.Mock( logging_default_format_string="NOCTXT: %(message)s") formatter = formatters.ContextFormatter(config=fake_config) formatter.format(record) @testtools.skipIf(platform.system() != 'Linux', 'works only on Linux platform.') class DaemonTest(base.BaseTestCase): @mock.patch('os.setuid') @mock.patch('os.setgid') @mock.patch('os.setgroups') @mock.patch('oslo_privsep.capabilities.set_keepcaps') @mock.patch('oslo_privsep.capabilities.drop_all_caps_except') def test_drop_privs(self, mock_dropcaps, mock_keepcaps, mock_setgroups, mock_setgid, mock_setuid): channel = mock.NonCallableMock() context = get_fake_context() manager = mock.Mock() manager.attach_mock(mock_setuid, "setuid") manager.attach_mock(mock_setgid, "setgid") expected_calls = [mock.call.setgid(84), mock.call.setuid(42)] d = daemon.Daemon(channel, context) d._drop_privs() mock_setuid.assert_called_once_with(42) mock_setgid.assert_called_once_with(84) mock_setgroups.assert_called_once_with([]) assert manager.mock_calls == expected_calls self.assertCountEqual( [mock.call(True), mock.call(False)], mock_keepcaps.mock_calls) mock_dropcaps.assert_called_once_with( set((capabilities.CAP_SYS_ADMIN, capabilities.CAP_NET_ADMIN)), set((capabilities.CAP_SYS_ADMIN, capabilities.CAP_NET_ADMIN)), []) @testtools.skipIf(platform.system() != 'Linux', 'works only on Linux platform.') class WithContextTest(testctx.TestContextTestCase): def test_unexported(self): self.assertRaisesRegex( NameError, 'undecorated not exported', testctx.context._wrap, undecorated) class ClientChannelTestCase(base.BaseTestCase): DICT = { 'string_1': ('tuple_1', b'tuple_2'), b'byte_1': ['list_1', 'list_2'], } EXPECTED = { 'string_1': ('tuple_1', b'tuple_2'), 'byte_1': ['list_1', 'list_2'], } def setUp(self): super(ClientChannelTestCase, self).setUp() context = get_fake_context() with mock.patch.object(comm.ClientChannel, '__init__'), \ mock.patch.object(daemon._ClientChannel, 'exchange_ping'): self.client_channel = daemon._ClientChannel(mock.ANY, context) @mock.patch.object(daemon.LOG.logger, 'handle') def test_out_of_band_log_message(self, handle_mock): message = [comm.Message.LOG, self.DICT] self.assertEqual(self.client_channel.log, daemon.LOG) with mock.patch.object(pylogging, 'makeLogRecord') as mock_make_log, \ mock.patch.object(daemon.LOG, 'isEnabledFor', return_value=True) as mock_enabled: self.client_channel.out_of_band(message) mock_make_log.assert_called_once_with(self.EXPECTED) handle_mock.assert_called_once_with(mock_make_log.return_value) mock_enabled.assert_called_once_with( mock_make_log.return_value.levelno) def test_out_of_band_not_log_message(self): with mock.patch.object(daemon.LOG, 'warning') as mock_warning: self.client_channel.out_of_band([comm.Message.PING]) mock_warning.assert_called_once() @mock.patch.object(daemon.logging, 'getLogger') @mock.patch.object(pylogging, 'makeLogRecord') def test_out_of_band_log_message_context_logger(self, make_log_mock, get_logger_mock): logger_name = 'os_brick.privileged' context = get_fake_context(conf_attrs={'logger_name': logger_name}) with mock.patch.object(comm.ClientChannel, '__init__'), \ mock.patch.object(daemon._ClientChannel, 'exchange_ping'): channel = daemon._ClientChannel(mock.ANY, context) get_logger_mock.assert_called_once_with(logger_name) self.assertEqual(get_logger_mock.return_value, channel.log) message = [comm.Message.LOG, self.DICT] channel.out_of_band(message) make_log_mock.assert_called_once_with(self.EXPECTED) channel.log.isEnabledFor.assert_called_once_with( make_log_mock.return_value.levelno) channel.log.logger.handle.assert_called_once_with( make_log_mock.return_value) class UnMonkeyPatch(base.BaseTestCase): def test_un_monkey_patch(self): self.assertFalse(any( eventlet.patcher.is_monkey_patched(eventlet_mod_name) for eventlet_mod_name in daemon.EVENTLET_MODULES)) eventlet.monkey_patch() self.assertTrue(any( eventlet.patcher.is_monkey_patched(eventlet_mod_name) for eventlet_mod_name in daemon.EVENTLET_MODULES)) daemon.un_monkey_patch() for eventlet_mod_name, func_modules in daemon.EVENTLET_LIBRARIES: if not eventlet.patcher.is_monkey_patched(eventlet_mod_name): continue for name, green_mod in func_modules(): orig_mod = eventlet.patcher.original(name) patched_mod = sys.modules.get(name) for attr_name in green_mod.__patched__: un_monkey_patched_attr = getattr(patched_mod, attr_name, None) original_attr = getattr(orig_mod, attr_name, None) self.assertEqual(un_monkey_patched_attr, original_attr) ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/oslo_privsep/tests/test_priv_context.py0000664000175000017500000001621100000000000024230 0ustar00zuulzuul00000000000000# Copyright 2015 Rackspace Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import logging import os import pipes import platform import sys import tempfile import time from unittest import mock import testtools from oslo_privsep import comm from oslo_privsep import daemon from oslo_privsep import priv_context from oslo_privsep.tests import testctx LOG = logging.getLogger(__name__) @testctx.context.entrypoint def priv_getpid(): return os.getpid() @testctx.context.entrypoint def add1(arg): return arg + 1 @testctx.context.entrypoint_with_timeout(0.2) def do_some_long(long_timeout=0.4): time.sleep(long_timeout) return 42 class CustomError(Exception): def __init__(self, code, msg): super(CustomError, self).__init__(code, msg) self.code = code self.msg = msg def __str__(self): return 'Code %s: %s' % (self.code, self.msg) @testctx.context.entrypoint def fail(custom=False): if custom: raise CustomError(42, 'omg!') else: raise RuntimeError("I can't let you do that Dave") @testtools.skipIf(platform.system() != 'Linux', 'works only on Linux platform.') class PrivContextTest(testctx.TestContextTestCase): @mock.patch.object(priv_context, 'sys') def test_init_windows(self, mock_sys): mock_sys.platform = 'win32' context = priv_context.PrivContext('test', capabilities=[]) self.assertFalse(context.client_mode) @mock.patch.object(priv_context, 'sys') def test_set_client_mode(self, mock_sys): context = priv_context.PrivContext('test', capabilities=[]) self.assertTrue(context.client_mode) context.set_client_mode(False) self.assertFalse(context.client_mode) # client_mode should remain to False on win32. mock_sys.platform = 'win32' self.assertRaises(RuntimeError, context.set_client_mode, True) def test_helper_command(self): self.privsep_conf.privsep.helper_command = 'foo --bar' _, temp_path = tempfile.mkstemp() cmd = testctx.context.helper_command(temp_path) expected = [ 'foo', '--bar', '--privsep_context', testctx.context.pypath, '--privsep_sock_path', temp_path, ] self.assertEqual(expected, cmd) def test_helper_command_default(self): self.privsep_conf.config_file = ['/bar.conf'] _, temp_path = tempfile.mkstemp() cmd = testctx.context.helper_command(temp_path) expected = [ 'sudo', 'privsep-helper', '--config-file', '/bar.conf', # --config-dir arg should be skipped '--privsep_context', testctx.context.pypath, '--privsep_sock_path', temp_path, ] self.assertEqual(expected, cmd) def test_helper_command_default_dirtoo(self): self.privsep_conf.config_file = ['/bar.conf', '/baz.conf'] self.privsep_conf.config_dir = ['/foo.d'] _, temp_path = tempfile.mkstemp() cmd = testctx.context.helper_command(temp_path) expected = [ 'sudo', 'privsep-helper', '--config-file', '/bar.conf', '--config-file', '/baz.conf', '--config-dir', '/foo.d', '--privsep_context', testctx.context.pypath, '--privsep_sock_path', temp_path, ] self.assertEqual(expected, cmd) def test_init_known_contexts(self): self.assertEqual(testctx.context.helper_command('/sock')[:2], ['sudo', 'privsep-helper']) priv_context.init(root_helper=['sudo', 'rootwrap']) self.assertEqual(testctx.context.helper_command('/sock')[:3], ['sudo', 'rootwrap', 'privsep-helper']) def test_start_acquires_lock(self): context = priv_context.PrivContext('test', capabilities=[]) context.channel = "something not None" context.start_lock = mock.Mock() context.start_lock.__enter__ = mock.Mock() context.start_lock.__exit__ = mock.Mock() self.assertFalse(context.start_lock.__enter__.called) context.start() self.assertTrue(context.start_lock.__enter__.called) @testtools.skipIf(platform.system() != 'Linux', 'works only on Linux platform.') class SeparationTest(testctx.TestContextTestCase): def test_getpid(self): # Verify that priv_getpid() was executed in another process. priv_pid = priv_getpid() self.assertNotMyPid(priv_pid) def test_client_mode(self): self.assertNotMyPid(priv_getpid()) self.addCleanup(testctx.context.set_client_mode, True) testctx.context.set_client_mode(False) # priv_getpid() should now run locally (and return our pid) self.assertEqual(os.getpid(), priv_getpid()) testctx.context.set_client_mode(True) # priv_getpid() should now run remotely again self.assertNotMyPid(priv_getpid()) @testtools.skipIf(platform.system() != 'Linux', 'works only on Linux platform.') class RootwrapTest(testctx.TestContextTestCase): def setUp(self): super(RootwrapTest, self).setUp() testctx.context.stop() # Generate a command that will run daemon.helper_main without # requiring it to be properly installed. cmd = [ 'env', 'PYTHON_PATH=%s' % os.path.pathsep.join(sys.path), sys.executable, daemon.__file__, ] if LOG.isEnabledFor(logging.DEBUG): cmd.append('--debug') self.privsep_conf.set_override( 'helper_command', ' '.join(map(pipes.quote, cmd)), group=testctx.context.cfg_section) testctx.context.start(method=priv_context.Method.ROOTWRAP) def test_getpid(self): # Verify that priv_getpid() was executed in another process. priv_pid = priv_getpid() self.assertNotMyPid(priv_pid) def test_long_call_with_timeout(self): self.assertRaises( comm.PrivsepTimeout, do_some_long ) def test_long_call_within_timeout(self): res = do_some_long(0.001) self.assertEqual(42, res) @testtools.skipIf(platform.system() != 'Linux', 'works only on Linux platform.') class SerializationTest(testctx.TestContextTestCase): def test_basic_functionality(self): self.assertEqual(43, add1(42)) def test_raises_standard(self): self.assertRaisesRegex( RuntimeError, "I can't let you do that Dave", fail) def test_raises_custom(self): exc = self.assertRaises(CustomError, fail, custom=True) self.assertEqual(exc.code, 42) self.assertEqual(exc.msg, 'omg!') ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/oslo_privsep/tests/testctx.py0000664000175000017500000000275400000000000022152 0ustar00zuulzuul00000000000000# Copyright 2015 Rackspace Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import os from oslotest import base from oslo_privsep import priv_context import oslo_privsep.tests from oslo_privsep.tests import fixture context = priv_context.PrivContext( # This context allows entrypoints anywhere below oslo_privsep.tests. oslo_privsep.tests.__name__, pypath=__name__ + '.context', # This is one of the rare cases where we actually want zero powers: capabilities=[], ) class TestContextTestCase(base.BaseTestCase): def setUp(self): super(TestContextTestCase, self).setUp() privsep_fixture = self.useFixture( fixture.UnprivilegedPrivsepFixture(context)) self.privsep_conf = privsep_fixture.conf def assertNotMyPid(self, pid): # Verify that `pid` is some positive integer, that isn't our pid self.assertIsInstance(pid, int) self.assertTrue(pid > 0) self.assertNotEqual(os.getpid(), pid) ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/oslo_privsep/version.py0000664000175000017500000000126400000000000020772 0ustar00zuulzuul00000000000000# Copyright 2016 OpenStack Foundation # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import pbr.version version_info = pbr.version.VersionInfo('oslo.privsep') ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1724253560.1051352 oslo.privsep-3.4.0/releasenotes/0000775000175000017500000000000000000000000016675 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1724253560.1171355 oslo.privsep-3.4.0/releasenotes/notes/0000775000175000017500000000000000000000000020025 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/releasenotes/notes/add_entrypoint_with_timeout_decorator-9aab5a74153b3632.yaml0000664000175000017500000000065600000000000032732 0ustar00zuulzuul00000000000000--- features: - | Add ``timeout`` as parameter to ``PrivContext`` and add ``entrypoint_with_timeout`` decorator to cover the issues with commands which take random time to finish. ``PrivsepTimeout`` is raised if timeout is reached. ``Warning``: The daemon (the root process) task won't stop when timeout is reached. That means we'll have less available threads if the related thread never finishes. ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/releasenotes/notes/add_reno-3b4ae0789e9c45b4.yaml0000664000175000017500000000007100000000000024706 0ustar00zuulzuul00000000000000--- other: - Switch to reno for managing release notes.././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/releasenotes/notes/add_thread_pool_size-a54e6f27ab019f96.yaml0000664000175000017500000000040400000000000027274 0ustar00zuulzuul00000000000000--- features: - | Privsep now uses multithreading to allow concurrency in executing privileged commands. The number of concurrent threads defaults to the available CPU cores, but can be adjusted by the new ``thread_pool_size`` config option. ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/releasenotes/notes/auto-restart-client-channel-619545294557bf2b.yaml0000664000175000017500000000136000000000000030234 0ustar00zuulzuul00000000000000--- fixes: - | When the privsep helper dies, the client side PrivContext now restarts the client channel and the helper so that privileged commands can continue to be processed. See `bug 1715374`_ for details. In conjunction with the fix for `bug 1794708`_ in oslo.service, the nova-compute service now behaves correctly when it receives ``SIGHUP``. .. note:: This only works for the ``ROOTWRAP`` method of starting the daemon. With the ``FORK`` method we've dropped privileges and no longer have the ability to restart the daemon in privileged mode. .. _`bug 1715374`: https://bugs.launchpad.net/nova/+bug/1715374 .. _`bug 1794708`: https://bugs.launchpad.net/oslo.service/+bug/1794708 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/releasenotes/notes/context-logger-06b475357bebadc7.yaml0000664000175000017500000000112000000000000026140 0ustar00zuulzuul00000000000000--- features: - | ``PrivContext`` accepts a new string parameter called ``logger_name`` to define the logger we want to use for the daemon logs of this context. By default all contexts use ``oslo_privsep.daemon``, but in some cases we may need finer grained log levels, for example nova running in debug mode could log its own privsep calls on INFO level regardless, but leave all libraries' privsep calls, such as os-brick's, to be logged in the normal DEBUG level. See `bug 1922052`_. .. _`bug 1922052`: https://bugs.launchpad.net/nova/+bug/1922052 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/releasenotes/notes/drop-python27-support-6da3028c1cf099eb.yaml0000664000175000017500000000017700000000000027357 0ustar00zuulzuul00000000000000--- upgrade: - | Support for Python 2.7 has been dropped. The minimum version of Python now supported is Python 3.6. ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/releasenotes/notes/setgid-should-be-called-before-setuid-fcf01083df9d5369.yaml0000664000175000017500000000014000000000000032246 0ustar00zuulzuul00000000000000--- fixes: - | Fixed the failing setgid call when overriding both uid and gid to non root ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/releasenotes/notes/un-monkey-patch-privileged-daemon-160e00296549df3d.yaml0000664000175000017500000000113200000000000031373 0ustar00zuulzuul00000000000000--- other: - | The ``oslo.privsep`` client can be called from a program using eventlet. If ``eventlet.monkey_patch``, some libraries will be patched, for example ``threading`` or ``os``. When the root daemon is forked from the client process, those libraries remain patched. Now, when the daemon is forked from the client process, those libraries and methods are restored to the original values. The goal is to prevent some timeouts when using eventlet threads (user threads); system threads are preemptive and the code does not need to care about the executor token. ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1724253560.1211357 oslo.privsep-3.4.0/releasenotes/source/0000775000175000017500000000000000000000000020175 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/releasenotes/source/2023.1.rst0000664000175000017500000000020200000000000021446 0ustar00zuulzuul00000000000000=========================== 2023.1 Series Release Notes =========================== .. release-notes:: :branch: stable/2023.1 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/releasenotes/source/2023.2.rst0000664000175000017500000000020200000000000021447 0ustar00zuulzuul00000000000000=========================== 2023.2 Series Release Notes =========================== .. release-notes:: :branch: stable/2023.2 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/releasenotes/source/2024.1.rst0000664000175000017500000000020200000000000021447 0ustar00zuulzuul00000000000000=========================== 2024.1 Series Release Notes =========================== .. release-notes:: :branch: stable/2024.1 ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1724253560.1211357 oslo.privsep-3.4.0/releasenotes/source/_static/0000775000175000017500000000000000000000000021623 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/releasenotes/source/_static/.placeholder0000664000175000017500000000000000000000000024074 0ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1724253560.1211357 oslo.privsep-3.4.0/releasenotes/source/_templates/0000775000175000017500000000000000000000000022332 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/releasenotes/source/_templates/.placeholder0000664000175000017500000000000000000000000024603 0ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/releasenotes/source/conf.py0000664000175000017500000002114300000000000021475 0ustar00zuulzuul00000000000000# -*- coding: utf-8 -*- # Copyright (C) 2020 Red Hat, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. # See the License for the specific language governing permissions and # limitations under the License. # This file is execfile()d with the current directory set to its # containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # sys.path.insert(0, os.path.abspath('.')) # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. # needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ 'openstackdocstheme', 'reno.sphinxext', ] # openstackdocstheme options openstackdocs_repo_name = 'openstack/oslo.privsep' openstackdocs_bug_project = 'oslo.privsep' openstackdocs_bug_tag = '' # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. # source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. copyright = '2016, oslo.privsep Developers' # Release notes do not need a version in the title, they span # multiple versions. # The full version, including alpha/beta/rc tags. release = '' # The short X.Y version. version = '' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. # language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: # today = '' # Else, today_fmt is used as the format for a strftime call. # today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = [] # The reST default role (used for this markup: `text`) to use for all # documents. # default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. # add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). # add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. # show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'native' # A list of ignored prefixes for module index sorting. # modindex_common_prefix = [] # If true, keep warnings as "system message" paragraphs in the built documents. # keep_warnings = False # -- Options for HTML output ---------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. html_theme = 'openstackdocs' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. # html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. # html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". # html_title = None # A shorter title for the navigation bar. Default is the same as html_title. # html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. # html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. # html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied # directly to the root of the documentation. # html_extra_path = [] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. # html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. # html_use_smartypants = True # Custom sidebar templates, maps document names to template names. # html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. # html_additional_pages = {} # If false, no module index is generated. # html_domain_indices = True # If false, no index is generated. # html_use_index = True # If true, the index is split into individual pages for each letter. # html_split_index = False # If true, links to the reST sources are added to the pages. # html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. # html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. # html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. # html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). # html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = 'oslo.privsepReleaseNotesDoc' # -- Options for LaTeX output --------------------------------------------- # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ ('index', 'oslo.privsepReleaseNotes.tex', 'oslo.privsep Release Notes Documentation', 'oslo.privsep Developers', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. # latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. # latex_use_parts = False # If true, show page references after internal links. # latex_show_pagerefs = False # If true, show URL addresses after external links. # latex_show_urls = False # Documents to append as an appendix to all manuals. # latex_appendices = [] # If false, no module index is generated. # latex_domain_indices = True # -- Options for manual page output --------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ ('index', 'oslo.privsepReleaseNotes', 'oslo.privsep Release Notes Documentation', ['oslo.privsep Developers'], 1) ] # If true, show URL addresses after external links. # man_show_urls = False # -- Options for Texinfo output ------------------------------------------- # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ ('index', 'oslo.privsepReleaseNotes', 'oslo.privsep Release Notes Documentation', 'oslo.privsep Developers', 'oslo.privsepReleaseNotes', 'OpenStack library for privilege separation.', 'Miscellaneous'), ] # Documents to append as an appendix to all manuals. # texinfo_appendices = [] # If false, no module index is generated. # texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. # texinfo_show_urls = 'footnote' # If true, do not generate a @detailmenu in the "Top" node's menu. # texinfo_no_detailmenu = False # -- Options for Internationalization output ------------------------------ locale_dirs = ['locale/'] ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/releasenotes/source/index.rst0000664000175000017500000000043100000000000022034 0ustar00zuulzuul00000000000000============================ oslo.privsep Release Notes ============================ .. toctree:: :maxdepth: 1 unreleased 2024.1 2023.2 2023.1 zed yoga xena wallaby victoria ussuri train stein rocky queens pike ocata newton ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1724253560.1051352 oslo.privsep-3.4.0/releasenotes/source/locale/0000775000175000017500000000000000000000000021434 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1724253560.1051352 oslo.privsep-3.4.0/releasenotes/source/locale/en_GB/0000775000175000017500000000000000000000000022406 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1724253560.1211357 oslo.privsep-3.4.0/releasenotes/source/locale/en_GB/LC_MESSAGES/0000775000175000017500000000000000000000000024173 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/releasenotes/source/locale/en_GB/LC_MESSAGES/releasenotes.po0000664000175000017500000001604300000000000027230 0ustar00zuulzuul00000000000000# Andi Chandler , 2017. #zanata # Andi Chandler , 2018. #zanata # Andi Chandler , 2023. #zanata msgid "" msgstr "" "Project-Id-Version: oslo.privsep\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-05-08 11:10+0000\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "PO-Revision-Date: 2023-06-21 09:00+0000\n" "Last-Translator: Andi Chandler \n" "Language-Team: English (United Kingdom)\n" "Language: en_GB\n" "X-Generator: Zanata 4.3.3\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" msgid "1.13.0" msgstr "1.13.0" msgid "1.31.0" msgstr "1.31.0" msgid "1.33.3" msgstr "1.33.3" msgid "1.33.4" msgstr "1.33.4" msgid "2.0.0" msgstr "2.0.0" msgid "2.1.2" msgstr "2.1.2" msgid "2.3.0" msgstr "2.3.0" msgid "2.6.0" msgstr "2.6.0" msgid "2023.1 Series Release Notes" msgstr "2023.1 Series Release Notes" msgid "" "Add ``timeout`` as parameter to ``PrivContext`` and add " "``entrypoint_with_timeout`` decorator to cover the issues with commands " "which take random time to finish. ``PrivsepTimeout`` is raised if timeout is " "reached." msgstr "" "Add ``timeout`` as a parameter to ``PrivContext`` and add " "``entrypoint_with_timeout`` decorator to cover the issues with commands " "which take random time to finish. ``PrivsepTimeout`` is raised if a timeout " "is reached." msgid "Bug Fixes" msgstr "Bug Fixes" msgid "" "By default all contexts use ``oslo_privsep.daemon``, but in some cases we " "may need finer grained log levels, for example nova running in debug mode " "could log its own privsep calls on INFO level regardless, but leave all " "libraries' privsep calls, such as os-brick's, to be logged in the normal " "DEBUG level." msgstr "" "By default all contexts use ``oslo_privsep.daemon``, but in some cases, we " "may need finer-grained log levels, for example, Nova running in debug mode " "could log its own privsep calls on INFO level regardless, but leave all " "libraries' privsep calls, such as os-brick's, to be logged in the normal " "DEBUG level." msgid "New Features" msgstr "New Features" msgid "Newton Series Release Notes" msgstr "Newton Series Release Notes" msgid "Ocata Series Release Notes" msgstr "Ocata Series Release Notes" msgid "Other Notes" msgstr "Other Notes" msgid "Pike Series Release Notes" msgstr "Pike Series Release Notes" msgid "" "Privsep now uses multithreading to allow concurrency in executing privileged " "commands. The number of concurrent threads defaults to the available CPU " "cores, but can be adjusted by the new ``thread_pool_size`` config option." msgstr "" "Privsep now uses multithreading to allow concurrency in executing privileged " "commands. The number of concurrent threads defaults to the available CPU " "cores but can be adjusted by the new ``thread_pool_size`` config option." msgid "Queens Series Release Notes" msgstr "Queens Series Release Notes" msgid "Rocky Series Release Notes" msgstr "Rocky Series Release Notes" msgid "See `bug 1922052`_." msgstr "See `bug 1922052`_." msgid "Stein Series Release Notes" msgstr "Stein Series Release Notes" msgid "" "Support for Python 2.7 has been dropped. The minimum version of Python now " "supported is Python 3.6." msgstr "" "Support for Python 2.7 has been dropped. The minimum version of Python now " "supported is Python 3.6." msgid "Switch to reno for managing release notes." msgstr "Switch to Reno for managing release notes." msgid "" "The ``oslo.privsep`` client can be called from a program using eventlet. If " "``eventlet.monkey_patch``, some libraries will be patched, for example " "``threading`` or ``os``. When the root daemon is forked from the client " "process, those libraries remain patched. Now, when the daemon is forked from " "the client process, those libraries and methods are restored to the original " "values. The goal is to prevent some timeouts when using eventlet threads " "(user threads); system threads are preemptive and the code does not need to " "care about the executor token." msgstr "" "The ``oslo.privsep`` client can be called from a program using eventlet. If " "``eventlet.monkey_patch``, some libraries will be patched, for example " "``threading`` or ``os``. When the root daemon is forked from the client " "process, those libraries remain patched. Now, when the daemon is forked from " "the client process, those libraries and methods are restored to the original " "values. The goal is to prevent some timeouts when using eventlet threads " "(user threads); system threads are preemptive and the code does not need to " "care about the executor token." msgid "" "This only works for the ``ROOTWRAP`` method of starting the daemon. With the " "``FORK`` method we've dropped privileges and no longer have the ability to " "restart the daemon in privileged mode." msgstr "" "This only works for the ``ROOTWRAP`` method of starting the daemon. With the " "``FORK`` method we've dropped privileges and no longer have the ability to " "restart the daemon in privileged mode." msgid "Train Series Release Notes" msgstr "Train Series Release Notes" msgid "Unreleased Release Notes" msgstr "Unreleased Release Notes" msgid "Upgrade Notes" msgstr "Upgrade Notes" msgid "Ussuri Series Release Notes" msgstr "Ussuri Series Release Notes" msgid "Victoria Series Release Notes" msgstr "Victoria Series Release Notes" msgid "Wallaby Series Release Notes" msgstr "Wallaby Series Release Notes" msgid "" "When the privsep helper dies, the client side PrivContext now restarts the " "client channel and the helper so that privileged commands can continue to be " "processed. See `bug 1715374`_ for details. In conjunction with the fix for " "`bug 1794708`_ in oslo.service, the nova-compute service now behaves " "correctly when it receives ``SIGHUP``." msgstr "" "When the privsep helper dies, the client side PrivContext now restarts the " "client channel and the helper so that privileged commands can continue to be " "processed. See `bug 1715374`_ for details. In conjunction with the fix for " "`bug 1794708`_ in oslo.service, the nova-compute service now behaves " "correctly when it receives ``SIGHUP``." msgid "Xena Series Release Notes" msgstr "Xena Series Release Notes" msgid "Yoga Series Release Notes" msgstr "Yoga Series Release Notes" msgid "Zed Series Release Notes" msgstr "Zed Series Release Notes" msgid "" "``PrivContext`` accepts a new string parameter called ``logger_name`` to " "define the logger we want to use for the daemon logs of this context." msgstr "" "``PrivContext`` accepts a new string parameter called ``logger_name`` to " "define the logger we want to use for the daemon logs of this context." msgid "" "``Warning``: The daemon (the root process) task won't stop when timeout is " "reached. That means we'll have less available threads if the related thread " "never finishes." msgstr "" "``Warning``: The daemon (the root process) task won't stop when the timeout " "is reached. That means we'll have fewer available threads if the related " "thread never finishes." msgid "oslo.privsep Release Notes" msgstr "oslo.privsep Release Notes" ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1724253560.1051352 oslo.privsep-3.4.0/releasenotes/source/locale/fr/0000775000175000017500000000000000000000000022043 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1724253560.1211357 oslo.privsep-3.4.0/releasenotes/source/locale/fr/LC_MESSAGES/0000775000175000017500000000000000000000000023630 5ustar00zuulzuul00000000000000././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/releasenotes/source/locale/fr/LC_MESSAGES/releasenotes.po0000664000175000017500000000171300000000000026663 0ustar00zuulzuul00000000000000# Gérald LONLAS , 2016. #zanata msgid "" msgstr "" "Project-Id-Version: oslo.privsep Release Notes 1.14.1\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2016-10-23 20:38+0000\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "PO-Revision-Date: 2016-10-22 06:04+0000\n" "Last-Translator: Gérald LONLAS \n" "Language-Team: French\n" "Language: fr\n" "X-Generator: Zanata 3.7.3\n" "Plural-Forms: nplurals=2; plural=(n > 1)\n" msgid "1.13.0" msgstr "1.13.0" msgid "Newton Series Release Notes" msgstr "Note de release pour Newton" msgid "Other Notes" msgstr "Autres notes" msgid "Switch to reno for managing release notes." msgstr "Commence à utiliser reno pour la gestion des notes de release" msgid "Unreleased Release Notes" msgstr "Note de release pour les changements non déployées" msgid "oslo.privsep Release Notes" msgstr "Note de release pour oslo.privsep" ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/releasenotes/source/newton.rst0000664000175000017500000000021600000000000022240 0ustar00zuulzuul00000000000000============================= Newton Series Release Notes ============================= .. release-notes:: :branch: origin/stable/newton ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/releasenotes/source/ocata.rst0000664000175000017500000000023000000000000022011 0ustar00zuulzuul00000000000000=================================== Ocata Series Release Notes =================================== .. release-notes:: :branch: origin/stable/ocata ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/releasenotes/source/pike.rst0000664000175000017500000000021700000000000021657 0ustar00zuulzuul00000000000000=================================== Pike Series Release Notes =================================== .. release-notes:: :branch: stable/pike ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/releasenotes/source/queens.rst0000664000175000017500000000022300000000000022224 0ustar00zuulzuul00000000000000=================================== Queens Series Release Notes =================================== .. release-notes:: :branch: stable/queens ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/releasenotes/source/rocky.rst0000664000175000017500000000022100000000000022051 0ustar00zuulzuul00000000000000=================================== Rocky Series Release Notes =================================== .. release-notes:: :branch: stable/rocky ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/releasenotes/source/stein.rst0000664000175000017500000000022100000000000022044 0ustar00zuulzuul00000000000000=================================== Stein Series Release Notes =================================== .. release-notes:: :branch: stable/stein ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/releasenotes/source/train.rst0000664000175000017500000000017600000000000022050 0ustar00zuulzuul00000000000000========================== Train Series Release Notes ========================== .. release-notes:: :branch: stable/train ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/releasenotes/source/unreleased.rst0000664000175000017500000000014400000000000023055 0ustar00zuulzuul00000000000000========================== Unreleased Release Notes ========================== .. release-notes:: ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/releasenotes/source/ussuri.rst0000664000175000017500000000020200000000000022253 0ustar00zuulzuul00000000000000=========================== Ussuri Series Release Notes =========================== .. release-notes:: :branch: stable/ussuri ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/releasenotes/source/victoria.rst0000664000175000017500000000022000000000000022541 0ustar00zuulzuul00000000000000============================= Victoria Series Release Notes ============================= .. release-notes:: :branch: unmaintained/victoria ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/releasenotes/source/wallaby.rst0000664000175000017500000000021400000000000022357 0ustar00zuulzuul00000000000000============================ Wallaby Series Release Notes ============================ .. release-notes:: :branch: unmaintained/wallaby ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/releasenotes/source/xena.rst0000664000175000017500000000020000000000000021652 0ustar00zuulzuul00000000000000========================= Xena Series Release Notes ========================= .. release-notes:: :branch: unmaintained/xena ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/releasenotes/source/yoga.rst0000664000175000017500000000020000000000000021656 0ustar00zuulzuul00000000000000========================= Yoga Series Release Notes ========================= .. release-notes:: :branch: unmaintained/yoga ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/releasenotes/source/zed.rst0000664000175000017500000000017400000000000021513 0ustar00zuulzuul00000000000000======================== Zed Series Release Notes ======================== .. release-notes:: :branch: unmaintained/zed ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/requirements.txt0000664000175000017500000000033200000000000017466 0ustar00zuulzuul00000000000000oslo.log>=3.36.0 # Apache-2.0 oslo.i18n>=3.15.3 # Apache-2.0 oslo.config>=5.2.0 # Apache-2.0 oslo.utils>=3.33.0 # Apache-2.0 cffi>=1.14.0 # MIT eventlet>=0.21.0 # MIT greenlet>=0.4.14 # MIT msgpack>=0.6.0 # Apache-2.0 ././@PaxHeader0000000000000000000000000000003400000000000011452 xustar000000000000000028 mtime=1724253560.1251357 oslo.privsep-3.4.0/setup.cfg0000664000175000017500000000203600000000000016026 0ustar00zuulzuul00000000000000[metadata] name = oslo.privsep summary = OpenStack library for privilege separation description_file = README.rst author = OpenStack author_email = openstack-discuss@lists.openstack.org home_page = https://docs.openstack.org/oslo.privsep/latest/ python_requires = >=3.8 classifier = Environment :: OpenStack Intended Audience :: Information Technology Intended Audience :: System Administrators License :: OSI Approved :: Apache Software License Operating System :: POSIX :: Linux Programming Language :: Python Programming Language :: Python :: 3 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 Programming Language :: Python :: 3.11 Programming Language :: Python :: 3 :: Only Programming Language :: Python :: Implementation :: CPython [files] packages = oslo_privsep [entry_points] console_scripts = privsep-helper = oslo_privsep.daemon:helper_main oslo.config.opts = oslo.privsep = oslo_privsep.priv_context:_list_opts [egg_info] tag_build = tag_date = 0 ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/setup.py0000664000175000017500000000127100000000000015717 0ustar00zuulzuul00000000000000# Copyright (c) 2013 Hewlett-Packard Development Company, L.P. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. # See the License for the specific language governing permissions and # limitations under the License. import setuptools setuptools.setup( setup_requires=['pbr>=2.0.0'], pbr=True) ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/test-requirements.txt0000664000175000017500000000032700000000000020447 0ustar00zuulzuul00000000000000hacking>=6.1.0,<6.2.0 # Apache-2.0 oslotest>=3.2.0 # Apache-2.0 fixtures>=3.0.0 # Apache-2.0/BSD stestr>=2.0.0 # Apache-2.0 # Bandit security code scanner bandit>=1.7.0,<1.8.0 # Apache-2.0 pre-commit>=2.6.0 # MIT ././@PaxHeader0000000000000000000000000000002600000000000011453 xustar000000000000000022 mtime=1724253533.0 oslo.privsep-3.4.0/tox.ini0000664000175000017500000000357100000000000015525 0ustar00zuulzuul00000000000000[tox] minversion = 3.18.0 envlist = py3,pypy,pep8 ignore_basepython_conflict = true [testenv] basepython = python3 deps = -c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master} -r{toxinidir}/test-requirements.txt -r{toxinidir}/requirements.txt commands = stestr run --slowest {posargs} [testenv:pep8] deps = -r{toxinidir}/test-requirements.txt commands = pre-commit run -a # Run security linter bandit -r oslo_privsep -x tests -n5 --skip B404,B603 [testenv:venv] commands = {posargs} [testenv:docs] allowlist_externals = rm deps = {[testenv]deps} -r{toxinidir}/doc/requirements.txt commands = rm -rf doc/build doc/source/reference/api sphinx-build -W --keep-going -b html doc/source doc/build/html [testenv:cover] deps = {[testenv]deps} coverage setenv = PYTHON=coverage run --source oslo_privsep --parallel-mode commands = coverage erase stestr run {posargs} coverage combine coverage html -d cover coverage xml -o cover/coverage.xml coverage report --show-missing [flake8] # E123, E125 skipped as they are invalid PEP-8. # [H106] Don’t put vim configuration in source files # [H203] Use assertIs(Not)None to check for None # [W504] line break after binary operator show-source = True ignore = E123,E125,W504 builtins = _ exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,build enable-extensions = H106,H203 [hacking] import_exceptions = oslo_privsep._i18n [testenv:releasenotes] allowlist_externals = rm deps = -c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master} -r{toxinidir}/doc/requirements.txt commands = rm -rf releasenotes/build sphinx-build -a -E -W -d releasenotes/build/doctrees --keep-going -b html releasenotes/source releasenotes/build/html [testenv:functional] basepython = python3 setenv = OS_TEST_PATH=./oslo_privsep/functional OS_LOG_CAPTURE=1