From 3c0e282f7cbf67be94b6963f214dbbe34dddaee0 Mon Sep 17 00:00:00 2001 From: Michael Tremer Date: Sat, 15 Oct 2011 15:50:19 +0200 Subject: [PATCH] Replace support for capabilities from pyxattr to libcap. --- INSTALL | 2 +- po/pakfire.pot | 18 ++--- python/pakfire/packages/file.py | 49 ++++--------- python/pakfire/packages/packager.py | 1 - python/pakfire/util.py | 4 +- python/src/Makefile | 2 +- python/src/_pakfiremodule.c | 3 + python/src/capabilities.c | 104 ++++++++++++++++++++++++++++ python/src/capabilities.h | 29 ++++++++ 9 files changed, 164 insertions(+), 48 deletions(-) create mode 100644 python/src/capabilities.c create mode 100644 python/src/capabilities.h diff --git a/INSTALL b/INSTALL index c234ed000..0eb1dd6a4 100644 --- a/INSTALL +++ b/INSTALL @@ -5,8 +5,8 @@ Requirements: * Python 2.6 or greater (not Python 3.x) * pyliblzma * python-progressbar - * python-xattr * python-argsparse (included in Python 2.7) + * libcap * libsolv diff --git a/po/pakfire.pot b/po/pakfire.pot index 00eb0e9e0..655af5e14 100644 --- a/po/pakfire.pot +++ b/po/pakfire.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2011-10-14 23:03+0200\n" +"POT-Creation-Date: 2011-10-15 16:48+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -349,7 +349,7 @@ msgid "Do not verify build dependencies." msgstr "" #: ../python/pakfire/compress.py:133 -#: ../python/pakfire/packages/packager.py:496 +#: ../python/pakfire/packages/packager.py:495 #, python-format msgid "Compressing %s" msgstr "" @@ -487,27 +487,27 @@ msgstr "" msgid "Config file saved as %s." msgstr "" -#: ../python/pakfire/packages/file.py:111 +#: ../python/pakfire/packages/file.py:95 #, python-format msgid "Could not extract file: /%(src)s - %(dst)s" msgstr "" -#: ../python/pakfire/packages/file.py:164 +#: ../python/pakfire/packages/file.py:145 #, python-format msgid "Filename: %s" msgstr "" -#: ../python/pakfire/packages/file.py:278 +#: ../python/pakfire/packages/file.py:259 #, python-format msgid "File in archive is missing in file metadata: /%s. Skipping." msgstr "" -#: ../python/pakfire/packages/file.py:329 +#: ../python/pakfire/packages/file.py:310 #, python-format msgid "Config file created as %s" msgstr "" -#: ../python/pakfire/packages/file.py:343 +#: ../python/pakfire/packages/file.py:324 #, python-format msgid "Could not remove file: /%s" msgstr "" @@ -521,11 +521,11 @@ msgid "Package version is undefined." msgstr "" #. Load progressbar. -#: ../python/pakfire/packages/packager.py:334 +#: ../python/pakfire/packages/packager.py:333 msgid "Packaging" msgstr "" -#: ../python/pakfire/packages/packager.py:622 +#: ../python/pakfire/packages/packager.py:621 #, python-format msgid "Building source package %s:" msgstr "" diff --git a/python/pakfire/packages/file.py b/python/pakfire/packages/file.py index a2bd88c04..26a4e2ed3 100644 --- a/python/pakfire/packages/file.py +++ b/python/pakfire/packages/file.py @@ -26,7 +26,6 @@ import re import shutil import tarfile import tempfile -import xattr import pakfire.filelist import pakfire.util as util @@ -43,8 +42,6 @@ PAYLOAD_COMPRESSION_MAGIC = { } class InnerTarFile(tarfile.TarFile): - SUPPORTED_XATTRS = ("security.capability",) - def __init__(self, *args, **kwargs): # Force the PAX format. kwargs["format"] = tarfile.PAX_FORMAT @@ -53,31 +50,18 @@ class InnerTarFile(tarfile.TarFile): def add(self, name, arcname=None, recursive=None, exclude=None, filter=None): """ - Emulate the add function with xattrs support. + Emulate the add function with capability support. """ tarinfo = self.gettarinfo(name, arcname) if tarinfo.isreg(): attrs = [] - # Use new modules code... - if hasattr(xattr, "get_all"): - attrs = xattr.get_all(name) - - # ...or use the deprecated API. - else: - for attr in xattr.listxattr(name): - val = xattr.getxattr(name, attr) - attrs.append((attr, val)) - - for attr, val in attrs: - # Skip all attrs that are not supported (e.g. selinux). - if not attr in self.SUPPORTED_XATTRS: - continue - - logging.debug("Saving xattr %s=%s from %s" % (attr, val, name)) - - tarinfo.pax_headers[attr] = val + # Save capabilities. + caps = util.get_capabilities(name) + if caps: + logging.debug("Saving capabilities for %s: %s" % (name, caps)) + tarinfo.pax_headers["PAKFIRE.capabilities"] = caps # Append the tar header and data to the archive. f = tarfile.bltn_open(name, "rb") @@ -111,19 +95,16 @@ class InnerTarFile(tarfile.TarFile): logging.warning(_("Could not extract file: /%(src)s - %(dst)s") \ % { "src" : member.name, "dst" : e, }) - # ...and then apply the extended attributes. - if member.pax_headers: - for attr, val in member.pax_headers.items(): - # Skip all attrs that are not supported (e.g. selinux). - if not attr in self.SUPPORTED_XATTRS: - continue - - logging.debug("Restoring xattr %s=%s to %s" % (attr, val, target)) - if hasattr(xattr, "set"): - xattr.set(target, attr, val) + if path: + target = os.path.join(path, member.name) + else: + target = "/%s" % member.name - else: - xattr.setxattr(target, attr, val) + # ...and then apply the capabilities. + caps = member.pax_headers.get("PAKFIRE.capabilities", None) + if caps: + logging.debug("Restoring capabilities for /%s: %s" % (member.name, caps)) + util.set_capabilities(target, caps) class FilePackage(Package): diff --git a/python/pakfire/packages/packager.py b/python/pakfire/packages/packager.py index 9a4b658aa..57273c092 100644 --- a/python/pakfire/packages/packager.py +++ b/python/pakfire/packages/packager.py @@ -34,7 +34,6 @@ import tarfile import tempfile import time import uuid -import xattr import zlib import pakfire.compress diff --git a/python/pakfire/util.py b/python/pakfire/util.py index 7d1690ab5..58c34a2ab 100644 --- a/python/pakfire/util.py +++ b/python/pakfire/util.py @@ -39,8 +39,8 @@ import time from constants import * from i18n import _ -# Import binary version of version_compare -from _pakfire import version_compare +# Import binary version of version_compare and capability functions +from _pakfire import version_compare, get_capabilities, set_capabilities def cli_is_interactive(): """ diff --git a/python/src/Makefile b/python/src/Makefile index 2e0062623..190bfc847 100644 --- a/python/src/Makefile +++ b/python/src/Makefile @@ -5,7 +5,7 @@ include ../../Makeconfig MODULENAME = _pakfire.so # Libs that are to be linked into the module. -MODULELIBS = -lpython$(PYTHON_VERSION) -lsolv -lsolvext +MODULELIBS = -lcap -lpython$(PYTHON_VERSION) -lsolv -lsolvext SOURCES = $(wildcard *.c) OBJECTS = $(patsubst %.c,%.o,$(SOURCES)) diff --git a/python/src/_pakfiremodule.c b/python/src/_pakfiremodule.c index 6e1870fed..d5e63db4d 100644 --- a/python/src/_pakfiremodule.c +++ b/python/src/_pakfiremodule.c @@ -20,6 +20,7 @@ #include +#include "capabilities.h" #include "config.h" #include "pool.h" #include "problem.h" @@ -35,6 +36,8 @@ static PyMethodDef pakfireModuleMethods[] = { {"version_compare", (PyCFunction)version_compare, METH_VARARGS, NULL}, + {"get_capabilities", (PyCFunction)get_capabilities, METH_VARARGS, NULL}, + {"set_capabilities", (PyCFunction)set_capabilities, METH_VARARGS, NULL}, { NULL, NULL, 0, NULL } }; diff --git a/python/src/capabilities.c b/python/src/capabilities.c new file mode 100644 index 000000000..c33607a7f --- /dev/null +++ b/python/src/capabilities.c @@ -0,0 +1,104 @@ +/*############################################################################# +# # +# Pakfire - The IPFire package management system # +# Copyright (C) 2011 Pakfire development team # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +#############################################################################*/ + +#include + +#include +#include + +#include "config.h" + +PyObject * +get_capabilities(PyObject *self, PyObject *args) { + const char *filename; + cap_t cap_d; + char *exception = NULL; + + if (!PyArg_ParseTuple(args, "s", &filename)) { + /* XXX raise exception */ + return NULL; + } + + cap_d = cap_get_file(filename); + if (cap_d == NULL) { + if (errno != ENODATA) { + snprintf(exception, STRING_SIZE - 1, "Failed to get capabilities of file %s (%s).", + filename, strerror(errno)); + PyErr_SetString(PyExc_RuntimeError, exception); + return NULL; + } + Py_RETURN_NONE; + } + + char *result = cap_to_text(cap_d, NULL); + cap_free(cap_d); + + if (!result) { + snprintf(exception, STRING_SIZE - 1, "Failed to get capabilities of human readable format at %s (%s).", + filename, strerror(errno)); + PyErr_SetString(PyExc_RuntimeError, exception); + return NULL; + } + + // Remove leading two characters '= '. + int i; + for (i = 0; i < 2; i++) { + result++; + } + + PyObject * ret = Py_BuildValue("s", result); + cap_free(result); + + return ret; +} + +PyObject * +set_capabilities(PyObject *self, PyObject *args) { + const char *filename; + const char *input; + char *exception = NULL; + char buf[STRING_SIZE]; + cap_t cap_d; + int ret; + + if (!PyArg_ParseTuple(args, "ss", &filename, &input)) { + /* XXX raise exception */ + return NULL; + } + + snprintf(buf, STRING_SIZE - 1, "= %s", input); + cap_d = cap_from_text(buf); + if (cap_d == NULL) { + PyErr_SetString(PyExc_ValueError, "Could not read capability string."); + return NULL; + } + + ret = cap_set_file(filename, cap_d); + cap_free(cap_d); + + if (ret != 0) { + snprintf(exception, STRING_SIZE - 1, "Failed to set capabilities on file %s (%s).", + filename, strerror(errno)); + PyErr_SetString(PyExc_RuntimeError, exception); + return NULL; + } + + return Py_BuildValue("i", ret); +} diff --git a/python/src/capabilities.h b/python/src/capabilities.h new file mode 100644 index 000000000..8f820cd5e --- /dev/null +++ b/python/src/capabilities.h @@ -0,0 +1,29 @@ +/*############################################################################# +# # +# Pakfire - The IPFire package management system # +# Copyright (C) 2011 Pakfire development team # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +#############################################################################*/ + +#ifndef PAKFIRE_CAPS_H +#define PAKFIRE_CAPS_H + +#include + +extern PyObject *get_capabilities(PyObject *self, PyObject *args); +extern PyObject *set_capabilities(PyObject *self, PyObject *args); + +#endif -- 2.39.5