|
Packit |
517ee8 |
/*
|
|
Packit |
517ee8 |
* Copyright 2010-2011 Red Hat Inc., Durham, North Carolina.
|
|
Packit |
517ee8 |
* All Rights Reserved.
|
|
Packit |
517ee8 |
*
|
|
Packit |
517ee8 |
* This library is free software; you can redistribute it and/or
|
|
Packit |
517ee8 |
* modify it under the terms of the GNU Lesser General Public
|
|
Packit |
517ee8 |
* License as published by the Free Software Foundation; either
|
|
Packit |
517ee8 |
* version 2.1 of the License, or (at your option) any later version.
|
|
Packit |
517ee8 |
*
|
|
Packit |
517ee8 |
* This library is distributed in the hope that it will be useful,
|
|
Packit |
517ee8 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
517ee8 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
517ee8 |
* Lesser General Public License for more details.
|
|
Packit |
517ee8 |
*
|
|
Packit |
517ee8 |
* You should have received a copy of the GNU Lesser General Public
|
|
Packit |
517ee8 |
* License along with this library; if not, write to the Free Software
|
|
Packit |
517ee8 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
Packit |
517ee8 |
*
|
|
Packit |
517ee8 |
* Authors:
|
|
Packit |
517ee8 |
* "Daniel Kopecek" <dkopecek@redhat.com>
|
|
Packit |
517ee8 |
* "Tomas Heinrich" <theinric@redhat.com>
|
|
Packit |
517ee8 |
*/
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
#ifdef HAVE_CONFIG_H
|
|
Packit |
517ee8 |
#include <config.h>
|
|
Packit |
517ee8 |
#endif
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
#include <stdint.h>
|
|
Packit |
517ee8 |
#include <stdbool.h>
|
|
Packit |
517ee8 |
#include <string.h>
|
|
Packit |
517ee8 |
#include <sys/types.h>
|
|
Packit |
517ee8 |
#include <sys/stat.h>
|
|
Packit |
517ee8 |
#include <limits.h>
|
|
Packit |
517ee8 |
#include <errno.h>
|
|
Packit |
517ee8 |
#include <pcre.h>
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
#include "oscap_helpers.h"
|
|
Packit |
517ee8 |
#include "fsdev.h"
|
|
Packit |
517ee8 |
#include "_probe-api.h"
|
|
Packit |
517ee8 |
#include "probe/entcmp.h"
|
|
Packit |
517ee8 |
#include "debug_priv.h"
|
|
Packit |
517ee8 |
#include "oval_fts.h"
|
|
Packit |
517ee8 |
#if defined(OS_SOLARIS)
|
|
Packit |
517ee8 |
#include "fts_sun.h"
|
|
Packit |
517ee8 |
#include <sys/mntent.h>
|
|
Packit |
517ee8 |
#include <libzonecfg.h>
|
|
Packit |
517ee8 |
#include <sys/avl.h>
|
|
Packit |
517ee8 |
#elif defined(OS_AIX)
|
|
Packit |
517ee8 |
#include "fts_sun.h"
|
|
Packit |
517ee8 |
#else
|
|
Packit |
517ee8 |
#include <fts.h>
|
|
Packit |
517ee8 |
#endif
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
#undef OSCAP_FTS_DEBUG
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
static OVAL_FTS *OVAL_FTS_new()
|
|
Packit |
517ee8 |
{
|
|
Packit |
517ee8 |
OVAL_FTS *ofts = calloc(1, sizeof(OVAL_FTS));
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
ofts->max_depth = -1;
|
|
Packit |
517ee8 |
ofts->direction = -1;
|
|
Packit |
517ee8 |
ofts->filesystem = -1;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
return (ofts);
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
static void OVAL_FTS_free(OVAL_FTS *ofts)
|
|
Packit |
517ee8 |
{
|
|
Packit |
517ee8 |
if (ofts->ofts_match_path_fts != NULL)
|
|
Packit |
517ee8 |
fts_close(ofts->ofts_match_path_fts);
|
|
Packit |
517ee8 |
if (ofts->ofts_recurse_path_fts != NULL)
|
|
Packit |
517ee8 |
fts_close(ofts->ofts_recurse_path_fts);
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
free(ofts);
|
|
Packit |
517ee8 |
return;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
static int pathlen_from_ftse(int fts_pathlen, int fts_namelen)
|
|
Packit |
517ee8 |
{
|
|
Packit |
517ee8 |
int pathlen;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
if (fts_pathlen > fts_namelen) {
|
|
Packit |
517ee8 |
pathlen = fts_pathlen - fts_namelen;
|
|
Packit |
517ee8 |
if (pathlen > 1)
|
|
Packit |
517ee8 |
pathlen--; /* strip last slash */
|
|
Packit |
517ee8 |
} else {
|
|
Packit |
517ee8 |
pathlen = fts_pathlen;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
return pathlen;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
static OVAL_FTSENT *OVAL_FTSENT_new(OVAL_FTS *ofts, FTSENT *fts_ent)
|
|
Packit |
517ee8 |
{
|
|
Packit |
517ee8 |
OVAL_FTSENT *ofts_ent = calloc(1, sizeof(OVAL_FTSENT));
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
ofts_ent->fts_info = fts_ent->fts_info;
|
|
Packit |
517ee8 |
/* The 'shift' variable stores length of the prefix if the prefix
|
|
Packit |
517ee8 |
* is defined, otherwise it is set to 0. The value of 'shift' gives
|
|
Packit |
517ee8 |
* us information how many characters of the path string are part of
|
|
Packit |
517ee8 |
* the prefix and also where the actual path begins.
|
|
Packit |
517ee8 |
* We use it to remove the prefix from the path.
|
|
Packit |
517ee8 |
*/
|
|
Packit |
517ee8 |
const size_t shift = ofts->prefix ? strlen(ofts->prefix) : 0;
|
|
Packit |
517ee8 |
if (ofts->ofts_sfilename || ofts->ofts_sfilepath) {
|
|
Packit |
517ee8 |
ofts_ent->path_len = pathlen_from_ftse(fts_ent->fts_pathlen, fts_ent->fts_namelen) - shift;
|
|
Packit |
517ee8 |
if (ofts_ent->path_len > 0) {
|
|
Packit |
517ee8 |
ofts_ent->path = malloc(ofts_ent->path_len + 1);
|
|
Packit |
517ee8 |
strncpy(ofts_ent->path, fts_ent->fts_path + shift, ofts_ent->path_len);
|
|
Packit |
517ee8 |
ofts_ent->path[ofts_ent->path_len] = '\0';
|
|
Packit |
517ee8 |
} else {
|
|
Packit |
517ee8 |
ofts_ent->path_len = 1;
|
|
Packit |
517ee8 |
ofts_ent->path = strdup("/");
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
ofts_ent->file_len = fts_ent->fts_namelen;
|
|
Packit |
517ee8 |
ofts_ent->file = strdup(fts_ent->fts_name);
|
|
Packit |
517ee8 |
} else {
|
|
Packit |
517ee8 |
ofts_ent->path_len = fts_ent->fts_pathlen - shift;
|
|
Packit |
517ee8 |
if (ofts_ent->path_len > 0) {
|
|
Packit |
517ee8 |
ofts_ent->path = strdup(fts_ent->fts_path + shift);
|
|
Packit |
517ee8 |
} else {
|
|
Packit |
517ee8 |
ofts_ent->path_len = 1;
|
|
Packit |
517ee8 |
ofts_ent->path = strdup("/");
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
ofts_ent->file_len = -1;
|
|
Packit |
517ee8 |
ofts_ent->file = NULL;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
#if defined(OSCAP_FTS_DEBUG)
|
|
Packit |
517ee8 |
dD("New OVAL_FTSENT: file: '%s', path: '%s'.", ofts_ent->file, ofts_ent->path);
|
|
Packit |
517ee8 |
#endif
|
|
Packit |
517ee8 |
return (ofts_ent);
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
static void OVAL_FTSENT_free(OVAL_FTSENT *ofts_ent)
|
|
Packit |
517ee8 |
{
|
|
Packit |
517ee8 |
free(ofts_ent->path);
|
|
Packit |
517ee8 |
free(ofts_ent->file);
|
|
Packit |
517ee8 |
free(ofts_ent);
|
|
Packit |
517ee8 |
return;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
#if defined(OS_SOLARIS)
|
|
Packit |
517ee8 |
#ifndef MNTTYPE_SMB
|
|
Packit |
517ee8 |
#define MNTTYPE_SMB "smb"
|
|
Packit |
517ee8 |
#endif
|
|
Packit |
517ee8 |
#ifndef MNTTYPE_SMBFS
|
|
Packit |
517ee8 |
#define MNTTYPE_SMBFS "smbfs"
|
|
Packit |
517ee8 |
#endif
|
|
Packit |
517ee8 |
#ifndef MNTTYPE_PROC
|
|
Packit |
517ee8 |
#define MNTTYPE_PROC "proc"
|
|
Packit |
517ee8 |
#endif
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
typedef struct zone_path {
|
|
Packit |
517ee8 |
avl_node_t avl_link_next;
|
|
Packit |
517ee8 |
char zpath[MAXPATHLEN];
|
|
Packit |
517ee8 |
} zone_path_t;
|
|
Packit |
517ee8 |
static avl_tree_t avl_tree_list;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
static bool valid_remote_fs(char *fstype)
|
|
Packit |
517ee8 |
{
|
|
Packit |
517ee8 |
if (strcmp(fstype, MNTTYPE_NFS) == 0 ||
|
|
Packit |
517ee8 |
strcmp(fstype, MNTTYPE_SMBFS) == 0 ||
|
|
Packit |
517ee8 |
strcmp(fstype, MNTTYPE_SMB) == 0)
|
|
Packit |
517ee8 |
return (true);
|
|
Packit |
517ee8 |
return (false);
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
static bool valid_local_fs(char *fstype)
|
|
Packit |
517ee8 |
{
|
|
Packit |
517ee8 |
if (strcmp(fstype, MNTTYPE_SWAP) == 0 ||
|
|
Packit |
517ee8 |
strcmp(fstype, MNTTYPE_MNTFS) == 0 ||
|
|
Packit |
517ee8 |
strcmp(fstype, MNTTYPE_CTFS) == 0 ||
|
|
Packit |
517ee8 |
strcmp(fstype, MNTTYPE_OBJFS) == 0 ||
|
|
Packit |
517ee8 |
strcmp(fstype, MNTTYPE_SHAREFS) == 0 ||
|
|
Packit |
517ee8 |
strcmp(fstype, MNTTYPE_PROC) == 0 ||
|
|
Packit |
517ee8 |
strcmp(fstype, MNTTYPE_LOFS) == 0 ||
|
|
Packit |
517ee8 |
strcmp(fstype, MNTTYPE_AUTOFS) == 0)
|
|
Packit |
517ee8 |
return (false);
|
|
Packit |
517ee8 |
return (true);
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
/* function to compare two avl nodes in the avl tree */
|
|
Packit |
517ee8 |
static int compare_zoneroot(const void *entry1, const void *entry2)
|
|
Packit |
517ee8 |
{
|
|
Packit |
517ee8 |
zone_path_t *t1, *t2;
|
|
Packit |
517ee8 |
int comp;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
t1 = (zone_path_t *)entry1;
|
|
Packit |
517ee8 |
t2 = (zone_path_t *)entry2;
|
|
Packit |
517ee8 |
if ((comp = strcmp(t1->zpath, t2->zpath)) == 0) {
|
|
Packit |
517ee8 |
return (0);
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
return (comp > 0 ? 1 : -1);
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
int load_zones_path_list()
|
|
Packit |
517ee8 |
{
|
|
Packit |
517ee8 |
FILE *cookie;
|
|
Packit |
517ee8 |
char *name;
|
|
Packit |
517ee8 |
zone_state_t state_num;
|
|
Packit |
517ee8 |
zone_path_t *temp = NULL;
|
|
Packit |
517ee8 |
avl_index_t where;
|
|
Packit |
517ee8 |
char rpath[MAXPATHLEN];
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
cookie = setzoneent();
|
|
Packit |
517ee8 |
if (getzoneid() != GLOBAL_ZONEID)
|
|
Packit |
517ee8 |
return (0);
|
|
Packit |
517ee8 |
avl_create(&avl_tree_list, compare_zoneroot,
|
|
Packit |
517ee8 |
sizeof(zone_path_t), offsetof(zone_path_t, avl_link_next));
|
|
Packit |
517ee8 |
while ((name = getzoneent(cookie)) != NULL) {
|
|
Packit |
517ee8 |
if (strcmp(name, "global") == 0)
|
|
Packit |
517ee8 |
continue;
|
|
Packit |
517ee8 |
if (zone_get_state(name, &state_num) != Z_OK) {
|
|
Packit |
517ee8 |
dE("Could not get zone state for %s", name);
|
|
Packit |
517ee8 |
continue;
|
|
Packit |
517ee8 |
} else if (state_num > ZONE_STATE_CONFIGURED) {
|
|
Packit |
517ee8 |
temp = malloc(sizeof(zone_path_t));
|
|
Packit |
517ee8 |
if (temp == NULL) {
|
|
Packit |
517ee8 |
dE("Memory alloc failed");
|
|
Packit |
517ee8 |
return(1);
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
if (zone_get_zonepath(name, rpath,
|
|
Packit |
517ee8 |
sizeof(rpath)) != Z_OK) {
|
|
Packit |
517ee8 |
dE("Could not get zone path for %s",
|
|
Packit |
517ee8 |
name);
|
|
Packit |
517ee8 |
continue;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
if (oscap_realpath(rpath, temp->zpath) != NULL)
|
|
Packit |
517ee8 |
avl_add(&avl_tree_list, temp);
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
endzoneent(cookie);
|
|
Packit |
517ee8 |
return (0);
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
static void free_zones_path_list()
|
|
Packit |
517ee8 |
{
|
|
Packit |
517ee8 |
zone_path_t *temp;
|
|
Packit |
517ee8 |
void* cookie = NULL;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
while ((temp = avl_destroy_nodes(&avl_tree_list, &cookie)) != NULL) {
|
|
Packit |
517ee8 |
free(temp);
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
avl_destroy(&avl_tree_list);
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
static bool valid_local_zone(const char *path)
|
|
Packit |
517ee8 |
{
|
|
Packit |
517ee8 |
zone_path_t temp;
|
|
Packit |
517ee8 |
avl_index_t where;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
strlcpy(temp.zpath, path, sizeof(temp.zpath));
|
|
Packit |
517ee8 |
if (avl_find(&avl_tree_list, &temp, &where) != NULL)
|
|
Packit |
517ee8 |
return (true);
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
return (false);
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
#endif
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
static bool OVAL_FTS_localp(OVAL_FTS *ofts, const char *path, void *id)
|
|
Packit |
517ee8 |
{
|
|
Packit |
517ee8 |
#if defined(OS_SOLARIS)
|
|
Packit |
517ee8 |
if (id != NULL && (*(char*)id) != '\0') {
|
|
Packit |
517ee8 |
/* if not a valid local fs skip */
|
|
Packit |
517ee8 |
if (valid_local_fs((char*)id)) {
|
|
Packit |
517ee8 |
/* if recurse is local , skip remote fs
|
|
Packit |
517ee8 |
and non-global zones */
|
|
Packit |
517ee8 |
if (ofts->filesystem == OVAL_RECURSE_FS_LOCAL) {
|
|
Packit |
517ee8 |
return (!(valid_remote_fs((char*)id) ||
|
|
Packit |
517ee8 |
valid_local_zone(path)));
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
return (true);
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
return (false);
|
|
Packit |
517ee8 |
} else if (path != NULL) {
|
|
Packit |
517ee8 |
/* id was not set, because fts_read failed to stat the node */
|
|
Packit |
517ee8 |
struct stat sb;
|
|
Packit |
517ee8 |
if ((stat(path, &sb) == 0) && (valid_local_fs(sb.st_fstype))) {
|
|
Packit |
517ee8 |
/* if recurse is local , skip remote fs
|
|
Packit |
517ee8 |
and non-global zones */
|
|
Packit |
517ee8 |
if (ofts->filesystem == OVAL_RECURSE_FS_LOCAL) {
|
|
Packit |
517ee8 |
return (!(valid_remote_fs(sb.st_fstype) ||
|
|
Packit |
517ee8 |
valid_local_zone(path)));
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
return (true);
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
return (false);
|
|
Packit |
517ee8 |
} else {
|
|
Packit |
517ee8 |
return (false);
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
#else
|
|
Packit |
517ee8 |
if (id != NULL)
|
|
Packit |
517ee8 |
return (fsdev_search(ofts->localdevs, id) == 1 ? true : false);
|
|
Packit |
517ee8 |
else if (path != NULL)
|
|
Packit |
517ee8 |
return (fsdev_path(ofts->localdevs, path) == 1 ? true : false);
|
|
Packit |
517ee8 |
else
|
|
Packit |
517ee8 |
return (false);
|
|
Packit |
517ee8 |
#endif
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
static char *__regex_locate(char *str)
|
|
Packit |
517ee8 |
{
|
|
Packit |
517ee8 |
char *regex_sch = "^*?$.(["; /*<< regex start chars */
|
|
Packit |
517ee8 |
bool escaped = false;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
while (*str != '\0') {
|
|
Packit |
517ee8 |
if (*str == '\\')
|
|
Packit |
517ee8 |
escaped = !escaped;
|
|
Packit |
517ee8 |
else if (strchr(regex_sch, *str) != NULL) {
|
|
Packit |
517ee8 |
if (!escaped)
|
|
Packit |
517ee8 |
return (str);
|
|
Packit |
517ee8 |
else
|
|
Packit |
517ee8 |
escaped = false;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
++str;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
return (str);
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
static char *__string_unescape(char *str, size_t len)
|
|
Packit |
517ee8 |
{
|
|
Packit |
517ee8 |
char *ret_str;
|
|
Packit |
517ee8 |
size_t i, j;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
if (str == NULL || len == 0)
|
|
Packit |
517ee8 |
return NULL;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
ret_str = strndup(str, len);
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
if (ret_str == NULL)
|
|
Packit |
517ee8 |
return NULL;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
for (i = j = 0; i < len && j <= i; ++i) {
|
|
Packit |
517ee8 |
if (str[i] == '\\') {
|
|
Packit |
517ee8 |
if (str[i+1] == '\0') {
|
|
Packit |
517ee8 |
free(ret_str);
|
|
Packit |
517ee8 |
return NULL;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
ret_str[j] = str[i+1];
|
|
Packit |
517ee8 |
++j;
|
|
Packit |
517ee8 |
++i;
|
|
Packit |
517ee8 |
} else {
|
|
Packit |
517ee8 |
ret_str[j] = str[i];
|
|
Packit |
517ee8 |
++j;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
ret_str[j] = '\0';
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
return ret_str;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
static char *extract_fixed_path_prefix(char *path)
|
|
Packit |
517ee8 |
{
|
|
Packit |
517ee8 |
char *s;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
if (path[0] == '^')
|
|
Packit |
517ee8 |
path++;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
s = __regex_locate(path);
|
|
Packit |
517ee8 |
if (*s != '\0')
|
|
Packit |
517ee8 |
for (s--; s > (path + 1) && *s != '/'; s--);
|
|
Packit |
517ee8 |
if (s > (path + 1)) {
|
|
Packit |
517ee8 |
s = __string_unescape(path, (size_t) (s - path));
|
|
Packit |
517ee8 |
if (s != NULL) {
|
|
Packit |
517ee8 |
if (s[0] == '/')
|
|
Packit |
517ee8 |
return s;
|
|
Packit |
517ee8 |
free(s);
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
return strdup("/");
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
static int badpartial_check_slash(const char *pattern)
|
|
Packit |
517ee8 |
{
|
|
Packit |
517ee8 |
pcre *regex;
|
|
Packit |
517ee8 |
const char *errptr = NULL;
|
|
Packit |
517ee8 |
int errofs = 0, fb, ret;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
regex = pcre_compile(pattern + 1 /* skip '^' */, 0, &errptr, &errofs, NULL);
|
|
Packit |
517ee8 |
if (regex == NULL) {
|
|
Packit |
517ee8 |
dE("Failed to validate the pattern: pcre_compile(): "
|
|
Packit |
517ee8 |
"error: '%s', error offset: %d, pattern: '%s'.\n",
|
|
Packit |
517ee8 |
errptr, errofs, pattern);
|
|
Packit |
517ee8 |
return -1;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
ret = pcre_fullinfo(regex, NULL, PCRE_INFO_FIRSTBYTE, &fb;;
|
|
Packit |
517ee8 |
pcre_free(regex);
|
|
Packit |
517ee8 |
regex = NULL;
|
|
Packit |
517ee8 |
if (ret != 0) {
|
|
Packit |
517ee8 |
dE("Failed to validate the pattern: pcre_fullinfo(): "
|
|
Packit |
517ee8 |
"return code: %d, pattern: '%s'.\n", ret, pattern);
|
|
Packit |
517ee8 |
return -1;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
if (fb != '/') {
|
|
Packit |
517ee8 |
dE("Failed to validate the pattern: pcre_fullinfo(): "
|
|
Packit |
517ee8 |
"first byte: %d '%c', pattern: '%s' - the first "
|
|
Packit |
517ee8 |
"byte should be a '/'.\n", fb, fb, pattern);
|
|
Packit |
517ee8 |
return -2;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
return 0;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
#define TEST_PATH1 "/"
|
|
Packit |
517ee8 |
#define TEST_PATH2 "x"
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
static int badpartial_transform_pattern(char *pattern, pcre **regex_out)
|
|
Packit |
517ee8 |
{
|
|
Packit |
517ee8 |
/*
|
|
Packit |
517ee8 |
PCREPARTIAL(3)
|
|
Packit |
517ee8 |
http://pcre.org/pcre.txt
|
|
Packit |
517ee8 |
Last updated: 21 January 2012
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
For releases of PCRE prior to 8.00, because of the way
|
|
Packit |
517ee8 |
certain internal optimizations were implemented in the
|
|
Packit |
517ee8 |
pcre_exec() function, the PCRE_PARTIAL option (predecessor
|
|
Packit |
517ee8 |
of PCRE_PARTIAL_SOFT) could not be used with all patterns.
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
Items that were formerly restricted were repeated single
|
|
Packit |
517ee8 |
characters and repeated metasequences. If PCRE_PARTIAL was
|
|
Packit |
517ee8 |
set for a pattern that did not conform to the restrictions,
|
|
Packit |
517ee8 |
pcre_exec() returned the error code PCRE_ERROR_BADPARTIAL
|
|
Packit |
517ee8 |
(-13).
|
|
Packit |
517ee8 |
*/
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
int ret, brkt_lvl = 0, errofs = 0;
|
|
Packit |
517ee8 |
const char *rchars = "\\[]()*+{"; /* probably incomplete */
|
|
Packit |
517ee8 |
const char *test_path1 = TEST_PATH1;
|
|
Packit |
517ee8 |
const char *errptr = NULL;
|
|
Packit |
517ee8 |
char *s, *brkt_mark;
|
|
Packit |
517ee8 |
bool bracketed = false, found_regex = false;
|
|
Packit |
517ee8 |
pcre *regex;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
/* The processing bellow builds upon the assumption that
|
|
Packit |
517ee8 |
the pattern has been validated by pcre_compile() */
|
|
Packit |
517ee8 |
for (s = brkt_mark = pattern; (s = strpbrk(s, rchars)) != NULL; s++) {
|
|
Packit |
517ee8 |
switch (*s) {
|
|
Packit |
517ee8 |
case '\\':
|
|
Packit |
517ee8 |
s++;
|
|
Packit |
517ee8 |
break;
|
|
Packit |
517ee8 |
case '[':
|
|
Packit |
517ee8 |
if (!bracketed) {
|
|
Packit |
517ee8 |
bracketed = true;
|
|
Packit |
517ee8 |
if (s[1] == ']')
|
|
Packit |
517ee8 |
s++;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
break;
|
|
Packit |
517ee8 |
case ']':
|
|
Packit |
517ee8 |
bracketed = false;
|
|
Packit |
517ee8 |
break;
|
|
Packit |
517ee8 |
case '(':
|
|
Packit |
517ee8 |
if (!bracketed) {
|
|
Packit |
517ee8 |
if (brkt_lvl++ == 0)
|
|
Packit |
517ee8 |
brkt_mark = s;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
break;
|
|
Packit |
517ee8 |
case ')':
|
|
Packit |
517ee8 |
if (!bracketed)
|
|
Packit |
517ee8 |
brkt_lvl--;
|
|
Packit |
517ee8 |
break;
|
|
Packit |
517ee8 |
default:
|
|
Packit |
517ee8 |
if (!bracketed)
|
|
Packit |
517ee8 |
found_regex = true;
|
|
Packit |
517ee8 |
break;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
if (found_regex)
|
|
Packit |
517ee8 |
break;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
if (s == NULL) {
|
|
Packit |
517ee8 |
dW("Nonfatal failure: can't transform the pattern for partial "
|
|
Packit |
517ee8 |
"match optimization: none of the suspected culprits found, "
|
|
Packit |
517ee8 |
"pattern: '%s'.", pattern);
|
|
Packit |
517ee8 |
return -1;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
if (brkt_lvl > 0)
|
|
Packit |
517ee8 |
*brkt_mark = '\0';
|
|
Packit |
517ee8 |
else
|
|
Packit |
517ee8 |
*s = '\0';
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
regex = pcre_compile(pattern, 0, &errptr, &errofs, NULL);
|
|
Packit |
517ee8 |
if (regex == NULL) {
|
|
Packit |
517ee8 |
dW("Nonfatal failure: can't transform the pattern for partial "
|
|
Packit |
517ee8 |
"match optimization, error: '%s', error offset: %d, "
|
|
Packit |
517ee8 |
"pattern: '%s'.", errptr, errofs, pattern);
|
|
Packit |
517ee8 |
return -1;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
ret = pcre_exec(regex, NULL, test_path1, strlen(test_path1), 0,
|
|
Packit |
517ee8 |
PCRE_PARTIAL, NULL, 0);
|
|
Packit |
517ee8 |
if (ret != PCRE_ERROR_PARTIAL && ret < 0) {
|
|
Packit |
517ee8 |
pcre_free(regex);
|
|
Packit |
517ee8 |
dW("Nonfatal failure: can't transform the pattern for partial "
|
|
Packit |
517ee8 |
"match optimization, pcre_exec() return code: %d, pattern: "
|
|
Packit |
517ee8 |
"'%s'.", ret, pattern);
|
|
Packit |
517ee8 |
return -1;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
if (regex_out != NULL)
|
|
Packit |
517ee8 |
*regex_out = regex;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
return 0;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
/* Verify that the path is usable and try to craft a regex to speed up
|
|
Packit |
517ee8 |
the filesystem traversal. If the path to match is ill-designed, an
|
|
Packit |
517ee8 |
ugly heuristic is employed to obtain something meaningfull. */
|
|
Packit |
517ee8 |
static int process_pattern_match(const char *path, pcre **regex_out)
|
|
Packit |
517ee8 |
{
|
|
Packit |
517ee8 |
int ret, errofs = 0;
|
|
Packit |
517ee8 |
char *pattern;
|
|
Packit |
517ee8 |
const char *test_path1 = TEST_PATH1;
|
|
Packit |
517ee8 |
//const char *test_path2 = TEST_PATH2;
|
|
Packit |
517ee8 |
const char *errptr = NULL;
|
|
Packit |
517ee8 |
pcre *regex;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
if (path[0] != '^') {
|
|
Packit |
517ee8 |
/* Matching has to have a fixed starting point and thus
|
|
Packit |
517ee8 |
every pattern has to start with a caret. */
|
|
Packit |
517ee8 |
size_t plen;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
plen = strlen(path) + 1;
|
|
Packit |
517ee8 |
pattern = malloc(plen + 1);
|
|
Packit |
517ee8 |
pattern[0] = '^';
|
|
Packit |
517ee8 |
memcpy(pattern + 1, path, plen);
|
|
Packit |
517ee8 |
dI("The pattern '%s' doesn't contain a leading caret - added. "
|
|
Packit |
517ee8 |
"All paths with the 'pattern match' operation must begin "
|
|
Packit |
517ee8 |
"with a caret.", path);
|
|
Packit |
517ee8 |
} else {
|
|
Packit |
517ee8 |
pattern = strdup(path);
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
regex = pcre_compile(pattern, 0, &errptr, &errofs, NULL);
|
|
Packit |
517ee8 |
if (regex == NULL) {
|
|
Packit |
517ee8 |
dE("Failed to validate the pattern: pcre_compile(): "
|
|
Packit |
517ee8 |
"error offset: %d, error: '%s', pattern: '%s'.\n",
|
|
Packit |
517ee8 |
errofs, errptr, pattern);
|
|
Packit |
517ee8 |
free(pattern);
|
|
Packit |
517ee8 |
return -1;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
ret = pcre_exec(regex, NULL, test_path1, strlen(test_path1), 0,
|
|
Packit |
517ee8 |
PCRE_PARTIAL, NULL, 0);
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
switch (ret) {
|
|
Packit |
517ee8 |
case PCRE_ERROR_PARTIAL:
|
|
Packit |
517ee8 |
/* The pattern has matched a prefix of the test path
|
|
Packit |
517ee8 |
and probably begins with a slash. Make sure that it
|
|
Packit |
517ee8 |
doesn't match an arbitrary prefix. */
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
/* todo:
|
|
Packit |
517ee8 |
Convince folks that they should really fix their
|
|
Packit |
517ee8 |
OVAL definitions that use ".*" as 'path' and then
|
|
Packit |
517ee8 |
uncomment this.
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
dD("pcre_exec() returned PCRE_ERROR_PARTIAL for pattern '%s' "
|
|
Packit |
517ee8 |
"and test path '%s'.\n", pattern, test_path1);
|
|
Packit |
517ee8 |
ret = pcre_exec(regex, NULL, test_path2, strlen(test_path2),
|
|
Packit |
517ee8 |
0, PCRE_PARTIAL, NULL, 0);
|
|
Packit |
517ee8 |
if (ret == PCRE_ERROR_PARTIAL || ret >= 0) {
|
|
Packit |
517ee8 |
dE("Failed to validate the pattern: test path '%s' "
|
|
Packit |
517ee8 |
"matched by pattern '%s' - the pattern is too "
|
|
Packit |
517ee8 |
"general, i.e. inefficient. This could take a "
|
|
Packit |
517ee8 |
"lifetime to complete.\n", test_path2, pattern);
|
|
Packit |
517ee8 |
pcre_free(regex);
|
|
Packit |
517ee8 |
free(pattern);
|
|
Packit |
517ee8 |
return -2;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
*/
|
|
Packit |
517ee8 |
break;
|
|
Packit |
517ee8 |
case PCRE_ERROR_BADPARTIAL:
|
|
Packit |
517ee8 |
dD("pcre_exec() returned PCRE_ERROR_BADPARTIAL for pattern "
|
|
Packit |
517ee8 |
"'%s' and a test path '%s'. Falling back to "
|
|
Packit |
517ee8 |
"pcre_fullinfo().\n", pattern, test_path1);
|
|
Packit |
517ee8 |
pcre_free(regex);
|
|
Packit |
517ee8 |
regex = NULL;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
/* Fallback to first byte check to determin if
|
|
Packit |
517ee8 |
the pattern begins with a slash. */
|
|
Packit |
517ee8 |
ret = badpartial_check_slash((const char *) pattern);
|
|
Packit |
517ee8 |
if (ret != 0) {
|
|
Packit |
517ee8 |
free(pattern);
|
|
Packit |
517ee8 |
return ret;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
/* The pattern contains features that this version of
|
|
Packit |
517ee8 |
PCRE can't handle for partial matching. At least
|
|
Packit |
517ee8 |
try to find the longest well-bracketed prefix that
|
|
Packit |
517ee8 |
can be handled. */
|
|
Packit |
517ee8 |
badpartial_transform_pattern(pattern, ®ex);
|
|
Packit |
517ee8 |
break;
|
|
Packit |
517ee8 |
case PCRE_ERROR_NOMATCH:
|
|
Packit |
517ee8 |
/* The pattern doesn't contain a leading slash (or
|
|
Packit |
517ee8 |
some part of this code is broken). Apologise to the
|
|
Packit |
517ee8 |
user and fail. */
|
|
Packit |
517ee8 |
dE("Failed to validate the pattern: pcre_exec() returned "
|
|
Packit |
517ee8 |
"PCRE_ERROR_NOMATCH for pattern '%s' and a test path '%s'. "
|
|
Packit |
517ee8 |
"This indicates the pattern doesn't match a leading '/'.\n",
|
|
Packit |
517ee8 |
pattern, test_path1);
|
|
Packit |
517ee8 |
pcre_free(regex);
|
|
Packit |
517ee8 |
free(pattern);
|
|
Packit |
517ee8 |
return -2;
|
|
Packit |
517ee8 |
default:
|
|
Packit |
517ee8 |
if (ret >= 0) {
|
|
Packit |
517ee8 |
/* The pattern actually matches the test
|
|
Packit |
517ee8 |
path. Iteresting… Make sure that it doesn't
|
|
Packit |
517ee8 |
match an arbitrary prefix. */
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
/* todo:
|
|
Packit |
517ee8 |
Convince folks that they should really fix
|
|
Packit |
517ee8 |
their OVAL definitions that use ".*" as
|
|
Packit |
517ee8 |
'path' and then uncomment this.
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
ret = pcre_exec(regex, NULL, test_path2, strlen(test_path2),
|
|
Packit |
517ee8 |
0, PCRE_PARTIAL, NULL, 0);
|
|
Packit |
517ee8 |
if (ret == PCRE_ERROR_PARTIAL || ret >= 0) {
|
|
Packit |
517ee8 |
dE("Failed to validate the pattern: test path '%s' "
|
|
Packit |
517ee8 |
"matched by pattern '%s' - the pattern is too "
|
|
Packit |
517ee8 |
"general, i.e. inefficient. This could take a "
|
|
Packit |
517ee8 |
"lifetime to complete.\n", test_path2, pattern);
|
|
Packit |
517ee8 |
pcre_free(regex);
|
|
Packit |
517ee8 |
free(pattern);
|
|
Packit |
517ee8 |
return -2;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
*/
|
|
Packit |
517ee8 |
break;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
/* Some other error. */
|
|
Packit |
517ee8 |
dE("Failed to validate the pattern: pcre_exec() return "
|
|
Packit |
517ee8 |
"code: %d, pattern '%s', test path '%s'.\n", ret,
|
|
Packit |
517ee8 |
pattern, test_path1);
|
|
Packit |
517ee8 |
pcre_free(regex);
|
|
Packit |
517ee8 |
free(pattern);
|
|
Packit |
517ee8 |
return -1;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
if (regex == NULL) {
|
|
Packit |
517ee8 |
dD("Disabling partial match optimization.");
|
|
Packit |
517ee8 |
} else {
|
|
Packit |
517ee8 |
dD("Enabling partial match optimization using "
|
|
Packit |
517ee8 |
"pattern: '%s'.", pattern);
|
|
Packit |
517ee8 |
if (regex_out != NULL)
|
|
Packit |
517ee8 |
*regex_out = regex;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
free(pattern);
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
return 0;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
#undef TEST_PATH1
|
|
Packit |
517ee8 |
#undef TEST_PATH2
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
OVAL_FTS *oval_fts_open(SEXP_t *path, SEXP_t *filename, SEXP_t *filepath, SEXP_t *behaviors, SEXP_t* result)
|
|
Packit |
517ee8 |
{
|
|
Packit |
517ee8 |
return oval_fts_open_prefixed(NULL, path, filename, filepath, behaviors, result);
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
OVAL_FTS *oval_fts_open_prefixed(const char *prefix, SEXP_t *path, SEXP_t *filename, SEXP_t *filepath, SEXP_t *behaviors, SEXP_t* result)
|
|
Packit |
517ee8 |
{
|
|
Packit |
517ee8 |
OVAL_FTS *ofts;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
char cstr_path[PATH_MAX+1];
|
|
Packit |
517ee8 |
char cstr_file[PATH_MAX+1];
|
|
Packit |
517ee8 |
char cstr_buff[32];
|
|
Packit |
517ee8 |
const char *paths[2] = { NULL, NULL };
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
SEXP_t *r0;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
int mtc_fts_options = FTS_PHYSICAL | FTS_COMFOLLOW | FTS_NOCHDIR;
|
|
Packit |
517ee8 |
int rec_fts_options = FTS_PHYSICAL | FTS_COMFOLLOW | FTS_NOCHDIR;
|
|
Packit |
517ee8 |
int max_depth = -1;
|
|
Packit |
517ee8 |
int direction = -1;
|
|
Packit |
517ee8 |
int recurse = -1;
|
|
Packit |
517ee8 |
int filesystem = -1;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
uint32_t path_op;
|
|
Packit |
517ee8 |
bool nilfilename = false;
|
|
Packit |
517ee8 |
pcre *regex = NULL;
|
|
Packit |
517ee8 |
struct stat st;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
if ((path != NULL || filename != NULL || filepath == NULL)
|
|
Packit |
517ee8 |
&& (path == NULL || filepath != NULL)) {
|
|
Packit |
517ee8 |
return NULL;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
if (behaviors == NULL) {
|
|
Packit |
517ee8 |
return NULL;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
if (path)
|
|
Packit |
517ee8 |
PROBE_ENT_AREF(path, r0, "operation", /**/);
|
|
Packit |
517ee8 |
else
|
|
Packit |
517ee8 |
PROBE_ENT_AREF(filepath, r0, "operation", /**/);
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
if (r0 != NULL) {
|
|
Packit |
517ee8 |
path_op = SEXP_number_getu(r0);
|
|
Packit |
517ee8 |
SEXP_free(r0);
|
|
Packit |
517ee8 |
} else {
|
|
Packit |
517ee8 |
path_op = OVAL_OPERATION_EQUALS;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
#if defined(OSCAP_FTS_DEBUG)
|
|
Packit |
517ee8 |
dD("path_op: %u, '%s'.", path_op, oval_operation_get_text(path_op));
|
|
Packit |
517ee8 |
#endif
|
|
Packit |
517ee8 |
if (path) { /* filepath == NULL */
|
|
Packit |
517ee8 |
PROBE_ENT_STRVAL(path, cstr_path, sizeof cstr_path,
|
|
Packit |
517ee8 |
return NULL;, return NULL;);
|
|
Packit |
517ee8 |
if (probe_ent_getvals(filename, NULL) == 0) {
|
|
Packit |
517ee8 |
nilfilename = true;
|
|
Packit |
517ee8 |
} else {
|
|
Packit |
517ee8 |
PROBE_ENT_STRVAL(filename, cstr_file, sizeof cstr_file,
|
|
Packit |
517ee8 |
return NULL;, /* noop */;);
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
#if defined(OSCAP_FTS_DEBUG)
|
|
Packit |
517ee8 |
dD("path: '%s', filename: '%s', filename: %d.", cstr_path, nilfilename ? "" : cstr_file, nilfilename);
|
|
Packit |
517ee8 |
#endif
|
|
Packit |
517ee8 |
} else { /* filepath != NULL */
|
|
Packit |
517ee8 |
PROBE_ENT_STRVAL(filepath, cstr_path, sizeof cstr_path, return NULL;, return NULL;);
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
/* max_depth */
|
|
Packit |
517ee8 |
PROBE_ENT_AREF(behaviors, r0, "max_depth", return NULL;);
|
|
Packit |
517ee8 |
SEXP_string_cstr_r(r0, cstr_buff, sizeof cstr_buff - 1);
|
|
Packit |
517ee8 |
max_depth = strtol(cstr_buff, NULL, 10);
|
|
Packit |
517ee8 |
if (errno == EINVAL || errno == ERANGE) {
|
|
Packit |
517ee8 |
dE("Invalid value of the `%s' attribute: %s", "recurse_direction", cstr_buff);
|
|
Packit |
517ee8 |
SEXP_free(r0);
|
|
Packit |
517ee8 |
return (NULL);
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
#if defined(OSCAP_FTS_DEBUG)
|
|
Packit |
517ee8 |
dD("bh.max_depth: %s => max_depth: %d", cstr_buff, max_depth);
|
|
Packit |
517ee8 |
#endif
|
|
Packit |
517ee8 |
SEXP_free(r0);
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
/* recurse_direction */
|
|
Packit |
517ee8 |
PROBE_ENT_AREF(behaviors, r0, "recurse_direction", return NULL;);
|
|
Packit |
517ee8 |
SEXP_string_cstr_r(r0, cstr_buff, sizeof cstr_buff - 1);
|
|
Packit |
517ee8 |
/* todo: use oscap_string_to_enum() */
|
|
Packit |
517ee8 |
if (strcmp(cstr_buff, "none") == 0) {
|
|
Packit |
517ee8 |
direction = OVAL_RECURSE_DIRECTION_NONE;
|
|
Packit |
517ee8 |
} else if (strcmp(cstr_buff, "down") == 0) {
|
|
Packit |
517ee8 |
direction = OVAL_RECURSE_DIRECTION_DOWN;
|
|
Packit |
517ee8 |
} else if (strcmp(cstr_buff, "up") == 0) {
|
|
Packit |
517ee8 |
direction = OVAL_RECURSE_DIRECTION_UP;
|
|
Packit |
517ee8 |
} else {
|
|
Packit |
517ee8 |
dE("Invalid direction: %s", cstr_buff);
|
|
Packit |
517ee8 |
SEXP_free(r0);
|
|
Packit |
517ee8 |
return (NULL);
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
#if defined(OSCAP_FTS_DEBUG)
|
|
Packit |
517ee8 |
dD("bh.direction: %s => direction: %d", cstr_buff, direction);
|
|
Packit |
517ee8 |
#endif
|
|
Packit |
517ee8 |
SEXP_free(r0);
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
/* recurse */
|
|
Packit |
517ee8 |
PROBE_ENT_AREF(behaviors, r0, "recurse", /**/);
|
|
Packit |
517ee8 |
if (r0 != NULL) {
|
|
Packit |
517ee8 |
SEXP_string_cstr_r(r0, cstr_buff, sizeof cstr_buff - 1);
|
|
Packit |
517ee8 |
/* todo: use oscap_string_to_enum() */
|
|
Packit |
517ee8 |
if (strcmp(cstr_buff, "symlinks and directories") == 0) {
|
|
Packit |
517ee8 |
recurse = OVAL_RECURSE_SYMLINKS_AND_DIRS;
|
|
Packit |
517ee8 |
} else if (strcmp(cstr_buff, "files and directories") == 0) {
|
|
Packit |
517ee8 |
recurse = OVAL_RECURSE_FILES_AND_DIRS;
|
|
Packit |
517ee8 |
} else if (strcmp(cstr_buff, "symlinks") == 0) {
|
|
Packit |
517ee8 |
recurse = OVAL_RECURSE_SYMLINKS;
|
|
Packit |
517ee8 |
} else if (strcmp(cstr_buff, "directories") == 0) {
|
|
Packit |
517ee8 |
recurse = OVAL_RECURSE_DIRS;
|
|
Packit |
517ee8 |
} else {
|
|
Packit |
517ee8 |
dE("Invalid recurse: %s", cstr_buff);
|
|
Packit |
517ee8 |
SEXP_free(r0);
|
|
Packit |
517ee8 |
return (NULL);
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
} else {
|
|
Packit |
517ee8 |
recurse = OVAL_RECURSE_SYMLINKS_AND_DIRS;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
#if defined(OSCAP_FTS_DEBUG)
|
|
Packit |
517ee8 |
dD("bh.recurse: %s => recurse: %d", cstr_buff, recurse);
|
|
Packit |
517ee8 |
#endif
|
|
Packit |
517ee8 |
SEXP_free(r0);
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
/* recurse_file_system */
|
|
Packit |
517ee8 |
PROBE_ENT_AREF(behaviors, r0, "recurse_file_system", /**/);
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
if (r0 != NULL) {
|
|
Packit |
517ee8 |
SEXP_string_cstr_r(r0, cstr_buff, sizeof cstr_buff - 1);
|
|
Packit |
517ee8 |
/* todo: use oscap_string_to_enum() */
|
|
Packit |
517ee8 |
if (strcmp(cstr_buff, "local") == 0) {
|
|
Packit |
517ee8 |
filesystem = OVAL_RECURSE_FS_LOCAL;
|
|
Packit |
517ee8 |
} else if (strcmp(cstr_buff, "all") == 0) {
|
|
Packit |
517ee8 |
filesystem = OVAL_RECURSE_FS_ALL;
|
|
Packit |
517ee8 |
} else if (strcmp(cstr_buff, "defined") == 0) {
|
|
Packit |
517ee8 |
filesystem = OVAL_RECURSE_FS_DEFINED;
|
|
Packit |
517ee8 |
rec_fts_options |= FTS_XDEV;
|
|
Packit |
517ee8 |
} else {
|
|
Packit |
517ee8 |
dE("Invalid recurse filesystem: %s", cstr_buff);
|
|
Packit |
517ee8 |
SEXP_free(r0);
|
|
Packit |
517ee8 |
return (NULL);
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
} else {
|
|
Packit |
517ee8 |
filesystem = OVAL_RECURSE_FS_ALL;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
#if defined(OSCAP_FTS_DEBUG)
|
|
Packit |
517ee8 |
dD("bh.filesystem: %s => filesystem: %d", cstr_buff, filesystem);
|
|
Packit |
517ee8 |
#endif
|
|
Packit |
517ee8 |
SEXP_free(r0);
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
/* todo:
|
|
Packit |
517ee8 |
Still missing is a propagation of the error to the
|
|
Packit |
517ee8 |
user. Currently, all the information is provided in the
|
|
Packit |
517ee8 |
debug log, but the oval_fts api has no way of passing this
|
|
Packit |
517ee8 |
information to the user.
|
|
Packit |
517ee8 |
*/
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
if (path_op == OVAL_OPERATION_EQUALS) {
|
|
Packit |
517ee8 |
paths[0] = strdup(cstr_path);
|
|
Packit |
517ee8 |
} else if (path_op == OVAL_OPERATION_PATTERN_MATCH) {
|
|
Packit |
517ee8 |
if (process_pattern_match(cstr_path, ®ex) != 0)
|
|
Packit |
517ee8 |
return NULL;
|
|
Packit |
517ee8 |
paths[0] = extract_fixed_path_prefix(cstr_path);
|
|
Packit |
517ee8 |
dD("Extracted fixed path: '%s'.", paths[0]);
|
|
Packit |
517ee8 |
} else {
|
|
Packit |
517ee8 |
paths[0] = strdup("/");
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
if (prefix != NULL) {
|
|
Packit |
517ee8 |
char *path_with_prefix = oscap_path_join(prefix, paths[0]);
|
|
Packit |
517ee8 |
free((void *) paths[0]);
|
|
Packit |
517ee8 |
paths[0] = path_with_prefix;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
dI("Opening file '%s'.", paths[0]);
|
|
Packit |
517ee8 |
/* Fail if the provided path doensn't actually exist. Symlinks
|
|
Packit |
517ee8 |
without targets are accepted. */
|
|
Packit |
517ee8 |
if (lstat(paths[0], &st) == -1) {
|
|
Packit |
517ee8 |
if (errno) {
|
|
Packit |
517ee8 |
dD("lstat() failed: errno: %d, '%s'.",
|
|
Packit |
517ee8 |
errno, strerror(errno));
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
free((void *) paths[0]);
|
|
Packit |
517ee8 |
return NULL;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
ofts = OVAL_FTS_new();
|
|
Packit |
517ee8 |
ofts->prefix = prefix;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
/* reset errno as fts_open() doesn't do it itself. */
|
|
Packit |
517ee8 |
errno = 0;
|
|
Packit |
517ee8 |
ofts->ofts_match_path_fts = fts_open((char * const *) paths, mtc_fts_options, NULL);
|
|
Packit |
517ee8 |
free((void *) paths[0]);
|
|
Packit |
517ee8 |
/* fts_open() doesn't return NULL for all errors (e.g. nonexistent paths),
|
|
Packit |
517ee8 |
so check errno to detect it. Far from being perfect. */
|
|
Packit |
517ee8 |
if (ofts->ofts_match_path_fts == NULL || errno != 0) {
|
|
Packit |
517ee8 |
dE("fts_open() failed, errno: %d \"%s\".", errno, strerror(errno));
|
|
Packit |
517ee8 |
OVAL_FTS_free(ofts);
|
|
Packit |
517ee8 |
return (NULL);
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
ofts->ofts_recurse_path_fts_opts = rec_fts_options;
|
|
Packit |
517ee8 |
ofts->ofts_path_op = path_op;
|
|
Packit |
517ee8 |
if (regex != NULL) {
|
|
Packit |
517ee8 |
const char *errptr = NULL;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
ofts->ofts_path_regex = regex;
|
|
Packit |
517ee8 |
ofts->ofts_path_regex_extra = pcre_study(regex, 0, &errptr);
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
if (filesystem == OVAL_RECURSE_FS_LOCAL) {
|
|
Packit |
517ee8 |
#if defined(OS_SOLARIS)
|
|
Packit |
517ee8 |
ofts->localdevs = NULL;
|
|
Packit |
517ee8 |
#else
|
|
Packit |
517ee8 |
ofts->localdevs = fsdev_init();
|
|
Packit |
517ee8 |
if (ofts->localdevs == NULL) {
|
|
Packit |
517ee8 |
dE("fsdev_init() failed.");
|
|
Packit |
517ee8 |
/* One dummy read to get rid of an uninitialized
|
|
Packit |
517ee8 |
* value in the FTS data before calling
|
|
Packit |
517ee8 |
* fts_close() on it. */
|
|
Packit |
517ee8 |
fts_read(ofts->ofts_match_path_fts);
|
|
Packit |
517ee8 |
oval_fts_close(ofts);
|
|
Packit |
517ee8 |
return (NULL);
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
#endif
|
|
Packit |
517ee8 |
} else if (filesystem == OVAL_RECURSE_FS_DEFINED) {
|
|
Packit |
517ee8 |
/* store the device id for future comparison */
|
|
Packit |
517ee8 |
FTSENT *fts_ent;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
fts_ent = fts_read(ofts->ofts_match_path_fts);
|
|
Packit |
517ee8 |
if (fts_ent != NULL) {
|
|
Packit |
517ee8 |
ofts->ofts_recurse_path_devid = fts_ent->fts_statp->st_dev;
|
|
Packit |
517ee8 |
fts_set(ofts->ofts_match_path_fts, fts_ent, FTS_AGAIN);
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
ofts->recurse = recurse;
|
|
Packit |
517ee8 |
ofts->filesystem = filesystem;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
if (path) { /* filepath == NULL */
|
|
Packit |
517ee8 |
ofts->ofts_spath = SEXP_ref(path); /* path entity */
|
|
Packit |
517ee8 |
if (!nilfilename)
|
|
Packit |
517ee8 |
ofts->ofts_sfilename = SEXP_ref(filename); /* filename entity */
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
ofts->max_depth = max_depth;
|
|
Packit |
517ee8 |
ofts->direction = direction;
|
|
Packit |
517ee8 |
} else { /* filepath != NULL */
|
|
Packit |
517ee8 |
ofts->ofts_sfilepath = SEXP_ref(filepath);
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
#if defined(OS_SOLARIS)
|
|
Packit |
517ee8 |
if (load_zones_path_list() != 0) {
|
|
Packit |
517ee8 |
dE("Failed to load zones path info. Recursing non-global zones.");
|
|
Packit |
517ee8 |
free_zones_path_list();
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
#endif
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
ofts->result = result;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
return (ofts);
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
static inline int _oval_fts_is_local(OVAL_FTS *ofts, FTSENT *fts_ent) {
|
|
Packit |
517ee8 |
# if defined(OS_SOLARIS)
|
|
Packit |
517ee8 |
/* pseudo filesystems will be skipped */
|
|
Packit |
517ee8 |
/* don't recurse into remote fs if local is specified */
|
|
Packit |
517ee8 |
return ((fts_ent->fts_info == FTS_D || fts_ent->fts_info == FTS_SL)
|
|
Packit |
517ee8 |
&& (!OVAL_FTS_localp(ofts, fts_ent->fts_path,
|
|
Packit |
517ee8 |
(fts_ent->fts_statp != NULL) ?
|
|
Packit |
517ee8 |
&fts_ent->fts_statp->st_fstype : NULL)));
|
|
Packit |
517ee8 |
#else
|
|
Packit |
517ee8 |
/* don't recurse into non-local filesystems */
|
|
Packit |
517ee8 |
return (ofts->filesystem == OVAL_RECURSE_FS_LOCAL
|
|
Packit |
517ee8 |
&& (fts_ent->fts_info == FTS_D || fts_ent->fts_info == FTS_SL)
|
|
Packit |
517ee8 |
&& (!OVAL_FTS_localp(ofts, fts_ent->fts_path,
|
|
Packit |
517ee8 |
(fts_ent->fts_statp != NULL) ?
|
|
Packit |
517ee8 |
&fts_ent->fts_statp->st_dev : NULL)));
|
|
Packit |
517ee8 |
#endif
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
/* find the first matching path or filepath */
|
|
Packit |
517ee8 |
static FTSENT *oval_fts_read_match_path(OVAL_FTS *ofts)
|
|
Packit |
517ee8 |
{
|
|
Packit |
517ee8 |
FTSENT *fts_ent = NULL;
|
|
Packit |
517ee8 |
SEXP_t *stmp;
|
|
Packit |
517ee8 |
oval_result_t ores;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
/* iterate until a match is found or all elements have been traversed */
|
|
Packit |
517ee8 |
for (;;) {
|
|
Packit |
517ee8 |
fts_ent = fts_read(ofts->ofts_match_path_fts);
|
|
Packit |
517ee8 |
if (fts_ent == NULL)
|
|
Packit |
517ee8 |
return NULL;
|
|
Packit |
517ee8 |
switch (fts_ent->fts_info) {
|
|
Packit |
517ee8 |
case FTS_DP:
|
|
Packit |
517ee8 |
continue;
|
|
Packit |
517ee8 |
case FTS_DC:
|
|
Packit |
517ee8 |
dW("Filesystem tree cycle detected at '%s'.", fts_ent->fts_path);
|
|
Packit |
517ee8 |
fts_set(ofts->ofts_match_path_fts, fts_ent, FTS_SKIP);
|
|
Packit |
517ee8 |
continue;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
#if defined(OSCAP_FTS_DEBUG)
|
|
Packit |
517ee8 |
dD("fts_path: '%s' (l=%d)."
|
|
Packit |
517ee8 |
"fts_name: '%s' (l=%d).\n"
|
|
Packit |
517ee8 |
"fts_info: %u.\n", fts_ent->fts_path, fts_ent->fts_pathlen,
|
|
Packit |
517ee8 |
fts_ent->fts_name, fts_ent->fts_namelen, fts_ent->fts_info);
|
|
Packit |
517ee8 |
#endif
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
if (fts_ent->fts_info == FTS_SL) {
|
|
Packit |
517ee8 |
#if defined(OSCAP_FTS_DEBUG)
|
|
Packit |
517ee8 |
dD("Only the target of a symlink gets reported, skipping '%s'.", fts_ent->fts_path, fts_ent->fts_name);
|
|
Packit |
517ee8 |
#endif
|
|
Packit |
517ee8 |
fts_set(ofts->ofts_match_path_fts, fts_ent, FTS_FOLLOW);
|
|
Packit |
517ee8 |
continue;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
if (_oval_fts_is_local(ofts, fts_ent)) {
|
|
Packit |
517ee8 |
dI("Don't recurse into non-local filesystems, skipping '%s'.", fts_ent->fts_path);
|
|
Packit |
517ee8 |
fts_set(ofts->ofts_recurse_path_fts, fts_ent, FTS_SKIP);
|
|
Packit |
517ee8 |
continue;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
/* don't recurse beyond the initial filesystem */
|
|
Packit |
517ee8 |
if (ofts->filesystem == OVAL_RECURSE_FS_DEFINED
|
|
Packit |
517ee8 |
&& (fts_ent->fts_info == FTS_D || fts_ent->fts_info == FTS_SL)
|
|
Packit |
517ee8 |
&& ofts->ofts_recurse_path_devid != fts_ent->fts_statp->st_dev) {
|
|
Packit |
517ee8 |
fts_set(ofts->ofts_recurse_path_fts, fts_ent, FTS_SKIP);
|
|
Packit |
517ee8 |
continue;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
const size_t shift = ofts->prefix ? strlen(ofts->prefix) : 0;
|
|
Packit |
517ee8 |
/* partial match optimization for OVAL_OPERATION_PATTERN_MATCH operation on path and filepath */
|
|
Packit |
517ee8 |
if (ofts->ofts_path_regex != NULL && fts_ent->fts_info == FTS_D) {
|
|
Packit |
517ee8 |
int ret, svec[3];
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
ret = pcre_exec(ofts->ofts_path_regex, ofts->ofts_path_regex_extra,
|
|
Packit |
517ee8 |
fts_ent->fts_path+shift, fts_ent->fts_pathlen-shift, 0, PCRE_PARTIAL,
|
|
Packit |
517ee8 |
svec, sizeof(svec) / sizeof(svec[0]));
|
|
Packit |
517ee8 |
if (ret < 0) {
|
|
Packit |
517ee8 |
switch (ret) {
|
|
Packit |
517ee8 |
case PCRE_ERROR_NOMATCH:
|
|
Packit |
517ee8 |
dD("Partial match optimization: PCRE_ERROR_NOMATCH, skipping.");
|
|
Packit |
517ee8 |
fts_set(ofts->ofts_match_path_fts, fts_ent, FTS_SKIP);
|
|
Packit |
517ee8 |
continue;
|
|
Packit |
517ee8 |
case PCRE_ERROR_PARTIAL:
|
|
Packit |
517ee8 |
dD("Partial match optimization: PCRE_ERROR_PARTIAL, continuing.");
|
|
Packit |
517ee8 |
continue;
|
|
Packit |
517ee8 |
default:
|
|
Packit |
517ee8 |
dE("pcre_exec() error: %d.", ret);
|
|
Packit |
517ee8 |
return NULL;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
if ((ofts->ofts_sfilepath && fts_ent->fts_info == FTS_D)
|
|
Packit |
517ee8 |
|| (!ofts->ofts_sfilepath && fts_ent->fts_info != FTS_D))
|
|
Packit |
517ee8 |
continue;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
stmp = SEXP_string_newf("%s", fts_ent->fts_path + shift);
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
if (ofts->ofts_sfilepath)
|
|
Packit |
517ee8 |
/* try to match filepath */
|
|
Packit |
517ee8 |
ores = probe_entobj_cmp(ofts->ofts_sfilepath, stmp);
|
|
Packit |
517ee8 |
else
|
|
Packit |
517ee8 |
/* try to match path */
|
|
Packit |
517ee8 |
ores = probe_entobj_cmp(ofts->ofts_spath, stmp);
|
|
Packit |
517ee8 |
SEXP_free(stmp);
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
if (ores == OVAL_RESULT_TRUE)
|
|
Packit |
517ee8 |
break;
|
|
Packit |
132cab |
if (ofts->ofts_path_op == OVAL_OPERATION_EQUALS) {
|
|
Packit |
132cab |
/* At this point the comparison result isn't OVAL_RESULT_TRUE. Since
|
|
Packit |
132cab |
we passed the exact path (from filepath or path elements) to
|
|
Packit |
132cab |
fts_open() we surely know that we can't find other items that would
|
|
Packit |
132cab |
be equal. Therefore we can terminate the matching. This can happen
|
|
Packit |
132cab |
if the filepath or path element references a variable that has
|
|
Packit |
132cab |
multiple different values. */
|
|
Packit |
132cab |
return NULL;
|
|
Packit |
132cab |
}
|
|
Packit |
517ee8 |
} /* for (;;) */
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
/*
|
|
Packit |
517ee8 |
* If we know that we are not going to return anything
|
|
Packit |
517ee8 |
* else, then we can close the path FTS and return NULL
|
|
Packit |
517ee8 |
* the next time...
|
|
Packit |
517ee8 |
*/
|
|
Packit |
517ee8 |
if (ofts->ofts_path_op == OVAL_OPERATION_EQUALS &&
|
|
Packit |
517ee8 |
ofts->direction == OVAL_RECURSE_DIRECTION_NONE &&
|
|
Packit |
517ee8 |
ofts->ofts_sfilename == NULL &&
|
|
Packit |
517ee8 |
ofts->ofts_sfilepath == NULL)
|
|
Packit |
517ee8 |
{
|
|
Packit |
517ee8 |
fts_set(ofts->ofts_match_path_fts, fts_ent, FTS_SKIP);
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
return fts_ent;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
/* find the first matching file or directory */
|
|
Packit |
517ee8 |
static FTSENT *oval_fts_read_recurse_path(OVAL_FTS *ofts)
|
|
Packit |
517ee8 |
{
|
|
Packit |
517ee8 |
FTSENT *out_fts_ent = NULL;
|
|
Packit |
517ee8 |
/* the condition below is correct because ofts_sfilepath is NULL here */
|
|
Packit |
517ee8 |
bool collect_dirs = (ofts->ofts_sfilename == NULL);
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
switch (ofts->direction) {
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
case OVAL_RECURSE_DIRECTION_DOWN:
|
|
Packit |
517ee8 |
case OVAL_RECURSE_DIRECTION_NONE:
|
|
Packit |
517ee8 |
if (ofts->direction == OVAL_RECURSE_DIRECTION_NONE
|
|
Packit |
517ee8 |
&& collect_dirs) {
|
|
Packit |
517ee8 |
/* the target is the directory itself */
|
|
Packit |
517ee8 |
out_fts_ent = ofts->ofts_match_path_fts_ent;
|
|
Packit |
517ee8 |
ofts->ofts_match_path_fts_ent = NULL;
|
|
Packit |
517ee8 |
break;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
/* initialize separate fts for recursion */
|
|
Packit |
517ee8 |
if (ofts->ofts_recurse_path_fts == NULL) {
|
|
Packit |
517ee8 |
char * const paths[2] = { ofts->ofts_match_path_fts_ent->fts_path, NULL };
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
#if defined(OSCAP_FTS_DEBUG)
|
|
Packit |
517ee8 |
dD("fts_open args: path: \"%s\", options: %d.",
|
|
Packit |
517ee8 |
paths[0], ofts->ofts_recurse_path_fts_opts);
|
|
Packit |
517ee8 |
#endif
|
|
Packit |
517ee8 |
/* reset errno as fts_open() doesn't do it itself. */
|
|
Packit |
517ee8 |
errno = 0;
|
|
Packit |
517ee8 |
ofts->ofts_recurse_path_fts = fts_open(paths,
|
|
Packit |
517ee8 |
ofts->ofts_recurse_path_fts_opts, NULL);
|
|
Packit |
517ee8 |
/* fts_open() doesn't return NULL for all errors
|
|
Packit |
517ee8 |
(e.g. nonexistent paths), so check errno to detect it.
|
|
Packit |
517ee8 |
Far from being perfect. */
|
|
Packit |
517ee8 |
if (ofts->ofts_recurse_path_fts == NULL || errno != 0) {
|
|
Packit |
517ee8 |
dE("fts_open() failed, errno: %d \"%s\".",
|
|
Packit |
517ee8 |
errno, strerror(errno));
|
|
Packit |
517ee8 |
#if !defined(OSCAP_FTS_DEBUG)
|
|
Packit |
517ee8 |
dE("fts_open args: path: \"%s\", options: %d.",
|
|
Packit |
517ee8 |
paths[0], ofts->ofts_recurse_path_fts_opts);
|
|
Packit |
517ee8 |
#endif
|
|
Packit |
517ee8 |
if (ofts->ofts_recurse_path_fts != NULL) {
|
|
Packit |
517ee8 |
fts_close(ofts->ofts_recurse_path_fts);
|
|
Packit |
517ee8 |
ofts->ofts_recurse_path_fts = NULL;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
return (NULL);
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
/* iterate until a match is found or all elements have been traversed */
|
|
Packit |
517ee8 |
while (out_fts_ent == NULL) {
|
|
Packit |
517ee8 |
FTSENT *fts_ent;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
fts_ent = fts_read(ofts->ofts_recurse_path_fts);
|
|
Packit |
517ee8 |
if (fts_ent == NULL) {
|
|
Packit |
517ee8 |
fts_close(ofts->ofts_recurse_path_fts);
|
|
Packit |
517ee8 |
ofts->ofts_recurse_path_fts = NULL;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
return NULL;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
switch (fts_ent->fts_info) {
|
|
Packit |
517ee8 |
case FTS_DP:
|
|
Packit |
517ee8 |
continue;
|
|
Packit |
517ee8 |
case FTS_DC:
|
|
Packit |
517ee8 |
dW("Filesystem tree cycle detected at '%s'.", fts_ent->fts_path);
|
|
Packit |
517ee8 |
fts_set(ofts->ofts_recurse_path_fts, fts_ent, FTS_SKIP);
|
|
Packit |
517ee8 |
continue;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
#if defined(OSCAP_FTS_DEBUG)
|
|
Packit |
517ee8 |
dD("fts_path: '%s' (l=%d)."
|
|
Packit |
517ee8 |
"fts_name: '%s' (l=%d).\n"
|
|
Packit |
517ee8 |
"fts_info: %u.\n", fts_ent->fts_path, fts_ent->fts_pathlen,
|
|
Packit |
517ee8 |
fts_ent->fts_name, fts_ent->fts_namelen, fts_ent->fts_info);
|
|
Packit |
517ee8 |
#endif
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
/* collect matching target */
|
|
Packit |
517ee8 |
if (collect_dirs) {
|
|
Packit |
517ee8 |
if (fts_ent->fts_info == FTS_D
|
|
Packit |
517ee8 |
&& (ofts->max_depth == -1 || fts_ent->fts_level <= ofts->max_depth))
|
|
Packit |
517ee8 |
out_fts_ent = fts_ent;
|
|
Packit |
517ee8 |
} else {
|
|
Packit |
517ee8 |
if (fts_ent->fts_info != FTS_D) {
|
|
Packit |
517ee8 |
SEXP_t *stmp;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
stmp = SEXP_string_newf("%s", fts_ent->fts_name);
|
|
Packit |
517ee8 |
oval_result_t result = probe_entobj_cmp(ofts->ofts_sfilename, stmp);
|
|
Packit |
517ee8 |
switch (result){
|
|
Packit |
517ee8 |
case OVAL_RESULT_TRUE:
|
|
Packit |
517ee8 |
out_fts_ent = fts_ent;
|
|
Packit |
517ee8 |
break;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
case OVAL_RESULT_ERROR:
|
|
Packit |
517ee8 |
probe_cobj_set_flag(ofts->result, SYSCHAR_FLAG_ERROR);
|
|
Packit |
517ee8 |
break;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
default:
|
|
Packit |
517ee8 |
break;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
SEXP_free(stmp);
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
if (fts_ent->fts_level > 0) { /* don't skip fts root */
|
|
Packit |
517ee8 |
/* limit recursion depth */
|
|
Packit |
517ee8 |
if (ofts->direction == OVAL_RECURSE_DIRECTION_NONE
|
|
Packit |
517ee8 |
|| (ofts->max_depth != -1 && fts_ent->fts_level > ofts->max_depth)) {
|
|
Packit |
517ee8 |
fts_set(ofts->ofts_recurse_path_fts, fts_ent, FTS_SKIP);
|
|
Packit |
517ee8 |
continue;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
/* limit recursion only to selected file types */
|
|
Packit |
517ee8 |
switch (fts_ent->fts_info) {
|
|
Packit |
517ee8 |
case FTS_D:
|
|
Packit |
517ee8 |
if (!(ofts->recurse & OVAL_RECURSE_DIRS)) {
|
|
Packit |
517ee8 |
fts_set(ofts->ofts_recurse_path_fts, fts_ent, FTS_SKIP);
|
|
Packit |
517ee8 |
continue;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
break;
|
|
Packit |
517ee8 |
case FTS_SL:
|
|
Packit |
517ee8 |
if (!(ofts->recurse & OVAL_RECURSE_SYMLINKS)) {
|
|
Packit |
517ee8 |
fts_set(ofts->ofts_recurse_path_fts, fts_ent, FTS_SKIP);
|
|
Packit |
517ee8 |
continue;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
fts_set(ofts->ofts_recurse_path_fts, fts_ent, FTS_FOLLOW);
|
|
Packit |
517ee8 |
break;
|
|
Packit |
517ee8 |
default:
|
|
Packit |
517ee8 |
continue;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
if (_oval_fts_is_local(ofts, fts_ent)) {
|
|
Packit |
517ee8 |
fts_set(ofts->ofts_recurse_path_fts, fts_ent, FTS_SKIP);
|
|
Packit |
517ee8 |
continue;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
/* don't recurse beyond the initial filesystem */
|
|
Packit |
517ee8 |
if (ofts->filesystem == OVAL_RECURSE_FS_DEFINED
|
|
Packit |
517ee8 |
&& (fts_ent->fts_info == FTS_D || fts_ent->fts_info == FTS_SL)
|
|
Packit |
517ee8 |
&& ofts->ofts_recurse_path_devid != fts_ent->fts_statp->st_dev) {
|
|
Packit |
517ee8 |
fts_set(ofts->ofts_recurse_path_fts, fts_ent, FTS_SKIP);
|
|
Packit |
517ee8 |
continue;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
break;
|
|
Packit |
517ee8 |
case OVAL_RECURSE_DIRECTION_UP:
|
|
Packit |
517ee8 |
if (ofts->ofts_recurse_path_pthcpy == NULL) {
|
|
Packit |
517ee8 |
ofts->ofts_recurse_path_pthcpy = \
|
|
Packit |
517ee8 |
ofts->ofts_recurse_path_curpth = strdup(ofts->ofts_match_path_fts_ent->fts_path);
|
|
Packit |
517ee8 |
ofts->ofts_recurse_path_curdepth = 0;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
while (ofts->max_depth == -1 || ofts->ofts_recurse_path_curdepth <= ofts->max_depth) {
|
|
Packit |
517ee8 |
/* initialize separate fts for recursion */
|
|
Packit |
517ee8 |
if (ofts->ofts_recurse_path_fts == NULL) {
|
|
Packit |
517ee8 |
char * const paths[2] = { ofts->ofts_recurse_path_curpth, NULL };
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
#if defined(OSCAP_FTS_DEBUG)
|
|
Packit |
517ee8 |
dD("fts_open args: path: \"%s\", options: %d.",
|
|
Packit |
517ee8 |
paths[0], ofts->ofts_recurse_path_fts_opts);
|
|
Packit |
517ee8 |
#endif
|
|
Packit |
517ee8 |
/* reset errno as fts_open() doesn't do it itself. */
|
|
Packit |
517ee8 |
errno = 0;
|
|
Packit |
517ee8 |
/* fts_open() doesn't return NULL for all errors
|
|
Packit |
517ee8 |
(e.g. nonexistent paths), so check errno to
|
|
Packit |
517ee8 |
detect it. Far from being perfect. */
|
|
Packit |
517ee8 |
ofts->ofts_recurse_path_fts = fts_open(paths,
|
|
Packit |
517ee8 |
ofts->ofts_recurse_path_fts_opts, NULL);
|
|
Packit |
517ee8 |
if (ofts->ofts_recurse_path_fts == NULL || errno != 0) {
|
|
Packit |
517ee8 |
dE("fts_open() failed, errno: %d \"%s\".",
|
|
Packit |
517ee8 |
errno, strerror(errno));
|
|
Packit |
517ee8 |
#if !defined(OSCAP_FTS_DEBUG)
|
|
Packit |
517ee8 |
dE("fts_open args: path: \"%s\", options: %d.",
|
|
Packit |
517ee8 |
paths[0], ofts->ofts_recurse_path_fts_opts);
|
|
Packit |
517ee8 |
#endif
|
|
Packit |
517ee8 |
if (ofts->ofts_recurse_path_fts != NULL) {
|
|
Packit |
517ee8 |
fts_close(ofts->ofts_recurse_path_fts);
|
|
Packit |
517ee8 |
ofts->ofts_recurse_path_fts = NULL;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
return (NULL);
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
/* iterate until a match is found or all elements have been traversed */
|
|
Packit |
517ee8 |
while (out_fts_ent == NULL) {
|
|
Packit |
517ee8 |
FTSENT *fts_ent;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
fts_ent = fts_read(ofts->ofts_recurse_path_fts);
|
|
Packit |
517ee8 |
if (fts_ent == NULL)
|
|
Packit |
517ee8 |
break;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
/*
|
|
Packit |
517ee8 |
it would be more accurate to obtain the device
|
|
Packit |
517ee8 |
id here, but for the sake of supporting the
|
|
Packit |
517ee8 |
comparison also in oval_fts_read_match_path(),
|
|
Packit |
517ee8 |
the device id is obtained in oval_fts_open_prefixed()
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
if (ofts->ofts_recurse_path_curdepth == 0)
|
|
Packit |
517ee8 |
ofts->ofts_recurse_path_devid = fts_ent->fts_statp->st_dev;
|
|
Packit |
517ee8 |
*/
|
|
Packit |
517ee8 |
#if defined(OS_SOLARIS)
|
|
Packit |
517ee8 |
if ((!OVAL_FTS_localp(ofts, fts_ent->fts_path,
|
|
Packit |
517ee8 |
(fts_ent->fts_statp != NULL) ?
|
|
Packit |
517ee8 |
&fts_ent->fts_statp->st_fstype : NULL)))
|
|
Packit |
517ee8 |
break;
|
|
Packit |
517ee8 |
#else
|
|
Packit |
517ee8 |
if (ofts->filesystem == OVAL_RECURSE_FS_LOCAL
|
|
Packit |
517ee8 |
&& (!OVAL_FTS_localp(ofts, fts_ent->fts_path,
|
|
Packit |
517ee8 |
(fts_ent->fts_statp != NULL) ?
|
|
Packit |
517ee8 |
&fts_ent->fts_statp->st_dev : NULL)))
|
|
Packit |
517ee8 |
break;
|
|
Packit |
517ee8 |
#endif
|
|
Packit |
517ee8 |
if (ofts->filesystem == OVAL_RECURSE_FS_DEFINED
|
|
Packit |
517ee8 |
&& ofts->ofts_recurse_path_devid != fts_ent->fts_statp->st_dev)
|
|
Packit |
517ee8 |
break;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
/* collect matching target */
|
|
Packit |
517ee8 |
if (collect_dirs) {
|
|
Packit |
517ee8 |
/* only fts root is collected */
|
|
Packit |
517ee8 |
if (fts_ent->fts_level == 0 && fts_ent->fts_info == FTS_D) {
|
|
Packit |
517ee8 |
out_fts_ent = fts_ent;
|
|
Packit |
517ee8 |
fts_set(ofts->ofts_recurse_path_fts, fts_ent, FTS_SKIP);
|
|
Packit |
517ee8 |
break;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
} else {
|
|
Packit |
517ee8 |
if (fts_ent->fts_info != FTS_D) {
|
|
Packit |
517ee8 |
SEXP_t *stmp;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
stmp = SEXP_string_newf("%s", fts_ent->fts_name);
|
|
Packit |
517ee8 |
if (probe_entobj_cmp(ofts->ofts_sfilename, stmp) == OVAL_RESULT_TRUE)
|
|
Packit |
517ee8 |
out_fts_ent = fts_ent;
|
|
Packit |
517ee8 |
SEXP_free(stmp);
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
if (fts_ent->fts_info == FTS_SL)
|
|
Packit |
517ee8 |
fts_set(ofts->ofts_recurse_path_fts, fts_ent, FTS_FOLLOW);
|
|
Packit |
517ee8 |
/* limit recursion only to fts root */
|
|
Packit |
517ee8 |
else if (fts_ent->fts_level > 0)
|
|
Packit |
517ee8 |
fts_set(ofts->ofts_recurse_path_fts, fts_ent, FTS_SKIP);
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
if (out_fts_ent != NULL)
|
|
Packit |
517ee8 |
break;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
fts_close(ofts->ofts_recurse_path_fts);
|
|
Packit |
517ee8 |
ofts->ofts_recurse_path_fts = NULL;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
if (!strcmp(ofts->ofts_recurse_path_curpth, "/"))
|
|
Packit |
517ee8 |
break;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
ofts->ofts_recurse_path_curpth = oscap_dirname(ofts->ofts_recurse_path_curpth);
|
|
Packit |
517ee8 |
ofts->ofts_recurse_path_curdepth++;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
if (out_fts_ent == NULL) {
|
|
Packit |
517ee8 |
free(ofts->ofts_recurse_path_pthcpy);
|
|
Packit |
517ee8 |
ofts->ofts_recurse_path_pthcpy = NULL;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
break;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
return out_fts_ent;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
OVAL_FTSENT *oval_fts_read(OVAL_FTS *ofts)
|
|
Packit |
517ee8 |
{
|
|
Packit |
517ee8 |
FTSENT *fts_ent;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
#if defined(OSCAP_FTS_DEBUG)
|
|
Packit |
517ee8 |
dD("ofts: %p.", ofts);
|
|
Packit |
517ee8 |
#endif
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
if (ofts == NULL)
|
|
Packit |
517ee8 |
return NULL;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
for (;;) {
|
|
Packit |
517ee8 |
if (ofts->ofts_match_path_fts_ent == NULL) {
|
|
Packit |
517ee8 |
ofts->ofts_match_path_fts_ent = oval_fts_read_match_path(ofts);
|
|
Packit |
517ee8 |
if (ofts->ofts_match_path_fts_ent == NULL)
|
|
Packit |
517ee8 |
return NULL;
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
if (ofts->ofts_sfilepath) {
|
|
Packit |
517ee8 |
fts_ent = ofts->ofts_match_path_fts_ent;
|
|
Packit |
517ee8 |
ofts->ofts_match_path_fts_ent = NULL;
|
|
Packit |
517ee8 |
break;
|
|
Packit |
517ee8 |
} else {
|
|
Packit |
517ee8 |
fts_ent = oval_fts_read_recurse_path(ofts);
|
|
Packit |
517ee8 |
if (fts_ent != NULL)
|
|
Packit |
517ee8 |
break;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
ofts->ofts_match_path_fts_ent = NULL;
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
// todo: is this true when variables are used?
|
|
Packit |
517ee8 |
/* with 'equals', there's only one potential target */
|
|
Packit |
517ee8 |
if (ofts->ofts_path_op == OVAL_OPERATION_EQUALS)
|
|
Packit |
517ee8 |
return (NULL);
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
return OVAL_FTSENT_new(ofts, fts_ent);
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
void oval_ftsent_free(OVAL_FTSENT *ofts_ent)
|
|
Packit |
517ee8 |
{
|
|
Packit |
517ee8 |
OVAL_FTSENT_free(ofts_ent);
|
|
Packit |
517ee8 |
}
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
int oval_fts_close(OVAL_FTS *ofts)
|
|
Packit |
517ee8 |
{
|
|
Packit |
517ee8 |
if (ofts->ofts_recurse_path_pthcpy != NULL)
|
|
Packit |
517ee8 |
free(ofts->ofts_recurse_path_pthcpy);
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
if (ofts->ofts_path_regex)
|
|
Packit |
517ee8 |
pcre_free(ofts->ofts_path_regex);
|
|
Packit |
517ee8 |
if (ofts->ofts_path_regex_extra)
|
|
Packit |
517ee8 |
pcre_free(ofts->ofts_path_regex_extra);
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
if (ofts->ofts_spath != NULL)
|
|
Packit |
517ee8 |
SEXP_free(ofts->ofts_spath);
|
|
Packit |
517ee8 |
if (ofts->ofts_sfilename != NULL)
|
|
Packit |
517ee8 |
SEXP_free(ofts->ofts_sfilename);
|
|
Packit |
517ee8 |
if (ofts->ofts_sfilepath != NULL)
|
|
Packit |
517ee8 |
SEXP_free(ofts->ofts_sfilepath);
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
fsdev_free(ofts->localdevs);
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
OVAL_FTS_free(ofts);
|
|
Packit |
517ee8 |
#if defined(OS_SOLARIS)
|
|
Packit |
517ee8 |
free_zones_path_list();
|
|
Packit |
517ee8 |
#endif
|
|
Packit |
517ee8 |
|
|
Packit |
517ee8 |
return (0);
|
|
Packit |
517ee8 |
}
|