New APIs: Implement POSIX ACLs.

This adds the following new APIs:
 - acl_get_file
 - acl_set_file
 - acl_delete_def_file
This commit is contained in:
Richard W.M. Jones
2012-11-22 14:49:54 +00:00
parent 784e53287e
commit 218b39acae
7 changed files with 274 additions and 14 deletions

17
TODO
View File

@@ -588,20 +588,11 @@ 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.
ACLs and capabilities
---------------------
Filesystem capabilities
-----------------------
We need to model both filesystem ACLs and filesystem capabilities
through the API. This is particularly important in order to be able
to implement SCAP.
ACLs can be read and written using the acl(5) library and the
functions like acl_set_file(3) etc.
Setting the ACL on a file sets the extended attribute
'system.posix_acl_access' to a binary blob. The kernel has a whole
bunch of complex code that seems to interpret these
(linux/fs/posix_acl.c).
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.

View File

@@ -692,6 +692,15 @@ AC_CHECK_LIB([magic],[magic_file],
],
[AC_MSG_WARN([libmagic not found, some core features will be disabled])])
dnl POSIX acl library (highly recommended)
AC_CHECK_LIB([acl],[acl_from_text],
[AC_CHECK_HEADER([sys/acl.h],
[AC_SUBST([ACL_LIBS], [-lacl])
AC_DEFINE([HAVE_ACL], [1], [Define to 1 if the POSIX acl library is available.])
], [])
],
[AC_MSG_WARN([POSIX acl library not found])])
dnl libvirt (highly recommended)
AC_ARG_WITH([libvirt],
[AS_HELP_STRING([--without-libvirt],

View File

@@ -88,6 +88,7 @@ endif
guestfsd_SOURCES = \
9p.c \
acl.c \
actions.h \
available.c \
augeas.c \
@@ -181,6 +182,7 @@ guestfsd_SOURCES = \
guestfsd_LDADD = \
liberrnostring.a \
libprotocol.a \
$(ACL_LIBS) \
$(SELINUX_LIB) \
$(AUGEAS_LIBS) \
$(HIVEX_LIBS) \

175
daemon/acl.c Normal file
View File

@@ -0,0 +1,175 @@
/* 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 <config.h>
#include <stdio.h>
#include <limits.h>
#include <unistd.h>
#include "guestfs_protocol.h"
#include "daemon.h"
#include "actions.h"
#include "optgroups.h"
#if defined(HAVE_ACL)
#include <sys/types.h>
#include <sys/acl.h>
int
optgroup_acl_available (void)
{
return 1;
}
char *
do_acl_get_file (const char *path, const char *acltype)
{
acl_type_t t;
acl_t acl;
char *r, *ret;
if (STREQ (acltype, "access"))
t = ACL_TYPE_ACCESS;
else if (STREQ (acltype, "default"))
t = ACL_TYPE_DEFAULT;
else {
reply_with_error ("invalid acltype parameter: %s", acltype);
return NULL;
}
CHROOT_IN;
acl = acl_get_file (path, t);
CHROOT_OUT;
if (acl == NULL) {
reply_with_perror ("%s", path);
return NULL;
}
r = acl_to_text (acl, NULL);
if (r == NULL) {
reply_with_perror ("acl_to_text");
acl_free (acl);
return NULL;
}
acl_free (acl);
/* 'r' is not an ordinary pointer that can be freed with free(3)!
* In the current implementation of libacl, if you try to do that it
* will segfault. We have to duplicate this into an ordinary
* buffer, then call acl_free (r).
*/
ret = strdup (r);
if (ret == NULL) {
reply_with_perror ("strdup");
acl_free (r);
return NULL;
}
acl_free (r);
return ret; /* caller frees */
}
int
do_acl_set_file (const char *path, const char *acltype, const char *aclstr)
{
acl_type_t t;
acl_t acl;
int r;
if (STREQ (acltype, "access"))
t = ACL_TYPE_ACCESS;
else if (STREQ (acltype, "default"))
t = ACL_TYPE_DEFAULT;
else {
reply_with_error ("invalid acltype parameter: %s", acltype);
return -1;
}
acl = acl_from_text (aclstr);
if (acl == NULL) {
reply_with_perror ("could not parse acl string: %s: acl_from_text", aclstr);
return -1;
}
CHROOT_IN;
r = acl_set_file (path, t, acl);
CHROOT_OUT;
if (r == -1) {
reply_with_perror ("%s", path);
acl_free (acl);
return -1;
}
acl_free (acl);
return 0;
}
int
do_acl_delete_def_file (const char *dir)
{
int r;
CHROOT_IN;
r = acl_delete_def_file (dir);
CHROOT_OUT;
if (r == -1) {
reply_with_perror ("%s", dir);
return -1;
}
return 0;
}
#else /* no acl library */
/* Note that the wrapper code (daemon/stubs.c) ensures that the
* functions below are never called because
* optgroup_acl_available returns false.
*/
int
optgroup_acl_available (void)
{
return 0;
}
char *
do_acl_get_file (const char *path, const char *acltype)
{
abort ();
}
int
do_acl_set_file (const char *path, const char *acltype, const char *acl)
{
abort ();
}
int
do_acl_delete_def_file (const char *dir)
{
abort ();
}
#endif /* no acl library */

View File

@@ -10408,6 +10408,88 @@ Make the C<lost+found> directory, normally in the root directory
of an ext2/3/4 filesystem. C<mountpoint> is the directory under
which we try to create the C<lost+found> directory." };
{ defaults with
name = "acl_get_file";
style = RString "acl", [Pathname "path"; String "acltype"], [];
proc_nr = Some 375;
optional = Some "acl";
tests = []; (* tested by acl_set_file *)
shortdesc = "get the POSIX ACL attached to a file";
longdesc = "\
This function returns the POSIX Access Control List (ACL) attached
to C<path>. The ACL is returned in \"long text form\" (see L<acl(5)>).
The C<acltype> parameter may be:
=over 4
=item C<access>
Return the ordinary (access) ACL for any file, directory or
other filesystem object.
=item C<default>
Return the default ACL. Normally this only makes sense if
C<path> is a directory.
=back" };
{ defaults with
name = "acl_set_file";
style = RErr, [Pathname "path"; String "acltype"; String "acl"], [];
proc_nr = Some 376;
optional = Some "acl";
tests = [
InitScratchFS, Always, TestRun (
[["touch"; "/acl_set_file_0"];
["acl_set_file"; "/acl_set_file_0"; "access"; "user::r-x,group::r-x,other::r-x"];
["acl_get_file"; "/acl_set_file_0"; "access"]]);
];
shortdesc = "set the POSIX ACL attached to a file";
longdesc = "\
This function sets the POSIX Access Control List (ACL) attached
to C<path>. The C<acl> parameter is the new ACL in either
\"long text form\" or \"short text form\" (see L<acl(5)>).
The C<acltype> parameter may be:
=over 4
=item C<access>
Set the ordinary (access) ACL for any file, directory or
other filesystem object.
=item C<default>
Set the default ACL. Normally this only makes sense if
C<path> is a directory.
=back" };
{ defaults with
name = "acl_delete_def_file";
style = RErr, [Pathname "dir"], [];
proc_nr = Some 377;
optional = Some "acl";
tests = [
(* Documentation for libacl says this should fail, but it doesn't.
* Therefore disable this test.
*)
InitScratchFS, Disabled, TestLastFail (
[["touch"; "/acl_delete_def_file_0"];
["acl_delete_def_file"; "/acl_delete_def_file_0"]]);
InitScratchFS, Always, TestRun (
[["mkdir"; "/acl_delete_def_file_1"];
["acl_set_file"; "/acl_delete_def_file_1"; "default"; "user::r-x,group::r-x,other::r-x"];
["acl_delete_def_file"; "/acl_delete_def_file_1"]]);
];
shortdesc = "delete the default POSIX ACL of a directory";
longdesc = "\
This function deletes the default POSIX Access Control List (ACL)
attached to directory C<dir>." };
]
(* Non-API meta-commands available only in guestfish.

View File

@@ -4,6 +4,7 @@ cat/virt-cat.c
cat/virt-filesystems.c
cat/virt-ls.c
daemon/9p.c
daemon/acl.c
daemon/augeas.c
daemon/available.c
daemon/base64.c

View File

@@ -1 +1 @@
374
377