mirror of
https://git.savannah.gnu.org/git/coreutils.git
synced 2025-09-10 07:59:52 +02:00
Compare commits
30 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9aee8e78ea | ||
|
|
ab511a2106 | ||
|
|
5e711ff948 | ||
|
|
6f5700ac8a | ||
|
|
8daf081cd2 | ||
|
|
3f619c59cf | ||
|
|
0db199df69 | ||
|
|
beb12e09f3 | ||
|
|
65ba507e17 | ||
|
|
795c052e33 | ||
|
|
09ef5a443f | ||
|
|
3765e5a26e | ||
|
|
b64a11dc76 | ||
|
|
82d98da743 | ||
|
|
ecf70125f9 | ||
|
|
1b569150c5 | ||
|
|
4269a52c1a | ||
|
|
b23de86834 | ||
|
|
7782da7bf5 | ||
|
|
2b5e4cb837 | ||
|
|
5f997760c9 | ||
|
|
10ca93af8f | ||
|
|
0278a4d7d3 | ||
|
|
2aab34d486 | ||
|
|
2912097e82 | ||
|
|
3238605998 | ||
|
|
1e9098dc83 | ||
|
|
27940f5d02 | ||
|
|
561c3a2b75 | ||
|
|
c1fb4bcb2a |
@@ -8,6 +8,7 @@ Makefile
|
||||
Makefile.in
|
||||
THANKS-to-translators
|
||||
aclocal.m4
|
||||
chcon
|
||||
config.status
|
||||
configure
|
||||
coreutils-*
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -13,6 +13,7 @@ Makefile.in
|
||||
THANKS-to-translators
|
||||
aclocal.m4
|
||||
autom4te.cache
|
||||
chcon
|
||||
config.cache
|
||||
config.h
|
||||
config.hin
|
||||
|
||||
2
AUTHORS
2
AUTHORS
@@ -4,6 +4,7 @@ each followed by the name(s) of its author(s).
|
||||
base64: Simon Josefsson
|
||||
basename: FIXME unknown
|
||||
cat: Torbjorn Granlund, Richard M. Stallman
|
||||
chcon: Russell Coker, Jim Meyering
|
||||
chgrp: David MacKenzie, Jim Meyering
|
||||
chmod: David MacKenzie, Jim Meyering
|
||||
chown: David MacKenzie, Jim Meyering
|
||||
@@ -60,6 +61,7 @@ pwd: Jim Meyering
|
||||
readlink: Dmitry V. Levin
|
||||
rm: Paul Rubin, David MacKenzie, Richard Stallman, Jim Meyering
|
||||
rmdir: David MacKenzie
|
||||
runcon: Russell Coker
|
||||
seq: Ulrich Drepper
|
||||
sha1sum: Ulrich Drepper, Scott Miller, David Madore
|
||||
sha224sum: Ulrich Drepper, Scott Miller, David Madore
|
||||
|
||||
@@ -486,9 +486,17 @@
|
||||
consistent, so this can be applied with patch -p0.
|
||||
Reported by Matthew Woehlke.
|
||||
|
||||
Arrange for "make check-root" to run the new root-only test.
|
||||
* tests/Makefile.am (t9): New target, to run tests/cp/cp-a-selinux.
|
||||
(all_t): Add t9.
|
||||
|
||||
* Makefile.maint (patch-check): Use patch with its -p2 option,
|
||||
since that makes this check slightly more strict.
|
||||
|
||||
Use a directory on a loopback device mounted with -o context=...
|
||||
* tests/cp/cp-a-selinux: Since this test now runs mount and umount,
|
||||
it is a root-only one.
|
||||
|
||||
2007-01-29 Jim Meyering <jim@meyering.net>
|
||||
|
||||
Plug a leak in ls.
|
||||
|
||||
208
ChangeLog-selinux
Normal file
208
ChangeLog-selinux
Normal file
@@ -0,0 +1,208 @@
|
||||
2007-03-18 Jim Meyering <jim@meyering.net>
|
||||
|
||||
* src/runcon.c (main): Don't reorder arguments. Reported by
|
||||
Ulrich Drepper in <http://bugzilla.redhat.com/232652>.
|
||||
* tests/misc/runcon-no-reorder: New file. Test for the above.
|
||||
* tests/misc/Makefile.am (TESTS): Add runcon-no-reorder.
|
||||
|
||||
* src/runcon.c (main): Remove "." at end of a diagnostic.
|
||||
|
||||
2007-02-02 Jim Meyering <jim@meyering.net>
|
||||
|
||||
* src/runcon.c: New program.
|
||||
* src/Makefile.am (bin_PROGRAMS): Add runcon.
|
||||
(runcon_LDADD): Define.
|
||||
* README: Add runcon to the list of programs.
|
||||
* AUTHORS: Add this: runcon: Russell Coker
|
||||
* tests/help-version: Add runcon as an exception.
|
||||
* man/Makefile.am (dist_man_MANS): Add runcon.1.
|
||||
(runcon.1): New dependency.
|
||||
|
||||
2007-01-31 Jim Meyering <jim@meyering.net>
|
||||
|
||||
mkfifo, mknod: Accept new "-Z, --context=C" option.
|
||||
* src/mkfifo.c, src/mknod.c: Include <selinux/selinux.h>.
|
||||
(main): Honor it.
|
||||
* src/Makefile.am (mkfifo_LDADD, mknod_LDADD): Use $(LIB_SELINUX).
|
||||
|
||||
mkdir: Accept new "-Z, --context=C" option.
|
||||
* src/mkdir.c: Include <selinux/selinux.h>.
|
||||
(main): Honor it.
|
||||
* src/Makefile.am (mkdir_LDADD): Use $(LIB_SELINUX).
|
||||
|
||||
* tests/cp/cp-a-selinux: New file. Test for the bug reported in
|
||||
<http://bugzilla.redhat.com/219900>.
|
||||
* tests/cp/Makefile.am (TESTS): Add cp-a-selinux.
|
||||
|
||||
* tests/selinux: New file.
|
||||
* tests/Makefile.am (EXTRA_DIST): Add selinux.
|
||||
* tests/misc/selinux: Source the new script, rather than open coding it.
|
||||
|
||||
Change how "cp -a" and "cp --preserve=context" work with SELinux.
|
||||
Now, cp -a attempts to preserve context, but failure to do so does
|
||||
not change cp's exit status. However "cp --preserve=context" is
|
||||
similar, but failure *does* cause cp to exit with nonzero status.
|
||||
* src/copy.h (struct cp_options) [require_preserve_context]: New member.
|
||||
* src/copy.c (copy_reg, copy_internal): Implement the above.
|
||||
* src/mv.c (cp_option_init): Initialize the new member.
|
||||
* src/install.c (cp_option_init): Likewise.
|
||||
* src/cp.c (cp_option_init): Likewise.
|
||||
(decode_preserve_arg): Set it or reset it.
|
||||
|
||||
FIXME: add an on-writable-NFS-only test
|
||||
|
||||
2007-01-20 Jim Meyering <jim@meyering.net>
|
||||
|
||||
cp, mv, install: add SELinux support, but unlike with the Red Hat
|
||||
patch, mv and cp do not provide the "-Z context" option.
|
||||
* src/copy.c: Include <selinux/selinux.h>.
|
||||
(restore_default_fscreatecon): New function.
|
||||
(copy_reg): Make cp --preserve=context work for existing destination.
|
||||
(copy_internal): Likewise for new destinations.
|
||||
* src/copy.h (cp_options) [preserve_security_context]: New member.
|
||||
* src/cp.c: Include <selinux/selinux.h>.
|
||||
(selinux_enabled): New global.
|
||||
(usage): Mention new --preserve=context option.
|
||||
(PRESERVE_CONTEXT): Define/use.
|
||||
(decode_preserve_arg): Handle PRESERVE_CONTEXT.
|
||||
(main): Remove an obsolete comment.
|
||||
If --preserve=context is specified on a system without SELinux
|
||||
enabled, give a diagnostic and fail.
|
||||
* src/mv.c: Include <selinux/selinux.h>.
|
||||
Set x->preserve_security_context if SELinux is enabled.
|
||||
* src/install.c: Accept new "-Z, --context=C" option.
|
||||
Accept --preserve-context option (but not -P option).
|
||||
Accept alternate spelling: --preserve_context, for now.
|
||||
Include <selinux/selinux.h> and "quotearg.h".
|
||||
(selinux_enabled, use_default_selinux_context): New globals.
|
||||
(PRESERVE_CONTEXT_OPTION): Define.
|
||||
(cp_option_init): Default: do not preserve security context.
|
||||
(setdefaultfilecon): New function.
|
||||
(main): Honor new options.
|
||||
* src/Makefile.am (mv_LDADD, cp_LDADD, ginstall_LDADD):
|
||||
Add $(LIB_SELINUX).
|
||||
* src/system.h (GETOPT_SELINUX_CONTEXT_OPTION_DECL): Define.
|
||||
|
||||
* tests/misc/selinux [VERBOSE]: Print version info for each
|
||||
of the tested tools, not just ls.
|
||||
|
||||
* src/c99-to-c89.diff: Remove the ls.c patch, now that I've
|
||||
temporarily removed the offending c99'ism.
|
||||
|
||||
* src/chcon.c (usage): Split a string literal that was longer than 509.
|
||||
|
||||
* src/ls.c (gobble_file): Don't call getfilecon unless print_scontext.
|
||||
Upon failed getfilecon, accept not just ENOTSUP, but also ENODATA.
|
||||
|
||||
* src/c99-to-c89.diff: Adjust offsets.
|
||||
|
||||
* AUTHORS: Add chcon.
|
||||
|
||||
* src/c99-to-c89.diff: Remove trailing blanks.
|
||||
|
||||
* src/chcon.c: Don't include "dirname.h". system.h already includes it.
|
||||
|
||||
* gl/lib/selinux-at.c: Remove a use of HAVE_CONFIG_H.
|
||||
|
||||
* src/c99-to-c89.diff: Handle a new c99'ism in ls.c.
|
||||
|
||||
* src/id.c (main): Tweak id -Z diagnostic.
|
||||
|
||||
id: Add SELinux support: -Z option.
|
||||
* src/id.c (main): Apply patches from Fedora, with these changes:
|
||||
Remove #ifdef WITH_SELINUX.
|
||||
Use error (EXIT_FAILURE, not fprintf+exit(1).
|
||||
* src/Makefile.am (id_LDADD): Define, so as to add $(LIB_SELINUX).
|
||||
|
||||
2007-01-06 Jim Meyering <jim@meyering.net>
|
||||
|
||||
stat: Add support for SELinux in the form of a %C format directive.
|
||||
* src/stat.c (follow_links): Make this variable file-global.
|
||||
(out_file_context): New function.
|
||||
(print_statfs): Honor %C.
|
||||
(print_stat): Honor %C.
|
||||
(do_stat): Remove follow_links parameter.
|
||||
(usage): Document the two %C directives.
|
||||
(main): Accept -Z (though it's a no-op).
|
||||
* src/Makefile.am (stat_LDADD): Define.
|
||||
|
||||
ls: Add support for SELinux and a slightly modified -Z option.
|
||||
I started with the patches from Red Hat.
|
||||
The entries below tell how the code evolved.
|
||||
|
||||
* src/ls.c (print_long_format, print_file_name_and_frills): When
|
||||
there is no security context (due to getfilecon/lgetfilecon failing
|
||||
with e.g. ENOTSUP), print it as "?", not "".
|
||||
* src/ls.c (print_file_name_and_frills): Make -Z work without -l.
|
||||
(length_of_file_name_and_frills): Likewise.
|
||||
|
||||
* src/ls.c: Remove the --lcontext and --scontext options.
|
||||
Change the way -Z, --context work so that it no longer implies -l.
|
||||
Thus, -Z -l will work like -lcontext and -Z without -l will work
|
||||
like --scontext.
|
||||
|
||||
Adjust tests to reflect new 'ls -l' syntax -- affects only
|
||||
systems with SELinux when operating on a file with no ACL.
|
||||
These tests assumed that everything before the first space on
|
||||
each line is the 10-byte mode string. But there may also be a "+"
|
||||
in the 11th column, just before the space. However, note that this
|
||||
is not new. The same thing would have happened even without the
|
||||
change below, when listing a file with an ACL.
|
||||
* tests/chmod/equals, tests/cp/cp-parents, tests/cp/fail-perm:
|
||||
* tests/cp/link-preserve, tests/install/basic-1, tests/misc/mknod:
|
||||
* tests/mkdir/parents, tests/mkdir/special-1, tests/mv/partition-perm:
|
||||
|
||||
Don't make compilation depend on USE_ACL. An SELinux security
|
||||
context counts as an "alternate access control method", so ls
|
||||
must output a "+" for each file with a security context.
|
||||
* src/ls.c [struct fileinfo] (have_acl): Declare unconditionally.
|
||||
(FILE_HAS_ACL): Remove macro definition. Use f->have_acl directly.
|
||||
(gobble_file): Record whether a file has a security context, and
|
||||
update the condition used to determine whether to print the "+".
|
||||
(gobble_file): Call getfilecon/lgetfilecon also when
|
||||
format == long_format, so that we get the "+".
|
||||
|
||||
* src/ls.c (gobble_file): Add a comment explaining why (with a
|
||||
security context option) ls doesn't exit nonzero due to e.g.,
|
||||
getfilecon failing with errno == ENOTSUP.
|
||||
|
||||
* src/ls.c (gobble_file): Ignore failure of getfilecon if it's due
|
||||
to ENOTSUP.
|
||||
|
||||
* src/ls.c (gobble_file): Factor out three small blocks using
|
||||
getfilecon and lgetfilecon.
|
||||
Don't ignore return value from getfilecon and lgetfilecon.
|
||||
|
||||
* src/ls.c (print_long_format): Don't use ?: (empty 2nd arg with C
|
||||
ternary operator).
|
||||
(print_scontext_format): Likewise.
|
||||
(print_scontext): Declare to be "bool", not int. Adjust uses.
|
||||
|
||||
* src/Makefile.am (dir_LDADD, ls_LDADD, vdir_LDADD): Add $(LIB_SELINUX).
|
||||
|
||||
* tests/misc/chcon: New file.
|
||||
* tests/misc/chcon-fail: New file.
|
||||
* tests/Makefile.am (check-root): Run new, root-only misc/chcon test.
|
||||
* tests/misc/Makefile.am (TESTS): Add chcon and chcon-fail.
|
||||
|
||||
* tests/misc/Makefile.am (TESTS): Add selinux.
|
||||
* tests/misc/selinux: New file.
|
||||
* tests/help-version: Skip chcon.
|
||||
* man/chcon.x: New file.
|
||||
* man/Makefile.am: Build chcon.1.
|
||||
|
||||
New program: chcon
|
||||
* gl/modules/selinux-at: New module. Check for libselinux and set
|
||||
LIB_SELINUX here, unconditionally, rather than depending on
|
||||
the configure-time --enable-selinux option.
|
||||
* gl/modules/selinux-h: New module.
|
||||
* bootstrap.conf (gnulib_modules): Add selinux-at.
|
||||
* gl/lib/selinux-at.c, gl/lib/selinux-at.h: New files.
|
||||
* gl/lib/se-selinux_.h: New file.
|
||||
* gl/lib/se-context_.h: New file.
|
||||
* gl/m4/selinux-selinux-h.m4: New file.
|
||||
* gl/m4/selinux-context-h.m4: New file.
|
||||
* src/Makefile.am (bin_PROGRAMS): Add chcon.
|
||||
(chcon_LDADD): Define.
|
||||
* README: Add chcon to the list of programs.
|
||||
* src/chcon.c: Rewrite the original (Red Hat) chcon to use fts.
|
||||
16
README
16
README
@@ -7,14 +7,14 @@ arbitrary limits.
|
||||
|
||||
The programs that can be built with this package are:
|
||||
|
||||
[ base64 basename cat chgrp chmod chown chroot cksum comm cp csplit cut date
|
||||
dd df dir dircolors dirname du echo env expand expr factor false fmt fold
|
||||
ginstall groups head hostid hostname id join kill link ln logname ls
|
||||
md5sum mkdir mkfifo mknod mv nice nl nohup od paste pathchk pinky pr
|
||||
printenv printf ptx pwd readlink rm rmdir seq sha1sum sha224sum sha256sum
|
||||
sha384sum sha512sum shred shuf sleep sort split stat stty su sum sync tac
|
||||
tail tee test touch tr true tsort tty uname unexpand uniq unlink uptime
|
||||
users vdir wc who whoami yes
|
||||
[ base64 basename cat chcon chgrp chmod chown chroot cksum comm cp
|
||||
csplit cut date dd df dir dircolors dirname du echo env expand expr
|
||||
factor false fmt fold ginstall groups head hostid hostname id join
|
||||
kill link ln logname ls md5sum mkdir mkfifo mknod mv nice nl nohup
|
||||
od paste pathchk pinky pr printenv printf ptx pwd readlink rm rmdir
|
||||
runcon seq sha1sum sha224sum sha256sum sha384sum sha512sum shred shuf
|
||||
sleep sort split stat stty su sum sync tac tail tee test touch tr true
|
||||
tsort tty uname unexpand uniq unlink uptime users vdir wc who whoami yes
|
||||
|
||||
See the file NEWS for a list of major changes in the current release.
|
||||
|
||||
|
||||
@@ -60,7 +60,9 @@ gnulib_modules="
|
||||
root-dev-ino
|
||||
rpmatch
|
||||
safe-read same
|
||||
save-cwd savedir savewd settime sha1 sig2str ssize_t stat-macros
|
||||
save-cwd savedir savewd
|
||||
selinux-at
|
||||
settime sha1 sig2str ssize_t stat-macros
|
||||
stat-time stdbool stdlib-safer stpcpy strftime
|
||||
strpbrk strtoimax strtoumax strverscmp sys_stat timespec tzset
|
||||
unicodeio unistd-safer unlink-busy unlinkdir unlocked-io
|
||||
|
||||
31
gl/lib/se-context_.h
Normal file
31
gl/lib/se-context_.h
Normal file
@@ -0,0 +1,31 @@
|
||||
#ifndef SELINUX_CONTEXT_H
|
||||
# define SELINUX_CONTEXT_H
|
||||
|
||||
# include <errno.h>
|
||||
/* Some systems don't have ENOSYS. */
|
||||
# ifndef ENOSYS
|
||||
# ifdef ENOTSUP
|
||||
# define ENOSYS ENOTSUP
|
||||
# else
|
||||
/* Some systems don't have ENOTSUP either. */
|
||||
# define ENOSYS EINVAL
|
||||
# endif
|
||||
# endif
|
||||
|
||||
typedef int context_t;
|
||||
static inline context_t context_new (char const *s)
|
||||
{ errno = ENOTSUP; return 0; }
|
||||
static inline char *context_str (context_t con)
|
||||
{ errno = ENOTSUP; return (void *) 0; }
|
||||
static inline void context_free (context_t c) {}
|
||||
|
||||
static inline int context_user_set (context_t sc, char const *s)
|
||||
{ errno = ENOTSUP; return -1; }
|
||||
static inline int context_role_set (context_t sc, char const *s)
|
||||
{ errno = ENOTSUP; return -1; }
|
||||
static inline int context_range_set (context_t sc, char const *s)
|
||||
{ errno = ENOTSUP; return -1; }
|
||||
static inline int context_type_set (context_t sc, char const *s)
|
||||
{ errno = ENOTSUP; return -1; }
|
||||
|
||||
#endif
|
||||
54
gl/lib/se-selinux_.h
Normal file
54
gl/lib/se-selinux_.h
Normal file
@@ -0,0 +1,54 @@
|
||||
#ifndef SELINUX_SELINUX_H
|
||||
# define SELINUX_SELINUX_H
|
||||
|
||||
# include <sys/types.h>
|
||||
# include <errno.h>
|
||||
/* Some systems don't have ENOSYS. */
|
||||
# ifndef ENOSYS
|
||||
# ifdef ENOTSUP
|
||||
# define ENOSYS ENOTSUP
|
||||
# else
|
||||
/* Some systems don't have ENOTSUP either. */
|
||||
# define ENOSYS EINVAL
|
||||
# endif
|
||||
# endif
|
||||
|
||||
typedef unsigned short security_class_t;
|
||||
# define security_context_t char*
|
||||
# define is_selinux_enabled() 0
|
||||
|
||||
static inline int getcon (security_context_t *con) { errno = ENOTSUP; return -1; }
|
||||
static inline void freecon (security_context_t con) {}
|
||||
|
||||
|
||||
static inline int getfscreatecon (security_context_t *con)
|
||||
{ errno = ENOTSUP; return -1; }
|
||||
static inline int setfscreatecon (security_context_t con)
|
||||
{ errno = ENOTSUP; return -1; }
|
||||
static inline int matchpathcon (char const *s, mode_t m,
|
||||
security_context_t *con)
|
||||
{ errno = ENOTSUP; return -1; }
|
||||
|
||||
static inline int getfilecon (char const *s, security_context_t *con)
|
||||
{ errno = ENOTSUP; return -1; }
|
||||
static inline int lgetfilecon (char const *s, security_context_t *con)
|
||||
{ errno = ENOTSUP; return -1; }
|
||||
static inline int setfilecon (char const *s, security_context_t con)
|
||||
{ errno = ENOTSUP; return -1; }
|
||||
static inline int lsetfilecon (char const *s, security_context_t con)
|
||||
{ errno = ENOTSUP; return -1; }
|
||||
static inline int fsetfilecon (int fd, security_context_t con)
|
||||
{ errno = ENOTSUP; return -1; }
|
||||
|
||||
static inline int security_check_context (security_context_t con)
|
||||
{ errno = ENOTSUP; return -1; }
|
||||
static inline int security_check_context_raw (security_context_t con)
|
||||
{ errno = ENOTSUP; return -1; }
|
||||
static inline int setexeccon (security_context_t con)
|
||||
{ errno = ENOTSUP; return -1; }
|
||||
static inline int security_compute_create (security_context_t scon,
|
||||
security_context_t tcon,
|
||||
security_class_t tclass,
|
||||
security_context_t *newcon)
|
||||
{ errno = ENOTSUP; return -1; }
|
||||
#endif
|
||||
92
gl/lib/selinux-at.c
Normal file
92
gl/lib/selinux-at.c
Normal file
@@ -0,0 +1,92 @@
|
||||
/* openat-style fd-relative functions for SE Linux
|
||||
Copyright (C) 2007 Free Software Foundation, 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, 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. */
|
||||
|
||||
/* written by Jim Meyering */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "selinux-at.h"
|
||||
#include "openat.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "dirname.h" /* solely for definition of IS_ABSOLUTE_FILE_NAME */
|
||||
#include "save-cwd.h"
|
||||
|
||||
#include "gettext.h"
|
||||
#define _(msgid) gettext (msgid)
|
||||
|
||||
#include "openat-priv.h"
|
||||
|
||||
#define AT_FUNC_NAME getfileconat
|
||||
#define AT_FUNC_F1 getfilecon
|
||||
#define AT_FUNC_F2 getfilecon
|
||||
#define AT_FUNC_USE_F1_COND 1
|
||||
#define AT_FUNC_POST_FILE_PARAM_DECLS , security_context_t *con
|
||||
#define AT_FUNC_POST_FILE_ARGS , con
|
||||
#include "at-func.c"
|
||||
#undef AT_FUNC_NAME
|
||||
#undef AT_FUNC_F1
|
||||
#undef AT_FUNC_F2
|
||||
#undef AT_FUNC_USE_F1_COND
|
||||
#undef AT_FUNC_POST_FILE_PARAM_DECLS
|
||||
#undef AT_FUNC_POST_FILE_ARGS
|
||||
|
||||
#define AT_FUNC_NAME lgetfileconat
|
||||
#define AT_FUNC_F1 lgetfilecon
|
||||
#define AT_FUNC_F2 lgetfilecon
|
||||
#define AT_FUNC_USE_F1_COND 1
|
||||
#define AT_FUNC_POST_FILE_PARAM_DECLS , security_context_t *con
|
||||
#define AT_FUNC_POST_FILE_ARGS , con
|
||||
#include "at-func.c"
|
||||
#undef AT_FUNC_NAME
|
||||
#undef AT_FUNC_F1
|
||||
#undef AT_FUNC_F2
|
||||
#undef AT_FUNC_USE_F1_COND
|
||||
#undef AT_FUNC_POST_FILE_PARAM_DECLS
|
||||
#undef AT_FUNC_POST_FILE_ARGS
|
||||
|
||||
#define AT_FUNC_NAME setfileconat
|
||||
#define AT_FUNC_F1 setfilecon
|
||||
#define AT_FUNC_F2 setfilecon
|
||||
#define AT_FUNC_USE_F1_COND 1
|
||||
#define AT_FUNC_POST_FILE_PARAM_DECLS , security_context_t con
|
||||
#define AT_FUNC_POST_FILE_ARGS , con
|
||||
#include "at-func.c"
|
||||
#undef AT_FUNC_NAME
|
||||
#undef AT_FUNC_F1
|
||||
#undef AT_FUNC_F2
|
||||
#undef AT_FUNC_USE_F1_COND
|
||||
#undef AT_FUNC_POST_FILE_PARAM_DECLS
|
||||
#undef AT_FUNC_POST_FILE_ARGS
|
||||
|
||||
#define AT_FUNC_NAME lsetfileconat
|
||||
#define AT_FUNC_F1 lsetfilecon
|
||||
#define AT_FUNC_F2 lsetfilecon
|
||||
#define AT_FUNC_USE_F1_COND 1
|
||||
#define AT_FUNC_POST_FILE_PARAM_DECLS , security_context_t con
|
||||
#define AT_FUNC_POST_FILE_ARGS , con
|
||||
#include "at-func.c"
|
||||
#undef AT_FUNC_NAME
|
||||
#undef AT_FUNC_F1
|
||||
#undef AT_FUNC_F2
|
||||
#undef AT_FUNC_USE_F1_COND
|
||||
#undef AT_FUNC_POST_FILE_PARAM_DECLS
|
||||
#undef AT_FUNC_POST_FILE_ARGS
|
||||
24
gl/lib/selinux-at.h
Normal file
24
gl/lib/selinux-at.h
Normal file
@@ -0,0 +1,24 @@
|
||||
/* Prototypes for openat-style fd-relative SELinux functions
|
||||
Copyright (C) 2007 Free Software Foundation, 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, 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 <selinux/selinux.h>
|
||||
#include <selinux/context.h>
|
||||
|
||||
int getfileconat (int fd, char const *file, security_context_t *con);
|
||||
int lgetfileconat (int fd, char const *file, security_context_t *con);
|
||||
int setfileconat (int fd, char const *file, security_context_t con);
|
||||
int lsetfileconat (int fd, char const *file, security_context_t con);
|
||||
18
gl/m4/selinux-context-h.m4
Normal file
18
gl/m4/selinux-context-h.m4
Normal file
@@ -0,0 +1,18 @@
|
||||
# serial 1 -*- Autoconf -*-
|
||||
# Copyright (C) 2006 Free Software Foundation, Inc.
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# From Jim Meyering
|
||||
# Provide <selinux/context.h>, if necessary.
|
||||
|
||||
AC_DEFUN([gl_HEADERS_SELINUX_CONTEXT_H],
|
||||
[
|
||||
AC_LIBSOURCES([se-context_.h])
|
||||
# Check for <selinux/context.h>,
|
||||
AC_CHECK_HEADERS([selinux/context.h],
|
||||
[SELINUX_CONTEXT_H=],
|
||||
[SELINUX_CONTEXT_H=selinux/context.h])
|
||||
AC_SUBST([SELINUX_CONTEXT_H])
|
||||
])
|
||||
18
gl/m4/selinux-selinux-h.m4
Normal file
18
gl/m4/selinux-selinux-h.m4
Normal file
@@ -0,0 +1,18 @@
|
||||
# serial 1 -*- Autoconf -*-
|
||||
# Copyright (C) 2006 Free Software Foundation, Inc.
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# From Jim Meyering
|
||||
# Provide <selinux/selinux.h>, if necessary.
|
||||
|
||||
AC_DEFUN([gl_HEADERS_SELINUX_SELINUX_H],
|
||||
[
|
||||
AC_LIBSOURCES([se-selinux_.h])
|
||||
# Check for <selinux/selinux.h>,
|
||||
AC_CHECK_HEADERS([selinux/selinux.h],
|
||||
[SELINUX_SELINUX_H=],
|
||||
[SELINUX_SELINUX_H=selinux/selinux.h])
|
||||
AC_SUBST([SELINUX_SELINUX_H])
|
||||
])
|
||||
32
gl/modules/selinux-at
Normal file
32
gl/modules/selinux-at
Normal file
@@ -0,0 +1,32 @@
|
||||
Description:
|
||||
openat-style fd-relative functions for SE Linux
|
||||
|
||||
Files:
|
||||
lib/selinux-at.c
|
||||
lib/selinux-at.h
|
||||
|
||||
Depends-on:
|
||||
selinux-h
|
||||
|
||||
configure.ac:
|
||||
# FIXME: put this in an .m4 file?
|
||||
# For runcon.
|
||||
AC_CHECK_HEADERS([selinux/flask.h])
|
||||
AC_LIBOBJ([selinux-at])
|
||||
ac_save_LIBS="$LIBS"
|
||||
AC_SEARCH_LIBS(setfilecon, selinux,
|
||||
[test "$ac_cv_search_setfilecon" = "none required" ||
|
||||
LIB_SELINUX=$ac_cv_search_setfilecon])
|
||||
AC_SUBST(LIB_SELINUX)
|
||||
LIBS="$ac_save_LIBS"
|
||||
|
||||
Makefile.am:
|
||||
|
||||
Include:
|
||||
selinux-at.h
|
||||
|
||||
License:
|
||||
LGPL
|
||||
|
||||
Maintainer:
|
||||
Jim Meyering
|
||||
54
gl/modules/selinux-h
Normal file
54
gl/modules/selinux-h
Normal file
@@ -0,0 +1,54 @@
|
||||
Description:
|
||||
SELinux-related headers for systems that lack them.
|
||||
|
||||
Files:
|
||||
lib/se-context_.h
|
||||
lib/se-selinux_.h
|
||||
m4/selinux-context-h.m4
|
||||
m4/selinux-selinux-h.m4
|
||||
|
||||
Depends-on:
|
||||
|
||||
configure.ac:
|
||||
gl_HEADERS_SELINUX_SELINUX_H
|
||||
gl_HEADERS_SELINUX_CONTEXT_H
|
||||
|
||||
Makefile.am:
|
||||
BUILT_SOURCES += $(SELINUX_SELINUX_H)
|
||||
selinux/selinux.h: se-selinux_.h
|
||||
mkdir -p selinux
|
||||
cp $(srcdir)/se-selinux_.h $@-t
|
||||
chmod a-x $@-t
|
||||
mv $@-t $@
|
||||
MOSTLYCLEANFILES += selinux/selinux.h selinux/selinux.h-t
|
||||
|
||||
BUILT_SOURCES += $(SELINUX_CONTEXT_H)
|
||||
selinux/context.h: se-context_.h
|
||||
mkdir -p selinux
|
||||
cp $(srcdir)/se-context_.h $@-t
|
||||
chmod a-x $@-t
|
||||
mv $@-t $@
|
||||
MOSTLYCLEANFILES += selinux/context.h selinux/context.h-t
|
||||
MOSTLYCLEANDIRS += selinux
|
||||
|
||||
Include:
|
||||
#include <selinux/selinux.h>
|
||||
#include <selinux/context.h>
|
||||
|
||||
License:
|
||||
LGPL
|
||||
|
||||
Maintainer:
|
||||
Jim Meyering
|
||||
|
||||
# lib/selinux-at.c
|
||||
#
|
||||
# # For runcon.
|
||||
# AC_CHECK_HEADERS([selinux/flask.h])
|
||||
#
|
||||
# ac_save_LIBS="$LIBS"
|
||||
# AC_SEARCH_LIBS(setfilecon, selinux,
|
||||
# [test "$ac_cv_search_setfilecon" = "none required" ||
|
||||
# LIB_SELINUX=$ac_cv_search_setfilecon])
|
||||
# AC_SUBST(LIB_SELINUX)
|
||||
# LIBS="$ac_save_LIBS"
|
||||
@@ -286,7 +286,14 @@ savedir.c
|
||||
savedir.h
|
||||
savewd.c
|
||||
savewd.h
|
||||
se-context.h
|
||||
se-context_.h
|
||||
se-selinux.h
|
||||
se-selinux_.h
|
||||
search.h
|
||||
selinux
|
||||
selinux-at.c
|
||||
selinux-at.h
|
||||
setenv.c
|
||||
setenv.h
|
||||
settime.c
|
||||
|
||||
7
lib/.gitignore
vendored
7
lib/.gitignore
vendored
@@ -279,6 +279,13 @@ savedir.c
|
||||
savedir.h
|
||||
savewd.c
|
||||
savewd.h
|
||||
se-context.h
|
||||
se-context_.h
|
||||
se-selinux.h
|
||||
se-selinux_.h
|
||||
selinux
|
||||
selinux-at.c
|
||||
selinux-at.h
|
||||
setenv.c
|
||||
setenv.h
|
||||
settime.c
|
||||
|
||||
@@ -175,6 +175,8 @@ same.m4
|
||||
save-cwd.m4
|
||||
savedir.m4
|
||||
savewd.m4
|
||||
selinux-context-h.m4
|
||||
selinux-selinux-h.m4
|
||||
setenv.m4
|
||||
settime.m4
|
||||
sha1.m4
|
||||
|
||||
2
m4/.gitignore
vendored
2
m4/.gitignore
vendored
@@ -168,6 +168,8 @@ same.m4
|
||||
save-cwd.m4
|
||||
savedir.m4
|
||||
savewd.m4
|
||||
selinux-context-h.m4
|
||||
selinux-selinux-h.m4
|
||||
setenv.m4
|
||||
settime.m4
|
||||
sha1.m4
|
||||
|
||||
@@ -18,14 +18,15 @@
|
||||
# 02110-1301, USA.
|
||||
|
||||
dist_man_MANS = \
|
||||
base64.1 basename.1 cat.1 chgrp.1 chmod.1 chown.1 cksum.1 comm.1 \
|
||||
base64.1 basename.1 cat.1 chcon.1 chgrp.1 chmod.1 chown.1 cksum.1 comm.1 \
|
||||
cp.1 csplit.1 cut.1 date.1 dd.1 df.1 dir.1 dircolors.1 dirname.1 du.1 \
|
||||
echo.1 env.1 expand.1 expr.1 factor.1 false.1 fmt.1 fold.1 groups.1 \
|
||||
head.1 hostname.1 id.1 install.1 join.1 kill.1 \
|
||||
link.1 ln.1 logname.1 \
|
||||
ls.1 md5sum.1 mkdir.1 mkfifo.1 mknod.1 mv.1 nl.1 nohup.1 od.1 \
|
||||
paste.1 pathchk.1 pr.1 printenv.1 printf.1 ptx.1 pwd.1 readlink.1 \
|
||||
rm.1 rmdir.1 seq.1 sha1sum.1 sha224sum.1 sha256sum.1 sha384sum.1 sha512sum.1 \
|
||||
rm.1 rmdir.1 runcon.1 seq.1 \
|
||||
sha1sum.1 sha224sum.1 sha256sum.1 sha384sum.1 sha512sum.1 \
|
||||
shred.1 shuf.1 sleep.1 sort.1 split.1 stat.1 \
|
||||
su.1 sum.1 sync.1 tac.1 tail.1 tee.1 test.1 touch.1 tr.1 true.1 tsort.1 \
|
||||
tty.1 unexpand.1 uniq.1 unlink.1 vdir.1 wc.1 \
|
||||
@@ -45,6 +46,7 @@ common_dep = $(top_srcdir)/configure.ac
|
||||
base64.1: $(common_dep) $(srcdir)/base64.x ../src/base64.c
|
||||
basename.1: $(common_dep) $(srcdir)/basename.x ../src/basename.c
|
||||
cat.1: $(common_dep) $(srcdir)/cat.x ../src/cat.c
|
||||
chcon.1: $(common_dep) $(srcdir)/chcon.x ../src/chcon.c
|
||||
chgrp.1: $(common_dep) $(srcdir)/chgrp.x ../src/chgrp.c
|
||||
chmod.1: $(common_dep) $(srcdir)/chmod.x ../src/chmod.c
|
||||
chown.1: $(common_dep) $(srcdir)/chown.x ../src/chown.c
|
||||
@@ -104,6 +106,7 @@ pwd.1: $(common_dep) $(srcdir)/pwd.x ../src/pwd.c
|
||||
readlink.1: $(common_dep) $(srcdir)/readlink.x ../src/readlink.c
|
||||
rm.1: $(common_dep) $(srcdir)/rm.x ../src/rm.c
|
||||
rmdir.1: $(common_dep) $(srcdir)/rmdir.x ../src/rmdir.c
|
||||
runcon.1: $(common_dep) $(srcdir)/runcon.x ../src/runcon.c
|
||||
seq.1: $(common_dep) $(srcdir)/seq.x ../src/seq.c
|
||||
sha1sum.1: $(common_dep) $(srcdir)/sha1sum.x ../src/md5sum.c
|
||||
sha224sum.1: $(common_dep) $(srcdir)/sha224sum.x ../src/md5sum.c
|
||||
|
||||
4
man/chcon.x
Normal file
4
man/chcon.x
Normal file
@@ -0,0 +1,4 @@
|
||||
[NAME]
|
||||
chcon \- change file security context
|
||||
[DESCRIPTION]
|
||||
.\" Add any additional description here
|
||||
14
man/runcon.x
Normal file
14
man/runcon.x
Normal file
@@ -0,0 +1,14 @@
|
||||
[NAME]
|
||||
runcon \- run command with specified security context
|
||||
[DESCRIPTION]
|
||||
Run COMMAND with completely-specified CONTEXT, or with current or
|
||||
transitioned security context modified by one or more of LEVEL,
|
||||
ROLE, TYPE, and USER.
|
||||
.PP
|
||||
If none of \fI-c\fR, \fI-t\fR, \fI-u\fR, \fI-r\fR, or \fI-l\fR, is specified,
|
||||
the first argument is used as the complete context. Any additional
|
||||
arguments after \fICOMMAND\fR are interpreted as arguments to the
|
||||
command.
|
||||
.PP
|
||||
Note that only carefully-chosen contexts are likely to successfully
|
||||
run.
|
||||
@@ -1,3 +1,11 @@
|
||||
2007-02-02 Jim Meyering <jim@meyering.net>
|
||||
|
||||
* POTFILES.in: Add src/runcon.c.
|
||||
|
||||
2007-01-13 Jim Meyering <jim@meyering.net>
|
||||
|
||||
* POTFILES.in: Add src/chcon.c.
|
||||
|
||||
2006-10-19 Jim Meyering <jim@meyering.net>
|
||||
|
||||
* POTFILES.in: Also include lib/regcomp.c, since it too uses gettext.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# List of files which contain translatable strings.
|
||||
# Copyright (C) 1996-2006 Free Software Foundation, Inc.
|
||||
# Copyright (C) 1996-2007 Free Software Foundation, Inc.
|
||||
|
||||
# These are nominally temporary...
|
||||
lib/acl.c
|
||||
@@ -33,6 +33,7 @@ lib/xstrtol.h
|
||||
src/base64.c
|
||||
src/basename.c
|
||||
src/cat.c
|
||||
src/chcon.c
|
||||
src/chgrp.c
|
||||
src/chmod.c
|
||||
src/chown-core.c
|
||||
@@ -90,6 +91,7 @@ src/readlink.c
|
||||
src/remove.c
|
||||
src/rm.c
|
||||
src/rmdir.c
|
||||
src/runcon.c
|
||||
src/seq.c
|
||||
src/setuidgid.c
|
||||
src/shred.c
|
||||
|
||||
@@ -19,14 +19,15 @@
|
||||
EXTRA_PROGRAMS = chroot df hostid nice pinky stty su uname uptime users who
|
||||
|
||||
bin_SCRIPTS = groups
|
||||
bin_PROGRAMS = [ chgrp chown chmod cp dd dircolors du \
|
||||
bin_PROGRAMS = [ chcon chgrp chown chmod cp dd dircolors du \
|
||||
ginstall link ln dir vdir ls mkdir \
|
||||
mkfifo mknod mv nohup readlink rm rmdir shred stat sync touch unlink \
|
||||
cat cksum comm csplit cut expand fmt fold head join md5sum \
|
||||
nl od paste pr ptx sha1sum sha224sum sha256sum sha384sum sha512sum \
|
||||
shuf sort split sum tac tail tr tsort unexpand uniq wc \
|
||||
basename date dirname echo env expr factor false \
|
||||
hostname id kill logname pathchk printenv printf pwd seq sleep tee \
|
||||
hostname id kill logname pathchk printenv printf pwd \
|
||||
runcon seq sleep tee \
|
||||
test true tty whoami yes \
|
||||
base64 \
|
||||
$(OPTIONAL_BIN_PROGS) $(DF_PROG)
|
||||
@@ -60,9 +61,14 @@ AM_CPPFLAGS = -I$(top_srcdir)/lib
|
||||
LDADD = ../lib/libcoreutils.a $(LIBINTL) ../lib/libcoreutils.a
|
||||
|
||||
# for eaccess in lib/euidaccess.c.
|
||||
cp_LDADD = $(LDADD) $(LIB_EACCESS)
|
||||
ginstall_LDADD = $(LDADD) $(LIB_EACCESS)
|
||||
mv_LDADD = $(LDADD) $(LIB_EACCESS)
|
||||
chcon_LDADD = $(LDADD) $(LIB_SELINUX)
|
||||
cp_LDADD = $(LDADD) $(LIB_EACCESS) $(LIB_SELINUX)
|
||||
ginstall_LDADD = $(LDADD) $(LIB_EACCESS) $(LIB_SELINUX)
|
||||
mkdir_LDADD = $(LDADD) $(LIB_SELINUX)
|
||||
mkfifo_LDADD = $(LDADD) $(LIB_SELINUX)
|
||||
mknod_LDADD = $(LDADD) $(LIB_SELINUX)
|
||||
mv_LDADD = $(LDADD) $(LIB_EACCESS) $(LIB_SELINUX)
|
||||
runcon_LDADD = $(LDADD) $(LIB_SELINUX)
|
||||
pathchk_LDADD = $(LDADD) $(LIB_EACCESS)
|
||||
rm_LDADD = $(LDADD) $(LIB_EACCESS)
|
||||
test_LDADD = $(LDADD) $(LIB_EACCESS)
|
||||
@@ -71,12 +77,13 @@ __LDADD = $(LDADD) $(LIB_EACCESS)
|
||||
|
||||
# for clock_gettime and fdatasync
|
||||
dd_LDADD = $(LDADD) $(LIB_GETHRXTIME) $(LIB_FDATASYNC)
|
||||
dir_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME)
|
||||
ls_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME)
|
||||
dir_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) $(LIB_SELINUX)
|
||||
id_LDADD = $(LDADD) $(LIB_SELINUX)
|
||||
ls_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) $(LIB_SELINUX)
|
||||
pr_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME)
|
||||
shred_LDADD = $(LDADD) $(LIB_GETHRXTIME) $(LIB_FDATASYNC)
|
||||
shuf_LDADD = $(LDADD) $(LIB_GETHRXTIME)
|
||||
vdir_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME)
|
||||
vdir_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) $(LIB_SELINUX)
|
||||
|
||||
## If necessary, add -lm to resolve use of pow in lib/strtod.c.
|
||||
sort_LDADD = $(LDADD) $(POW_LIB) $(LIB_GETHRXTIME)
|
||||
@@ -111,6 +118,8 @@ cp_LDADD += $(LIB_ACL)
|
||||
mv_LDADD += $(LIB_ACL)
|
||||
ginstall_LDADD += $(LIB_ACL)
|
||||
|
||||
stat_LDADD = $(LDADD) $(LIB_SELINUX)
|
||||
|
||||
$(PROGRAMS): ../lib/libcoreutils.a
|
||||
|
||||
SUFFIXES = .sh
|
||||
|
||||
590
src/chcon.c
Normal file
590
src/chcon.c
Normal file
@@ -0,0 +1,590 @@
|
||||
/* chcon -- change security context of files
|
||||
Copyright (C) 2005-2007 Free Software Foundation, 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, 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 <sys/types.h>
|
||||
#include <getopt.h>
|
||||
|
||||
#include "system.h"
|
||||
#include "dev-ino.h"
|
||||
#include "error.h"
|
||||
#include "openat.h"
|
||||
#include "quote.h"
|
||||
#include "quotearg.h"
|
||||
#include "root-dev-ino.h"
|
||||
#include "selinux-at.h"
|
||||
#include "xfts.h"
|
||||
|
||||
/* The official name of this program (e.g., no `g' prefix). */
|
||||
#define PROGRAM_NAME "chcon"
|
||||
|
||||
#define AUTHORS "Russell Coker", "Jim Meyering"
|
||||
|
||||
enum Change_status
|
||||
{
|
||||
CH_NOT_APPLIED,
|
||||
CH_SUCCEEDED,
|
||||
CH_FAILED,
|
||||
CH_NO_CHANGE_REQUESTED
|
||||
};
|
||||
|
||||
enum Verbosity
|
||||
{
|
||||
/* Print a message for each file that is processed. */
|
||||
V_high,
|
||||
|
||||
/* Print a message for each file whose attributes we change. */
|
||||
V_changes_only,
|
||||
|
||||
/* Do not be verbose. This is the default. */
|
||||
V_off
|
||||
};
|
||||
|
||||
/* The name the program was run with. */
|
||||
char *program_name;
|
||||
|
||||
/* If nonzero, and the systems has support for it, change the context
|
||||
of symbolic links rather than any files they point to. */
|
||||
static bool affect_symlink_referent;
|
||||
|
||||
/* If true, change the modes of directories recursively. */
|
||||
static bool recurse;
|
||||
|
||||
/* Level of verbosity. */
|
||||
static bool verbose;
|
||||
|
||||
/* Pointer to the device and inode numbers of `/', when --recursive.
|
||||
Otherwise NULL. */
|
||||
static struct dev_ino *root_dev_ino;
|
||||
|
||||
/* The name of the context file is being given. */
|
||||
static char const *specified_context;
|
||||
|
||||
/* Specific components of the context */
|
||||
static char const *specified_user;
|
||||
static char const *specified_role;
|
||||
static char const *specified_range;
|
||||
static char const *specified_type;
|
||||
|
||||
/* For long options that have no equivalent short option, use a
|
||||
non-character as a pseudo short option, starting with CHAR_MAX + 1. */
|
||||
enum
|
||||
{
|
||||
DEREFERENCE_OPTION = CHAR_MAX + 1,
|
||||
NO_PRESERVE_ROOT,
|
||||
PRESERVE_ROOT,
|
||||
REFERENCE_FILE_OPTION
|
||||
};
|
||||
|
||||
static struct option const long_options[] =
|
||||
{
|
||||
{"recursive", no_argument, NULL, 'R'},
|
||||
{"dereference", no_argument, NULL, DEREFERENCE_OPTION},
|
||||
{"no-dereference", no_argument, NULL, 'h'},
|
||||
{"no-preserve-root", no_argument, NULL, NO_PRESERVE_ROOT},
|
||||
{"preserve-root", no_argument, NULL, PRESERVE_ROOT},
|
||||
{"reference", required_argument, NULL, REFERENCE_FILE_OPTION},
|
||||
{"user", required_argument, NULL, 'u'},
|
||||
{"role", required_argument, NULL, 'r'},
|
||||
{"type", required_argument, NULL, 't'},
|
||||
{"range", required_argument, NULL, 'l'},
|
||||
{"verbose", no_argument, NULL, 'v'},
|
||||
{GETOPT_HELP_OPTION_DECL},
|
||||
{GETOPT_VERSION_OPTION_DECL},
|
||||
{NULL, 0, NULL, 0}
|
||||
};
|
||||
|
||||
/* Given a security context, CONTEXT, derive a context_t (*RET),
|
||||
setting any portions selected via the global variables, specified_user,
|
||||
specified_role, etc. */
|
||||
static int
|
||||
compute_context_from_mask (security_context_t context, context_t *ret)
|
||||
{
|
||||
bool ok = true;
|
||||
context_t new_context = context_new (context);
|
||||
if (!new_context)
|
||||
{
|
||||
error (0, errno, _("failed to create security context: %s"),
|
||||
quotearg_colon (context));
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define SET_COMPONENT(C, comp) \
|
||||
do \
|
||||
{ \
|
||||
if (specified_ ## comp \
|
||||
&& context_ ## comp ## _set ((C), specified_ ## comp)) \
|
||||
{ \
|
||||
error (0, errno, \
|
||||
_("failed to set %s security context component to %s"), \
|
||||
#comp, quote (specified_ ## comp)); \
|
||||
ok = false; \
|
||||
} \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
SET_COMPONENT (new_context, user);
|
||||
SET_COMPONENT (new_context, range);
|
||||
SET_COMPONENT (new_context, role);
|
||||
SET_COMPONENT (new_context, type);
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
int saved_errno = errno;
|
||||
context_free (new_context);
|
||||
errno = saved_errno;
|
||||
return 1;
|
||||
}
|
||||
|
||||
*ret = new_context;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Change the context of FILE, using specified components.
|
||||
If it is a directory and -R is given, recurse.
|
||||
Return 0 if successful, 1 if errors occurred. */
|
||||
|
||||
static int
|
||||
change_file_context (int fd, char const *file)
|
||||
{
|
||||
security_context_t file_context = NULL;
|
||||
context_t context;
|
||||
security_context_t context_string;
|
||||
int errors = 0;
|
||||
|
||||
if (specified_context == NULL)
|
||||
{
|
||||
int status = (affect_symlink_referent
|
||||
? getfileconat (fd, file, &file_context)
|
||||
: lgetfileconat (fd, file, &file_context));
|
||||
|
||||
if (status < 0 && errno != ENODATA)
|
||||
{
|
||||
error (0, errno, _("failed to get security context of %s"),
|
||||
quote (file));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* If the file doesn't have a context, and we're not setting all of
|
||||
the context components, there isn't really an obvious default.
|
||||
Thus, we just give up. */
|
||||
if (file_context == NULL)
|
||||
{
|
||||
error (0, 0, _("can't apply partial context to unlabeled file %s"),
|
||||
quote (file));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (compute_context_from_mask (file_context, &context))
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* FIXME: this should be done exactly once, in main. */
|
||||
context = context_new (specified_context);
|
||||
if (!context)
|
||||
abort ();
|
||||
}
|
||||
|
||||
context_string = context_str (context);
|
||||
|
||||
if (file_context == NULL || ! STREQ (context_string, file_context))
|
||||
{
|
||||
int fail = (affect_symlink_referent
|
||||
? setfileconat (fd, file, context_string)
|
||||
: lsetfileconat (fd, file, context_string));
|
||||
|
||||
if (fail)
|
||||
{
|
||||
errors = 1;
|
||||
error (0, errno, _("failed to change context of %s to %s"),
|
||||
quote_n (0, file), quote_n (1, context_string));
|
||||
}
|
||||
}
|
||||
|
||||
context_free (context);
|
||||
freecon (file_context);
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
/* Change the context of FILE.
|
||||
Return true if successful. This function is called
|
||||
once for every file system object that fts encounters. */
|
||||
|
||||
static bool
|
||||
process_file (FTS *fts, FTSENT *ent)
|
||||
{
|
||||
char const *file_full_name = ent->fts_path;
|
||||
char const *file = ent->fts_accpath;
|
||||
const struct stat *file_stats = ent->fts_statp;
|
||||
bool ok = true;
|
||||
|
||||
switch (ent->fts_info)
|
||||
{
|
||||
case FTS_D:
|
||||
if (recurse)
|
||||
{
|
||||
if (ROOT_DEV_INO_CHECK (root_dev_ino, ent->fts_statp))
|
||||
{
|
||||
/* This happens e.g., with "chcon -R --preserve-root ... /"
|
||||
and with "chcon -RH --preserve-root ... symlink-to-root". */
|
||||
ROOT_DEV_INO_WARN (file_full_name);
|
||||
/* Tell fts not to traverse into this hierarchy. */
|
||||
fts_set (fts, ent, FTS_SKIP);
|
||||
/* Ensure that we do not process "/" on the second visit. */
|
||||
ent = fts_read (fts);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case FTS_DP:
|
||||
if (! recurse)
|
||||
return true;
|
||||
break;
|
||||
|
||||
case FTS_NS:
|
||||
/* For a top-level file or directory, this FTS_NS (stat failed)
|
||||
indicator is determined at the time of the initial fts_open call.
|
||||
With programs like chmod, chown, and chgrp, that modify
|
||||
permissions, it is possible that the file in question is
|
||||
accessible when control reaches this point. So, if this is
|
||||
the first time we've seen the FTS_NS for this file, tell
|
||||
fts_read to stat it "again". */
|
||||
if (ent->fts_level == 0 && ent->fts_number == 0)
|
||||
{
|
||||
ent->fts_number = 1;
|
||||
fts_set (fts, ent, FTS_AGAIN);
|
||||
return true;
|
||||
}
|
||||
error (0, ent->fts_errno, _("cannot access %s"), quote (file_full_name));
|
||||
ok = false;
|
||||
break;
|
||||
|
||||
case FTS_ERR:
|
||||
error (0, ent->fts_errno, _("%s"), quote (file_full_name));
|
||||
ok = false;
|
||||
break;
|
||||
|
||||
case FTS_DNR:
|
||||
error (0, ent->fts_errno, _("cannot read directory %s"),
|
||||
quote (file_full_name));
|
||||
ok = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (ent->fts_info == FTS_DP
|
||||
&& ok && ROOT_DEV_INO_CHECK (root_dev_ino, file_stats))
|
||||
{
|
||||
ROOT_DEV_INO_WARN (file_full_name);
|
||||
ok = false;
|
||||
}
|
||||
|
||||
if (ok)
|
||||
{
|
||||
if (verbose)
|
||||
printf (_("changing security context of %s"),
|
||||
quote (file_full_name));
|
||||
|
||||
if (change_file_context (fts->fts_cwd_fd, file) != 0)
|
||||
ok = false;
|
||||
}
|
||||
|
||||
if ( ! recurse)
|
||||
fts_set (fts, ent, FTS_SKIP);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
/* Recursively operate on the specified FILES (the last entry
|
||||
of which is NULL). BIT_FLAGS controls how fts works.
|
||||
Return true if successful. */
|
||||
|
||||
static bool
|
||||
process_files (char **files, int bit_flags)
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
FTS *fts = xfts_open (files, bit_flags, NULL);
|
||||
|
||||
while (1)
|
||||
{
|
||||
FTSENT *ent;
|
||||
|
||||
ent = fts_read (fts);
|
||||
if (ent == NULL)
|
||||
{
|
||||
if (errno != 0)
|
||||
{
|
||||
/* FIXME: try to give a better message */
|
||||
error (0, errno, _("fts_read failed"));
|
||||
ok = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
ok &= process_file (fts, ent);
|
||||
}
|
||||
|
||||
/* Ignore failure, since the only way it can do so is in failing to
|
||||
return to the original directory, and since we're about to exit,
|
||||
that doesn't matter. */
|
||||
fts_close (fts);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
void
|
||||
usage (int status)
|
||||
{
|
||||
if (status != EXIT_SUCCESS)
|
||||
fprintf (stderr, _("Try `%s --help' for more information.\n"),
|
||||
program_name);
|
||||
else
|
||||
{
|
||||
printf (_("\
|
||||
Usage: %s [OPTION]... CONTEXT FILE...\n\
|
||||
or: %s [OPTION]... [-u USER] [-r ROLE] [-l RANGE] [-t TYPE] FILE...\n\
|
||||
or: %s [OPTION]... --reference=RFILE FILE...\n\
|
||||
"),
|
||||
program_name, program_name, program_name);
|
||||
fputs (_("\
|
||||
Change the security context of each FILE to CONTEXT.\n\
|
||||
With --reference, change the security context of each FILE to that of RFILE.\n\
|
||||
\n\
|
||||
-c, --changes like verbose but report only when a change is made\n\
|
||||
-h, --no-dereference affect symbolic links instead of any referenced file\n\
|
||||
(available only on systems with lchown system call)\n\
|
||||
"), stdout);
|
||||
fputs (_("\
|
||||
--reference=RFILE use RFILE's security context rather than specifying\n\
|
||||
a CONTEXT value\n\
|
||||
-R, --recursive operate on files and directories recursively\n\
|
||||
-v, --verbose output a diagnostic for every file processed\n\
|
||||
"), stdout);
|
||||
fputs (_("\
|
||||
-u, --user=USER set user USER in the target security context\n\
|
||||
-r, --role=ROLE set role ROLE in the target security context\n\
|
||||
-t, --type=TYPE set type TYPE in the target security context\n\
|
||||
-l, --range=RANGE set range RANGE in the target security context\n\
|
||||
\n\
|
||||
"), stdout);
|
||||
fputs (_("\
|
||||
The following options modify how a hierarchy is traversed when the -R\n\
|
||||
option is also specified. If more than one is specified, only the final\n\
|
||||
one takes effect.\n\
|
||||
\n\
|
||||
-H if a command line argument is a symbolic link\n\
|
||||
to a directory, traverse it\n\
|
||||
-L traverse every symbolic link to a directory\n\
|
||||
encountered\n\
|
||||
-P do not traverse any symbolic links (default)\n\
|
||||
\n\
|
||||
"), stdout);
|
||||
fputs (HELP_OPTION_DESCRIPTION, stdout);
|
||||
fputs (VERSION_OPTION_DESCRIPTION, stdout);
|
||||
}
|
||||
exit (status);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
security_context_t ref_context = NULL;
|
||||
|
||||
/* Bit flags that control how fts works. */
|
||||
int bit_flags = FTS_PHYSICAL;
|
||||
|
||||
/* 1 if --dereference, 0 if --no-dereference, -1 if neither has been
|
||||
specified. */
|
||||
int dereference = -1;
|
||||
|
||||
bool ok;
|
||||
bool preserve_root = false;
|
||||
bool component_specified = false;
|
||||
char *reference_file = NULL;
|
||||
int optc;
|
||||
|
||||
initialize_main (&argc, &argv);
|
||||
program_name = argv[0];
|
||||
setlocale (LC_ALL, "");
|
||||
bindtextdomain (PACKAGE, LOCALEDIR);
|
||||
textdomain (PACKAGE);
|
||||
|
||||
atexit (close_stdout);
|
||||
|
||||
while ((optc = getopt_long (argc, argv, "HLPRchvu:r:t:l:", long_options, NULL))
|
||||
!= -1)
|
||||
{
|
||||
switch (optc)
|
||||
{
|
||||
case 'H': /* Traverse command-line symlinks-to-directories. */
|
||||
bit_flags = FTS_COMFOLLOW | FTS_PHYSICAL;
|
||||
break;
|
||||
|
||||
case 'L': /* Traverse all symlinks-to-directories. */
|
||||
bit_flags = FTS_LOGICAL;
|
||||
break;
|
||||
|
||||
case 'P': /* Traverse no symlinks-to-directories. */
|
||||
bit_flags = FTS_PHYSICAL;
|
||||
break;
|
||||
|
||||
case 'h': /* --no-dereference: affect symlinks */
|
||||
dereference = 0;
|
||||
break;
|
||||
|
||||
case DEREFERENCE_OPTION: /* --dereference: affect the referent
|
||||
of each symlink */
|
||||
dereference = 1;
|
||||
break;
|
||||
|
||||
case NO_PRESERVE_ROOT:
|
||||
preserve_root = false;
|
||||
break;
|
||||
|
||||
case PRESERVE_ROOT:
|
||||
preserve_root = true;
|
||||
break;
|
||||
|
||||
case REFERENCE_FILE_OPTION:
|
||||
reference_file = optarg;
|
||||
break;
|
||||
|
||||
case 'R':
|
||||
recurse = true;
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
/* ignore */
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
verbose = true;
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
specified_user = optarg;
|
||||
component_specified = true;
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
specified_role = optarg;
|
||||
component_specified = true;
|
||||
break;
|
||||
|
||||
case 't':
|
||||
specified_type = optarg;
|
||||
component_specified = true;
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
specified_range = optarg;
|
||||
component_specified = true;
|
||||
break;
|
||||
|
||||
case_GETOPT_HELP_CHAR;
|
||||
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
|
||||
default:
|
||||
usage (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
if (recurse)
|
||||
{
|
||||
if (bit_flags == FTS_PHYSICAL)
|
||||
{
|
||||
if (dereference == 1)
|
||||
error (EXIT_FAILURE, 0,
|
||||
_("-R --dereference requires either -H or -L"));
|
||||
affect_symlink_referent = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dereference == 0)
|
||||
error (EXIT_FAILURE, 0, _("-R -h requires -P"));
|
||||
affect_symlink_referent = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bit_flags = FTS_PHYSICAL;
|
||||
affect_symlink_referent = (dereference != 0);
|
||||
}
|
||||
|
||||
if (argc - optind < (reference_file || component_specified ? 1 : 2))
|
||||
{
|
||||
if (argc <= optind)
|
||||
error (0, 0, _("missing operand"));
|
||||
else
|
||||
error (0, 0, _("missing operand after %s"), quote (argv[argc - 1]));
|
||||
usage (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (reference_file)
|
||||
{
|
||||
if (getfilecon (reference_file, &ref_context) < 0)
|
||||
error (EXIT_FAILURE, errno, _("failed to get security context of %s"),
|
||||
quote (reference_file));
|
||||
|
||||
specified_context = ref_context;
|
||||
}
|
||||
else if (component_specified)
|
||||
{
|
||||
/* FIXME: it's already null, so this is a no-op. */
|
||||
specified_context = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
context_t context;
|
||||
specified_context = argv[optind++];
|
||||
context = context_new (specified_context);
|
||||
if (!context)
|
||||
error (EXIT_FAILURE, 0, _("invalid context: %s"),
|
||||
quotearg_colon (specified_context));
|
||||
context_free (context);
|
||||
}
|
||||
|
||||
if (reference_file && component_specified)
|
||||
{
|
||||
error (0, 0, _("conflicting security context specifiers given"));
|
||||
usage (1);
|
||||
}
|
||||
|
||||
if (recurse & preserve_root)
|
||||
{
|
||||
static struct dev_ino dev_ino_buf;
|
||||
root_dev_ino = get_root_dev_ino (&dev_ino_buf);
|
||||
if (root_dev_ino == NULL)
|
||||
error (EXIT_FAILURE, errno, _("failed to get attributes of %s"),
|
||||
quote ("/"));
|
||||
}
|
||||
else
|
||||
{
|
||||
root_dev_ino = NULL;
|
||||
}
|
||||
|
||||
ok = process_files (argv + optind, bit_flags | FTS_NOSTAT);
|
||||
|
||||
exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
}
|
||||
86
src/copy.c
86
src/copy.c
@@ -21,6 +21,7 @@
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <sys/types.h>
|
||||
#include <selinux/selinux.h>
|
||||
|
||||
#if HAVE_HURD_H
|
||||
# include <hurd.h>
|
||||
@@ -302,6 +303,42 @@ copy_reg (char const *src_name, char const *dst_name,
|
||||
{
|
||||
dest_desc = open (dst_name, O_WRONLY | O_TRUNC | O_BINARY);
|
||||
|
||||
/* When using cp --preserve=context to copy to an existing destination,
|
||||
use the default context rather than that of the source. Why?
|
||||
1) the src context may prohibit writing, and
|
||||
2) because it's more consistent to use the same context
|
||||
that is used when the destination file doesn't already exist. */
|
||||
if (x->preserve_security_context && 0 <= dest_desc)
|
||||
{
|
||||
security_context_t con;
|
||||
if (getfscreatecon (&con) < 0)
|
||||
{
|
||||
error (0, errno, _("failed to get file system create context"));
|
||||
if (x->require_preserve_context)
|
||||
{
|
||||
return_val = false;
|
||||
goto close_src_desc;
|
||||
}
|
||||
}
|
||||
|
||||
if (con)
|
||||
{
|
||||
if (fsetfilecon (dest_desc, con) < 0)
|
||||
{
|
||||
error (0, errno,
|
||||
_("failed to set the security context of %s to %s"),
|
||||
quote_n (0, dst_name), quote_n (1, con));
|
||||
if (x->require_preserve_context)
|
||||
{
|
||||
return_val = false;
|
||||
freecon (con);
|
||||
goto close_src_desc;
|
||||
}
|
||||
}
|
||||
freecon(con);
|
||||
}
|
||||
}
|
||||
|
||||
if (dest_desc < 0 && x->unlink_dest_after_failed_open)
|
||||
{
|
||||
if (unlink (dst_name) != 0)
|
||||
@@ -995,6 +1032,15 @@ emit_verbose (char const *src, char const *dst, char const *backup_dst_name)
|
||||
putchar ('\n');
|
||||
}
|
||||
|
||||
/* A wrapper around "setfscreatecon (NULL)" that exits upon failure. */
|
||||
static void
|
||||
restore_default_fscreatecon_or_die (void)
|
||||
{
|
||||
if (setfscreatecon (NULL) != 0)
|
||||
error (EXIT_FAILURE, errno,
|
||||
_("failed to restore the default file creation context"));
|
||||
}
|
||||
|
||||
/* Copy the file SRC_NAME to the file DST_NAME. The files may be of
|
||||
any type. NEW_DST should be true if the file DST_NAME cannot
|
||||
exist because its parent directory was just created; NEW_DST should
|
||||
@@ -1343,7 +1389,7 @@ copy_internal (char const *src_name, char const *dst_name,
|
||||
|
||||
if (x->move_mode && src_sb.st_nlink == 1)
|
||||
{
|
||||
earlier_file = src_to_dest_lookup (src_sb.st_ino, src_sb.st_dev);
|
||||
earlier_file = src_to_dest_lookup (src_sb.st_ino, src_sb.st_dev);
|
||||
}
|
||||
else if ((x->preserve_links
|
||||
&& (1 < src_sb.st_nlink
|
||||
@@ -1533,6 +1579,38 @@ copy_internal (char const *src_name, char const *dst_name,
|
||||
|
||||
delayed_ok = true;
|
||||
|
||||
if (x->preserve_security_context)
|
||||
{
|
||||
security_context_t con;
|
||||
|
||||
if (0 <= lgetfilecon (src_name, &con))
|
||||
{
|
||||
if (setfscreatecon (con) < 0)
|
||||
{
|
||||
error (0, errno,
|
||||
_("failed to set default file creation context to %s"),
|
||||
quote (con));
|
||||
if (x->require_preserve_context)
|
||||
{
|
||||
freecon (con);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
freecon (con);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (errno != ENOTSUP && errno != ENODATA)
|
||||
{
|
||||
error (0, errno,
|
||||
_("failed to get security context of %s"),
|
||||
quote (src_name));
|
||||
if (x->require_preserve_context)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* In certain modes (cp's --symbolic-link), and for certain file types
|
||||
(symlinks and hard links) it doesn't make sense to preserve metadata,
|
||||
or it's possible to preserve only some of it.
|
||||
@@ -1762,6 +1840,9 @@ copy_internal (char const *src_name, char const *dst_name,
|
||||
}
|
||||
}
|
||||
|
||||
if (x->preserve_security_context)
|
||||
restore_default_fscreatecon_or_die ();
|
||||
|
||||
/* There's no need to preserve timestamps or permissions. */
|
||||
preserve_metadata = false;
|
||||
|
||||
@@ -1895,6 +1976,9 @@ copy_internal (char const *src_name, char const *dst_name,
|
||||
|
||||
un_backup:
|
||||
|
||||
if (x->preserve_security_context)
|
||||
restore_default_fscreatecon_or_die ();
|
||||
|
||||
/* We have failed to create the destination file.
|
||||
If we've just added a dev/ino entry via the remember_copied
|
||||
call above (i.e., unless we've just failed to create a hard link),
|
||||
|
||||
21
src/copy.h
21
src/copy.h
@@ -1,5 +1,5 @@
|
||||
/* core functions for copying files and directories
|
||||
Copyright (C) 89, 90, 91, 1995-2005 Free Software Foundation.
|
||||
Copyright (C) 89, 90, 91, 1995-2007 Free Software Foundation.
|
||||
|
||||
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
|
||||
@@ -142,10 +142,25 @@ struct cp_options
|
||||
|
||||
/* If true and any of the above (for preserve) file attributes cannot
|
||||
be applied to a destination file, treat it as a failure and return
|
||||
nonzero immediately. E.g. cp -p requires this be nonzero, mv requires
|
||||
it be zero. */
|
||||
nonzero immediately. E.g. for cp -p this must be true, for mv it
|
||||
must be false. */
|
||||
bool require_preserve;
|
||||
|
||||
/* If true, attempt to preserve the SELinux security context, too.
|
||||
Set this only if the kernel is SELinux enabled. */
|
||||
bool preserve_security_context;
|
||||
|
||||
/* Useful only when preserve_security_context is true.
|
||||
If true, a failed attempt to preserve a file's security context
|
||||
propagates failure "out" to the caller. If false, a failure to
|
||||
preserve a file's security context does not change the invoking
|
||||
application's exit status. Give diagnostics for failed syscalls
|
||||
regardless of this setting. For example, with "cp --preserve=context"
|
||||
this flag is "true", while with "cp -a", it is false. That means
|
||||
"cp -a" attempts to preserve any security context, but does not
|
||||
fail if it is unable to do so. */
|
||||
bool require_preserve_context;
|
||||
|
||||
/* If true, copy directories recursively and copy special files
|
||||
as themselves rather than copying their contents. */
|
||||
bool recursive;
|
||||
|
||||
32
src/cp.c
32
src/cp.c
@@ -21,6 +21,7 @@
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <getopt.h>
|
||||
#include <selinux/selinux.h>
|
||||
|
||||
#include "system.h"
|
||||
#include "argmatch.h"
|
||||
@@ -85,6 +86,9 @@ enum
|
||||
/* The invocation name of this program. */
|
||||
char *program_name;
|
||||
|
||||
/* True if the kernel is SELinux enabled. */
|
||||
static bool selinux_enabled;
|
||||
|
||||
/* If true, the command "cp x/e_file e_dir" uses "e_dir/x/e_file"
|
||||
as its destination instead of the usual "e_dir/e_file." */
|
||||
static bool parents_option = false;
|
||||
@@ -191,7 +195,7 @@ Mandatory arguments to long options are mandatory for short options too.\n\
|
||||
-p same as --preserve=mode,ownership,timestamps\n\
|
||||
--preserve[=ATTR_LIST] preserve the specified attributes (default:\n\
|
||||
mode,ownership,timestamps), if possible\n\
|
||||
additional attributes: links, all\n\
|
||||
additional attributes: context, links, all\n\
|
||||
"), stdout);
|
||||
fputs (_("\
|
||||
--no-preserve=ATTR_LIST don't preserve the specified attributes\n\
|
||||
@@ -749,6 +753,8 @@ cp_option_init (struct cp_options *x)
|
||||
x->preserve_links = false;
|
||||
x->preserve_mode = false;
|
||||
x->preserve_timestamps = false;
|
||||
x->preserve_security_context = false;
|
||||
x->require_preserve_context = false;
|
||||
|
||||
x->require_preserve = false;
|
||||
x->recursive = false;
|
||||
@@ -777,18 +783,19 @@ decode_preserve_arg (char const *arg, struct cp_options *x, bool on_off)
|
||||
PRESERVE_TIMESTAMPS,
|
||||
PRESERVE_OWNERSHIP,
|
||||
PRESERVE_LINK,
|
||||
PRESERVE_CONTEXT,
|
||||
PRESERVE_ALL
|
||||
};
|
||||
static enum File_attribute const preserve_vals[] =
|
||||
{
|
||||
PRESERVE_MODE, PRESERVE_TIMESTAMPS,
|
||||
PRESERVE_OWNERSHIP, PRESERVE_LINK, PRESERVE_ALL
|
||||
PRESERVE_OWNERSHIP, PRESERVE_LINK, PRESERVE_CONTEXT, PRESERVE_ALL
|
||||
};
|
||||
/* Valid arguments to the `--preserve' option. */
|
||||
static char const* const preserve_args[] =
|
||||
{
|
||||
"mode", "timestamps",
|
||||
"ownership", "links", "all", NULL
|
||||
"ownership", "links", "context", "all", NULL
|
||||
};
|
||||
ARGMATCH_VERIFY (preserve_args, preserve_vals);
|
||||
|
||||
@@ -824,11 +831,18 @@ decode_preserve_arg (char const *arg, struct cp_options *x, bool on_off)
|
||||
x->preserve_links = on_off;
|
||||
break;
|
||||
|
||||
case PRESERVE_CONTEXT:
|
||||
x->preserve_security_context = on_off;
|
||||
x->require_preserve_context = on_off;
|
||||
break;
|
||||
|
||||
case PRESERVE_ALL:
|
||||
x->preserve_mode = on_off;
|
||||
x->preserve_timestamps = on_off;
|
||||
x->preserve_ownership = on_off;
|
||||
x->preserve_links = on_off;
|
||||
if (selinux_enabled)
|
||||
x->preserve_security_context = on_off;
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -862,6 +876,7 @@ main (int argc, char **argv)
|
||||
|
||||
atexit (close_stdout);
|
||||
|
||||
selinux_enabled = (0 < is_selinux_enabled ());
|
||||
cp_option_init (&x);
|
||||
|
||||
/* FIXME: consider not calling getenv for SIMPLE_BACKUP_SUFFIX unless
|
||||
@@ -1048,9 +1063,6 @@ main (int argc, char **argv)
|
||||
x.dereference = DEREF_ALWAYS;
|
||||
}
|
||||
|
||||
/* The key difference between -d (--no-dereference) and not is the version
|
||||
of `stat' to call. */
|
||||
|
||||
if (x.recursive)
|
||||
x.copy_as_regular = copy_contents;
|
||||
|
||||
@@ -1059,6 +1071,14 @@ main (int argc, char **argv)
|
||||
if (x.unlink_dest_after_failed_open & (x.hard_link | x.symbolic_link))
|
||||
x.unlink_dest_before_opening = true;
|
||||
|
||||
if (x.preserve_security_context)
|
||||
{
|
||||
if (!selinux_enabled)
|
||||
error (EXIT_FAILURE, 0,
|
||||
_("cannot preserve security context "
|
||||
"without an SELinux-enabled kernel"));
|
||||
}
|
||||
|
||||
/* Allocate space for remembering copied and created files. */
|
||||
|
||||
hash_init ();
|
||||
|
||||
63
src/id.c
63
src/id.c
@@ -1,5 +1,5 @@
|
||||
/* id -- print real and effective UIDs and GIDs
|
||||
Copyright (C) 1989-2005 Free Software Foundation, Inc.
|
||||
Copyright (C) 1989-2007 Free Software Foundation, 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
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#include <getopt.h>
|
||||
#include <selinux/selinux.h>
|
||||
|
||||
#include "system.h"
|
||||
#include "error.h"
|
||||
@@ -37,6 +38,9 @@
|
||||
|
||||
int getugroups ();
|
||||
|
||||
/* If nonzero, output only the SELinux context. -Z */
|
||||
static int just_context = 0;
|
||||
|
||||
static void print_user (uid_t uid);
|
||||
static void print_group (gid_t gid);
|
||||
static void print_group_list (const char *username);
|
||||
@@ -55,8 +59,13 @@ static gid_t rgid, egid;
|
||||
/* True unless errors have been encountered. */
|
||||
static bool ok = true;
|
||||
|
||||
/* The SELinux context. Start with a known invalid value so print_full_info
|
||||
knows when `context' has not been set to a meaningful value. */
|
||||
static security_context_t context = NULL;
|
||||
|
||||
static struct option const longopts[] =
|
||||
{
|
||||
{"context", no_argument, NULL, 'Z'},
|
||||
{"group", no_argument, NULL, 'g'},
|
||||
{"groups", no_argument, NULL, 'G'},
|
||||
{"name", no_argument, NULL, 'n'},
|
||||
@@ -80,6 +89,7 @@ usage (int status)
|
||||
Print information for USERNAME, or the current user.\n\
|
||||
\n\
|
||||
-a ignore, for compatibility with other versions\n\
|
||||
-Z, --context print only the security context of the current user\n\
|
||||
-g, --group print only the effective group ID\n\
|
||||
-G, --groups print all group IDs\n\
|
||||
-n, --name print a name instead of a number, for -ugG\n\
|
||||
@@ -101,6 +111,7 @@ int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
int optc;
|
||||
int selinux_enabled = (is_selinux_enabled () > 0);
|
||||
|
||||
/* If true, output the list of all group IDs. -G */
|
||||
bool just_group_list = false;
|
||||
@@ -119,13 +130,22 @@ main (int argc, char **argv)
|
||||
|
||||
atexit (close_stdout);
|
||||
|
||||
while ((optc = getopt_long (argc, argv, "agnruG", longopts, NULL)) != -1)
|
||||
while ((optc = getopt_long (argc, argv, "agnruGZ", longopts, NULL)) != -1)
|
||||
{
|
||||
switch (optc)
|
||||
{
|
||||
case 'a':
|
||||
/* Ignore -a, for compatibility with SVR4. */
|
||||
break;
|
||||
|
||||
case 'Z':
|
||||
/* politely decline if we're not on a selinux-enabled kernel. */
|
||||
if (!selinux_enabled)
|
||||
error (EXIT_FAILURE, 0,
|
||||
_("--context (-Z) works only on an SELinux-enabled kernel"));
|
||||
just_context = 1;
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
just_group = true;
|
||||
break;
|
||||
@@ -148,19 +168,38 @@ main (int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
if (just_user + just_group + just_group_list > 1)
|
||||
error (EXIT_FAILURE, 0, _("cannot print only user and only group"));
|
||||
|
||||
if (just_user + just_group + just_group_list == 0 && (use_real | use_name))
|
||||
error (EXIT_FAILURE, 0,
|
||||
_("cannot print only names or real IDs in default format"));
|
||||
|
||||
if (argc - optind > 1)
|
||||
if (1 < argc - optind)
|
||||
{
|
||||
error (0, 0, _("extra operand %s"), quote (argv[optind + 1]));
|
||||
usage (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (argc - optind == 1 && just_context)
|
||||
error (EXIT_FAILURE, 0,
|
||||
_("cannot print security context when user specified"));
|
||||
|
||||
if (just_context && !selinux_enabled)
|
||||
error (EXIT_FAILURE, 0, _("\
|
||||
cannot display context when selinux not enabled or when displaying the id\n\
|
||||
of a different user"));
|
||||
|
||||
/* If we are on a selinux-enabled kernel, get our context.
|
||||
Otherwise, leave the context variable alone - it has
|
||||
been initialized known invalid value; if we see this invalid
|
||||
value later, we will know we are on a non-selinux kernel. */
|
||||
if (selinux_enabled)
|
||||
{
|
||||
if (getcon (&context) && just_context)
|
||||
error (EXIT_FAILURE, 0, _("can't get process context"));
|
||||
}
|
||||
|
||||
if (just_user + just_group + just_group_list + just_context > 1)
|
||||
error (EXIT_FAILURE, 0, _("cannot print \"only\" of more than one choice"));
|
||||
|
||||
if (just_user + just_group + just_group_list == 0 && (use_real | use_name))
|
||||
error (EXIT_FAILURE, 0,
|
||||
_("cannot print only names or real IDs in default format"));
|
||||
|
||||
if (argc - optind == 1)
|
||||
{
|
||||
struct passwd *pwd = getpwnam (argv[optind]);
|
||||
@@ -183,6 +222,8 @@ main (int argc, char **argv)
|
||||
print_group (use_real ? rgid : egid);
|
||||
else if (just_group_list)
|
||||
print_group_list (argv[optind]);
|
||||
else if (just_context)
|
||||
fputs (context, stdout);
|
||||
else
|
||||
print_full_info (argv[optind]);
|
||||
putchar ('\n');
|
||||
@@ -385,4 +426,6 @@ print_full_info (const char *username)
|
||||
free (groups);
|
||||
}
|
||||
#endif /* HAVE_GETGROUPS */
|
||||
if (context != NULL)
|
||||
printf (" context=%s", context);
|
||||
}
|
||||
|
||||
104
src/install.c
104
src/install.c
@@ -24,6 +24,7 @@
|
||||
#include <signal.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#include <selinux/selinux.h>
|
||||
|
||||
#include "system.h"
|
||||
#include "backupfile.h"
|
||||
@@ -35,6 +36,7 @@
|
||||
#include "mkdir-p.h"
|
||||
#include "modechange.h"
|
||||
#include "quote.h"
|
||||
#include "quotearg.h"
|
||||
#include "savewd.h"
|
||||
#include "stat-time.h"
|
||||
#include "utimens.h"
|
||||
@@ -49,6 +51,9 @@
|
||||
# include <sys/wait.h>
|
||||
#endif
|
||||
|
||||
static int selinux_enabled = 0;
|
||||
static bool use_default_selinux_context = true;
|
||||
|
||||
#if ! HAVE_ENDGRENT
|
||||
# define endgrent() ((void) 0)
|
||||
#endif
|
||||
@@ -121,15 +126,28 @@ static bool strip_files;
|
||||
/* If true, install a directory instead of a regular file. */
|
||||
static bool dir_arg;
|
||||
|
||||
/* For long options that have no equivalent short option, use a
|
||||
non-character as a pseudo short option, starting with CHAR_MAX + 1. */
|
||||
enum
|
||||
{
|
||||
PRESERVE_CONTEXT_OPTION = CHAR_MAX + 1
|
||||
};
|
||||
|
||||
static struct option const long_options[] =
|
||||
{
|
||||
{"backup", optional_argument, NULL, 'b'},
|
||||
{GETOPT_SELINUX_CONTEXT_OPTION_DECL},
|
||||
{"directory", no_argument, NULL, 'd'},
|
||||
{"group", required_argument, NULL, 'g'},
|
||||
{"mode", required_argument, NULL, 'm'},
|
||||
{"no-target-directory", no_argument, NULL, 'T'},
|
||||
{"owner", required_argument, NULL, 'o'},
|
||||
{"preserve-timestamps", no_argument, NULL, 'p'},
|
||||
{"preserve-context", no_argument, NULL, PRESERVE_CONTEXT_OPTION},
|
||||
/* Continue silent support for --preserve_context until Jan 2008. FIXME-obs
|
||||
After that, FIXME-obs: warn in, say, late 2008, and disable altogether
|
||||
a year or two later. */
|
||||
{"preserve_context", no_argument, NULL, PRESERVE_CONTEXT_OPTION},
|
||||
{"strip", no_argument, NULL, 's'},
|
||||
{"suffix", required_argument, NULL, 'S'},
|
||||
{"target-directory", required_argument, NULL, 't'},
|
||||
@@ -156,6 +174,7 @@ cp_option_init (struct cp_options *x)
|
||||
x->preserve_mode = false;
|
||||
x->preserve_timestamps = false;
|
||||
x->require_preserve = false;
|
||||
x->require_preserve_context = false;
|
||||
x->recursive = false;
|
||||
x->sparse_mode = SPARSE_AUTO;
|
||||
x->symbolic_link = false;
|
||||
@@ -169,11 +188,47 @@ cp_option_init (struct cp_options *x)
|
||||
x->stdin_tty = false;
|
||||
|
||||
x->update = false;
|
||||
x->preserve_security_context = false;
|
||||
x->verbose = false;
|
||||
x->dest_info = NULL;
|
||||
x->src_info = NULL;
|
||||
}
|
||||
|
||||
/* Modify file context to match the specified policy.
|
||||
If an error occurs the file will remain with the default directory
|
||||
context. */
|
||||
static void
|
||||
setdefaultfilecon (char const *file)
|
||||
{
|
||||
struct stat st;
|
||||
security_context_t scontext = NULL;
|
||||
if (selinux_enabled != 1)
|
||||
{
|
||||
/* Indicate no context found. */
|
||||
return;
|
||||
}
|
||||
if (lstat (file, &st) != 0)
|
||||
return;
|
||||
|
||||
/* If there's an error determining the context, or it has none,
|
||||
return to allow default context */
|
||||
if ((matchpathcon (file, st.st_mode, &scontext) != 0) ||
|
||||
(strcmp (scontext, "<<none>>") == 0))
|
||||
{
|
||||
if (scontext != NULL)
|
||||
freecon (scontext);
|
||||
return;
|
||||
}
|
||||
|
||||
if (lsetfilecon (file, scontext) < 0 && errno != ENOTSUP)
|
||||
error (0, errno,
|
||||
_("warning: %s: failed to change context to %s"),
|
||||
quotearg_colon (file), scontext);
|
||||
|
||||
freecon (scontext);
|
||||
return;
|
||||
}
|
||||
|
||||
/* FILE is the last operand of this command. Return true if FILE is a
|
||||
directory. But report an error there is a problem accessing FILE,
|
||||
or if FILE does not exist but would have to refer to an existing
|
||||
@@ -222,6 +277,9 @@ main (int argc, char **argv)
|
||||
bool no_target_directory = false;
|
||||
int n_files;
|
||||
char **file;
|
||||
security_context_t scontext = NULL;
|
||||
/* set iff kernel has extra selinux system calls */
|
||||
selinux_enabled = (0 < is_selinux_enabled ());
|
||||
|
||||
initialize_main (&argc, &argv);
|
||||
program_name = argv[0];
|
||||
@@ -243,7 +301,7 @@ main (int argc, char **argv)
|
||||
we'll actually use backup_suffix_string. */
|
||||
backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX");
|
||||
|
||||
while ((optc = getopt_long (argc, argv, "bcsDdg:m:o:pt:TvS:", long_options,
|
||||
while ((optc = getopt_long (argc, argv, "bcsDdg:m:o:pt:TvS:Z:", long_options,
|
||||
NULL)) != -1)
|
||||
{
|
||||
switch (optc)
|
||||
@@ -305,6 +363,27 @@ main (int argc, char **argv)
|
||||
case 'T':
|
||||
no_target_directory = true;
|
||||
break;
|
||||
|
||||
case PRESERVE_CONTEXT_OPTION:
|
||||
if ( ! selinux_enabled)
|
||||
{
|
||||
error (0, 0, _("Warning: ignoring --preserve-context; "
|
||||
"this kernel is not SELinux-enabled."));
|
||||
break;
|
||||
}
|
||||
x.preserve_security_context = true;
|
||||
use_default_selinux_context = false;
|
||||
break;
|
||||
case 'Z':
|
||||
if ( ! selinux_enabled)
|
||||
{
|
||||
error (0, 0, _("Warning: ignoring --context (-Z); "
|
||||
"this kernel is not SELinux-enabled."));
|
||||
break;
|
||||
}
|
||||
scontext = optarg;
|
||||
use_default_selinux_context = false;
|
||||
break;
|
||||
case_GETOPT_HELP_CHAR;
|
||||
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
|
||||
default:
|
||||
@@ -320,6 +399,11 @@ main (int argc, char **argv)
|
||||
error (EXIT_FAILURE, 0,
|
||||
_("target directory not allowed when installing a directory"));
|
||||
|
||||
if (x.preserve_security_context && scontext != NULL)
|
||||
error (EXIT_FAILURE, 0,
|
||||
_("cannot force target context to %s and preserve it"),
|
||||
quote (scontext));
|
||||
|
||||
if (backup_suffix_string)
|
||||
simple_backup_suffix = xstrdup (backup_suffix_string);
|
||||
|
||||
@@ -328,6 +412,11 @@ main (int argc, char **argv)
|
||||
version_control_string)
|
||||
: no_backups);
|
||||
|
||||
if (scontext && setfscreatecon (scontext) < 0)
|
||||
error (EXIT_FAILURE, errno,
|
||||
_("failed to set default file creation context to %s"),
|
||||
quote (scontext));
|
||||
|
||||
n_files = argc - optind;
|
||||
file = argv + optind;
|
||||
|
||||
@@ -503,6 +592,7 @@ copy_file (const char *from, const char *to, const struct cp_options *x)
|
||||
static bool
|
||||
change_attributes (char const *name)
|
||||
{
|
||||
bool ok = false;
|
||||
/* chown must precede chmod because on some systems,
|
||||
chown clears the set[ug]id bits for non-superusers,
|
||||
resulting in incorrect permissions.
|
||||
@@ -521,9 +611,12 @@ change_attributes (char const *name)
|
||||
else if (chmod (name, mode) != 0)
|
||||
error (0, errno, _("cannot change permissions of %s"), quote (name));
|
||||
else
|
||||
return true;
|
||||
ok = true;
|
||||
|
||||
return false;
|
||||
if (use_default_selinux_context)
|
||||
setdefaultfilecon (name);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
/* Set the timestamps of file TO to match those of file FROM.
|
||||
@@ -687,6 +780,11 @@ Mandatory arguments to long options are mandatory for short options too.\n\
|
||||
-T, --no-target-directory treat DEST as a normal file\n\
|
||||
-v, --verbose print the name of each directory as it is created\n\
|
||||
"), stdout);
|
||||
fputs (_("\
|
||||
--preserve-context preserve SELinux security context\n\
|
||||
-Z, --context=CONTEXT set SELinux security context of files and directories\n\
|
||||
"), stdout);
|
||||
|
||||
fputs (HELP_OPTION_DESCRIPTION, stdout);
|
||||
fputs (VERSION_OPTION_DESCRIPTION, stdout);
|
||||
fputs (_("\
|
||||
|
||||
91
src/ls.c
91
src/ls.c
@@ -61,6 +61,7 @@
|
||||
#include <pwd.h>
|
||||
#include <getopt.h>
|
||||
#include <signal.h>
|
||||
#include <selinux/selinux.h>
|
||||
|
||||
/* Use SA_NOCLDSTOP as a proxy for whether the sigaction machinery is
|
||||
present. */
|
||||
@@ -167,24 +168,20 @@ struct fileinfo
|
||||
zero. */
|
||||
mode_t linkmode;
|
||||
|
||||
/* SELinux security context. */
|
||||
security_context_t scontext;
|
||||
|
||||
bool stat_ok;
|
||||
|
||||
/* For symbolic link and color printing, true if linked-to file
|
||||
exists, otherwise false. */
|
||||
bool linkok;
|
||||
|
||||
#if USE_ACL
|
||||
/* For long listings, true if the file has an access control list. */
|
||||
/* For long listings, true if the file has an access control list,
|
||||
or an SELinux security context. */
|
||||
bool have_acl;
|
||||
#endif
|
||||
};
|
||||
|
||||
#if USE_ACL
|
||||
# define FILE_HAS_ACL(F) ((F)->have_acl)
|
||||
#else
|
||||
# define FILE_HAS_ACL(F) 0
|
||||
#endif
|
||||
|
||||
#define LEN_STR_PAIR(s) sizeof (s) - 1, s
|
||||
|
||||
/* Null is a valid character in a color indicator (think about Epson
|
||||
@@ -320,14 +317,12 @@ static struct pending *pending_dirs;
|
||||
static time_t current_time = TYPE_MINIMUM (time_t);
|
||||
static int current_time_ns = -1;
|
||||
|
||||
static bool print_scontext;
|
||||
|
||||
/* Whether any of the files has an ACL. This affects the width of the
|
||||
mode column. */
|
||||
|
||||
#if USE_ACL
|
||||
static bool any_has_acl;
|
||||
#else
|
||||
enum { any_has_acl = false };
|
||||
#endif
|
||||
|
||||
/* The number of columns to use for columns containing inode numbers,
|
||||
block sizes, link counts, owners, groups, authors, major device
|
||||
@@ -336,6 +331,7 @@ enum { any_has_acl = false };
|
||||
static int inode_number_width;
|
||||
static int block_size_width;
|
||||
static int nlink_width;
|
||||
static int scontext_width;
|
||||
static int owner_width;
|
||||
static int group_width;
|
||||
static int author_width;
|
||||
@@ -787,6 +783,7 @@ static struct option const long_options[] =
|
||||
{"time-style", required_argument, NULL, TIME_STYLE_OPTION},
|
||||
{"color", optional_argument, NULL, COLOR_OPTION},
|
||||
{"block-size", required_argument, NULL, BLOCK_SIZE_OPTION},
|
||||
{"context", no_argument, 0, 'Z'},
|
||||
{"author", no_argument, NULL, AUTHOR_OPTION},
|
||||
{GETOPT_HELP_OPTION_DECL},
|
||||
{GETOPT_VERSION_OPTION_DECL},
|
||||
@@ -1246,6 +1243,7 @@ main (int argc, char **argv)
|
||||
|
||||
format_needs_stat = sort_type == sort_time || sort_type == sort_size
|
||||
|| format == long_format
|
||||
|| print_scontext
|
||||
|| print_block_size;
|
||||
format_needs_type = (! format_needs_stat
|
||||
&& (recursive
|
||||
@@ -1439,6 +1437,7 @@ decode_switches (int argc, char **argv)
|
||||
ignore_mode = IGNORE_DEFAULT;
|
||||
ignore_patterns = NULL;
|
||||
hide_patterns = NULL;
|
||||
print_scontext = false;
|
||||
|
||||
/* FIXME: put this in a function. */
|
||||
{
|
||||
@@ -1514,7 +1513,7 @@ decode_switches (int argc, char **argv)
|
||||
}
|
||||
|
||||
while ((c = getopt_long (argc, argv,
|
||||
"abcdfghiklmnopqrstuvw:xABCDFGHI:LNQRST:UX1",
|
||||
"abcdfghiklmnopqrstuvw:xABCDFGHI:LNQRST:UXZ1",
|
||||
long_options, NULL)) != -1)
|
||||
{
|
||||
switch (c)
|
||||
@@ -1813,6 +1812,10 @@ decode_switches (int argc, char **argv)
|
||||
file_output_block_size = output_block_size = 1;
|
||||
break;
|
||||
|
||||
case 'Z':
|
||||
print_scontext = true;
|
||||
break;
|
||||
|
||||
case_GETOPT_HELP_CHAR;
|
||||
|
||||
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
|
||||
@@ -2516,18 +2519,22 @@ clear_files (void)
|
||||
struct fileinfo *f = sorted_file[i];
|
||||
free (f->name);
|
||||
free (f->linkname);
|
||||
if (f->scontext)
|
||||
{
|
||||
freecon (f->scontext);
|
||||
f->scontext = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
cwd_n_used = 0;
|
||||
#if USE_ACL
|
||||
any_has_acl = false;
|
||||
#endif
|
||||
inode_number_width = 0;
|
||||
block_size_width = 0;
|
||||
nlink_width = 0;
|
||||
owner_width = 0;
|
||||
group_width = 0;
|
||||
author_width = 0;
|
||||
scontext_width = 0;
|
||||
major_device_number_width = 0;
|
||||
minor_device_number_width = 0;
|
||||
file_size_width = 0;
|
||||
@@ -2589,9 +2596,11 @@ gobble_file (char const *name, enum filetype type, ino_t inode,
|
||||
)))))
|
||||
|
||||
{
|
||||
/* FIXME-c99: move this decl "down", once ls.c stabilizes. */
|
||||
bool file_has_security_context = false;
|
||||
/* Absolute name of this file. */
|
||||
char *absolute_name;
|
||||
|
||||
bool do_deref;
|
||||
int err;
|
||||
|
||||
if (name[0] == '/' || dirname[0] == 0)
|
||||
@@ -2606,6 +2615,7 @@ gobble_file (char const *name, enum filetype type, ino_t inode,
|
||||
{
|
||||
case DEREF_ALWAYS:
|
||||
err = stat (absolute_name, &f->stat);
|
||||
do_deref = true;
|
||||
break;
|
||||
|
||||
case DEREF_COMMAND_LINE_ARGUMENTS:
|
||||
@@ -2614,6 +2624,7 @@ gobble_file (char const *name, enum filetype type, ino_t inode,
|
||||
{
|
||||
bool need_lstat;
|
||||
err = stat (absolute_name, &f->stat);
|
||||
do_deref = true;
|
||||
|
||||
if (dereference == DEREF_COMMAND_LINE_ARGUMENTS)
|
||||
break;
|
||||
@@ -2632,9 +2643,26 @@ gobble_file (char const *name, enum filetype type, ino_t inode,
|
||||
|
||||
default: /* DEREF_NEVER */
|
||||
err = lstat (absolute_name, &f->stat);
|
||||
do_deref = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (err == 0 && print_scontext)
|
||||
{
|
||||
int attr_len = (do_deref
|
||||
? getfilecon (absolute_name, &f->scontext)
|
||||
: lgetfilecon (absolute_name, &f->scontext));
|
||||
err = (attr_len < 0);
|
||||
file_has_security_context = (err == 0);
|
||||
|
||||
/* When requesting security context information, don't make
|
||||
ls fail just because the file (even a command line argument)
|
||||
isn't on the right type of file system. I.e., a getfilecon
|
||||
failure isn't in the same class as a stat failure. */
|
||||
if (err && (errno == ENOTSUP || errno == ENODATA))
|
||||
err = 0;
|
||||
}
|
||||
|
||||
if (err != 0)
|
||||
{
|
||||
/* Failure to stat a command line argument leads to
|
||||
@@ -2653,16 +2681,14 @@ gobble_file (char const *name, enum filetype type, ino_t inode,
|
||||
|
||||
f->stat_ok = true;
|
||||
|
||||
#if USE_ACL
|
||||
if (format == long_format)
|
||||
{
|
||||
int n = file_has_acl (absolute_name, &f->stat);
|
||||
f->have_acl = (0 < n);
|
||||
f->have_acl = (0 < n || file_has_security_context);
|
||||
any_has_acl |= f->have_acl;
|
||||
if (n < 0)
|
||||
error (0, errno, "%s", quotearg_colon (absolute_name));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (S_ISLNK (f->stat.st_mode)
|
||||
&& (format == long_format || check_symlink_color))
|
||||
@@ -2738,6 +2764,13 @@ gobble_file (char const *name, enum filetype type, ino_t inode,
|
||||
author_width = len;
|
||||
}
|
||||
|
||||
if (print_scontext)
|
||||
{
|
||||
int len = f->scontext ? strlen (f->scontext) : 0;
|
||||
if (scontext_width < len)
|
||||
scontext_width = len;
|
||||
}
|
||||
|
||||
{
|
||||
char buf[INT_BUFSIZE_BOUND (uintmax_t)];
|
||||
int len = strlen (umaxtostr (f->stat.st_nlink, buf));
|
||||
@@ -3387,7 +3420,7 @@ print_long_format (const struct fileinfo *f)
|
||||
struct tm *when_local;
|
||||
|
||||
/* Compute the mode string, except remove the trailing space if no
|
||||
files in this directory have ACLs. */
|
||||
file in this directory has an ACL or SELinux security context. */
|
||||
if (f->stat_ok)
|
||||
filemodestring (&f->stat, modebuf);
|
||||
else
|
||||
@@ -3398,7 +3431,7 @@ print_long_format (const struct fileinfo *f)
|
||||
}
|
||||
if (! any_has_acl)
|
||||
modebuf[10] = '\0';
|
||||
else if (FILE_HAS_ACL (f))
|
||||
else if (f->have_acl)
|
||||
modebuf[10] = '+';
|
||||
|
||||
switch (time_type)
|
||||
@@ -3463,7 +3496,7 @@ print_long_format (const struct fileinfo *f)
|
||||
|
||||
DIRED_INDENT ();
|
||||
|
||||
if (print_owner | print_group | print_author)
|
||||
if (print_owner | print_group | print_author | print_scontext)
|
||||
{
|
||||
DIRED_FPUTS (buf, stdout, p - buf);
|
||||
|
||||
@@ -3476,6 +3509,10 @@ print_long_format (const struct fileinfo *f)
|
||||
if (print_author)
|
||||
format_user (f->stat.st_author, author_width, f->stat_ok);
|
||||
|
||||
if (print_scontext)
|
||||
format_user_or_group ((f->scontext ? f->scontext : "?"),
|
||||
0, scontext_width);
|
||||
|
||||
p = buf;
|
||||
}
|
||||
|
||||
@@ -3812,6 +3849,10 @@ print_file_name_and_frills (const struct fileinfo *f)
|
||||
human_readable (ST_NBLOCKS (f->stat), buf, human_output_opts,
|
||||
ST_NBLOCKSIZE, output_block_size));
|
||||
|
||||
if (print_scontext)
|
||||
printf ("%*s ", format == with_commas ? 0 : scontext_width,
|
||||
(f->scontext ? f->scontext : "?"));
|
||||
|
||||
print_name_with_quoting (f->name, FILE_OR_LINK_MODE (f), f->linkok,
|
||||
f->stat_ok, f->filetype, NULL);
|
||||
|
||||
@@ -3975,6 +4016,9 @@ length_of_file_name_and_frills (const struct fileinfo *f)
|
||||
output_block_size))
|
||||
: block_size_width);
|
||||
|
||||
if (print_scontext)
|
||||
len += 1 + (format == with_commas ? strlen (f->scontext) : scontext_width);
|
||||
|
||||
quote_name (NULL, f->name, filename_quoting_options, &name_width);
|
||||
len += name_width;
|
||||
|
||||
@@ -4403,6 +4447,7 @@ Mandatory arguments to long options are mandatory for short options too.\n\
|
||||
-w, --width=COLS assume screen width instead of current value\n\
|
||||
-x list entries by lines instead of by columns\n\
|
||||
-X sort alphabetically by entry extension\n\
|
||||
-Z, --context print any SELinux security context of each file\n\
|
||||
-1 list one file per line\n\
|
||||
"), stdout);
|
||||
fputs (HELP_OPTION_DESCRIPTION, stdout);
|
||||
|
||||
18
src/mkdir.c
18
src/mkdir.c
@@ -1,5 +1,5 @@
|
||||
/* mkdir -- make directories
|
||||
Copyright (C) 90, 1995-2002, 2004, 2005, 2006 Free Software Foundation, Inc.
|
||||
Copyright (C) 90, 1995-2002, 2004-2007 Free Software Foundation, 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
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <stdio.h>
|
||||
#include <getopt.h>
|
||||
#include <sys/types.h>
|
||||
#include <selinux/selinux.h>
|
||||
|
||||
#include "system.h"
|
||||
#include "error.h"
|
||||
@@ -40,6 +41,7 @@ char *program_name;
|
||||
|
||||
static struct option const longopts[] =
|
||||
{
|
||||
{GETOPT_SELINUX_CONTEXT_OPTION_DECL},
|
||||
{"mode", required_argument, NULL, 'm'},
|
||||
{"parents", no_argument, NULL, 'p'},
|
||||
{"verbose", no_argument, NULL, 'v'},
|
||||
@@ -68,6 +70,8 @@ Mandatory arguments to long options are mandatory for short options too.\n\
|
||||
-m, --mode=MODE set file mode (as in chmod), not a=rwx - umask\n\
|
||||
-p, --parents no error if existing, make parent directories as needed\n\
|
||||
-v, --verbose print a message for each created directory\n\
|
||||
-Z, --context=CTX set the SELinux security context of each created\n\
|
||||
directory to CTX\n\
|
||||
"), stdout);
|
||||
fputs (HELP_OPTION_DESCRIPTION, stdout);
|
||||
fputs (VERSION_OPTION_DESCRIPTION, stdout);
|
||||
@@ -140,7 +144,9 @@ main (int argc, char **argv)
|
||||
{
|
||||
const char *specified_mode = NULL;
|
||||
int optc;
|
||||
security_context_t scontext = NULL;
|
||||
struct mkdir_options options;
|
||||
|
||||
options.make_ancestor_function = NULL;
|
||||
options.mode = S_IRWXUGO;
|
||||
options.mode_bits = 0;
|
||||
@@ -154,7 +160,7 @@ main (int argc, char **argv)
|
||||
|
||||
atexit (close_stdout);
|
||||
|
||||
while ((optc = getopt_long (argc, argv, "pm:v", longopts, NULL)) != -1)
|
||||
while ((optc = getopt_long (argc, argv, "pm:vZ:", longopts, NULL)) != -1)
|
||||
{
|
||||
switch (optc)
|
||||
{
|
||||
@@ -167,6 +173,9 @@ main (int argc, char **argv)
|
||||
case 'v': /* --verbose */
|
||||
options.created_directory_format = _("created directory %s");
|
||||
break;
|
||||
case 'Z':
|
||||
scontext = optarg;
|
||||
break;
|
||||
case_GETOPT_HELP_CHAR;
|
||||
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
|
||||
default:
|
||||
@@ -180,6 +189,11 @@ main (int argc, char **argv)
|
||||
usage (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (scontext && setfscreatecon (scontext) < 0)
|
||||
error (EXIT_FAILURE, errno,
|
||||
_("failed to set default file creation context to %s"),
|
||||
quote (optarg));
|
||||
|
||||
if (options.make_ancestor_function || specified_mode)
|
||||
{
|
||||
mode_t umask_value = umask (0);
|
||||
|
||||
18
src/mkfifo.c
18
src/mkfifo.c
@@ -1,5 +1,5 @@
|
||||
/* mkfifo -- make fifo's (named pipes)
|
||||
Copyright (C) 90, 91, 1995-2006 Free Software Foundation, Inc.
|
||||
Copyright (C) 90, 91, 1995-2007 Free Software Foundation, 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
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <stdio.h>
|
||||
#include <getopt.h>
|
||||
#include <sys/types.h>
|
||||
#include <selinux/selinux.h>
|
||||
|
||||
#include "system.h"
|
||||
#include "error.h"
|
||||
@@ -37,6 +38,7 @@ char *program_name;
|
||||
|
||||
static struct option const longopts[] =
|
||||
{
|
||||
{GETOPT_SELINUX_CONTEXT_OPTION_DECL},
|
||||
{"mode", required_argument, NULL, 'm'},
|
||||
{GETOPT_HELP_OPTION_DECL},
|
||||
{GETOPT_VERSION_OPTION_DECL},
|
||||
@@ -55,6 +57,9 @@ usage (int status)
|
||||
fputs (_("\
|
||||
Create named pipes (FIFOs) with the given NAMEs.\n\
|
||||
\n\
|
||||
"), stdout);
|
||||
fputs (_("\
|
||||
-Z, --context=CTX set the SELinux security context of each NAME to CTX\n\
|
||||
"), stdout);
|
||||
fputs (_("\
|
||||
Mandatory arguments to long options are mandatory for short options too.\n\
|
||||
@@ -76,6 +81,7 @@ main (int argc, char **argv)
|
||||
char const *specified_mode = NULL;
|
||||
int exit_status = EXIT_SUCCESS;
|
||||
int optc;
|
||||
security_context_t scontext = NULL;
|
||||
|
||||
initialize_main (&argc, &argv);
|
||||
program_name = argv[0];
|
||||
@@ -85,13 +91,16 @@ main (int argc, char **argv)
|
||||
|
||||
atexit (close_stdout);
|
||||
|
||||
while ((optc = getopt_long (argc, argv, "m:", longopts, NULL)) != -1)
|
||||
while ((optc = getopt_long (argc, argv, "m:Z:", longopts, NULL)) != -1)
|
||||
{
|
||||
switch (optc)
|
||||
{
|
||||
case 'm':
|
||||
specified_mode = optarg;
|
||||
break;
|
||||
case 'Z':
|
||||
scontext = optarg;
|
||||
break;
|
||||
case_GETOPT_HELP_CHAR;
|
||||
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
|
||||
default:
|
||||
@@ -105,6 +114,11 @@ main (int argc, char **argv)
|
||||
usage (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (scontext && setfscreatecon (scontext) < 0)
|
||||
error (EXIT_FAILURE, errno,
|
||||
_("failed to set default file creation context to %s"),
|
||||
quote (optarg));
|
||||
|
||||
newmode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
|
||||
if (specified_mode)
|
||||
{
|
||||
|
||||
18
src/mknod.c
18
src/mknod.c
@@ -1,5 +1,5 @@
|
||||
/* mknod -- make special files
|
||||
Copyright (C) 90, 91, 1995-2006 Free Software Foundation, Inc.
|
||||
Copyright (C) 90, 91, 1995-2007 Free Software Foundation, 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
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <stdio.h>
|
||||
#include <getopt.h>
|
||||
#include <sys/types.h>
|
||||
#include <selinux/selinux.h>
|
||||
|
||||
#include "system.h"
|
||||
#include "error.h"
|
||||
@@ -38,6 +39,7 @@ char *program_name;
|
||||
|
||||
static struct option const longopts[] =
|
||||
{
|
||||
{GETOPT_SELINUX_CONTEXT_OPTION_DECL},
|
||||
{"mode", required_argument, NULL, 'm'},
|
||||
{GETOPT_HELP_OPTION_DECL},
|
||||
{GETOPT_VERSION_OPTION_DECL},
|
||||
@@ -57,6 +59,9 @@ usage (int status)
|
||||
fputs (_("\
|
||||
Create the special file NAME of the given TYPE.\n\
|
||||
\n\
|
||||
"), stdout);
|
||||
fputs(_("\
|
||||
-Z, --context=CTX set the SELinux security context of NAME to CTX\n\
|
||||
"), stdout);
|
||||
fputs (_("\
|
||||
Mandatory arguments to long options are mandatory for short options too.\n\
|
||||
@@ -92,6 +97,7 @@ main (int argc, char **argv)
|
||||
int optc;
|
||||
int expected_operands;
|
||||
mode_t node_type;
|
||||
security_context_t scontext = NULL;
|
||||
|
||||
initialize_main (&argc, &argv);
|
||||
program_name = argv[0];
|
||||
@@ -101,13 +107,16 @@ main (int argc, char **argv)
|
||||
|
||||
atexit (close_stdout);
|
||||
|
||||
while ((optc = getopt_long (argc, argv, "m:", longopts, NULL)) != -1)
|
||||
while ((optc = getopt_long (argc, argv, "m:Z:", longopts, NULL)) != -1)
|
||||
{
|
||||
switch (optc)
|
||||
{
|
||||
case 'm':
|
||||
specified_mode = optarg;
|
||||
break;
|
||||
case 'Z':
|
||||
scontext = optarg;
|
||||
break;
|
||||
case_GETOPT_HELP_CHAR;
|
||||
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
|
||||
default:
|
||||
@@ -157,6 +166,11 @@ main (int argc, char **argv)
|
||||
usage (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (scontext && setfscreatecon (scontext) < 0)
|
||||
error (EXIT_FAILURE, errno,
|
||||
_("failed to set default file creation context to %s"),
|
||||
quote (optarg));
|
||||
|
||||
/* Only check the first character, to allow mnemonic usage like
|
||||
`mknod /dev/rst0 character 18 0'. */
|
||||
|
||||
|
||||
5
src/mv.c
5
src/mv.c
@@ -22,6 +22,7 @@
|
||||
#include <getopt.h>
|
||||
#include <sys/types.h>
|
||||
#include <assert.h>
|
||||
#include <selinux/selinux.h>
|
||||
|
||||
#include "system.h"
|
||||
#include "argmatch.h"
|
||||
@@ -113,6 +114,8 @@ rm_option_init (struct rm_options *x)
|
||||
static void
|
||||
cp_option_init (struct cp_options *x)
|
||||
{
|
||||
bool selinux_enabled = (0 < is_selinux_enabled ());
|
||||
|
||||
x->copy_as_regular = false; /* FIXME: maybe make this an option */
|
||||
x->dereference = DEREF_NEVER;
|
||||
x->unlink_dest_before_opening = false;
|
||||
@@ -126,7 +129,9 @@ cp_option_init (struct cp_options *x)
|
||||
x->preserve_links = true;
|
||||
x->preserve_mode = true;
|
||||
x->preserve_timestamps = true;
|
||||
x->preserve_security_context = selinux_enabled;
|
||||
x->require_preserve = false; /* FIXME: maybe make this an option */
|
||||
x->require_preserve_context = false;
|
||||
x->recursive = true;
|
||||
x->sparse_mode = SPARSE_AUTO; /* FIXME: maybe make this an option */
|
||||
x->symbolic_link = false;
|
||||
|
||||
249
src/runcon.c
Normal file
249
src/runcon.c
Normal file
@@ -0,0 +1,249 @@
|
||||
/*
|
||||
* runcon [ context |
|
||||
* ( [ -c ] [ -r role ] [-t type] [ -u user ] [ -l levelrange ] )
|
||||
* command [arg1 [arg2 ...] ]
|
||||
*
|
||||
* attempt to run the specified command with the specified context.
|
||||
*
|
||||
* -r role : use the current context with the specified role
|
||||
* -t type : use the current context with the specified type
|
||||
* -u user : use the current context with the specified user
|
||||
* -l level : use the current context with the specified level range
|
||||
* -c : compute process transition context before modifying
|
||||
*
|
||||
* Contexts are interpreted as follows:
|
||||
*
|
||||
* Number of MLS
|
||||
* components system?
|
||||
*
|
||||
* 1 - type
|
||||
* 2 - role:type
|
||||
* 3 Y role:type:range
|
||||
* 3 N user:role:type
|
||||
* 4 Y user:role:type:range
|
||||
* 4 N error
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <getopt.h>
|
||||
#include <selinux/selinux.h>
|
||||
#include <selinux/context.h>
|
||||
#ifdef HAVE_SELINUX_FLASK_H
|
||||
# include <selinux/flask.h>
|
||||
#else
|
||||
# define SECCLASS_PROCESS 0
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include "system.h"
|
||||
#include "error.h"
|
||||
#include "quote.h"
|
||||
#include "quotearg.h"
|
||||
|
||||
/* The official name of this program (e.g., no `g' prefix). */
|
||||
#define PROGRAM_NAME "runcon"
|
||||
|
||||
#define AUTHORS "Russell Coker"
|
||||
|
||||
static struct option long_options[] = {
|
||||
{"role", required_argument, NULL, 'r'},
|
||||
{"type", required_argument, NULL, 't'},
|
||||
{"user", required_argument, NULL, 'u'},
|
||||
{"range", required_argument, NULL, 'l'},
|
||||
{"compute", no_argument, NULL, 'c'},
|
||||
{GETOPT_HELP_OPTION_DECL},
|
||||
{GETOPT_VERSION_OPTION_DECL},
|
||||
{NULL, 0, NULL, 0}
|
||||
};
|
||||
|
||||
/* The name the program was run with. */
|
||||
char *program_name;
|
||||
|
||||
void
|
||||
usage (int status)
|
||||
{
|
||||
if (status != EXIT_SUCCESS)
|
||||
fprintf (stderr, _("Try `%s --help' for more information.\n"),
|
||||
program_name);
|
||||
else
|
||||
{
|
||||
printf (_("\
|
||||
Usage: %s CONTEXT COMMAND [args]\n\
|
||||
or: %s [ -c ] [-u USER] [-r ROLE] [-t TYPE] [-l RANGE] COMMAND [args]\n\
|
||||
"), program_name, program_name);
|
||||
fputs (_("\
|
||||
Run a program in a different security context.\n\
|
||||
With neither CONTEXT nor COMMAND, print the current security context.\n\
|
||||
\n\
|
||||
CONTEXT Complete security context\n\
|
||||
-c, --compute compute process transition context before modifying\n\
|
||||
-t, --type=TYPE type (for same role as parent)\n\
|
||||
-u, --user=USER user identity\n\
|
||||
-r, --role=ROLE role\n\
|
||||
-l, --range=RANGE levelrange\n\
|
||||
\n\
|
||||
"), stdout);
|
||||
fputs (HELP_OPTION_DESCRIPTION, stdout);
|
||||
fputs (VERSION_OPTION_DESCRIPTION, stdout);
|
||||
}
|
||||
exit (status);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv, char **envp)
|
||||
{
|
||||
char *role = NULL;
|
||||
char *range = NULL;
|
||||
char *user = NULL;
|
||||
char *type = NULL;
|
||||
char *context = NULL;
|
||||
security_context_t cur_context = NULL;
|
||||
security_context_t file_context = NULL;
|
||||
security_context_t new_context = NULL;
|
||||
bool compute_trans = false;
|
||||
|
||||
context_t con;
|
||||
|
||||
initialize_main (&argc, &argv);
|
||||
program_name = argv[0];
|
||||
setlocale (LC_ALL, "");
|
||||
bindtextdomain (PACKAGE, LOCALEDIR);
|
||||
textdomain (PACKAGE);
|
||||
|
||||
atexit (close_stdout);
|
||||
|
||||
while (1)
|
||||
{
|
||||
int option_index = 0;
|
||||
int c = getopt_long (argc, argv, "+r:t:u:l:c", long_options,
|
||||
&option_index);
|
||||
if (c == -1)
|
||||
break;
|
||||
switch (c)
|
||||
{
|
||||
case 'r':
|
||||
if (role)
|
||||
error (EXIT_FAILURE, 0, _("multiple roles"));
|
||||
role = optarg;
|
||||
break;
|
||||
case 't':
|
||||
if (type)
|
||||
error (EXIT_FAILURE, 0, _("multiple types"));
|
||||
type = optarg;
|
||||
break;
|
||||
case 'u':
|
||||
if (user)
|
||||
error (EXIT_FAILURE, 0, _("multiple users"));
|
||||
user = optarg;
|
||||
break;
|
||||
case 'l':
|
||||
if (range)
|
||||
error (EXIT_FAILURE, 0, _("multiple levelranges"));
|
||||
range = optarg;
|
||||
break;
|
||||
case 'c':
|
||||
compute_trans = true;
|
||||
break;
|
||||
|
||||
case_GETOPT_HELP_CHAR;
|
||||
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
|
||||
default:
|
||||
usage (EXIT_FAILURE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (argc - optind == 0)
|
||||
{
|
||||
if (getcon (&cur_context) < 0)
|
||||
error (EXIT_FAILURE, errno, _("failed to get current context"));
|
||||
fputs (cur_context, stdout);
|
||||
fputc ('\n', stdout);
|
||||
exit (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
if (!(user || role || type || range || compute_trans))
|
||||
{
|
||||
if (optind >= argc)
|
||||
{
|
||||
error (0, 0, _("you must specify -c, -t, -u, -l, -r, or context"));
|
||||
usage (1);
|
||||
}
|
||||
context = argv[optind++];
|
||||
}
|
||||
|
||||
if (optind >= argc)
|
||||
{
|
||||
error (0, 0, _("no command specified"));
|
||||
usage (1);
|
||||
}
|
||||
|
||||
if (is_selinux_enabled () != 1)
|
||||
error (EXIT_FAILURE, 0,
|
||||
_("runcon may be used only on a SELinux kernel"));
|
||||
|
||||
if (context)
|
||||
{
|
||||
con = context_new (context);
|
||||
if (!con)
|
||||
error (EXIT_FAILURE, errno, _("failed to create security context: %s"),
|
||||
quotearg_colon (context));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (getcon (&cur_context) < 0)
|
||||
error (EXIT_FAILURE, errno, _("failed to get current context"));
|
||||
|
||||
/* We will generate context based on process transition */
|
||||
if (compute_trans)
|
||||
{
|
||||
/* Get context of file to be executed */
|
||||
if (getfilecon (argv[optind], &file_context) == -1)
|
||||
error (EXIT_FAILURE, errno,
|
||||
_("failed to get security context of %s"),
|
||||
quote (argv[optind]));
|
||||
/* compute result of process transition */
|
||||
if (security_compute_create (cur_context, file_context,
|
||||
SECCLASS_PROCESS, &new_context) != 0)
|
||||
error (EXIT_FAILURE, errno,
|
||||
_("failed to compute a new context"));
|
||||
/* free contexts */
|
||||
freecon (file_context);
|
||||
freecon (cur_context);
|
||||
|
||||
/* set cur_context equal to new_context */
|
||||
cur_context = new_context;
|
||||
}
|
||||
|
||||
con = context_new (cur_context);
|
||||
if (!con)
|
||||
error (EXIT_FAILURE, errno, _("failed to create security context: %s"),
|
||||
quotearg_colon (cur_context));
|
||||
if (user && context_user_set (con, user))
|
||||
error (EXIT_FAILURE, errno, _("failed to set new user %s"), user);
|
||||
if (type && context_type_set (con, type))
|
||||
error (EXIT_FAILURE, errno, _("failed to set new type %s"), type);
|
||||
if (range && context_range_set (con, range))
|
||||
error (EXIT_FAILURE, errno, _("failed to set new range %s"), range);
|
||||
if (role && context_role_set (con, role))
|
||||
error (EXIT_FAILURE, errno, _("failed to set new role %s"), role);
|
||||
}
|
||||
|
||||
if (security_check_context (context_str (con)) < 0)
|
||||
error (EXIT_FAILURE, errno, _("invalid context: %s"),
|
||||
quotearg_colon (context_str (con)));
|
||||
|
||||
if (setexeccon (context_str (con)) != 0)
|
||||
error (EXIT_FAILURE, errno, _("unable to set security context %s"),
|
||||
quote (context_str (con)));
|
||||
if (cur_context != NULL)
|
||||
freecon (cur_context);
|
||||
|
||||
execvp (argv[optind], argv + optind);
|
||||
|
||||
{
|
||||
int exit_status = (errno == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE);
|
||||
error (0, errno, "%s", argv[optind]);
|
||||
exit (exit_status);
|
||||
}
|
||||
}
|
||||
47
src/stat.c
47
src/stat.c
@@ -54,6 +54,7 @@
|
||||
#elif HAVE_OS_H /* BeOS */
|
||||
# include <fs_info.h>
|
||||
#endif
|
||||
#include <selinux/selinux.h>
|
||||
|
||||
#include "system.h"
|
||||
|
||||
@@ -158,6 +159,7 @@ enum
|
||||
};
|
||||
|
||||
static struct option const long_options[] = {
|
||||
{"context", no_argument, 0, 'Z'},
|
||||
{"dereference", no_argument, NULL, 'L'},
|
||||
{"file-system", no_argument, NULL, 'f'},
|
||||
{"filesystem", no_argument, NULL, 'f'}, /* obsolete and undocumented alias */
|
||||
@@ -171,6 +173,9 @@ static struct option const long_options[] = {
|
||||
|
||||
char *program_name;
|
||||
|
||||
/* Whether to follow symbolic links; True for --dereference (-L). */
|
||||
static bool follow_links;
|
||||
|
||||
/* Whether to interpret backslash-escape sequences.
|
||||
True for --printf=FMT, not for --format=FMT (-c). */
|
||||
static bool interpret_backslash_escapes;
|
||||
@@ -394,6 +399,26 @@ out_uint_x (char *pformat, size_t prefix_len, uintmax_t arg)
|
||||
printf (pformat, arg);
|
||||
}
|
||||
|
||||
/* Very specialized function (modifies FORMAT), just so as to avoid
|
||||
duplicating this code between both print_statfs and print_stat. */
|
||||
static void
|
||||
out_file_context (char const *filename, char *pformat, size_t prefix_len)
|
||||
{
|
||||
char *scontext;
|
||||
if ((follow_links
|
||||
? getfilecon (filename, &scontext)
|
||||
: lgetfilecon (filename, &scontext)) < 0)
|
||||
{
|
||||
error (0, errno, _("failed to get security context of %s"),
|
||||
quote (filename));
|
||||
scontext = NULL;
|
||||
}
|
||||
strcpy (pformat + prefix_len, "s");
|
||||
printf (pformat, (scontext ? scontext : "?"));
|
||||
if (scontext)
|
||||
freecon (scontext);
|
||||
}
|
||||
|
||||
/* print statfs info */
|
||||
static void
|
||||
print_statfs (char *pformat, size_t prefix_len, char m, char const *filename,
|
||||
@@ -472,7 +497,9 @@ print_statfs (char *pformat, size_t prefix_len, char m, char const *filename,
|
||||
case 'd':
|
||||
out_int (pformat, prefix_len, statfsbuf->f_ffree);
|
||||
break;
|
||||
|
||||
case 'C':
|
||||
out_file_context (filename, pformat, prefix_len);
|
||||
break;
|
||||
default:
|
||||
fputc ('?', stdout);
|
||||
break;
|
||||
@@ -595,6 +622,9 @@ print_stat (char *pformat, size_t prefix_len, char m,
|
||||
else
|
||||
out_uint (pformat, prefix_len, statbuf->st_ctime);
|
||||
break;
|
||||
case 'C':
|
||||
out_file_context (filename, pformat, prefix_len);
|
||||
break;
|
||||
default:
|
||||
fputc ('?', stdout);
|
||||
break;
|
||||
@@ -774,8 +804,7 @@ do_statfs (char const *filename, bool terse, char const *format)
|
||||
|
||||
/* stat the file and print what we find */
|
||||
static bool
|
||||
do_stat (char const *filename, bool follow_links, bool terse,
|
||||
char const *format)
|
||||
do_stat (char const *filename, bool terse, char const *format)
|
||||
{
|
||||
struct stat statbuf;
|
||||
|
||||
@@ -853,6 +882,7 @@ The valid format sequences for files (without --file-system):\n\
|
||||
%A Access rights in human readable form\n\
|
||||
%b Number of blocks allocated (see %B)\n\
|
||||
%B The size in bytes of each block reported by %b\n\
|
||||
%C SELinux security context string\n\
|
||||
"), stdout);
|
||||
fputs (_("\
|
||||
%d Device number in decimal\n\
|
||||
@@ -892,6 +922,7 @@ Valid format sequences for file systems:\n\
|
||||
%c Total file nodes in file system\n\
|
||||
%d Free file nodes in file system\n\
|
||||
%f Free blocks in file system\n\
|
||||
%C SELinux security context string\n\
|
||||
"), stdout);
|
||||
fputs (_("\
|
||||
%i File System ID in hex\n\
|
||||
@@ -913,7 +944,6 @@ main (int argc, char *argv[])
|
||||
{
|
||||
int c;
|
||||
int i;
|
||||
bool follow_links = false;
|
||||
bool fs = false;
|
||||
bool terse = false;
|
||||
char *format = NULL;
|
||||
@@ -927,7 +957,7 @@ main (int argc, char *argv[])
|
||||
|
||||
atexit (close_stdout);
|
||||
|
||||
while ((c = getopt_long (argc, argv, "c:fLt", long_options, NULL)) != -1)
|
||||
while ((c = getopt_long (argc, argv, "c:fLtZ", long_options, NULL)) != -1)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
@@ -955,6 +985,11 @@ main (int argc, char *argv[])
|
||||
terse = true;
|
||||
break;
|
||||
|
||||
case 'Z': /* FIXME: remove in 2008, warn in 2007 */
|
||||
/* Ignored, for compatibility with distributions
|
||||
that implemented this before upstream. */
|
||||
break;
|
||||
|
||||
case_GETOPT_HELP_CHAR;
|
||||
|
||||
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
|
||||
@@ -973,7 +1008,7 @@ main (int argc, char *argv[])
|
||||
for (i = optind; i < argc; i++)
|
||||
ok &= (fs
|
||||
? do_statfs (argv[i], terse, format)
|
||||
: do_stat (argv[i], follow_links, terse, format));
|
||||
: do_stat (argv[i], terse, format));
|
||||
|
||||
exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
}
|
||||
|
||||
@@ -399,6 +399,8 @@ enum
|
||||
"help", no_argument, NULL, GETOPT_HELP_CHAR
|
||||
#define GETOPT_VERSION_OPTION_DECL \
|
||||
"version", no_argument, NULL, GETOPT_VERSION_CHAR
|
||||
#define GETOPT_SELINUX_CONTEXT_OPTION_DECL \
|
||||
"context", required_argument, NULL, 'Z'
|
||||
|
||||
#define case_GETOPT_HELP_CHAR \
|
||||
case GETOPT_HELP_CHAR: \
|
||||
|
||||
@@ -18,7 +18,7 @@ EXTRA_DIST = \
|
||||
$(TESTS) Coreutils.pm Makefile.am.in README acl envvar-check \
|
||||
expensive group-names input-tty lang-default mk-script \
|
||||
other-fs-tmpdir priv-check \
|
||||
rwx-to-mode sample-test setgid-check sparse-file \
|
||||
rwx-to-mode sample-test selinux setgid-check sparse-file \
|
||||
umask-check very-expensive
|
||||
|
||||
## N O T E :: Please do not add new tests/ directories.
|
||||
@@ -30,7 +30,7 @@ SUBDIRS = \
|
||||
tsort unexpand uniq wc
|
||||
## N O T E :: Please do not add new directories.
|
||||
|
||||
all_t = t1 t2 t3 t4 t5 t6 t7
|
||||
all_t = t1 t2 t3 t4 t5 t6 t7 t8 t9
|
||||
.PHONY: check-root $(all_t)
|
||||
check-root: $(all_t)
|
||||
|
||||
@@ -48,6 +48,10 @@ t6:
|
||||
cd rm && $(MAKE) check TESTS=one-file-system
|
||||
t7:
|
||||
cd ls && $(MAKE) check TESTS=nameless-uid
|
||||
t8:
|
||||
cd misc && $(MAKE) check TESTS=chcon
|
||||
t9:
|
||||
cd cp && $(MAKE) check TESTS=cp-a-selinux
|
||||
|
||||
check-recursive: root-hint
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ for src in u g o; do
|
||||
for dest in u g o; do
|
||||
test $dest = $src && continue
|
||||
chmod a=,$src=rwx,$dest=$src,$src= f || fail=1
|
||||
set _ `ls -l f`; shift; actual_perms=$1
|
||||
actual_perms=`ls -l f|cut -b-10`
|
||||
expected_perms=`eval 'echo \$expected_'$dest`
|
||||
test "$actual_perms" = "$expected_perms" || fail=1
|
||||
done
|
||||
@@ -59,7 +59,7 @@ done
|
||||
|
||||
umask 027
|
||||
chmod a=,u=rwx,=u f || fail=1
|
||||
set _ `ls -l f`; shift; actual_perms=$1
|
||||
actual_perms=`ls -l f|cut -b-10`
|
||||
test "$actual_perms" = "-rwxr-x---" || fail=1
|
||||
|
||||
(exit $fail); exit $fail
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
# 02110-1301, USA.
|
||||
|
||||
TESTS = \
|
||||
cp-a-selinux \
|
||||
file-perm-race parent-perm-race \
|
||||
backup-dir \
|
||||
src-base-dot \
|
||||
|
||||
94
tests/cp/cp-a-selinux
Executable file
94
tests/cp/cp-a-selinux
Executable file
@@ -0,0 +1,94 @@
|
||||
#!/bin/sh
|
||||
# Ensure that cp -a and cp --preserve=context work properly.
|
||||
# In particular, test on a writable NFS partition.
|
||||
|
||||
# Copyright (C) 2007 Free Software Foundation, 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.
|
||||
|
||||
if test "$VERBOSE" = yes; then
|
||||
set -x
|
||||
cp --version
|
||||
fi
|
||||
|
||||
. $srcdir/../envvar-check
|
||||
. $srcdir/../lang-default
|
||||
. $srcdir/../selinux
|
||||
PRIV_CHECK_ARG=require-root . $srcdir/../priv-check
|
||||
|
||||
pwd=`pwd`
|
||||
t0=`echo "$0"|sed 's,.*/,,'`.tmp; tmp=$t0/$$
|
||||
trap 'status=$?; cd "$pwd"; umount $tmp/mnt; chmod -R u+rwx $t0 && rm -rf $t0 && exit $status' 0
|
||||
trap '(exit $?); exit $?' 1 2 13 15
|
||||
|
||||
framework_failure=0
|
||||
mkdir -p $tmp || framework_failure=1
|
||||
cd $tmp || framework_failure=1
|
||||
|
||||
# Create a file system, then mount it with the context=... option.
|
||||
dd if=/dev/zero of=blob bs=8192 count=200 > /dev/null 2>&1 \
|
||||
|| framework_failure=1
|
||||
mkdir mnt || framework_failure=1
|
||||
mkfs -t ext2 -F blob > /dev/null 2>&1 || framework_failure=1
|
||||
mount -oloop,context=system_u:object_r:removable_t blob mnt \
|
||||
|| framework_failure=1
|
||||
cd mnt || framework_failure=1
|
||||
|
||||
echo > f || framework_failure=1
|
||||
echo > g || framework_failure=1
|
||||
|
||||
if test $framework_failure = 1; then
|
||||
echo "$0: failure in testing framework" 1>&2
|
||||
(exit 1); exit 1
|
||||
fi
|
||||
|
||||
fail=0
|
||||
|
||||
# /bin/cp from coreutils-6.7-3.fc7 would fail this test by letting cp
|
||||
# succeed (giving no diagnostics), yet leaving the destination file empty.
|
||||
cp -a f g 2>err || fail=1
|
||||
test -s g || fail=1 # The destination file must not be empty.
|
||||
test -s err && fail=1 # There must be no stderr output.
|
||||
|
||||
rm -f g err
|
||||
echo > g
|
||||
|
||||
# =====================================================
|
||||
# Here, we expect cp to fail, because it cannot set the SELinux
|
||||
# security context through NFS or a mount with fixed context.
|
||||
cp --preserve=context f g 2> out && fail=1
|
||||
|
||||
# Here, we *do* expect the destination to be empty.
|
||||
test -s g && fail=1
|
||||
|
||||
# An alternative to the current approach would be to run in a confined
|
||||
# domain (maybe creating/loading it) that lacks the required permissions
|
||||
# to the file type.
|
||||
# Note: this test could also be run by a regular (non-root) user in an
|
||||
# NFS mounted directory. When doing that, I get this diagnostic:
|
||||
# cp: failed to set the security context of `g' to `system_u:object_r:nfs_t': \
|
||||
# Operation not supported
|
||||
sed "s/ .g' to .*//" out > k
|
||||
mv k out
|
||||
|
||||
cat <<\EOF > exp || fail=1
|
||||
cp: failed to set the security context of
|
||||
EOF
|
||||
|
||||
cmp out exp || fail=1
|
||||
test $fail = 1 && diff out exp 2> /dev/null
|
||||
|
||||
(exit $fail); exit $fail
|
||||
@@ -75,8 +75,8 @@ test -d d/f && fail=1
|
||||
# Check that re_protect works.
|
||||
chmod go=w d/a
|
||||
cp -a --parents d/a/b/c e || fail=1
|
||||
p=`ls -ld e/d|sed 's/ .*//'`; case $p in drwxr-xr-x);; *) fail=1;; esac
|
||||
p=`ls -ld e/d/a|sed 's/ .*//'`; case $p in drwx-w--w-);; *) fail=1;; esac
|
||||
p=`ls -ld e/d/a/b/c|sed 's/ .*//'`; case $p in drwxr-xr-x);; *) fail=1;; esac
|
||||
p=`ls -ld e/d|cut -b-10`; case $p in drwxr-xr-x);; *) fail=1;; esac
|
||||
p=`ls -ld e/d/a|cut -b-10`; case $p in drwx-w--w-);; *) fail=1;; esac
|
||||
p=`ls -ld e/d/a/b/c|cut -b-10`; case $p in drwxr-xr-x);; *) fail=1;; esac
|
||||
|
||||
(exit $fail); exit $fail
|
||||
|
||||
@@ -52,9 +52,8 @@ cp -pR D DD > /dev/null 2>&1 && fail=1
|
||||
|
||||
# Permissions on DD must be `dr-x------'
|
||||
|
||||
set X `ls -ld DD`
|
||||
shift
|
||||
test "$1" = dr-x------ || fail=1
|
||||
mode=`ls -ld DD|cut -b-10`
|
||||
test "$mode" = dr-x------ || fail=1
|
||||
|
||||
chmod 0 D
|
||||
ln -s D/D symlink
|
||||
|
||||
@@ -98,7 +98,7 @@ rm -rf a b c d
|
||||
touch a; chmod 731 a
|
||||
umask 077
|
||||
cp -a --no-preserve=mode a b
|
||||
set _ `ls -l b`; shift; mode=$1
|
||||
mode=`ls -l b|cut -b-10`
|
||||
test "$mode" = "-rwx------" || fail=1
|
||||
umask 022
|
||||
# --------------------------------------
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
# Make sure all these programs work properly
|
||||
# when invoked with --help or --version.
|
||||
|
||||
# Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software
|
||||
# Foundation, Inc.
|
||||
# Copyright (C) 2000-2007 Free Software Foundation, 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
|
||||
@@ -72,6 +71,8 @@ for lang in C fr da; do
|
||||
|
||||
# Skip `test'; it doesn't accept --help or --version.
|
||||
test $i = test && continue;
|
||||
test $i = chcon && continue;
|
||||
test $i = runcon && continue;
|
||||
|
||||
# false fails even when invoked with --help or --version.
|
||||
if test $i = false; then
|
||||
@@ -197,7 +198,7 @@ lbracket_args=": ]"
|
||||
|
||||
for i in $all_programs; do
|
||||
# Skip these.
|
||||
case $i in chroot|stty|tty|false) continue;; esac
|
||||
case $i in chroot|stty|tty|false|chcon|runcon) continue;; esac
|
||||
|
||||
rm -rf $tmp_in $tmp_in2 $tmp_dir $tmp_out
|
||||
echo > $tmp_in
|
||||
|
||||
@@ -98,9 +98,8 @@ ginstall -s -c -m 555 $dd $dir || fail=1
|
||||
test -f $dd || fail=1
|
||||
|
||||
# Make sure that the destination file has the requested permissions.
|
||||
set X `ls -l $dir/$dd`
|
||||
shift
|
||||
test "$1" = -r-xr-xr-x || fail=1
|
||||
mode=`ls -l $dir/$dd|cut -b-10`
|
||||
test "$mode" = -r-xr-xr-x || fail=1
|
||||
|
||||
# These failed in coreutils CVS from 2004-06-25 to 2004-08-11.
|
||||
ginstall -d . || fail=1
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Make miscellaneous coreutils tests. -*-Makefile-*-
|
||||
|
||||
# Copyright (C) 200-2007 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2001-2007 Free Software Foundation, 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
|
||||
@@ -43,6 +43,9 @@ TESTS = \
|
||||
pr \
|
||||
df-P \
|
||||
pwd-unreadable-parent \
|
||||
chcon \
|
||||
chcon-fail \
|
||||
selinux \
|
||||
cut \
|
||||
wc-files0-from \
|
||||
wc-files0 \
|
||||
@@ -70,6 +73,7 @@ TESTS = \
|
||||
printf \
|
||||
printf-hex \
|
||||
pwd-long \
|
||||
runcon-no-reorder \
|
||||
sha224sum \
|
||||
sha256sum \
|
||||
sha384sum \
|
||||
|
||||
73
tests/misc/chcon
Executable file
73
tests/misc/chcon
Executable file
@@ -0,0 +1,73 @@
|
||||
#!/bin/sh
|
||||
# exercise chcon
|
||||
|
||||
if test "$VERBOSE" = yes; then
|
||||
set -x
|
||||
chcon --version
|
||||
fi
|
||||
|
||||
. $srcdir/../lang-default
|
||||
PRIV_CHECK_ARG=require-root . $srcdir/../priv-check
|
||||
|
||||
pwd=`pwd`
|
||||
t0=`echo "$0"|sed 's,.*/,,'`.tmp; tmp=$t0/$$
|
||||
trap 'status=$?; cd $pwd; chmod -R u+rwx $t0; rm -rf $t0 && exit $status' 0
|
||||
trap '(exit $?); exit $?' 1 2 13 15
|
||||
|
||||
framework_failure=0
|
||||
mkdir -p $tmp || framework_failure=1
|
||||
cd $tmp || framework_failure=1
|
||||
mkdir -p d/sub/s2 || framework_failure=1
|
||||
touch f g d/sub/1 d/sub/2 || framework_failure=1
|
||||
|
||||
if test $framework_failure = 1; then
|
||||
echo "$0: failure in testing framework" 1>&2
|
||||
(exit 1); exit 1
|
||||
fi
|
||||
|
||||
fail=0
|
||||
|
||||
# Set to a specified context.
|
||||
u1=root
|
||||
r1=object_r
|
||||
t1=tmp_t
|
||||
ctx=$u1:$r1:$t1
|
||||
chcon $ctx f || fail=1
|
||||
stat --printf='f|%C\n' f > out || fail=1
|
||||
|
||||
# Use --reference.
|
||||
chcon --ref=f g || fail=1
|
||||
stat --printf='g|%C\n' g >> out || fail=1
|
||||
|
||||
# Change the individual parts of the context, one by one.
|
||||
u2=user_u
|
||||
r2=object_r
|
||||
t2=file_t
|
||||
l2=SystemLow-SystemHigh
|
||||
for i in --user=$u2 --role=$r2 --type=$t2 --range=$l2; do
|
||||
chcon $i f || fail=1
|
||||
stat --printf="f|$i|"'%C\n' f >> out || fail=1
|
||||
done
|
||||
|
||||
# Same, but change back using the short-named options.
|
||||
for i in -u$u1 -r$r1 -t$t1; do
|
||||
chcon $i f || fail=1
|
||||
stat --printf="f|$i|"'%C\n' f >> out || fail=1
|
||||
done
|
||||
|
||||
cat <<EOF > exp || fail=1
|
||||
f|$ctx
|
||||
g|$ctx
|
||||
f|--user=$u2|$u2:$r1:$t1
|
||||
f|--role=$r2|$u2:$r2:$t1
|
||||
f|--type=$t2|$u2:$r2:$t2
|
||||
f|--range=$l2|$u2:$r2:$t2:$l2
|
||||
f|-uroot|root:object_r:file_t:SystemLow-SystemHigh
|
||||
f|-robject_r|root:object_r:file_t:SystemLow-SystemHigh
|
||||
f|-ttmp_t|root:object_r:tmp_t:SystemLow-SystemHigh
|
||||
EOF
|
||||
|
||||
cmp out exp || fail=1
|
||||
test $fail = 1 && diff out exp 2> /dev/null
|
||||
|
||||
(exit $fail); exit $fail
|
||||
41
tests/misc/chcon-fail
Executable file
41
tests/misc/chcon-fail
Executable file
@@ -0,0 +1,41 @@
|
||||
#!/bin/sh
|
||||
# Ensure that chcon fails when it should.
|
||||
# These tests don't use any actual SE Linux syscalls.
|
||||
|
||||
if test "$VERBOSE" = yes; then
|
||||
set -x
|
||||
chcon --version
|
||||
fi
|
||||
|
||||
. $srcdir/../lang-default
|
||||
|
||||
pwd=`pwd`
|
||||
t0=`echo "$0"|sed 's,.*/,,'`.tmp; tmp=$t0/$$
|
||||
trap 'status=$?; cd $pwd; chmod -R u+rwx $t0; rm -rf $t0 && exit $status' 0
|
||||
trap '(exit $?); exit $?' 1 2 13 15
|
||||
|
||||
framework_failure=0
|
||||
mkdir -p $tmp || framework_failure=1
|
||||
cd $tmp || framework_failure=1
|
||||
|
||||
if test $framework_failure = 1; then
|
||||
echo "$0: failure in testing framework" 1>&2
|
||||
(exit 1); exit 1
|
||||
fi
|
||||
|
||||
fail=0
|
||||
|
||||
# neither context nor file
|
||||
chcon 2> /dev/null && fail=1
|
||||
|
||||
# No file
|
||||
chcon CON 2> /dev/null && fail=1
|
||||
|
||||
# No file
|
||||
touch f
|
||||
chcon --reference=f 2> /dev/null && fail=1
|
||||
|
||||
# No file
|
||||
chcon -u anyone 2> /dev/null && fail=1
|
||||
|
||||
(exit $fail); exit $fail
|
||||
@@ -42,15 +42,15 @@ fail=0
|
||||
umask 777
|
||||
|
||||
mknod -m 734 f1 p || fail=1
|
||||
set _ `ls -dgo f1`; shift; mode=$1
|
||||
mode=`ls -dgo f1|cut -b-10`
|
||||
test $mode = prwx-wxr-- || fail=1
|
||||
|
||||
mkfifo -m 734 f2 || fail=1
|
||||
set _ `ls -dgo f2`; shift; mode=$1
|
||||
mode=`ls -dgo f2|cut -b-10`
|
||||
test $mode = prwx-wxr-- || fail=1
|
||||
|
||||
mkdir -m 734 f3 || fail=1
|
||||
set _ `ls -dgo f3`; shift; mode=$1
|
||||
mode=`ls -dgo f3|cut -b-10`
|
||||
test $mode = drwx-wxr-- || test $mode = drwx-wsr-- || fail=1
|
||||
|
||||
(exit $fail); exit $fail
|
||||
|
||||
57
tests/misc/runcon-no-reorder
Executable file
57
tests/misc/runcon-no-reorder
Executable file
@@ -0,0 +1,57 @@
|
||||
#!/bin/sh
|
||||
# Ensure that runcon does not reorder its arguments.
|
||||
|
||||
# Copyright (C) 2007 Free Software Foundation, 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.
|
||||
|
||||
if test "$VERBOSE" = yes; then
|
||||
set -x
|
||||
runcon --version
|
||||
fi
|
||||
|
||||
. $srcdir/../lang-default
|
||||
|
||||
pwd=`pwd`
|
||||
t0=`echo "$0"|sed 's,.*/,,'`.tmp; tmp=$t0/$$
|
||||
trap 'status=$?; cd "$pwd" && chmod -R u+rwx $t0 && rm -rf $t0 && exit $status' 0
|
||||
trap '(exit $?); exit $?' 1 2 13 15
|
||||
|
||||
framework_failure=0
|
||||
mkdir -p $tmp || framework_failure=1
|
||||
cd $tmp || framework_failure=1
|
||||
|
||||
cat <<\EOF > exp || framework_failure=1
|
||||
runcon: runcon may be used only on a SELinux kernel
|
||||
EOF
|
||||
|
||||
if test $framework_failure = 1; then
|
||||
echo "$0: failure in testing framework" 1>&2
|
||||
(exit 1); exit 1
|
||||
fi
|
||||
|
||||
fail=0
|
||||
|
||||
# This test works even on systems without SELinux.
|
||||
# On such a system it fails with the above diagnostic, which is fine.
|
||||
# Before the no-reorder change, it would have failed with a diagnostic
|
||||
# about -j being an invalid option.
|
||||
runcon -t unconfined_t true -j 2> out && : > exp
|
||||
|
||||
cmp out exp || fail=1
|
||||
test $fail = 1 && diff out exp 2> /dev/null
|
||||
|
||||
(exit $fail); exit $fail
|
||||
61
tests/misc/selinux
Executable file
61
tests/misc/selinux
Executable file
@@ -0,0 +1,61 @@
|
||||
#!/bin/sh
|
||||
# Test SELinux-related options.
|
||||
|
||||
if test "$VERBOSE" = yes; then
|
||||
set -x
|
||||
chcon --version
|
||||
cp --version
|
||||
ls --version
|
||||
mv --version
|
||||
stat --version
|
||||
fi
|
||||
|
||||
. $srcdir/../envvar-check
|
||||
. $srcdir/../lang-default
|
||||
. $srcdir/../selinux
|
||||
PRIV_CHECK_ARG=require-non-root . $srcdir/../priv-check
|
||||
|
||||
pwd=`pwd`
|
||||
t0=`echo "$0"|sed 's,.*/,,'`.tmp; tmp=$t0/$$
|
||||
trap 'status=$?; cd $pwd; chmod -R u+rwx $t0; rm -rf $t0 && exit $status' 0
|
||||
trap '(exit $?); exit $?' 1 2 13 15
|
||||
|
||||
framework_failure=0
|
||||
mkdir -p $tmp || framework_failure=1
|
||||
cd $tmp || framework_failure=1
|
||||
|
||||
# Create a regular file, dir, fifo.
|
||||
touch f || framework_failure=1
|
||||
mkdir d s1 s2 || framework_failure=1
|
||||
mkfifo p || framework_failure=1
|
||||
|
||||
if test $framework_failure = 1; then
|
||||
echo "$0: failure in testing framework" 1>&2
|
||||
(exit 1); exit 1
|
||||
fi
|
||||
|
||||
fail=0
|
||||
|
||||
ctx=root:object_r:tmp_t
|
||||
# FIXME, what if $ctx is no different from the default. Not likely.
|
||||
# give each a different context, via chcon
|
||||
chcon $ctx f d p || fail=1
|
||||
# inspect that context with both ls -Z and stat.
|
||||
for i in d f p; do
|
||||
c=`ls -dogZ $i|cut -d' ' -f3`; test x$c = x$ctx || fail=1
|
||||
c=`stat --printf %C $i`; test x$c = x$ctx || fail=1
|
||||
done
|
||||
|
||||
# Copy each to a new directory and ensure that context is preserved.
|
||||
cp -r --preserve=all d f p s1 || fail=1
|
||||
for i in d f p; do
|
||||
c=`stat --printf %C s1/$i`; test x$c = x$ctx || fail=1
|
||||
done
|
||||
|
||||
# Now, move each to a new directory and ensure that context is preserved.
|
||||
mv d f p s2 || fail=1
|
||||
for i in d f p; do
|
||||
c=`stat --printf %C s2/$i`; test x$c = x$ctx || fail=1
|
||||
done
|
||||
|
||||
(exit $fail); exit $fail
|
||||
@@ -65,12 +65,12 @@ d_mode_arg=`"$abs_srcdir/../rwx-to-mode" $d_mode_str`
|
||||
mkdir -p -m $d_mode_arg a/b/c/d
|
||||
|
||||
# Make sure the permissions of `a' haven't been changed.
|
||||
p=`ls -ld a|sed 's/ .*//'`; case $p in $mode_str);; *) fail=1;; esac
|
||||
p=`ls -ld a|cut -b-10`; case $p in $mode_str);; *) fail=1;; esac
|
||||
# `b's and `c's should reflect the umask
|
||||
p=`ls -ld a/b|sed 's/ .*//'`; case $p in drwx------);; *) fail=1;; esac
|
||||
p=`ls -ld a/b/c|sed 's/ .*//'`; case $p in drwx------);; *) fail=1;; esac
|
||||
p=`ls -ld a/b|cut -b-10`; case $p in drwx------);; *) fail=1;; esac
|
||||
p=`ls -ld a/b/c|cut -b-10`; case $p in drwx------);; *) fail=1;; esac
|
||||
|
||||
# `d's perms are determined by the -m argument.
|
||||
p=`ls -ld a/b/c/d|sed 's/ .*//'`; case $p in $d_mode_str);; *) fail=1;; esac
|
||||
p=`ls -ld a/b/c/d|cut -b-10`; case $p in $d_mode_str);; *) fail=1;; esac
|
||||
|
||||
(exit $fail); exit $fail
|
||||
|
||||
@@ -33,8 +33,8 @@ output_mode_string=drwxr-x-wT
|
||||
mkdir -m$set_mode_string $tmp || fail=1
|
||||
|
||||
test -d $tmp || fail=1
|
||||
set -- `ls -ld $tmp`
|
||||
case "$1" in
|
||||
mode=`ls -ld $tmp|cut -b-10`
|
||||
case "$mode" in
|
||||
$output_mode_string) ;;
|
||||
*) fail=1 ;;
|
||||
esac
|
||||
@@ -49,8 +49,8 @@ mkdir -m$set_mode_string $tmp2 2> /dev/null && fail=1
|
||||
mkdir --parents -m$set_mode_string $tmp2 || fail=1
|
||||
|
||||
test -d $tmp2 || fail=1
|
||||
set -- `ls -ld $tmp2`
|
||||
case "$1" in
|
||||
mode=`ls -ld $tmp2|cut -b-10`
|
||||
case "$mode" in
|
||||
$output_mode_string) ;;
|
||||
*) fail=1 ;;
|
||||
esac
|
||||
|
||||
@@ -49,7 +49,7 @@ test -f file && fail=1
|
||||
test -f $other_partition_tmpdir/file || fail=1
|
||||
|
||||
# This would have failed with the mv from fileutils-4.0i.
|
||||
set _ `ls -l $other_partition_tmpdir/file`; shift; mode=$1
|
||||
mode=`ls -l $other_partition_tmpdir/file|cut -b-10`
|
||||
test "$mode" = "-rwxrwxrwx" || fail=1
|
||||
|
||||
exit $fail
|
||||
|
||||
24
tests/selinux
Normal file
24
tests/selinux
Normal file
@@ -0,0 +1,24 @@
|
||||
# Is a test expensive?
|
||||
# Copyright (C) 2007 Free Software Foundation, 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.
|
||||
|
||||
test "`ls -Zd .`" = '? .' &&
|
||||
{
|
||||
echo "$0: skipping this test; this system (or maybe just" 1>&2
|
||||
echo " the current file system) lacks SELinux support" 1>&2
|
||||
(exit 77); exit 77
|
||||
}
|
||||
Reference in New Issue
Block a user