|
Chris PeBenito |
473ea7 |
#include <unistd.h>
|
|
Chris PeBenito |
473ea7 |
#include <fcntl.h>
|
|
Chris PeBenito |
473ea7 |
#include <sys/stat.h>
|
|
Chris PeBenito |
473ea7 |
#include <string.h>
|
|
Chris PeBenito |
473ea7 |
#include "selinux_internal.h"
|
|
Chris PeBenito |
473ea7 |
#include <stdio.h>
|
|
Chris PeBenito |
473ea7 |
#include <stdio_ext.h>
|
|
Chris PeBenito |
473ea7 |
#include <stdlib.h>
|
|
Chris PeBenito |
473ea7 |
#include <ctype.h>
|
|
Chris PeBenito |
473ea7 |
#include <errno.h>
|
|
Chris PeBenito |
473ea7 |
#include <limits.h>
|
|
Chris PeBenito |
473ea7 |
#include <regex.h>
|
|
Chris PeBenito |
473ea7 |
#include <stdarg.h>
|
|
Chris PeBenito |
473ea7 |
#include "policy.h"
|
|
Chris PeBenito |
473ea7 |
#include "context_internal.h"
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
static void
|
|
Chris PeBenito |
473ea7 |
#ifdef __GNUC__
|
|
Chris PeBenito |
473ea7 |
__attribute__ ((format (printf, 1, 2)))
|
|
Chris PeBenito |
473ea7 |
#endif
|
|
Chris PeBenito |
473ea7 |
default_printf(const char *fmt, ...)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
va_list ap;
|
|
Chris PeBenito |
473ea7 |
va_start(ap, fmt);
|
|
Chris PeBenito |
473ea7 |
vfprintf(stderr, fmt, ap);
|
|
Chris PeBenito |
473ea7 |
va_end(ap);
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
/* If MLS is disabled, strip any MLS level field from the context.
|
|
Chris PeBenito |
473ea7 |
This allows file_contexts with MLS levels to be processed on
|
|
Chris PeBenito |
473ea7 |
a non-MLS system that otherwise has the same policy. */
|
|
Chris PeBenito |
473ea7 |
static inline int STRIP_LEVEL(char **context, int mls_enabled)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
char *str;
|
|
Chris PeBenito |
473ea7 |
context_t con;
|
|
Chris PeBenito |
473ea7 |
int rc = -1;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
if (mls_enabled)
|
|
Chris PeBenito |
473ea7 |
return 0;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
con = context_new(*context);
|
|
Chris PeBenito |
473ea7 |
if (!con)
|
|
Chris PeBenito |
473ea7 |
return rc;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
if (context_range_set(con,NULL))
|
|
Chris PeBenito |
473ea7 |
goto out;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
str = context_str(con);
|
|
Chris PeBenito |
473ea7 |
if (!str)
|
|
Chris PeBenito |
473ea7 |
goto out;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
str = strdup(str);
|
|
Chris PeBenito |
473ea7 |
if (!str)
|
|
Chris PeBenito |
473ea7 |
goto out;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
free(*context);
|
|
Chris PeBenito |
473ea7 |
*context = str;
|
|
Chris PeBenito |
473ea7 |
rc = 0;
|
|
Chris PeBenito |
473ea7 |
out:
|
|
Chris PeBenito |
473ea7 |
context_free(con);
|
|
Chris PeBenito |
473ea7 |
return rc;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
static void (*myprintf)(const char *fmt, ...) = &default_printf;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
void set_matchpathcon_printf(void (*f)(const char *fmt, ...))
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
if (f)
|
|
Chris PeBenito |
473ea7 |
myprintf = f;
|
|
Chris PeBenito |
473ea7 |
else
|
|
Chris PeBenito |
473ea7 |
myprintf = &default_printf;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
static int default_invalidcon(const char *path, unsigned lineno, char *context)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
if (security_check_context(context) < 0 && errno != ENOENT) {
|
|
Chris PeBenito |
473ea7 |
myprintf("%s: line %u has invalid context %s\n", path, lineno, context);
|
|
Chris PeBenito |
473ea7 |
return 1;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
return 0;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
static int (*myinvalidcon)(const char *p, unsigned l, char *c) = &default_invalidcon;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
void set_matchpathcon_invalidcon(int (*f)(const char *p, unsigned l, char *c))
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
if (f)
|
|
Chris PeBenito |
473ea7 |
myinvalidcon = f;
|
|
Chris PeBenito |
473ea7 |
else
|
|
Chris PeBenito |
473ea7 |
myinvalidcon = &default_invalidcon;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
static unsigned int myflags;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
void set_matchpathcon_flags(unsigned int flags)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
myflags = flags;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
/*
|
|
Chris PeBenito |
473ea7 |
* A file security context specification.
|
|
Chris PeBenito |
473ea7 |
*/
|
|
Chris PeBenito |
473ea7 |
typedef struct spec {
|
|
Chris PeBenito |
473ea7 |
char *regex_str; /* regular expession string for diagnostic messages */
|
|
Chris PeBenito |
473ea7 |
char *type_str; /* type string for diagnostic messages */
|
|
Chris PeBenito |
473ea7 |
char *context; /* context string */
|
|
Chris PeBenito |
473ea7 |
regex_t regex; /* compiled regular expression */
|
|
Chris PeBenito |
473ea7 |
mode_t mode; /* mode format value */
|
|
Chris PeBenito |
473ea7 |
int matches; /* number of matching pathnames */
|
|
Chris PeBenito |
473ea7 |
int hasMetaChars; /* indicates whether the RE has
|
|
Chris PeBenito |
473ea7 |
any meta characters.
|
|
Chris PeBenito |
473ea7 |
0 = no meta chars
|
|
Chris PeBenito |
473ea7 |
1 = has one or more meta chars */
|
|
Chris PeBenito |
473ea7 |
int stem_id; /* indicates which of the stem-compression
|
|
Chris PeBenito |
473ea7 |
* items it matches */
|
|
Chris PeBenito |
473ea7 |
} spec_t;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
typedef struct stem {
|
|
Chris PeBenito |
473ea7 |
char *buf;
|
|
Chris PeBenito |
473ea7 |
int len;
|
|
Chris PeBenito |
473ea7 |
} stem_t;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
static stem_t *stem_arr = NULL;
|
|
Chris PeBenito |
473ea7 |
static int num_stems = 0;
|
|
Chris PeBenito |
473ea7 |
static int alloc_stems = 0;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
static const char * const regex_chars = ".^$?*+|[({";
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
/* Return the length of the text that can be considered the stem, returns 0
|
|
Chris PeBenito |
473ea7 |
* if there is no identifiable stem */
|
|
Chris PeBenito |
473ea7 |
static int get_stem_from_spec(const char * const buf)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
const char *tmp = strchr(buf + 1, '/');
|
|
Chris PeBenito |
473ea7 |
const char *ind;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
if(!tmp)
|
|
Chris PeBenito |
473ea7 |
return 0;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
for(ind = buf; ind < tmp; ind++)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
if(strchr(regex_chars, (int)*ind))
|
|
Chris PeBenito |
473ea7 |
return 0;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
return tmp - buf;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
/* return the length of the text that is the stem of a file name */
|
|
Chris PeBenito |
473ea7 |
static int get_stem_from_file_name(const char * const buf)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
const char *tmp = strchr(buf + 1, '/');
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
if(!tmp)
|
|
Chris PeBenito |
473ea7 |
return 0;
|
|
Chris PeBenito |
473ea7 |
return tmp - buf;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
/* find the stem of a file spec, returns the index into stem_arr for a new
|
|
Chris PeBenito |
473ea7 |
* or existing stem, (or -1 if there is no possible stem - IE for a file in
|
|
Chris PeBenito |
473ea7 |
* the root directory or a regex that is too complex for us). Makes buf
|
|
Chris PeBenito |
473ea7 |
* point to the text AFTER the stem. */
|
|
Chris PeBenito |
473ea7 |
static int find_stem_from_spec(const char **buf)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
int i;
|
|
Chris PeBenito |
473ea7 |
int stem_len = get_stem_from_spec(*buf);
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
if(!stem_len)
|
|
Chris PeBenito |
473ea7 |
return -1;
|
|
Chris PeBenito |
473ea7 |
for(i = 0; i < num_stems; i++)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
if(stem_len == stem_arr[i].len && !strncmp(*buf, stem_arr[i].buf, stem_len))
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
*buf += stem_len;
|
|
Chris PeBenito |
473ea7 |
return i;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
if(num_stems == alloc_stems)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
stem_t *tmp_arr;
|
|
Chris PeBenito |
473ea7 |
alloc_stems = alloc_stems * 2 + 16;
|
|
Chris PeBenito |
473ea7 |
tmp_arr = realloc(stem_arr, sizeof(stem_t) * alloc_stems);
|
|
Chris PeBenito |
473ea7 |
if(!tmp_arr)
|
|
Chris PeBenito |
473ea7 |
return -1;
|
|
Chris PeBenito |
473ea7 |
stem_arr = tmp_arr;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
stem_arr[num_stems].len = stem_len;
|
|
Chris PeBenito |
473ea7 |
stem_arr[num_stems].buf = malloc(stem_len + 1);
|
|
Chris PeBenito |
473ea7 |
if(!stem_arr[num_stems].buf)
|
|
Chris PeBenito |
473ea7 |
return -1;
|
|
Chris PeBenito |
473ea7 |
memcpy(stem_arr[num_stems].buf, *buf, stem_len);
|
|
Chris PeBenito |
473ea7 |
stem_arr[num_stems].buf[stem_len] = '\0';
|
|
Chris PeBenito |
473ea7 |
num_stems++;
|
|
Chris PeBenito |
473ea7 |
*buf += stem_len;
|
|
Chris PeBenito |
473ea7 |
return num_stems - 1;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
/* find the stem of a file name, returns the index into stem_arr (or -1 if
|
|
Chris PeBenito |
473ea7 |
* there is no match - IE for a file in the root directory or a regex that is
|
|
Chris PeBenito |
473ea7 |
* too complex for us). Makes buf point to the text AFTER the stem. */
|
|
Chris PeBenito |
473ea7 |
static int find_stem_from_file(const char **buf)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
int i;
|
|
Chris PeBenito |
473ea7 |
int stem_len = get_stem_from_file_name(*buf);
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
if(!stem_len)
|
|
Chris PeBenito |
473ea7 |
return -1;
|
|
Chris PeBenito |
473ea7 |
for(i = 0; i < num_stems; i++)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
if(stem_len == stem_arr[i].len && !strncmp(*buf, stem_arr[i].buf, stem_len))
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
*buf += stem_len;
|
|
Chris PeBenito |
473ea7 |
return i;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
return -1;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
/*
|
|
Chris PeBenito |
473ea7 |
* The array of specifications, initially in the
|
|
Chris PeBenito |
473ea7 |
* same order as in the specification file.
|
|
Chris PeBenito |
473ea7 |
* Sorting occurs based on hasMetaChars
|
|
Chris PeBenito |
473ea7 |
*/
|
|
Chris PeBenito |
473ea7 |
static spec_t *spec_arr;
|
|
Chris PeBenito |
473ea7 |
static unsigned int nspec;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
/*
|
|
Chris PeBenito |
473ea7 |
* An association between an inode and a
|
|
Chris PeBenito |
473ea7 |
* specification.
|
|
Chris PeBenito |
473ea7 |
*/
|
|
Chris PeBenito |
473ea7 |
typedef struct file_spec {
|
|
Chris PeBenito |
473ea7 |
ino_t ino; /* inode number */
|
|
Chris PeBenito |
473ea7 |
int specind; /* index of specification in spec */
|
|
Chris PeBenito |
473ea7 |
char *file; /* full pathname for diagnostic messages about conflicts */
|
|
Chris PeBenito |
473ea7 |
struct file_spec *next; /* next association in hash bucket chain */
|
|
Chris PeBenito |
473ea7 |
} file_spec_t;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
/*
|
|
Chris PeBenito |
473ea7 |
* The hash table of associations, hashed by inode number.
|
|
Chris PeBenito |
473ea7 |
* Chaining is used for collisions, with elements ordered
|
|
Chris PeBenito |
473ea7 |
* by inode number in each bucket. Each hash bucket has a dummy
|
|
Chris PeBenito |
473ea7 |
* header.
|
|
Chris PeBenito |
473ea7 |
*/
|
|
Chris PeBenito |
473ea7 |
#define HASH_BITS 16
|
|
Chris PeBenito |
473ea7 |
#define HASH_BUCKETS (1 << HASH_BITS)
|
|
Chris PeBenito |
473ea7 |
#define HASH_MASK (HASH_BUCKETS-1)
|
|
Chris PeBenito |
473ea7 |
static file_spec_t *fl_head;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
/*
|
|
Chris PeBenito |
473ea7 |
* Try to add an association between an inode and
|
|
Chris PeBenito |
473ea7 |
* a specification. If there is already an association
|
|
Chris PeBenito |
473ea7 |
* for the inode and it conflicts with this specification,
|
|
Chris PeBenito |
473ea7 |
* then use the specification that occurs later in the
|
|
Chris PeBenito |
473ea7 |
* specification array.
|
|
Chris PeBenito |
473ea7 |
*/
|
|
Chris PeBenito |
473ea7 |
int matchpathcon_filespec_add(ino_t ino, int specind, const char *file)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
file_spec_t *prevfl, *fl;
|
|
Chris PeBenito |
473ea7 |
int h, no_conflict, ret;
|
|
Chris PeBenito |
473ea7 |
struct stat sb;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
if (!fl_head) {
|
|
Chris PeBenito |
473ea7 |
fl_head = malloc(sizeof(file_spec_t)*HASH_BUCKETS);
|
|
Chris PeBenito |
473ea7 |
if (!fl_head)
|
|
Chris PeBenito |
473ea7 |
goto oom;
|
|
Chris PeBenito |
473ea7 |
memset(fl_head, 0, sizeof(file_spec_t)*HASH_BUCKETS);
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
h = (ino + (ino >> HASH_BITS)) & HASH_MASK;
|
|
Chris PeBenito |
473ea7 |
for (prevfl = &fl_head[h], fl = fl_head[h].next; fl;
|
|
Chris PeBenito |
473ea7 |
prevfl = fl, fl = fl->next) {
|
|
Chris PeBenito |
473ea7 |
if (ino == fl->ino) {
|
|
Chris PeBenito |
473ea7 |
ret = lstat(fl->file, &sb);
|
|
Chris PeBenito |
473ea7 |
if (ret < 0 || sb.st_ino != ino) {
|
|
Chris PeBenito |
473ea7 |
fl->specind = specind;
|
|
Chris PeBenito |
473ea7 |
free(fl->file);
|
|
Chris PeBenito |
473ea7 |
fl->file = malloc(strlen(file) + 1);
|
|
Chris PeBenito |
473ea7 |
if (!fl->file)
|
|
Chris PeBenito |
473ea7 |
goto oom;
|
|
Chris PeBenito |
473ea7 |
strcpy(fl->file, file);
|
|
Chris PeBenito |
473ea7 |
return fl->specind;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
no_conflict = (strcmp(spec_arr[fl->specind].context,spec_arr[specind].context) == 0);
|
|
Chris PeBenito |
473ea7 |
if (no_conflict)
|
|
Chris PeBenito |
473ea7 |
return fl->specind;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
myprintf("%s: conflicting specifications for %s and %s, using %s.\n",
|
|
Chris PeBenito |
473ea7 |
__FUNCTION__, file, fl->file,
|
|
Chris PeBenito |
473ea7 |
((specind > fl->specind) ? spec_arr[specind].
|
|
Chris PeBenito |
473ea7 |
context : spec_arr[fl->specind].context));
|
|
Chris PeBenito |
473ea7 |
fl->specind =
|
|
Chris PeBenito |
473ea7 |
(specind >
|
|
Chris PeBenito |
473ea7 |
fl->specind) ? specind : fl->specind;
|
|
Chris PeBenito |
473ea7 |
free(fl->file);
|
|
Chris PeBenito |
473ea7 |
fl->file = malloc(strlen(file) + 1);
|
|
Chris PeBenito |
473ea7 |
if (!fl->file)
|
|
Chris PeBenito |
473ea7 |
goto oom;
|
|
Chris PeBenito |
473ea7 |
strcpy(fl->file, file);
|
|
Chris PeBenito |
473ea7 |
return fl->specind;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
if (ino > fl->ino)
|
|
Chris PeBenito |
473ea7 |
break;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
fl = malloc(sizeof(file_spec_t));
|
|
Chris PeBenito |
473ea7 |
if (!fl)
|
|
Chris PeBenito |
473ea7 |
goto oom;
|
|
Chris PeBenito |
473ea7 |
fl->ino = ino;
|
|
Chris PeBenito |
473ea7 |
fl->specind = specind;
|
|
Chris PeBenito |
473ea7 |
fl->file = malloc(strlen(file) + 1);
|
|
Chris PeBenito |
473ea7 |
if (!fl->file)
|
|
Chris PeBenito |
473ea7 |
goto oom_freefl;
|
|
Chris PeBenito |
473ea7 |
strcpy(fl->file, file);
|
|
Chris PeBenito |
473ea7 |
fl->next = prevfl->next;
|
|
Chris PeBenito |
473ea7 |
prevfl->next = fl;
|
|
Chris PeBenito |
473ea7 |
return fl->specind;
|
|
Chris PeBenito |
473ea7 |
oom_freefl:
|
|
Chris PeBenito |
473ea7 |
free(fl);
|
|
Chris PeBenito |
473ea7 |
oom:
|
|
Chris PeBenito |
473ea7 |
myprintf("%s: insufficient memory for file label entry for %s\n",
|
|
Chris PeBenito |
473ea7 |
__FUNCTION__, file);
|
|
Chris PeBenito |
473ea7 |
return -1;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
/*
|
|
Chris PeBenito |
473ea7 |
* Evaluate the association hash table distribution.
|
|
Chris PeBenito |
473ea7 |
*/
|
|
Chris PeBenito |
473ea7 |
void matchpathcon_filespec_eval(void)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
file_spec_t *fl;
|
|
Chris PeBenito |
473ea7 |
int h, used, nel, len, longest;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
if (!fl_head)
|
|
Chris PeBenito |
473ea7 |
return;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
used = 0;
|
|
Chris PeBenito |
473ea7 |
longest = 0;
|
|
Chris PeBenito |
473ea7 |
nel = 0;
|
|
Chris PeBenito |
473ea7 |
for (h = 0; h < HASH_BUCKETS; h++) {
|
|
Chris PeBenito |
473ea7 |
len = 0;
|
|
Chris PeBenito |
473ea7 |
for (fl = fl_head[h].next; fl; fl = fl->next) {
|
|
Chris PeBenito |
473ea7 |
len++;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
if (len)
|
|
Chris PeBenito |
473ea7 |
used++;
|
|
Chris PeBenito |
473ea7 |
if (len > longest)
|
|
Chris PeBenito |
473ea7 |
longest = len;
|
|
Chris PeBenito |
473ea7 |
nel += len;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
myprintf
|
|
Chris PeBenito |
473ea7 |
("%s: hash table stats: %d elements, %d/%d buckets used, longest chain length %d\n",
|
|
Chris PeBenito |
473ea7 |
__FUNCTION__, nel, used, HASH_BUCKETS, longest);
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
/*
|
|
Chris PeBenito |
473ea7 |
* Destroy the association hash table.
|
|
Chris PeBenito |
473ea7 |
*/
|
|
Chris PeBenito |
473ea7 |
void matchpathcon_filespec_destroy(void)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
file_spec_t *fl, *tmp;
|
|
Chris PeBenito |
473ea7 |
int h;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
if (!fl_head)
|
|
Chris PeBenito |
473ea7 |
return;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
for (h = 0; h < HASH_BUCKETS; h++) {
|
|
Chris PeBenito |
473ea7 |
fl = fl_head[h].next;
|
|
Chris PeBenito |
473ea7 |
while (fl) {
|
|
Chris PeBenito |
473ea7 |
tmp = fl;
|
|
Chris PeBenito |
473ea7 |
fl = fl->next;
|
|
Chris PeBenito |
473ea7 |
free(tmp->file);
|
|
Chris PeBenito |
473ea7 |
free(tmp);
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
fl_head[h].next = NULL;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
free(fl_head);
|
|
Chris PeBenito |
473ea7 |
fl_head = NULL;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
/*
|
|
Chris PeBenito |
473ea7 |
* Warn about duplicate specifications.
|
|
Chris PeBenito |
473ea7 |
*/
|
|
Chris PeBenito |
473ea7 |
static void nodups_specs(const char *path)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
unsigned int ii, jj;
|
|
Chris PeBenito |
473ea7 |
struct spec *curr_spec;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
for (ii = 0; ii < nspec; ii++) {
|
|
Chris PeBenito |
473ea7 |
curr_spec = &spec_arr[ii];
|
|
Chris PeBenito |
473ea7 |
for (jj = ii + 1; jj < nspec; jj++) {
|
|
Chris PeBenito |
473ea7 |
if ((!strcmp(spec_arr[jj].regex_str, curr_spec->regex_str))
|
|
Chris PeBenito |
473ea7 |
&&
|
|
Chris PeBenito |
473ea7 |
(!spec_arr[jj].mode || !curr_spec->mode
|
|
Chris PeBenito |
473ea7 |
|| spec_arr[jj].mode == curr_spec->mode)) {
|
|
Chris PeBenito |
473ea7 |
if (strcmp(spec_arr[jj].context, curr_spec->context)) {
|
|
Chris PeBenito |
473ea7 |
myprintf(
|
|
Chris PeBenito |
473ea7 |
"%s: Multiple different specifications for %s (%s and %s).\n",
|
|
Chris PeBenito |
473ea7 |
path, curr_spec->regex_str,
|
|
Chris PeBenito |
473ea7 |
spec_arr[jj].context,
|
|
Chris PeBenito |
473ea7 |
curr_spec->context);
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
else {
|
|
Chris PeBenito |
473ea7 |
myprintf(
|
|
Chris PeBenito |
473ea7 |
"%s: Multiple same specifications for %s.\n",
|
|
Chris PeBenito |
473ea7 |
path, curr_spec->regex_str);
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
/* Determine if the regular expression specification has any meta characters. */
|
|
Chris PeBenito |
473ea7 |
static void spec_hasMetaChars(struct spec *spec)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
char *c;
|
|
Chris PeBenito |
473ea7 |
int len;
|
|
Chris PeBenito |
473ea7 |
char *end;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
c = spec->regex_str;
|
|
Chris PeBenito |
473ea7 |
len = strlen(spec->regex_str);
|
|
Chris PeBenito |
473ea7 |
end = c + len;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
spec->hasMetaChars = 0;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
/* Look at each character in the RE specification string for a
|
|
Chris PeBenito |
473ea7 |
* meta character. Return when any meta character reached. */
|
|
Chris PeBenito |
473ea7 |
while (c != end) {
|
|
Chris PeBenito |
473ea7 |
switch(*c) {
|
|
Chris PeBenito |
473ea7 |
case '.':
|
|
Chris PeBenito |
473ea7 |
case '^':
|
|
Chris PeBenito |
473ea7 |
case '$':
|
|
Chris PeBenito |
473ea7 |
case '?':
|
|
Chris PeBenito |
473ea7 |
case '*':
|
|
Chris PeBenito |
473ea7 |
case '+':
|
|
Chris PeBenito |
473ea7 |
case '|':
|
|
Chris PeBenito |
473ea7 |
case '[':
|
|
Chris PeBenito |
473ea7 |
case '(':
|
|
Chris PeBenito |
473ea7 |
case '{':
|
|
Chris PeBenito |
473ea7 |
spec->hasMetaChars = 1;
|
|
Chris PeBenito |
473ea7 |
return;
|
|
Chris PeBenito |
473ea7 |
case '\\': /* skip the next character */
|
|
Chris PeBenito |
473ea7 |
c++;
|
|
Chris PeBenito |
473ea7 |
break;
|
|
Chris PeBenito |
473ea7 |
default:
|
|
Chris PeBenito |
473ea7 |
break;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
c++;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
return;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
static int process_line( const char *path, char *line_buf, int pass, unsigned lineno, int mls_enabled) {
|
|
Chris PeBenito |
473ea7 |
int items, len, regerr;
|
|
Chris PeBenito |
473ea7 |
char *buf_p;
|
|
Chris PeBenito |
473ea7 |
char *regex, *type, *context;
|
|
Chris PeBenito |
473ea7 |
char *anchored_regex;
|
|
Chris PeBenito |
473ea7 |
len = strlen(line_buf);
|
|
Chris PeBenito |
473ea7 |
if (line_buf[len - 1] == '\n')
|
|
Chris PeBenito |
473ea7 |
line_buf[len - 1] = 0;
|
|
Chris PeBenito |
473ea7 |
buf_p = line_buf;
|
|
Chris PeBenito |
473ea7 |
while (isspace(*buf_p))
|
|
Chris PeBenito |
473ea7 |
buf_p++;
|
|
Chris PeBenito |
473ea7 |
/* Skip comment lines and empty lines. */
|
|
Chris PeBenito |
473ea7 |
if (*buf_p == '#' || *buf_p == 0)
|
|
Chris PeBenito |
473ea7 |
return 0;
|
|
Chris PeBenito |
473ea7 |
items =
|
|
Chris PeBenito |
473ea7 |
sscanf(line_buf, "%as %as %as", ®ex, &type,
|
|
Chris PeBenito |
473ea7 |
&context);
|
|
Chris PeBenito |
473ea7 |
if (items < 2) {
|
|
Chris PeBenito |
473ea7 |
myprintf("%s: line %d is missing fields\n, skipping", path, lineno);
|
|
Chris PeBenito |
473ea7 |
return 0;
|
|
Chris PeBenito |
473ea7 |
} else if (items == 2) {
|
|
Chris PeBenito |
473ea7 |
/* The type field is optional. */
|
|
Chris PeBenito |
473ea7 |
free(context);
|
|
Chris PeBenito |
473ea7 |
context = type;
|
|
Chris PeBenito |
473ea7 |
type = 0;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
if (pass == 1) {
|
|
Chris PeBenito |
473ea7 |
/* On the second pass, compile and store the specification in spec. */
|
|
Chris PeBenito |
473ea7 |
const char *reg_buf = regex;
|
|
Chris PeBenito |
473ea7 |
char *cp;
|
|
Chris PeBenito |
473ea7 |
spec_arr[nspec].stem_id = find_stem_from_spec(®_buf);
|
|
Chris PeBenito |
473ea7 |
spec_arr[nspec].regex_str = regex;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
/* Anchor the regular expression. */
|
|
Chris PeBenito |
473ea7 |
len = strlen(reg_buf);
|
|
Chris PeBenito |
473ea7 |
cp = anchored_regex = malloc(len + 3);
|
|
Chris PeBenito |
473ea7 |
if (!anchored_regex)
|
|
Chris PeBenito |
473ea7 |
return -1;
|
|
Chris PeBenito |
473ea7 |
/* Create ^...$ regexp. */
|
|
Chris PeBenito |
473ea7 |
*cp++ = '^';
|
|
Chris PeBenito |
473ea7 |
cp = mempcpy(cp, reg_buf, len);
|
|
Chris PeBenito |
473ea7 |
*cp++ = '$';
|
|
Chris PeBenito |
473ea7 |
*cp = '\0';
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
/* Compile the regular expression. */
|
|
Chris PeBenito |
473ea7 |
regerr =
|
|
Chris PeBenito |
473ea7 |
regcomp(&spec_arr[nspec].regex,
|
|
Chris PeBenito |
473ea7 |
anchored_regex,
|
|
Chris PeBenito |
473ea7 |
REG_EXTENDED | REG_NOSUB);
|
|
Chris PeBenito |
473ea7 |
if (regerr != 0) {
|
|
Chris PeBenito |
473ea7 |
size_t errsz = 0;
|
|
Chris PeBenito |
473ea7 |
char *errbuf = NULL;
|
|
Chris PeBenito |
473ea7 |
errsz = regerror(regerr, &spec_arr[nspec].regex,
|
|
Chris PeBenito |
473ea7 |
errbuf, errsz);
|
|
Chris PeBenito |
473ea7 |
if (errsz)
|
|
Chris PeBenito |
473ea7 |
errbuf = malloc(errsz);
|
|
Chris PeBenito |
473ea7 |
if (errbuf)
|
|
Chris PeBenito |
473ea7 |
(void) regerror(regerr,
|
|
Chris PeBenito |
473ea7 |
&spec_arr[nspec].regex,
|
|
Chris PeBenito |
473ea7 |
errbuf, errsz);
|
|
Chris PeBenito |
473ea7 |
myprintf("%s: line %d has invalid regex %s: %s\n", path, lineno, anchored_regex, (errbuf ? errbuf : "out of memory"));
|
|
Chris PeBenito |
473ea7 |
free(anchored_regex);
|
|
Chris PeBenito |
473ea7 |
return 0;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
free(anchored_regex);
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
/* Convert the type string to a mode format */
|
|
Chris PeBenito |
473ea7 |
spec_arr[nspec].type_str = type;
|
|
Chris PeBenito |
473ea7 |
spec_arr[nspec].mode = 0;
|
|
Chris PeBenito |
473ea7 |
if (!type)
|
|
Chris PeBenito |
473ea7 |
goto skip_type;
|
|
Chris PeBenito |
473ea7 |
len = strlen(type);
|
|
Chris PeBenito |
473ea7 |
if (type[0] != '-' || len != 2) {
|
|
Chris PeBenito |
473ea7 |
myprintf("%s: line %d has invalid file type %s\n", path, lineno, type);
|
|
Chris PeBenito |
473ea7 |
return 0;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
switch (type[1]) {
|
|
Chris PeBenito |
473ea7 |
case 'b':
|
|
Chris PeBenito |
473ea7 |
spec_arr[nspec].mode = S_IFBLK;
|
|
Chris PeBenito |
473ea7 |
break;
|
|
Chris PeBenito |
473ea7 |
case 'c':
|
|
Chris PeBenito |
473ea7 |
spec_arr[nspec].mode = S_IFCHR;
|
|
Chris PeBenito |
473ea7 |
break;
|
|
Chris PeBenito |
473ea7 |
case 'd':
|
|
Chris PeBenito |
473ea7 |
spec_arr[nspec].mode = S_IFDIR;
|
|
Chris PeBenito |
473ea7 |
break;
|
|
Chris PeBenito |
473ea7 |
case 'p':
|
|
Chris PeBenito |
473ea7 |
spec_arr[nspec].mode = S_IFIFO;
|
|
Chris PeBenito |
473ea7 |
break;
|
|
Chris PeBenito |
473ea7 |
case 'l':
|
|
Chris PeBenito |
473ea7 |
spec_arr[nspec].mode = S_IFLNK;
|
|
Chris PeBenito |
473ea7 |
break;
|
|
Chris PeBenito |
473ea7 |
case 's':
|
|
Chris PeBenito |
473ea7 |
spec_arr[nspec].mode = S_IFSOCK;
|
|
Chris PeBenito |
473ea7 |
break;
|
|
Chris PeBenito |
473ea7 |
case '-':
|
|
Chris PeBenito |
473ea7 |
spec_arr[nspec].mode = S_IFREG;
|
|
Chris PeBenito |
473ea7 |
break;
|
|
Chris PeBenito |
473ea7 |
default:
|
|
Chris PeBenito |
473ea7 |
myprintf("%s: line %d has invalid file type %s\n", path, lineno, type);
|
|
Chris PeBenito |
473ea7 |
return 0;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
skip_type:
|
|
Chris PeBenito |
473ea7 |
if (strcmp(context, "<<none>>")) {
|
|
Chris PeBenito |
473ea7 |
if (context_translations) {
|
|
Chris PeBenito |
473ea7 |
if (raw_to_trans_context(context,
|
|
Chris PeBenito |
473ea7 |
&spec_arr[nspec].context)) {
|
|
Chris PeBenito |
473ea7 |
myprintf("%s: line %u has invalid "
|
|
Chris PeBenito |
473ea7 |
"context %s\n",
|
|
Chris PeBenito |
473ea7 |
path, lineno, context);
|
|
Chris PeBenito |
473ea7 |
return 0;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
free(context);
|
|
Chris PeBenito |
473ea7 |
context = spec_arr[nspec].context;
|
|
Chris PeBenito |
473ea7 |
} else {
|
|
Chris PeBenito |
473ea7 |
if (STRIP_LEVEL(&context, mls_enabled))
|
|
Chris PeBenito |
473ea7 |
return -1;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
if (myinvalidcon(path, lineno, context))
|
|
Chris PeBenito |
473ea7 |
return 0;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
spec_arr[nspec].context = context;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
/* Determine if specification has
|
|
Chris PeBenito |
473ea7 |
* any meta characters in the RE */
|
|
Chris PeBenito |
473ea7 |
spec_hasMetaChars(&spec_arr[nspec]);
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
nspec++;
|
|
Chris PeBenito |
473ea7 |
if (pass == 0) {
|
|
Chris PeBenito |
473ea7 |
free(regex);
|
|
Chris PeBenito |
473ea7 |
if (type)
|
|
Chris PeBenito |
473ea7 |
free(type);
|
|
Chris PeBenito |
473ea7 |
free(context);
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
return 0;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
int matchpathcon_init(const char *path)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
FILE *fp;
|
|
Chris PeBenito |
473ea7 |
FILE *localfp = NULL;
|
|
Chris PeBenito |
473ea7 |
FILE *homedirfp = NULL;
|
|
Chris PeBenito |
473ea7 |
char local_path[PATH_MAX + 1];
|
|
Chris PeBenito |
473ea7 |
char homedir_path[PATH_MAX + 1];
|
|
Chris PeBenito |
473ea7 |
char *line_buf = NULL;
|
|
Chris PeBenito |
473ea7 |
size_t line_len = 0;
|
|
Chris PeBenito |
473ea7 |
unsigned int lineno, pass, i, j, maxnspec;
|
|
Chris PeBenito |
473ea7 |
spec_t *spec_copy=NULL;
|
|
Chris PeBenito |
473ea7 |
int status=-1;
|
|
Chris PeBenito |
473ea7 |
int mls_enabled=is_selinux_mls_enabled();
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
/* Open the specification file. */
|
|
Chris PeBenito |
473ea7 |
if (!path)
|
|
Chris PeBenito |
473ea7 |
path = selinux_file_context_path();
|
|
Chris PeBenito |
473ea7 |
if ((fp = fopen(path, "r")) == NULL)
|
|
Chris PeBenito |
473ea7 |
return -1;
|
|
Chris PeBenito |
473ea7 |
__fsetlocking(fp, FSETLOCKING_BYCALLER);
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
if ((myflags & MATCHPATHCON_BASEONLY) == 0) {
|
|
Chris PeBenito |
473ea7 |
snprintf(homedir_path, sizeof(homedir_path), "%s.homedirs", path);
|
|
Chris PeBenito |
473ea7 |
homedirfp = fopen(homedir_path, "r");
|
|
Chris PeBenito |
473ea7 |
if (homedirfp != NULL)
|
|
Chris PeBenito |
473ea7 |
__fsetlocking(homedirfp, FSETLOCKING_BYCALLER);
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
snprintf(local_path, sizeof(local_path), "%s.local", path);
|
|
Chris PeBenito |
473ea7 |
localfp = fopen(local_path, "r");
|
|
Chris PeBenito |
473ea7 |
if (localfp != NULL)
|
|
Chris PeBenito |
473ea7 |
__fsetlocking(localfp, FSETLOCKING_BYCALLER);
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
/*
|
|
Chris PeBenito |
473ea7 |
* Perform two passes over the specification file.
|
|
Chris PeBenito |
473ea7 |
* The first pass counts the number of specifications and
|
|
Chris PeBenito |
473ea7 |
* performs simple validation of the input. At the end
|
|
Chris PeBenito |
473ea7 |
* of the first pass, the spec array is allocated.
|
|
Chris PeBenito |
473ea7 |
* The second pass performs detailed validation of the input
|
|
Chris PeBenito |
473ea7 |
* and fills in the spec array.
|
|
Chris PeBenito |
473ea7 |
*/
|
|
Chris PeBenito |
473ea7 |
maxnspec = UINT_MAX / sizeof(spec_t);
|
|
Chris PeBenito |
473ea7 |
for (pass = 0; pass < 2; pass++) {
|
|
Chris PeBenito |
473ea7 |
lineno = 0;
|
|
Chris PeBenito |
473ea7 |
nspec = 0;
|
|
Chris PeBenito |
473ea7 |
while (getline(&line_buf, &line_len, fp) > 0 && nspec < maxnspec) {
|
|
Chris PeBenito |
473ea7 |
if (process_line(path, line_buf, pass, ++lineno, mls_enabled) != 0)
|
|
Chris PeBenito |
473ea7 |
goto finish;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
lineno = 0;
|
|
Chris PeBenito |
473ea7 |
if (homedirfp)
|
|
Chris PeBenito |
473ea7 |
while (getline(&line_buf, &line_len, homedirfp) > 0 && nspec < maxnspec) {
|
|
Chris PeBenito |
473ea7 |
if (process_line(homedir_path, line_buf, pass, ++lineno, mls_enabled) != 0)
|
|
Chris PeBenito |
473ea7 |
goto finish;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
lineno = 0;
|
|
Chris PeBenito |
473ea7 |
if (localfp)
|
|
Chris PeBenito |
473ea7 |
while (getline(&line_buf, &line_len, localfp) > 0 && nspec < maxnspec) {
|
|
Chris PeBenito |
473ea7 |
if (process_line(local_path, line_buf, pass, ++lineno, mls_enabled) != 0)
|
|
Chris PeBenito |
473ea7 |
goto finish;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
if (pass == 0) {
|
|
Chris PeBenito |
473ea7 |
if (nspec == 0) {
|
|
Chris PeBenito |
473ea7 |
status = 0;
|
|
Chris PeBenito |
473ea7 |
goto finish;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
if ((spec_arr = malloc(sizeof(spec_t) * nspec)) ==
|
|
Chris PeBenito |
473ea7 |
NULL)
|
|
Chris PeBenito |
473ea7 |
goto finish;
|
|
Chris PeBenito |
473ea7 |
memset(spec_arr, '\0', sizeof(spec_t) * nspec);
|
|
Chris PeBenito |
473ea7 |
maxnspec = nspec;
|
|
Chris PeBenito |
473ea7 |
rewind(fp);
|
|
Chris PeBenito |
473ea7 |
if (homedirfp) rewind(homedirfp);
|
|
Chris PeBenito |
473ea7 |
if (localfp) rewind(localfp);
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
free(line_buf);
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
/* Move exact pathname specifications to the end. */
|
|
Chris PeBenito |
473ea7 |
spec_copy = malloc(sizeof(spec_t) * nspec);
|
|
Chris PeBenito |
473ea7 |
if (!spec_copy)
|
|
Chris PeBenito |
473ea7 |
goto finish;
|
|
Chris PeBenito |
473ea7 |
j = 0;
|
|
Chris PeBenito |
473ea7 |
for (i = 0; i < nspec; i++) {
|
|
Chris PeBenito |
473ea7 |
if (spec_arr[i].hasMetaChars)
|
|
Chris PeBenito |
473ea7 |
memcpy(&spec_copy[j++], &spec_arr[i], sizeof(spec_t));
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
for (i = 0; i < nspec; i++) {
|
|
Chris PeBenito |
473ea7 |
if (!spec_arr[i].hasMetaChars)
|
|
Chris PeBenito |
473ea7 |
memcpy(&spec_copy[j++], &spec_arr[i], sizeof(spec_t));
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
free(spec_arr);
|
|
Chris PeBenito |
473ea7 |
spec_arr = spec_copy;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
nodups_specs(path);
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
status = 0;
|
|
Chris PeBenito |
473ea7 |
finish:
|
|
Chris PeBenito |
473ea7 |
fclose(fp);
|
|
Chris PeBenito |
473ea7 |
if (spec_arr != spec_copy) free(spec_arr);
|
|
Chris PeBenito |
473ea7 |
if (homedirfp) fclose(homedirfp);
|
|
Chris PeBenito |
473ea7 |
if (localfp) fclose(localfp);
|
|
Chris PeBenito |
473ea7 |
return status;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
hidden_def(matchpathcon_init)
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
static int matchpathcon_common(const char *name,
|
|
Chris PeBenito |
473ea7 |
mode_t mode)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
int i, ret, file_stem;
|
|
Chris PeBenito |
473ea7 |
const char *buf = name;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
if (!nspec) {
|
|
Chris PeBenito |
473ea7 |
ret = matchpathcon_init(NULL);
|
|
Chris PeBenito |
473ea7 |
if (ret < 0)
|
|
Chris PeBenito |
473ea7 |
return ret;
|
|
Chris PeBenito |
473ea7 |
if (!nspec) {
|
|
Chris PeBenito |
473ea7 |
errno = ENOENT;
|
|
Chris PeBenito |
473ea7 |
return -1;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
file_stem = find_stem_from_file(&buf;;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
mode &= S_IFMT;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
/*
|
|
Chris PeBenito |
473ea7 |
* Check for matching specifications in reverse order, so that
|
|
Chris PeBenito |
473ea7 |
* the last matching specification is used.
|
|
Chris PeBenito |
473ea7 |
*/
|
|
Chris PeBenito |
473ea7 |
for (i = nspec - 1; i >= 0; i--)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
/* if the spec in question matches no stem or has the same
|
|
Chris PeBenito |
473ea7 |
* stem as the file AND if the spec in question has no mode
|
|
Chris PeBenito |
473ea7 |
* specified or if the mode matches the file mode then we do
|
|
Chris PeBenito |
473ea7 |
* a regex check */
|
|
Chris PeBenito |
473ea7 |
if( (spec_arr[i].stem_id == -1 || spec_arr[i].stem_id == file_stem)
|
|
Chris PeBenito |
473ea7 |
&& (!mode || !spec_arr[i].mode || ( (mode & S_IFMT) == spec_arr[i].mode ) ) )
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
if(spec_arr[i].stem_id == -1)
|
|
Chris PeBenito |
473ea7 |
ret = regexec(&spec_arr[i].regex, name, 0, NULL, 0);
|
|
Chris PeBenito |
473ea7 |
else
|
|
Chris PeBenito |
473ea7 |
ret = regexec(&spec_arr[i].regex, buf, 0, NULL, 0);
|
|
Chris PeBenito |
473ea7 |
if (ret == 0)
|
|
Chris PeBenito |
473ea7 |
break;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
if (ret == REG_NOMATCH)
|
|
Chris PeBenito |
473ea7 |
continue;
|
|
Chris PeBenito |
473ea7 |
/* else it's an error */
|
|
Chris PeBenito |
473ea7 |
return -1;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
if (i < 0) {
|
|
Chris PeBenito |
473ea7 |
/* No matching specification. */
|
|
Chris PeBenito |
473ea7 |
errno = ENOENT;
|
|
Chris PeBenito |
473ea7 |
return -1;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
spec_arr[i].matches++;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
return i;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
int matchpathcon(const char *name,
|
|
Chris PeBenito |
473ea7 |
mode_t mode,
|
|
Chris PeBenito |
473ea7 |
security_context_t *con)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
int i = matchpathcon_common(name, mode);
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
if (i < 0)
|
|
Chris PeBenito |
473ea7 |
return -1;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
if (strcmp(spec_arr[i].context, "<<none>>") == 0) {
|
|
Chris PeBenito |
473ea7 |
errno = ENOENT;
|
|
Chris PeBenito |
473ea7 |
return -1;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
*con = strdup(spec_arr[i].context);
|
|
Chris PeBenito |
473ea7 |
if (!(*con))
|
|
Chris PeBenito |
473ea7 |
return -1;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
return 0;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
int matchpathcon_index(const char *name,
|
|
Chris PeBenito |
473ea7 |
mode_t mode,
|
|
Chris PeBenito |
473ea7 |
security_context_t *con)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
int i = matchpathcon_common(name, mode);
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
if (i < 0)
|
|
Chris PeBenito |
473ea7 |
return -1;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
*con = strdup(spec_arr[i].context);
|
|
Chris PeBenito |
473ea7 |
if (!(*con))
|
|
Chris PeBenito |
473ea7 |
return -1;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
return i;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
void matchpathcon_checkmatches(char *str)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
unsigned int i;
|
|
Chris PeBenito |
473ea7 |
for (i = 0; i < nspec; i++) {
|
|
Chris PeBenito |
473ea7 |
if (spec_arr[i].matches == 0) {
|
|
Chris PeBenito |
473ea7 |
if (spec_arr[i].type_str) {
|
|
Chris PeBenito |
473ea7 |
myprintf
|
|
Chris PeBenito |
473ea7 |
("%s: Warning! No matches for (%s, %s, %s)\n",
|
|
Chris PeBenito |
473ea7 |
str, spec_arr[i].regex_str,
|
|
Chris PeBenito |
473ea7 |
spec_arr[i].type_str, spec_arr[i].context);
|
|
Chris PeBenito |
473ea7 |
} else {
|
|
Chris PeBenito |
473ea7 |
myprintf
|
|
Chris PeBenito |
473ea7 |
("%s: Warning! No matches for (%s, %s)\n",
|
|
Chris PeBenito |
473ea7 |
str, spec_arr[i].regex_str,
|
|
Chris PeBenito |
473ea7 |
spec_arr[i].context);
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
}
|