diff --git a/libselinux/include/selinux/selinux.h b/libselinux/include/selinux/selinux.h index f110dcf..d29b0c1 100644 --- a/libselinux/include/selinux/selinux.h +++ b/libselinux/include/selinux/selinux.h @@ -566,7 +566,7 @@ extern int selinux_file_context_cmp(const security_context_t a, /* * Verify the context of the file 'path' against policy. - * Return 0 if correct. + * Return 1 if match, 0 if not and -1 on error. */ extern int selinux_file_context_verify(const char *path, mode_t mode); diff --git a/libselinux/man/man3/selinux_file_context_cmp.3 b/libselinux/man/man3/selinux_file_context_cmp.3 index 51e8c20..cd67188 100644 --- a/libselinux/man/man3/selinux_file_context_cmp.3 +++ b/libselinux/man/man3/selinux_file_context_cmp.3 @@ -1,25 +1,75 @@ -.TH "selinux_file_context_cmp" "3" "21 November 2009" "sds@tycho.nsa.gov" "SELinux API documentation" +.TH "selinux_file_context_cmp" "3" "08 March 2011" "SELinux API documentation" + .SH "NAME" -selinux_file_context_cmp, selinux_file_context_verify \- comparison of two file contexts. +selinux_file_context_cmp \- Compare two SELinux security contexts excluding the 'user' component. .SH "SYNOPSIS" .B #include .sp - -.BI "int selinux_file_context_cmp(const security_context_t " a ", const security_context_t " b ");" - -.BI "int selinux_file_context_verify(const char *" path ", mode_t " mode ");" +.BI "int selinux_file_context_cmp(const security_context_t " a ", " +.RS +.BI "const security_context_t " b ");" +.RE .SH "DESCRIPTION" .B selinux_file_context_cmp -compares two file contexts to see if their differences are "significant", the function runs the strcmp function ignoring the user componant of the file context. -.sp -.B selinux_file_context_verify -compares the file context on disk to the system default. +compares two context strings excluding the user component with +.B strcmp(3) +as shown in the +.B EXAMPLE +section. .sp +This is useful as for most object contexts, the user component is not relevant. .SH "RETURN VALUE" -Returns zero on success or \-1 otherwise. +The return values follow the +.B strcmp(3) +function, where: +.RS +0 if they are equal. +.RE +.RS +1 if +.I a +is greater than +.I b +.RE +.RS +\-1 if +.I a +is less than +.I b +.RE + +.SH "ERRORS" +None. + +.SH "NOTES" +The contexts being compared do not specifically need to be file contexts. + +.SH "EXAMPLE" +If context +.I a +is: +.RS +user_u:user_r:user_t:s0 +.RE +.sp +and context +.I b +is: +.RS +root:user_r:user_t:s0 +.RE +.sp +then the actual strings compared are: +.RS +:user_r:user_t:s0 and :user_r:user_t:s0 +.RE +.sp +Therefore they will match and +.B selinux_file_context_cmp +will return zero. .SH "SEE ALSO" -.BR selinux "(8), " selinux_lsetfilecon "(3), " matchpathcon "(3), " freecon "(3), " setfilecon "(3), " setfscreatecon "(3)" +.BR selinux "(8)" diff --git a/libselinux/man/man3/selinux_file_context_verify.3 b/libselinux/man/man3/selinux_file_context_verify.3 index d777547..e22be70 100644 --- a/libselinux/man/man3/selinux_file_context_verify.3 +++ b/libselinux/man/man3/selinux_file_context_verify.3 @@ -1 +1,98 @@ -.so man3/selinux_file_context_cmp.3 +.TH "selinux_file_context_verify" "3" "08 March 2011" "SELinux API documentation" + +.SH "NAME" +selinux_file_context_verify \- Compare the SELinux security context on disk to the default security context required by the policy file contexts file. + +.SH "SYNOPSIS" +.B #include +.sp +.BI "int selinux_file_context_verify(const char *" path ", mode_t " mode ");" + +.SH "DESCRIPTION" +.B selinux_file_context_verify +compares the context of the specified +.I path +that is held on disk (in the extended attribute), to the system default entry held in the file contexts series of files. +.sp +The +.I mode +may be zero. +.sp +Note that the two contexts are compared for "significant" differences (i.e. the user component of the contexts are ignored) as shown in the +.B EXAMPLE +section. + +.SH "RETURN VALUE" +If the contexts significantly match, 1 (one) is returned. +.sp +If the contexts do not match 0 (zero) is returned and +.I errno +is set to either +.B ENOENT +or +.B EINVAL +for the reasons listed in the +.B ERRORS +section, or if +.I errno += 0 then the contexts did not match. +.sp +On failure \-1 is returned and +.I errno +set appropriately. + +.SH "ERRORS" +.TP +.B ENOTSUP +if extended attributes are not supported by the file system. +.TP +.B ENOENT +if there is no entry in the file contexts series of files or +.I path +does not exist. +.TP +.B EINVAL +if the entry in the file contexts series of files or +.I path +are invalid, or the returned context fails validation. +.TP +.B ENOMEM +if attempt to allocate memory failed. + +.SH "FILES" +The following configuration files (the file contexts series of files) supporting the active policy will be used (should they exist) to determine the +.I path +default context: +.sp +.RS +contexts/files/file_contexts - This file must exist. +.sp +contexts/files/file_contexts.local - If exists has local customizations. +.sp +contexts/files/file_contexts.homedirs - If exists has users home directory customizations. +.sp +contexts/files/file_contexts.subs - If exists has substitutions that are then applied to the 'in memory' version of the file contexts files. +.RE + +.SH "EXAMPLE" +If the files context is: +.RS +unconfined_u:object_r:admin_home_t:s0 +.RE +.sp +and the default context defined in the file contexts file is: +.RS +system_u:object_r:admin_home_t:s0 +.RE +.sp +then the actual strings compared are: +.RS +:object_r:admin_home_t:s0 and :object_r:admin_home_t:s0 +.RE +.sp +Therefore they will match and +.B selinux_file_context_verify +will return 1. + +.SH "SEE ALSO" +.BR selinux "(8)" diff --git a/libselinux/src/Makefile b/libselinux/src/Makefile index 15f7c1a..7680008 100644 --- a/libselinux/src/Makefile +++ b/libselinux/src/Makefile @@ -10,7 +10,8 @@ LIBDIR ?= $(PREFIX)/lib SHLIBDIR ?= $(PREFIX)/lib INCLUDEDIR ?= $(PREFIX)/include PYLIBVER ?= $(shell $(PYTHON) -c 'import sys;print("python%d.%d" % sys.version_info[0:2])') -PYINC ?= $(shell pkg-config --cflags `basename $(PYTHON)`) +PYINC ?= $(shell pkg-config --cflags $(PYPREFIX)) +PYTHONLIBDIR ?= $(shell pkg-config --libs $(PYPREFIX)) PYLIBDIR ?= $(LIBDIR)/$(PYLIBVER) RUBYLIBVER ?= $(shell ruby -e 'print RUBY_VERSION.split(".")[0..1].join(".")') RUBYPLATFORM ?= $(shell ruby -e 'print RUBY_PLATFORM') @@ -78,7 +79,7 @@ $(SWIGRUBYLOBJ): $(SWIGRUBYCOUT) $(CC) $(filter-out -Werror, $(CFLAGS)) -I$(RUBYINC) -fPIC -DSHARED -c -o $@ $< $(SWIGSO): $(SWIGLOBJ) - $(CC) $(CFLAGS) $(LDFLAGS) -shared -o $@ $< -L. -lselinux -L$(LIBDIR) -Wl,-soname,$@ + $(CC) $(CFLAGS) $(LDFLAGS) -shared -o $@ $< -L. -lselinux -L$(LIBDIR) $(PYTHONLIBDIR) -Wl,-soname,$@,-z,defs $(SWIGRUBYSO): $(SWIGRUBYLOBJ) $(CC) $(CFLAGS) $(LDFLAGS) -shared -o $@ $^ -L. -lselinux -L$(LIBDIR) -Wl,-soname,$@ diff --git a/libselinux/src/callbacks.c b/libselinux/src/callbacks.c index b245364..7c47222 100644 --- a/libselinux/src/callbacks.c +++ b/libselinux/src/callbacks.c @@ -16,6 +16,7 @@ default_selinux_log(int type __attribute__((unused)), const char *fmt, ...) { int rc; va_list ap; + if (is_selinux_enabled() == 0) return 0; va_start(ap, fmt); rc = vfprintf(stderr, fmt, ap); va_end(ap); diff --git a/libselinux/src/matchpathcon.c b/libselinux/src/matchpathcon.c index 5fd8fe4..410dd9d 100644 --- a/libselinux/src/matchpathcon.c +++ b/libselinux/src/matchpathcon.c @@ -2,9 +2,11 @@ #include #include #include +#include #include "selinux_internal.h" #include "label_internal.h" #include "callbacks.h" +#include static __thread struct selabel_handle *hnd; @@ -61,7 +63,7 @@ static void { va_list ap; va_start(ap, fmt); - vfprintf(stderr, fmt, ap); + vsyslog(LOG_ERR, fmt, ap); va_end(ap); } @@ -337,14 +339,82 @@ void matchpathcon_fini(void) } } -int matchpathcon(const char *name, mode_t mode, security_context_t * con) +/* + * We do not want to resolve a symlink to a real path if it is the final + * component of the name. Thus we split the pathname on the last "/" and + * determine a real path component of the first portion. We then have to + * copy the last part back on to get the final real path. Wheww. + */ +static int symlink_realpath(const char *name, char *resolved_path) +{ + char *last_component; + char *tmp_path, *p; + size_t len = 0; + int rc = 0; + + tmp_path = strdup(name); + if (!tmp_path) { + fprintf(stderr, "symlink_realpath(%s) strdup() failed: %s\n", + name, strerror(errno)); + rc = -1; + goto out; + } + + last_component = strrchr(tmp_path, '/'); + + if (last_component == tmp_path) { + last_component++; + p = strcpy(resolved_path, "/"); + } else if (last_component) { + *last_component = '\0'; + last_component++; + p = realpath(tmp_path, resolved_path); + } else { + last_component = tmp_path; + p = realpath("./", resolved_path); + } + + if (!p) { + fprintf(stderr, "symlink_realpath(%s) realpath() failed: %s\n", + name, strerror(errno)); + rc = -1; + goto out; + } + + len = strlen(p); + if (len + strlen(last_component) + 1 > PATH_MAX) { + fprintf(stderr, "symlink_realpath(%s) failed: Filename too long \n", + name); + rc = -1; + goto out; + } + + resolved_path += len; + strcpy(resolved_path, last_component); +out: + free(tmp_path); + return rc; +} + +int matchpathcon(const char *path, mode_t mode, security_context_t * con) { + char stackpath[PATH_MAX + 1]; + char *p = NULL; if (!hnd && (matchpathcon_init_prefix(NULL, NULL) < 0)) return -1; + if (S_ISLNK(mode)) { + if (!symlink_realpath(path, stackpath)) + path = stackpath; + } else { + p = realpath(path, stackpath); + if (p) + path = p; + } + return notrans ? - selabel_lookup_raw(hnd, con, name, mode) : - selabel_lookup(hnd, con, name, mode); + selabel_lookup_raw(hnd, con, path, mode) : + selabel_lookup(hnd, con, path, mode); } int matchpathcon_index(const char *name, mode_t mode, security_context_t * con) @@ -394,7 +464,7 @@ int selinux_file_context_verify(const char *path, mode_t mode) rc = lgetfilecon_raw(path, &con); if (rc == -1) { if (errno != ENOTSUP) - return 1; + return -1; else return 0; } @@ -404,11 +474,18 @@ int selinux_file_context_verify(const char *path, mode_t mode) if (selabel_lookup_raw(hnd, &fcontext, path, mode) != 0) { if (errno != ENOENT) - rc = 1; + rc = -1; else rc = 0; - } else + } else { + /* + * Need to set errno to 0 as it can be set to ENOENT if the + * file_contexts.subs file does not exist (see selabel_open in + * label.c), thus causing confusion if errno is checked on return. + */ + errno = 0; rc = (selinux_file_context_cmp(fcontext, con) == 0); + } freecon(con); freecon(fcontext); diff --git a/libselinux/utils/matchpathcon.c b/libselinux/utils/matchpathcon.c index 3ecd52f..5f0a4c2 100644 --- a/libselinux/utils/matchpathcon.c +++ b/libselinux/utils/matchpathcon.c @@ -43,63 +43,6 @@ int printmatchpathcon(char *path, int header, int mode) return 0; } -/* - * We do not want to resolve a symlink to a real path if it is the final - * component of the name. Thus we split the pathname on the last "/" and - * determine a real path component of the first portion. We then have to - * copy the last part back on to get the final real path. Wheww. - */ -static int symlink_realpath(char *name, char *resolved_path) -{ - char *last_component; - char *tmp_path, *p; - size_t len = 0; - int rc = 0; - - tmp_path = strdup(name); - if (!tmp_path) { - fprintf(stderr, "symlink_realpath(%s) strdup() failed: %s\n", - name, strerror(errno)); - rc = -1; - goto out; - } - - last_component = strrchr(tmp_path, '/'); - - if (last_component == tmp_path) { - last_component++; - p = strcpy(resolved_path, "/"); - } else if (last_component) { - *last_component = '\0'; - last_component++; - p = realpath(tmp_path, resolved_path); - } else { - last_component = tmp_path; - p = realpath("./", resolved_path); - } - - if (!p) { - fprintf(stderr, "symlink_realpath(%s) realpath() failed: %s\n", - name, strerror(errno)); - rc = -1; - goto out; - } - - len = strlen(p); - if (len + strlen(last_component) + 1 > PATH_MAX) { - fprintf(stderr, "symlink_realpath(%s) failed: Filename too long \n", - name); - rc = -1; - goto out; - } - - resolved_path += len; - strcpy(resolved_path, last_component); -out: - free(tmp_path); - return rc; -} - int main(int argc, char **argv) { int i, init = 0; @@ -166,8 +109,7 @@ int main(int argc, char **argv) for (i = optind; i < argc; i++) { int rc, mode = 0; struct stat buf; - char *p, *path = argv[i]; - char stackpath[PATH_MAX + 1]; + char *path = argv[i]; int len = strlen(path); if (len > 1 && path[len - 1 ] == '/') path[len - 1 ] = '\0'; @@ -175,31 +117,23 @@ int main(int argc, char **argv) if (lstat(path, &buf) == 0) mode = buf.st_mode; - if (S_ISLNK(mode)) { - rc = symlink_realpath(path, stackpath); - if (!rc) - path = stackpath; - } else { - p = realpath(path, stackpath); - if (p) - path = p; - } - if (verify) { rc = selinux_file_context_verify(path, mode); if (quiet) { - if (rc) + if (rc == 1) continue; else exit(1); } - if (rc) { + if (rc == -1) { + printf("%s error: %s\n", path, strerror(errno)); + exit(1); + } else if (rc == 1) { printf("%s verified.\n", path); } else { security_context_t con; - int rc; error = 1; if (notrans) rc = lgetfilecon_raw(path, &con);