diff options
Diffstat (limited to 'libqpol/src/util.c')
-rw-r--r-- | libqpol/src/util.c | 231 |
1 files changed, 231 insertions, 0 deletions
diff --git a/libqpol/src/util.c b/libqpol/src/util.c new file mode 100644 index 0000000..7c49876 --- /dev/null +++ b/libqpol/src/util.c @@ -0,0 +1,231 @@ +/** + * @file + * + * Implementation of utility functions. + * + * @author Jeremy A. Mowery jmowery@tresys.com + * @author Jason Tang jtang@tresys.com + * + * Copyright (C) 2006-2008 Tresys Technology, LLC + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <config.h> + +#include "qpol_internal.h" + +#include <qpol/util.h> + +#include <glob.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/stat.h> +#include <sys/types.h> + +#include <selinux/selinux.h> + +const char *libqpol_get_version(void) +{ + return LIBQPOL_VERSION_STRING; +} + +static int search_policy_source_file(char **path) +{ + int error; + char *source_path; + if (asprintf(&source_path, "%s/src/policy/policy.conf", selinux_policy_root()) < 0) { + return -1; + } + if (access(source_path, R_OK) < 0) { + error = errno; + free(source_path); + errno = error; + return 1; + } + *path = source_path; + return 0; +} + +static int get_binpol_version(const char *policy_fname) +{ + FILE *policy_fp = NULL; + int ret_version, error; + + policy_fp = fopen(policy_fname, "r"); + if (policy_fp == NULL) { + return -1; + } + if (!qpol_is_file_binpol(policy_fp)) { + error = errno; + fclose(policy_fp); + errno = error; + return -1; + } + ret_version = qpol_binpol_version(policy_fp); + fclose(policy_fp); + return ret_version; +} + +static int search_policy_binary_file(char **path) +{ + const char *binary_path; + if ((binary_path = selinux_binary_policy_path()) == NULL) { + return -1; + } + + int expected_version = -1, latest_version = -1; +#ifdef LIBSELINUX + /* if the system has SELinux enabled, prefer the policy whose + name matches the current policy version */ + if ((expected_version = security_policyvers()) < 0) { + return -1; + } +#endif + + glob_t glob_buf; + struct stat fs; + int rt, error = 0, retval = -1; + size_t i; + char *pattern = NULL; + if (asprintf(&pattern, "%s.*", binary_path) < 0) { + return -1; + } + glob_buf.gl_offs = 1; + glob_buf.gl_pathc = 0; + rt = glob(pattern, GLOB_DOOFFS, NULL, &glob_buf); + if (rt != 0 && rt != GLOB_NOMATCH) { + errno = EIO; + return -1; + } + + for (i = 0; i < glob_buf.gl_pathc; i++) { + char *p = glob_buf.gl_pathv[i + glob_buf.gl_offs]; + if (stat(p, &fs) != 0) { + error = errno; + goto cleanup; + } + if (S_ISDIR(fs.st_mode)) + continue; + + if ((rt = get_binpol_version(p)) < 0) { + error = errno; + goto cleanup; + } + + if (rt > latest_version || rt == expected_version) { + free(*path); + if ((*path = strdup(p)) == NULL) { + error = errno; + goto cleanup; + } + if (rt == expected_version) { + break; + } + latest_version = rt; + } + } + + if (*path == NULL) { + retval = 1; + } else { + retval = 0; + } + cleanup: + free(pattern); + globfree(&glob_buf); + if (retval == -1) { + errno = error; + } + return retval; +} + +int qpol_default_policy_find(char **path) +{ + int rt; + if (path == NULL) { + errno = EINVAL; + return -1; + } + *path = NULL; + /* Try default source policy first as a source policy contains + * more useful information. */ + if ((rt = search_policy_source_file(path)) <= 0) { + return rt; + } + /* Try a binary policy */ + return search_policy_binary_file(path); +} + +#include <stdlib.h> +#include <bzlib.h> +#include <string.h> +#include <sys/sendfile.h> + +#define BZ2_MAGICSTR "BZh" +#define BZ2_MAGICLEN (sizeof(BZ2_MAGICSTR)-1) + +/* qpol_bunzip() uncompresses a file to '*data', returning the total number of + * uncompressed bytes in the file. + * Returns -1 if file could not be decompressed. + * Originally from libsemanage/src/direct_api.c, with slight mods */ +ssize_t qpol_bunzip(FILE *f, char **data) +{ + BZFILE* b; + size_t nBuf; + char buf[1<<18]; + size_t size = sizeof(buf); + int bzerror; + size_t total=0; + int small=0; // Set to 1 to use less memory decompressing (about 2x slower) + + bzerror = fread(buf, 1, BZ2_MAGICLEN, f); + rewind(f); + if ((bzerror != BZ2_MAGICLEN) || memcmp(buf, BZ2_MAGICSTR, BZ2_MAGICLEN)) + return -1; + + b = BZ2_bzReadOpen ( &bzerror, f, 0, small, NULL, 0 ); + if ( bzerror != BZ_OK ) { + BZ2_bzReadClose ( &bzerror, b ); + return -1; + } + + char *uncompress = realloc(NULL, size); + + while ( bzerror == BZ_OK) { + nBuf = BZ2_bzRead ( &bzerror, b, buf, sizeof(buf)); + if (( bzerror == BZ_OK ) || ( bzerror == BZ_STREAM_END )) { + if (total + nBuf > size) { + size *= 2; + uncompress = realloc(uncompress, size); + } + memcpy(&uncompress[total], buf, nBuf); + total += nBuf; + } + } + if ( bzerror != BZ_STREAM_END ) { + BZ2_bzReadClose ( &bzerror, b ); + free(uncompress); + return -1; + } + BZ2_bzReadClose ( &bzerror, b ); + + *data = uncompress; + return total; +} + |