From a0a0be8d0eaf4bf83b10ad0939edcfa71342b99b Mon Sep 17 00:00:00 2001 From: Andreas Jaeger Date: Mon, 17 Apr 2017 19:38:50 +0200 Subject: [PATCH] Retire repo This repo was created by accident, use deb-python-oslo.privsep instead. Needed-By: I1ac1a06931c8b6dd7c2e73620a0302c29e605f03 Change-Id: I81894aea69b9d09b0977039623c26781093a397a --- .coveragerc | 7 - .gitignore | 52 -- .gitreview | 4 - .mailmap | 3 - .testr.conf | 7 - CONTRIBUTING.rst | 17 - HACKING.rst | 4 - LICENSE | 176 ------- README.rst | 29 -- README.txt | 13 + babel.cfg | 2 - doc/source/api.rst | 12 - doc/source/conf.py | 75 --- doc/source/contributing.rst | 5 - doc/source/history.rst | 1 - doc/source/index.rst | 25 - doc/source/installation.rst | 7 - doc/source/usage.rst | 7 - oslo_privsep/__init__.py | 0 oslo_privsep/_i18n.py | 41 -- oslo_privsep/capabilities.py | 151 ------ oslo_privsep/comm.py | 183 ------- oslo_privsep/daemon.py | 478 ------------------ .../LC_MESSAGES/oslo_privsep-log-warning.po | 18 - .../locale/de/LC_MESSAGES/oslo_privsep.po | 53 -- .../LC_MESSAGES/oslo_privsep-log-error.po | 26 - .../LC_MESSAGES/oslo_privsep-log-info.po | 41 -- .../LC_MESSAGES/oslo_privsep-log-warning.po | 18 - .../locale/en_GB/LC_MESSAGES/oslo_privsep.po | 66 --- oslo_privsep/priv_context.py | 225 --------- oslo_privsep/tests/__init__.py | 0 oslo_privsep/tests/fixture.py | 55 -- oslo_privsep/tests/test_capabilities.py | 88 ---- oslo_privsep/tests/test_comm.py | 104 ---- oslo_privsep/tests/test_daemon.py | 106 ---- oslo_privsep/tests/test_priv_context.py | 191 ------- oslo_privsep/tests/testctx.py | 44 -- requirements.txt | 13 - setup.cfg | 55 -- setup.py | 29 -- test-requirements.txt | 12 - tox.ini | 33 -- 42 files changed, 13 insertions(+), 2463 deletions(-) delete mode 100644 .coveragerc delete mode 100644 .gitignore delete mode 100644 .gitreview delete mode 100644 .mailmap delete mode 100644 .testr.conf delete mode 100644 CONTRIBUTING.rst delete mode 100644 HACKING.rst delete mode 100644 LICENSE delete mode 100644 README.rst create mode 100644 README.txt delete mode 100644 babel.cfg delete mode 100644 doc/source/api.rst delete mode 100755 doc/source/conf.py delete mode 100644 doc/source/contributing.rst delete mode 100644 doc/source/history.rst delete mode 100644 doc/source/index.rst delete mode 100644 doc/source/installation.rst delete mode 100644 doc/source/usage.rst delete mode 100644 oslo_privsep/__init__.py delete mode 100644 oslo_privsep/_i18n.py delete mode 100644 oslo_privsep/capabilities.py delete mode 100644 oslo_privsep/comm.py delete mode 100644 oslo_privsep/daemon.py delete mode 100644 oslo_privsep/locale/de/LC_MESSAGES/oslo_privsep-log-warning.po delete mode 100644 oslo_privsep/locale/de/LC_MESSAGES/oslo_privsep.po delete mode 100644 oslo_privsep/locale/en_GB/LC_MESSAGES/oslo_privsep-log-error.po delete mode 100644 oslo_privsep/locale/en_GB/LC_MESSAGES/oslo_privsep-log-info.po delete mode 100644 oslo_privsep/locale/en_GB/LC_MESSAGES/oslo_privsep-log-warning.po delete mode 100644 oslo_privsep/locale/en_GB/LC_MESSAGES/oslo_privsep.po delete mode 100644 oslo_privsep/priv_context.py delete mode 100644 oslo_privsep/tests/__init__.py delete mode 100644 oslo_privsep/tests/fixture.py delete mode 100644 oslo_privsep/tests/test_capabilities.py delete mode 100644 oslo_privsep/tests/test_comm.py delete mode 100644 oslo_privsep/tests/test_daemon.py delete mode 100644 oslo_privsep/tests/test_priv_context.py delete mode 100644 oslo_privsep/tests/testctx.py delete mode 100644 requirements.txt delete mode 100644 setup.cfg delete mode 100644 setup.py delete mode 100644 test-requirements.txt delete mode 100644 tox.ini diff --git a/.coveragerc b/.coveragerc deleted file mode 100644 index c13db97..0000000 --- a/.coveragerc +++ /dev/null @@ -1,7 +0,0 @@ -[run] -branch = True -source = privsep -omit = privsep/tests/*,privsep/openstack/* - -[report] -ignore-errors = True diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 86bfb1a..0000000 --- a/.gitignore +++ /dev/null @@ -1,52 +0,0 @@ -*.py[cod] - -# C extensions -*.so - -# Packages -*.egg -*.egg-info -dist -build -eggs -/.eggs/ -parts -bin -var -sdist -develop-eggs -.installed.cfg -lib -lib64 - -# Installer logs -pip-log.txt - -# Unit test / coverage reports -.coverage -.tox -nosetests.xml -.testrepository - -# Translations -*.mo - -# Mr Developer -.mr.developer.cfg -.project -.pydevproject - -# Complexity -output/*.html -output/*/index.html - -# Sphinx -doc/build - -# pbr generates these -AUTHORS -ChangeLog - -# Editors -*~ -.*.swp diff --git a/.gitreview b/.gitreview deleted file mode 100644 index 6787749..0000000 --- a/.gitreview +++ /dev/null @@ -1,4 +0,0 @@ -[gerrit] -host=review.openstack.org -port=29418 -project=openstack/oslo.privsep.git diff --git a/.mailmap b/.mailmap deleted file mode 100644 index 516ae6f..0000000 --- a/.mailmap +++ /dev/null @@ -1,3 +0,0 @@ -# Format is: -# -# diff --git a/.testr.conf b/.testr.conf deleted file mode 100644 index 9b22871..0000000 --- a/.testr.conf +++ /dev/null @@ -1,7 +0,0 @@ -[DEFAULT] -test_command=OS_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1} \ - OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1} \ - OS_TEST_TIMEOUT=${OS_TEST_TIMEOUT:-60} \ - ${PYTHON:-python} -m subunit.run discover -t ./ ./oslo_privsep $LISTOPT $IDOPTION -test_id_option=--load-list $IDFILE -test_list_option=--list diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst deleted file mode 100644 index 5477886..0000000 --- a/CONTRIBUTING.rst +++ /dev/null @@ -1,17 +0,0 @@ -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 diff --git a/HACKING.rst b/HACKING.rst deleted file mode 100644 index e76ccf2..0000000 --- a/HACKING.rst +++ /dev/null @@ -1,4 +0,0 @@ -oslo.privsep Style Commandments -====================================================== - -Read the OpenStack Style Commandments http://docs.openstack.org/developer/hacking/ diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 68c771a..0000000 --- a/LICENSE +++ /dev/null @@ -1,176 +0,0 @@ - - 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. - diff --git a/README.rst b/README.rst deleted file mode 100644 index 3e4c587..0000000 --- a/README.rst +++ /dev/null @@ -1,29 +0,0 @@ -============ -oslo.privsep -============ - -.. image:: https://img.shields.io/pypi/v/oslo.privsep.svg - :target: https://pypi.python.org/pypi/oslo.privsep/ - :alt: Latest Version - -.. image:: https://img.shields.io/pypi/dm/oslo.privsep.svg - :target: https://pypi.python.org/pypi/oslo.privsep/ - :alt: Downloads - -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: http://docs.openstack.org/developer/oslo.privsep -* Source: http://git.openstack.org/cgit/openstack/oslo.privsep -* Bugs: http://bugs.launchpad.net/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 diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..26ad926 --- /dev/null +++ b/README.txt @@ -0,0 +1,13 @@ +This project is no longer maintained. + +The contents of this repository are still available in the Git +source code management system. To see the contents of this +repository before it reached its end of life, please check out the +previous commit with "git checkout HEAD^1". + +Use instead the project deb-python-oslo.privsep at +http://git.openstack.org/cgit/openstack/deb-python-oslo.privsep . + +For any further questions, please email +openstack-dev@lists.openstack.org or join #openstack-dev on +Freenode. diff --git a/babel.cfg b/babel.cfg deleted file mode 100644 index 15cd6cb..0000000 --- a/babel.cfg +++ /dev/null @@ -1,2 +0,0 @@ -[python: **.py] - diff --git a/doc/source/api.rst b/doc/source/api.rst deleted file mode 100644 index 971225e..0000000 --- a/doc/source/api.rst +++ /dev/null @@ -1,12 +0,0 @@ -===== - API -===== - -.. Use autodoc directives to describe the *public* modules and classes - in the library. - - If the modules are completely unrelated, create an api subdirectory - and use a separate file for each (see oslo.utils). - - If there is only one submodule, a single api.rst file like this - sufficient (see oslo.i18n). diff --git a/doc/source/conf.py b/doc/source/conf.py deleted file mode 100755 index 8f94961..0000000 --- a/doc/source/conf.py +++ /dev/null @@ -1,75 +0,0 @@ -# -*- coding: utf-8 -*- -# 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 -import sys - -sys.path.insert(0, os.path.abspath('../..')) -# -- 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', - #'sphinx.ext.intersphinx', - 'oslosphinx' -] - -# autodoc generation is a bit aggressive and a nuisance when doing heavy -# text edit cycles. -# execute "export SPHINX_DEBUG=1" in your terminal to disable - -# The suffix of source filenames. -source_suffix = '.rst' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = u'oslo.privsep' -copyright = u'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 = 'sphinx' - -# -- 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_path = ["."] -# html_theme = '_theme' -# html_static_path = ['static'] - -# Output file base name for HTML help builder. -htmlhelp_basename = '%sdoc' % project - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, author, documentclass -# [howto/manual]). -latex_documents = [ - ('index', - '%s.tex' % project, - u'%s Documentation' % project, - u'OpenStack Foundation', 'manual'), -] - -# Example configuration for intersphinx: refer to the Python standard library. -#intersphinx_mapping = {'http://docs.python.org/': None} diff --git a/doc/source/contributing.rst b/doc/source/contributing.rst deleted file mode 100644 index 2ca75d1..0000000 --- a/doc/source/contributing.rst +++ /dev/null @@ -1,5 +0,0 @@ -============== - Contributing -============== - -.. include:: ../../CONTRIBUTING.rst diff --git a/doc/source/history.rst b/doc/source/history.rst deleted file mode 100644 index 69ed4fe..0000000 --- a/doc/source/history.rst +++ /dev/null @@ -1 +0,0 @@ -.. include:: ../../ChangeLog diff --git a/doc/source/index.rst b/doc/source/index.rst deleted file mode 100644 index 62470a3..0000000 --- a/doc/source/index.rst +++ /dev/null @@ -1,25 +0,0 @@ -============== - oslo.privsep -============== - -OpenStack library for privilege separation - -Contents -======== - -.. toctree:: - :maxdepth: 2 - - installation - api - usage - contributing - history - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` - diff --git a/doc/source/installation.rst b/doc/source/installation.rst deleted file mode 100644 index 4bb4dbe..0000000 --- a/doc/source/installation.rst +++ /dev/null @@ -1,7 +0,0 @@ -============== - Installation -============== - -At the command line:: - - $ pip install oslo.privsep diff --git a/doc/source/usage.rst b/doc/source/usage.rst deleted file mode 100644 index b0d166e..0000000 --- a/doc/source/usage.rst +++ /dev/null @@ -1,7 +0,0 @@ -======= - Usage -======= - -To use oslo.privsep in a project:: - - import oslo_privsep diff --git a/oslo_privsep/__init__.py b/oslo_privsep/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/oslo_privsep/_i18n.py b/oslo_privsep/_i18n.py deleted file mode 100644 index 795cd56..0000000 --- a/oslo_privsep/_i18n.py +++ /dev/null @@ -1,41 +0,0 @@ -# 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 http://docs.openstack.org/developer/oslo.i18n/usage.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 - -# Translators for log levels. -# -# The abbreviated names are meant to reflect the usual use of a short -# name like '_'. The "L" is for "log" and the other letter comes from -# the level. -_LI = _translators.log_info -_LW = _translators.log_warning -_LE = _translators.log_error -_LC = _translators.log_critical diff --git a/oslo_privsep/capabilities.py b/oslo_privsep/capabilities.py deleted file mode 100644 index 9a97b42..0000000 --- a/oslo_privsep/capabilities.py +++ /dev/null @@ -1,151 +0,0 @@ -# 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 os -import platform - -import cffi - -# Expand as necessary -CAP_CHOWN = 0 -CAP_DAC_OVERRIDE = 1 -CAP_FOWNER = 3 -CAP_KILL = 5 -CAP_SETPCAP = 8 -CAP_NET_BIND_SERVICE = 10 -CAP_NET_BROADCAST = 11 -CAP_NET_ADMIN = 12 -CAP_NET_RAW = 13 -CAP_SYS_ADMIN = 21 - -# Convenience dicts for human readable values -CAPS_BYNAME = {} -CAPS_BYVALUE = {} -for k, v in globals().copy().items(): - if k.startswith('CAP_'): - CAPS_BYNAME[k] = v - CAPS_BYVALUE[v] = k - -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() -crt = ffi.dlopen(None) -ffi.cdef(CDEF) - - -if platform.system() == 'Linux': - # mock.patching crt.* directly seems to upset cffi. Use an - # indirection point here for easier testing. - _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)), - ) diff --git a/oslo_privsep/comm.py b/oslo_privsep/comm.py deleted file mode 100644 index 632fdbc..0000000 --- a/oslo_privsep/comm.py +++ /dev/null @@ -1,183 +0,0 @@ -# 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 logging -import socket -import threading - -import msgpack -import six - -from oslo_privsep._i18n import _ - - -LOG = logging.getLogger(__name__) - - -try: - import greenlet - - def _get_thread_ident(): - # This returns something sensible, even if the current thread - # isn't a greenthread - return id(greenlet.getcurrent()) - -except ImportError: - def _get_thread_ident(): - return threading.current_thread().ident - - -class Serializer(object): - def __init__(self, writesock): - self.writesock = writesock - - def send(self, msg): - buf = msgpack.packb(msg, use_bin_type=True) - 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(six.Iterator): - def __init__(self, readsock): - self.readsock = readsock - self.unpacker = msgpack.Unpacker(use_list=False, encoding='utf-8') - - def __iter__(self): - return self - - def __next__(self): - while True: - try: - return next(self.unpacker) - except StopIteration: - buf = self.readsock.recv(4096) - if not buf: - raise - self.unpacker.feed(buf) - - -class Future(object): - """A very simple object to track the return of a function call""" - - def __init__(self, lock): - self.condvar = threading.Condition(lock) - self.error = None - self.data = None - - 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""" - self.condvar.wait() - if self.error is not None: - raise self.error - return self.data - - -class ClientChannel(object): - def __init__(self, sock): - 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""" - for msg in reader: - msgid, data = msg - with self.lock: - assert msgid in self.outstanding_msgs - 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) - - def send_recv(self, msg): - myid = _get_thread_ident() - future = Future(self.lock) - - with self.lock: - assert myid not in self.outstanding_msgs - self.outstanding_msgs[myid] = future - try: - self.writer.send((myid, msg)) - - reply = future.result() - finally: - del self.outstanding_msgs[myid] - - return reply - - def close(self): - with self.lock: - self.writer.close() - - self.reader_thread.join() - - -class ServerChannel(six.Iterator): - """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) diff --git a/oslo_privsep/daemon.py b/oslo_privsep/daemon.py deleted file mode 100644 index 27bc427..0000000 --- a/oslo_privsep/daemon.py +++ /dev/null @@ -1,478 +0,0 @@ -# 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). - -''' - -import enum -import errno -import io -import logging as pylogging -import os -import platform -import socket -import subprocess -import sys -import tempfile -import threading - -if platform.system() == 'Linux': - import fcntl - import grp - import pwd - -import eventlet -from oslo_config import cfg -from oslo_log import log as logging -from oslo_utils import importutils - -from oslo_privsep import capabilities -from oslo_privsep import comm -from oslo_privsep._i18n import _, _LE, _LI - - -LOG = logging.getLogger(__name__) - - -@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 - - -@enum.unique -class Message(enum.IntEnum): - """Types of messages sent across the communication channel""" - PING = 1 - PONG = 2 - CALL = 3 - RET = 4 - ERR = 5 - - -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 _ClientChannel(comm.ClientChannel): - """Our protocol, layered on the basic primitives in comm.ClientChannel""" - - def __init__(self, sock): - super(_ClientChannel, self).__init__(sock) - self.exchange_ping() - - def exchange_ping(self): - try: - # exchange "ready" messages - reply = self.send_recv((Message.PING.value,)) - success = reply[0] == Message.PONG - except Exception as e: - LOG.exception( - _LE('Error while sending initial PING to privsep: %s'), e) - success = False - if not success: - msg = _('Privsep daemon failed to start') - LOG.critical(msg) - raise FailedToDropPrivileges(msg) - - def remote_call(self, name, args, kwargs): - result = self.send_recv((Message.CALL.value, name, args, kwargs)) - if result[0] == Message.RET: - # (RET, return value) - return result[1] - elif result[0] == 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 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) - - -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() - - log_fd = _fd_logger() - - if os.fork() == 0: - # child - - # replace root logger early (to capture any errors below) - replace_logging(pylogging.StreamHandler(log_fd)) - - sock_a.close() - Daemon(comm.ServerChannel(sock_b), context=context).run() - LOG.debug('privsep daemon exiting') - os._exit(0) - - # parent - - sock_b.close() - super(ForkingClientChannel, self).__init__(sock_a) - - -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(_LI('Running privsep helper: %s'), cmd) - proc = subprocess.Popen(cmd, shell=False, stderr=_fd_logger()) - if proc.wait() != 0: - msg = (_LE('privsep helper command exited non-zero (%s)') % - proc.returncode) - LOG.critical(msg) - raise FailedToDropPrivileges(msg) - LOG.info(_LI('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) - - -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) - - 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) - - if self.user is not None: - setuid(self.user) - - if self.group is not None: - setgid(self.group) - - finally: - capabilities.set_keepcaps(False) - - LOG.info(_LI('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' - return '|'.join(sorted(capabilities.CAPS_BYVALUE[c] - for c in capset)) - - eff, prm, inh = capabilities.get_caps() - LOG.info( - _LI('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, cmd, *args): - if cmd == Message.PING: - return (Message.PONG.value,) - - elif cmd == Message.CALL: - 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 (Message.RET.value, ret) - - raise ProtocolError(_('Unknown privsep cmd: %s') % cmd) - - def loop(self): - """Main body of daemon request loop""" - LOG.info(_LI('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: - LOG.debug('privsep: request[%(msgid)s]: %(req)s', - {'msgid': msgid, 'req': msg}) - try: - reply = self._process_cmd(*msg) - 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 = (Message.ERR.value, cls_name, e.args) - - try: - LOG.debug('privsep: reply[%(msgid)s]: %(reply)s', - {'msgid': msgid, 'reply': reply}) - self.channel.send((msgid, reply)) - except IOError as e: - if e.errno == errno.EPIPE: - # Write stream closed, exit loop - break - raise - - 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') - logging.setup(cfg.CONF, 'privsep') - - # We always log to stderr. Replace the root logger we just set up. - replace_logging(pylogging.StreamHandler(sys.stderr)) - - LOG.info(_LI('privsep daemon starting')) - - 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(_LE('--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. - - 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() diff --git a/oslo_privsep/locale/de/LC_MESSAGES/oslo_privsep-log-warning.po b/oslo_privsep/locale/de/LC_MESSAGES/oslo_privsep-log-warning.po deleted file mode 100644 index ce07bf5..0000000 --- a/oslo_privsep/locale/de/LC_MESSAGES/oslo_privsep-log-warning.po +++ /dev/null @@ -1,18 +0,0 @@ -# Andreas Jaeger , 2016. #zanata -msgid "" -msgstr "" -"Project-Id-Version: oslo.privsep 1.5.1.dev2\n" -"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" -"POT-Creation-Date: 2016-04-19 13:52+0000\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"PO-Revision-Date: 2015-11-13 04:56+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 "privsep daemon already running" -msgstr "Der Privsep Dämon läuft bereits." diff --git a/oslo_privsep/locale/de/LC_MESSAGES/oslo_privsep.po b/oslo_privsep/locale/de/LC_MESSAGES/oslo_privsep.po deleted file mode 100644 index c1bc4d2..0000000 --- a/oslo_privsep/locale/de/LC_MESSAGES/oslo_privsep.po +++ /dev/null @@ -1,53 +0,0 @@ -# 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." diff --git a/oslo_privsep/locale/en_GB/LC_MESSAGES/oslo_privsep-log-error.po b/oslo_privsep/locale/en_GB/LC_MESSAGES/oslo_privsep-log-error.po deleted file mode 100644 index f5f0647..0000000 --- a/oslo_privsep/locale/en_GB/LC_MESSAGES/oslo_privsep-log-error.po +++ /dev/null @@ -1,26 +0,0 @@ -# Andi Chandler , 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 11:12+0000\n" -"Last-Translator: Andi Chandler \n" -"Language-Team: English (United Kingdom)\n" -"Language: en-GB\n" -"X-Generator: Zanata 3.7.3\n" -"Plural-Forms: nplurals=2; plural=(n != 1)\n" - -msgid "--privsep_context must be the (python) name of a PrivContext object" -msgstr "--privsep_context must be the (python) name of a PrivContext object" - -#, python-format -msgid "Error while sending initial PING to privsep: %s" -msgstr "Error while sending initial PING to privsep: %s" - -#, python-format -msgid "privsep helper command exited non-zero (%s)" -msgstr "privsep helper command exited non-zero (%s)" diff --git a/oslo_privsep/locale/en_GB/LC_MESSAGES/oslo_privsep-log-info.po b/oslo_privsep/locale/en_GB/LC_MESSAGES/oslo_privsep-log-info.po deleted file mode 100644 index fbf7e9a..0000000 --- a/oslo_privsep/locale/en_GB/LC_MESSAGES/oslo_privsep-log-info.po +++ /dev/null @@ -1,41 +0,0 @@ -# Andi Chandler , 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 11:13+0000\n" -"Last-Translator: Andi Chandler \n" -"Language-Team: English (United Kingdom)\n" -"Language: en-GB\n" -"X-Generator: Zanata 3.7.3\n" -"Plural-Forms: nplurals=2; plural=(n != 1)\n" - -#, python-format -msgid "Running privsep helper: %s" -msgstr "Running privsep helper: %s" - -msgid "Spawned new privsep daemon via rootwrap" -msgstr "Spawned new privsep daemon via rootwrap" - -#, python-format -msgid "privsep daemon running as pid %s" -msgstr "privsep daemon running as pid %s" - -msgid "privsep daemon starting" -msgstr "privsep daemon starting" - -#, python-format -msgid "" -"privsep process running with capabilities (eff/prm/inh): %(eff)s/%(prm)s/" -"%(inh)s" -msgstr "" -"privsep process running with capabilities (eff/prm/inh): %(eff)s/%(prm)s/" -"%(inh)s" - -#, python-format -msgid "privsep process running with uid/gid: %(uid)s/%(gid)s" -msgstr "privsep process running with uid/gid: %(uid)s/%(gid)s" diff --git a/oslo_privsep/locale/en_GB/LC_MESSAGES/oslo_privsep-log-warning.po b/oslo_privsep/locale/en_GB/LC_MESSAGES/oslo_privsep-log-warning.po deleted file mode 100644 index 74d79b3..0000000 --- a/oslo_privsep/locale/en_GB/LC_MESSAGES/oslo_privsep-log-warning.po +++ /dev/null @@ -1,18 +0,0 @@ -# Andi Chandler , 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 11:13+0000\n" -"Last-Translator: Andi Chandler \n" -"Language-Team: English (United Kingdom)\n" -"Language: en-GB\n" -"X-Generator: Zanata 3.7.3\n" -"Plural-Forms: nplurals=2; plural=(n != 1)\n" - -msgid "privsep daemon already running" -msgstr "privsep daemon already running" diff --git a/oslo_privsep/locale/en_GB/LC_MESSAGES/oslo_privsep.po b/oslo_privsep/locale/en_GB/LC_MESSAGES/oslo_privsep.po deleted file mode 100644 index 2475bf3..0000000 --- a/oslo_privsep/locale/en_GB/LC_MESSAGES/oslo_privsep.po +++ /dev/null @@ -1,66 +0,0 @@ -# Andi Chandler , 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 11:12+0000\n" -"Last-Translator: Andi Chandler \n" -"Language-Team: English (United Kingdom)\n" -"Language: en-GB\n" -"X-Generator: Zanata 3.7.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 "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" - -#, 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." diff --git a/oslo_privsep/priv_context.py b/oslo_privsep/priv_context.py deleted file mode 100644 index 737f3b0..0000000 --- a/oslo_privsep/priv_context.py +++ /dev/null @@ -1,225 +0,0 @@ -# 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 enum -import functools -import logging -import shlex -import sys - -from oslo_config import cfg -from oslo_config import types -from oslo_utils import importutils - -from oslo_privsep import capabilities -from oslo_privsep import daemon -from oslo_privsep._i18n import _, _LW, _LE - - -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.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.')), -] - -_ENTRYPOINT_ATTR = 'privsep_entrypoint' -_HELPER_COMMAND_PREFIX = ['sudo'] - - -@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): - - # 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 - - cfg.CONF.register_opts(OPTS, group=cfg_section) - cfg.CONF.set_default('capabilities', group=cfg_section, - default=capabilities) - - @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. - assert self.pypath is not None, ( - 'helper_command requires priv_context ' - 'pypath to be specified') - assert importutils.import_class(self.pypath) is self, ( - '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: - cmd.extend(['--config-dir', cfg.CONF.config_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( - _LE("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.""" - - assert func.__module__.startswith(self.prefix), ( - '%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. - assert getattr(func, _ENTRYPOINT_ATTR, None) is None, ( - '%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, **kwargs): - if self.client_mode: - name = '%s.%s' % (func.__module__, func.__name__) - if self.channel is None: - self.start() - return self.channel.remote_call(name, args, kwargs) - else: - return func(*args, **kwargs) - - def start(self, method=Method.ROOTWRAP): - if self.channel is not None: - LOG.warning(_LW('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 diff --git a/oslo_privsep/tests/__init__.py b/oslo_privsep/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/oslo_privsep/tests/fixture.py b/oslo_privsep/tests/fixture.py deleted file mode 100644 index f5d810a..0000000 --- a/oslo_privsep/tests/fixture.py +++ /dev/null @@ -1,55 +0,0 @@ -# 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) diff --git a/oslo_privsep/tests/test_capabilities.py b/oslo_privsep/tests/test_capabilities.py deleted file mode 100644 index af9ae14..0000000 --- a/oslo_privsep/tests/test_capabilities.py +++ /dev/null @@ -1,88 +0,0 @@ -# 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 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.assertItemsEqual( - [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.assertItemsEqual( - ([17, 24, 49], - [8, 10, 35, 56], - [24, 31, 40]), - capabilities.get_caps()) diff --git a/oslo_privsep/tests/test_comm.py b/oslo_privsep/tests/test_comm.py deleted file mode 100644 index 72f7aef..0000000 --- a/oslo_privsep/tests/test_comm.py +++ /dev/null @@ -1,104 +0,0 @@ -# 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 six - -from oslotest import base - -from oslo_privsep import comm - - -class BufSock(object): - def __init__(self): - self.readpos = 0 - self.buf = six.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 = u'\u4e09\u9df9' - 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) diff --git a/oslo_privsep/tests/test_daemon.py b/oslo_privsep/tests/test_daemon.py deleted file mode 100644 index d7068c3..0000000 --- a/oslo_privsep/tests/test_daemon.py +++ /dev/null @@ -1,106 +0,0 @@ -# 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 mock -import platform -import time - -from oslotest import base -import testtools - -from oslo_privsep import capabilities -from oslo_privsep import daemon -from oslo_privsep.tests import testctx - - -LOG = logging.getLogger(__name__) - - -def undecorated(): - pass - - -@testctx.context.entrypoint -def logme(level, msg): - LOG.log(level, '%s', msg) - - -@testtools.skipIf(platform.system() != 'Linux', - 'works only on Linux platform.') -class LogTest(testctx.TestContextTestCase): - def setUp(self): - super(LogTest, self).setUp() - self.logger = self.useFixture(fixtures.FakeLogger( - name=None, level=logging.INFO)) - - def test_priv_log(self): - logme(logging.DEBUG, u'test@DEBUG') - logme(logging.WARN, u'test@WARN') - - time.sleep(0.1) # Hack to give logging thread a chance to run - - # TODO(gus): Currently severity information is lost and - # everything is logged as INFO. Fixing this probably requires - # writing structured messages to the logging socket. - # - # self.assertNotIn('test@DEBUG', self.logger.output) - - self.assertIn(u'test@WARN', self.logger.output) - - -@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 = mock.NonCallableMock() - context.conf.user = 42 - context.conf.group = 84 - context.conf.capabilities = [ - capabilities.CAP_SYS_ADMIN, capabilities.CAP_NET_ADMIN] - - 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([]) - - self.assertItemsEqual( - [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.assertRaisesRegexp( - NameError, 'undecorated not exported', - testctx.context._wrap, undecorated) diff --git a/oslo_privsep/tests/test_priv_context.py b/oslo_privsep/tests/test_priv_context.py deleted file mode 100644 index eaddb9f..0000000 --- a/oslo_privsep/tests/test_priv_context.py +++ /dev/null @@ -1,191 +0,0 @@ -# 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 mock -import testtools - -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 - - -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' - cmd = testctx.context.helper_command('/tmp/sockpath') - expected = [ - 'foo', '--bar', - '--privsep_context', testctx.context.pypath, - '--privsep_sock_path', '/tmp/sockpath', - ] - self.assertEqual(expected, cmd) - - def test_helper_command_default(self): - self.privsep_conf.config_file = ['/bar.conf'] - cmd = testctx.context.helper_command('/tmp/sockpath') - expected = [ - 'sudo', 'privsep-helper', - '--config-file', '/bar.conf', - # --config-dir arg should be skipped - '--privsep_context', testctx.context.pypath, - '--privsep_sock_path', '/tmp/sockpath', - ] - 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' - cmd = testctx.context.helper_command('/tmp/sockpath') - expected = [ - 'sudo', 'privsep-helper', - '--config-file', '/bar.conf', - '--config-file', '/baz.conf', - '--config-dir', '/foo.d', - '--privsep_context', testctx.context.pypath, - '--privsep_sock_path', '/tmp/sockpath', - ] - 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']) - - -@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) - - -@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.assertRaisesRegexp( - 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!') diff --git a/oslo_privsep/tests/testctx.py b/oslo_privsep/tests/testctx.py deleted file mode 100644 index 0b19ced..0000000 --- a/oslo_privsep/tests/testctx.py +++ /dev/null @@ -1,44 +0,0 @@ -# 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) diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 34304cd..0000000 --- a/requirements.txt +++ /dev/null @@ -1,13 +0,0 @@ -# The order of packages is significant, because pip processes them in the order -# of appearance. Changing the order has an impact on the overall integration -# process, which may cause wedges in the gate later. - -oslo.log>=1.14.0 # Apache-2.0 -oslo.i18n>=2.1.0 # Apache-2.0 -oslo.config>=3.12.0 # Apache-2.0 -oslo.utils>=3.16.0 # Apache-2.0 -enum34;python_version=='2.7' or python_version=='2.6' or python_version=='3.3' # BSD -cffi # MIT -eventlet!=0.18.3,>=0.18.2 # MIT -greenlet>=0.3.2 # MIT -msgpack-python>=0.4.0 # Apache-2.0 diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index f39b2fe..0000000 --- a/setup.cfg +++ /dev/null @@ -1,55 +0,0 @@ -[metadata] -name = oslo.privsep -summary = OpenStack library for privilege separation -description-file = - README.rst -author = OpenStack -author-email = openstack-dev@lists.openstack.org -home-page = http://launchpad.net/oslo -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 :: 2 - Programming Language :: Python :: 2.7 - Programming Language :: Python :: 3 - Programming Language :: Python :: 3.4 - -[files] -packages = - oslo_privsep - -[pbr] -warnerrors = true - -[build_sphinx] -source-dir = doc/source -build-dir = doc/build -all_files = 1 - -[entry_points] -console_scripts = - privsep-helper = oslo_privsep.daemon:helper_main - -[upload_sphinx] -upload-dir = doc/build/html - -[compile_catalog] -directory = oslo.privsep/locale -domain = oslo_privsep - -[update_catalog] -domain = oslo_privsep -output_dir = oslo_privsep/locale -input_file = oslo_privsep/locale/oslo_privsep.pot - -[extract_messages] -keywords = _ gettext ngettext l_ lazy_gettext -mapping_file = babel.cfg -output_file = oslo_privsep/locale/oslo_privsep.pot - -[wheel] -universal = true diff --git a/setup.py b/setup.py deleted file mode 100644 index 782bb21..0000000 --- a/setup.py +++ /dev/null @@ -1,29 +0,0 @@ -# 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. - -# THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT -import setuptools - -# In python < 2.7.4, a lazy loading of package `pbr` will break -# setuptools if some other modules registered functions in `atexit`. -# solution from: http://bugs.python.org/issue15881#msg170215 -try: - import multiprocessing # noqa -except ImportError: - pass - -setuptools.setup( - setup_requires=['pbr>=1.8'], - pbr=True) diff --git a/test-requirements.txt b/test-requirements.txt deleted file mode 100644 index b3deaba..0000000 --- a/test-requirements.txt +++ /dev/null @@ -1,12 +0,0 @@ -# The order of packages is significant, because pip processes them in the order -# of appearance. Changing the order has an impact on the overall integration -# process, which may cause wedges in the gate later. - -hacking<0.11,>=0.10.2 -oslotest>=1.10.0 # Apache-2.0 -mock>=2.0 # BSD -fixtures>=3.0.0 # Apache-2.0/BSD - -# These are needed for docs generation -oslosphinx!=3.4.0,>=2.5.0 # Apache-2.0 -sphinx!=1.3b1,<1.3,>=1.2.1 # BSD diff --git a/tox.ini b/tox.ini deleted file mode 100644 index 1a2c3ae..0000000 --- a/tox.ini +++ /dev/null @@ -1,33 +0,0 @@ -[tox] -minversion = 1.6 -envlist = py34,py27,pypy,pep8 - -[testenv] -whitelist_externals = - /bin/sh -deps = -r{toxinidir}/test-requirements.txt -commands = python setup.py testr --slowest --testr-args='{posargs}' - -[testenv:pep8] -commands = flake8 - -[testenv:venv] -commands = {posargs} - -[testenv:docs] -commands = python setup.py build_sphinx - -[testenv:cover] -commands = python setup.py testr --coverage --testr-args='{posargs}' - -[flake8] -# E123, E125 skipped as they are invalid PEP-8. - -show-source = True -ignore = E123,E125 -builtins = _ -exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,build - -[hacking] -import_exceptions = - oslo_privsep._i18n