From fae8d7cafb66e0da697cde71f7e9444165c76ff7 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Thu, 22 Nov 2012 14:49:54 +0000 Subject: New APIs: Implement Linux filesystem capabilities. This adds the following new APIs: - cap_get_file - cap_set_file --- README | 2 + TODO | 14 ------ configure.ac | 9 ++++ daemon/Makefile.am | 2 + daemon/cap.c | 131 +++++++++++++++++++++++++++++++++++++++++++++++++++ generator/actions.ml | 28 +++++++++++ po/POTFILES | 1 + src/MAX_PROC_NR | 2 +- 8 files changed, 174 insertions(+), 15 deletions(-) create mode 100644 daemon/cap.c diff --git a/README b/README index 1c0c6ef5..53804153 100644 --- a/README +++ b/README @@ -110,6 +110,8 @@ For basic functionality and the C tools: - getfacl, getfattr libraries and programs (optional) +- Linux capabilities library (libcap) (optional) + - netpbm, icoutils (optional) These programs are used to render icons from guests. diff --git a/TODO b/TODO index d0939bcf..295bcfe8 100644 --- a/TODO +++ b/TODO @@ -587,17 +587,3 @@ is very poorly designed and essentially impossible for us to use: particularly if we also want to maintain backwards compatibility with Ruby 1.8, and/or maintain volatile VALUEs on the stack. - -Filesystem capabilities ------------------------ - -We need to model filesystem capabilities through the API. This is -particularly important in order to be able to implement SCAP. - -Filesystem capabilities can be read and written using the libcap(3) -library and functions like cap_get_file, cap_set_file. - -Setting fs capabilities on a file sets the extended attribute -'security.capability' to a binary blob. These are implemented using a -Linux Security Module (security/capability.c) and presumably by -something in exec, but I couldn't see exactly how this works. diff --git a/configure.ac b/configure.ac index 6f930f5b..c79f3a7c 100644 --- a/configure.ac +++ b/configure.ac @@ -701,6 +701,15 @@ AC_CHECK_LIB([acl],[acl_from_text], ], [AC_MSG_WARN([POSIX acl library not found])]) +dnl Linux capabilities library (libcap) (highly recommended) +AC_CHECK_LIB([cap],[cap_from_text], + [AC_CHECK_HEADER([sys/capability.h], + [AC_SUBST([CAP_LIBS], [-lcap]) + AC_DEFINE([HAVE_CAP], [1], [Define to 1 if the Linux capabilities library (libcap) is available.]) + ], []) + ], + [AC_MSG_WARN([Linux capabilities library (libcap) not found])]) + dnl libvirt (highly recommended) AC_ARG_WITH([libvirt], [AS_HELP_STRING([--without-libvirt], diff --git a/daemon/Makefile.am b/daemon/Makefile.am index 2f70c8ee..46fa7c59 100644 --- a/daemon/Makefile.am +++ b/daemon/Makefile.am @@ -96,6 +96,7 @@ guestfsd_SOURCES = \ blkid.c \ blockdev.c \ btrfs.c \ + cap.c \ checksum.c \ cmp.c \ command.c \ @@ -183,6 +184,7 @@ guestfsd_LDADD = \ liberrnostring.a \ libprotocol.a \ $(ACL_LIBS) \ + $(CAP_LIBS) \ $(SELINUX_LIB) \ $(AUGEAS_LIBS) \ $(HIVEX_LIBS) \ diff --git a/daemon/cap.c b/daemon/cap.c new file mode 100644 index 00000000..3572704c --- /dev/null +++ b/daemon/cap.c @@ -0,0 +1,131 @@ +/* libguestfs - the guestfsd daemon + * Copyright (C) 2012 Red Hat Inc. + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include + +#include +#include +#include + +#include "guestfs_protocol.h" +#include "daemon.h" +#include "actions.h" +#include "optgroups.h" + +#if defined(HAVE_CAP) + +#include + +int +optgroup_linuxcaps_available (void) +{ + return 1; +} + +char * +do_cap_get_file (const char *path) +{ + cap_t cap; + char *r, *ret; + + CHROOT_IN; + cap = cap_get_file (path); + CHROOT_OUT; + + if (cap == NULL) { + reply_with_perror ("%s", path); + return NULL; + } + + r = cap_to_text (cap, NULL); + if (r == NULL) { + reply_with_perror ("cap_to_text"); + cap_free (cap); + return NULL; + } + + cap_free (cap); + + /* 'r' is not an ordinary pointer that can be freed with free(3)! + * In the current implementation of libcap, if you try to do that it + * will segfault. We have to duplicate this into an ordinary + * buffer, then call cap_free (r). + */ + ret = strdup (r); + if (ret == NULL) { + reply_with_perror ("strdup"); + cap_free (r); + return NULL; + } + cap_free (r); + + return ret; /* caller frees */ +} + +int +do_cap_set_file (const char *path, const char *capstr) +{ + cap_t cap; + int r; + + cap = cap_from_text (capstr); + if (cap == NULL) { + reply_with_perror ("could not parse cap string: %s: cap_from_text", capstr); + return -1; + } + + CHROOT_IN; + r = cap_set_file (path, cap); + CHROOT_OUT; + + if (r == -1) { + reply_with_perror ("%s", path); + cap_free (cap); + return -1; + } + + cap_free (cap); + + return 0; +} + +#else /* no libcap */ + +/* Note that the wrapper code (daemon/stubs.c) ensures that the + * functions below are never called because + * optgroup_linuxcaps_available returns false. + */ +int +optgroup_linuxcaps_available (void) +{ + return 0; +} + +char * +do_cap_get_file (const char *path) +{ + abort (); +} + +int +do_cap_set_file (const char *path, const char *cap) +{ + abort (); +} + +#endif /* no libcap */ diff --git a/generator/actions.ml b/generator/actions.ml index 0a222273..bf0e82b1 100644 --- a/generator/actions.ml +++ b/generator/actions.ml @@ -10490,6 +10490,34 @@ C is a directory. This function deletes the default POSIX Access Control List (ACL) attached to directory C." }; + { defaults with + name = "cap_get_file"; + style = RString "cap", [Pathname "path"], []; + proc_nr = Some 378; + optional = Some "linuxcaps"; + tests = []; (* tested by cap_set_file *) + shortdesc = "get the Linux capabilities attached to a file"; + longdesc = "\ +This function returns the Linux capabilities attached to C. +The capabilities set is returned in text form (see L)." }; + + { defaults with + name = "cap_set_file"; + style = RErr, [Pathname "path"; String "cap"], []; + proc_nr = Some 379; + optional = Some "linuxcaps"; + tests = [ + InitScratchFS, Always, TestOutput ( + [["touch"; "/cap_set_file_0"]; + ["cap_set_file"; "/cap_set_file_0"; "cap_chown=p cap_chown+e"]; + ["cap_get_file"; "/cap_set_file_0"]], "= cap_chown+ep"); + ]; + shortdesc = "set the Linux capabilities attached to a file"; + longdesc = "\ +This function sets the Linux capabilities attached to C. +The capabilities set C should be passed in text form +(see L)." }; + ] (* Non-API meta-commands available only in guestfish. diff --git a/po/POTFILES b/po/POTFILES index 7e289eb9..9cd667ef 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -11,6 +11,7 @@ daemon/base64.c daemon/blkid.c daemon/blockdev.c daemon/btrfs.c +daemon/cap.c daemon/checksum.c daemon/cmp.c daemon/command.c diff --git a/src/MAX_PROC_NR b/src/MAX_PROC_NR index 66a899ac..3b2f92ea 100644 --- a/src/MAX_PROC_NR +++ b/src/MAX_PROC_NR @@ -1 +1 @@ -377 +379 -- cgit