2015-03-25 17:09:25 -05:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2014
|
|
|
|
* Canonical, Ltd. (All rights reserved)
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of version 2 of the GNU General Public
|
|
|
|
* License published by the Free Software Foundation.
|
|
|
|
*
|
|
|
|
* 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, contact Novell, Inc. or Canonical
|
|
|
|
* Ltd.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <dirent.h>
|
2015-08-12 12:22:41 -05:00
|
|
|
#include <fcntl.h>
|
2015-03-25 17:09:25 -05:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
|
|
|
#include "lib.h"
|
|
|
|
#include "parser.h"
|
|
|
|
#include "policy_cache.h"
|
|
|
|
|
|
|
|
#define le16_to_cpu(x) ((uint16_t)(le16toh (*(uint16_t *) x)))
|
|
|
|
|
|
|
|
const char header_string[] = "\004\010\000version\000\002";
|
|
|
|
#define HEADER_STRING_SIZE 12
|
2017-08-29 08:58:34 -05:00
|
|
|
#define VERSION_STRING_SIZE 4
|
2015-03-25 17:09:25 -05:00
|
|
|
bool valid_cached_file_version(const char *cachename)
|
|
|
|
{
|
2017-08-29 08:58:34 -05:00
|
|
|
char buffer[HEADER_STRING_SIZE + VERSION_STRING_SIZE];
|
2015-03-25 17:09:26 -05:00
|
|
|
autofclose FILE *f;
|
2015-03-25 17:09:25 -05:00
|
|
|
if (!(f = fopen(cachename, "r"))) {
|
2015-03-25 17:09:27 -05:00
|
|
|
PERROR("Error: Could not read cache file '%s', skipping...\n", cachename);
|
2015-03-25 17:09:25 -05:00
|
|
|
return false;
|
|
|
|
}
|
2017-08-29 08:58:34 -05:00
|
|
|
size_t res = fread(buffer, 1, HEADER_STRING_SIZE + VERSION_STRING_SIZE, f);
|
|
|
|
if (res < HEADER_STRING_SIZE + VERSION_STRING_SIZE) {
|
2020-08-28 08:35:45 -07:00
|
|
|
pwarn(WARN_DEBUG_CACHE, "%s: cache file '%s' invalid size\n", progname, cachename);
|
2015-03-25 17:09:25 -05:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 12 byte header that is always the same and then 4 byte version # */
|
|
|
|
if (memcmp(buffer, header_string, HEADER_STRING_SIZE) != 0) {
|
2020-08-28 08:35:45 -07:00
|
|
|
pwarn(WARN_DEBUG_CACHE, "%s: cache file '%s' has wrong header\n", progname, cachename);
|
2015-03-25 17:09:25 -05:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t version = cpu_to_le32(ENCODE_VERSION(force_complain,
|
|
|
|
policy_version,
|
|
|
|
parser_abi_version,
|
|
|
|
kernel_abi_version));
|
2017-08-29 08:58:34 -05:00
|
|
|
if (memcmp(buffer + HEADER_STRING_SIZE, &version, VERSION_STRING_SIZE) != 0) {
|
2020-08-28 08:35:45 -07:00
|
|
|
pwarn(WARN_DEBUG_CACHE, "%s: cache file '%s' has wrong version\n", progname, cachename);
|
2015-03-25 17:09:25 -05:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-06-06 01:22:53 -07:00
|
|
|
void set_cache_tstamp(struct timespec t)
|
2015-03-25 17:09:25 -05:00
|
|
|
{
|
|
|
|
mru_skip_cache = 0;
|
2015-06-06 01:22:53 -07:00
|
|
|
cache_tstamp = t;
|
2015-03-25 17:09:25 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void update_mru_tstamp(FILE *file, const char *name)
|
|
|
|
{
|
|
|
|
struct stat stat_file;
|
2015-06-06 01:22:53 -07:00
|
|
|
if (fstat(fileno(file), &stat_file))
|
2015-03-25 17:09:25 -05:00
|
|
|
return;
|
2015-06-06 01:22:53 -07:00
|
|
|
if (tstamp_cmp(mru_policy_tstamp, stat_file.st_mtim) < 0)
|
|
|
|
/* keep track of the most recent policy tstamp */
|
|
|
|
mru_policy_tstamp = stat_file.st_mtim;
|
|
|
|
if (tstamp_is_null(cache_tstamp))
|
|
|
|
return;
|
|
|
|
if (tstamp_cmp(stat_file.st_mtim, cache_tstamp) > 0) {
|
2020-08-28 08:35:45 -07:00
|
|
|
pwarn(WARN_DEBUG_CACHE, "%s: file '%s' is newer than cache file\n", progname, name);
|
2015-03-25 17:09:25 -05:00
|
|
|
mru_skip_cache = 1;
|
2015-06-06 01:22:53 -07:00
|
|
|
}
|
2015-03-25 17:09:25 -05:00
|
|
|
}
|
|
|
|
|
2018-03-05 23:46:25 -08:00
|
|
|
char *cache_filename(aa_policy_cache *pc, int dir, const char *basename)
|
2015-03-25 17:09:26 -05:00
|
|
|
{
|
|
|
|
char *cachename;
|
2018-03-05 23:46:25 -08:00
|
|
|
autofree char *path;
|
2015-03-25 17:09:26 -05:00
|
|
|
|
2018-03-05 23:46:25 -08:00
|
|
|
path = aa_policy_cache_dir_path(pc, dir);
|
|
|
|
if (!path || asprintf(&cachename, "%s/%s", path, basename) < 0) {
|
2015-03-25 17:09:27 -05:00
|
|
|
PERROR("Memory allocation error.");
|
2018-03-05 23:46:25 -08:00
|
|
|
return NULL;
|
2015-03-25 17:09:26 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
return cachename;
|
|
|
|
}
|
|
|
|
|
|
|
|
void valid_read_cache(const char *cachename)
|
|
|
|
{
|
|
|
|
struct stat stat_bin;
|
|
|
|
|
|
|
|
/* Load a binary cache if it exists and is newest */
|
|
|
|
if (!skip_read_cache) {
|
|
|
|
if (stat(cachename, &stat_bin) == 0 &&
|
|
|
|
stat_bin.st_size > 0) {
|
|
|
|
if (valid_cached_file_version(cachename))
|
2015-06-06 01:22:53 -07:00
|
|
|
set_cache_tstamp(stat_bin.st_mtim);
|
2015-03-25 17:09:26 -05:00
|
|
|
else if (!cond_clear_cache)
|
|
|
|
write_cache = 0;
|
|
|
|
} else {
|
|
|
|
if (!cond_clear_cache)
|
|
|
|
write_cache = 0;
|
2020-08-28 08:35:45 -07:00
|
|
|
pwarn(WARN_DEBUG_CACHE, "%s: Invalid or missing cache file '%s' (%s)\n", progname, cachename, strerror(errno));
|
2015-03-25 17:09:26 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int cache_hit(const char *cachename)
|
|
|
|
{
|
|
|
|
if (!mru_skip_cache) {
|
|
|
|
if (show_cache)
|
|
|
|
PERROR("Cache hit: %s\n", cachename);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
int setup_cache_tmp(const char **cachetmpname, const char *cachename)
|
|
|
|
{
|
|
|
|
char *tmpname;
|
|
|
|
int cache_fd = -1;
|
|
|
|
|
|
|
|
*cachetmpname = NULL;
|
|
|
|
if (write_cache) {
|
|
|
|
/* Otherwise, set up to save a cached copy */
|
2018-01-04 03:01:35 -08:00
|
|
|
if (asprintf(&tmpname, "%s-XXXXXX", cachename) < 0) {
|
2015-03-25 17:09:26 -05:00
|
|
|
perror("asprintf");
|
2018-01-04 03:01:35 -08:00
|
|
|
return -1;
|
2015-03-25 17:09:26 -05:00
|
|
|
}
|
|
|
|
if ((cache_fd = mkstemp(tmpname)) < 0) {
|
|
|
|
perror("mkstemp");
|
2018-01-04 03:01:35 -08:00
|
|
|
return -1;
|
2015-03-25 17:09:26 -05:00
|
|
|
}
|
|
|
|
*cachetmpname = tmpname;
|
|
|
|
}
|
|
|
|
|
|
|
|
return cache_fd;
|
|
|
|
}
|
|
|
|
|
|
|
|
void install_cache(const char *cachetmpname, const char *cachename)
|
|
|
|
{
|
|
|
|
/* Only install the generate cache file if it parsed correctly
|
|
|
|
and did not have write/close errors */
|
|
|
|
if (cachetmpname) {
|
2015-08-12 12:22:41 -05:00
|
|
|
struct timespec times[2];
|
|
|
|
|
2015-06-06 01:22:53 -07:00
|
|
|
/* set the mtime of the cache file to the most newest mtime
|
|
|
|
* of policy files used to generate it
|
|
|
|
*/
|
2015-08-12 12:22:41 -05:00
|
|
|
times[0].tv_sec = 0;
|
|
|
|
times[0].tv_nsec = UTIME_OMIT;
|
|
|
|
times[1] = mru_policy_tstamp;
|
|
|
|
if (utimensat(AT_FDCWD, cachetmpname, times, 0) < 0) {
|
|
|
|
PERROR("%s: Failed to set the mtime of cache file '%s': %m\n",
|
|
|
|
progname, cachename);
|
|
|
|
unlink(cachetmpname);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-03-25 17:09:26 -05:00
|
|
|
if (rename(cachetmpname, cachename) < 0) {
|
2020-10-11 12:22:23 +02:00
|
|
|
pwarn(WARN_CACHE, "Failed to write cache: %s\n", cachename);
|
2015-03-25 17:09:26 -05:00
|
|
|
unlink(cachetmpname);
|
|
|
|
}
|
|
|
|
else if (show_cache) {
|
|
|
|
PERROR("Wrote cache: %s\n", cachename);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|