264 lines
6.1 KiB
C
264 lines
6.1 KiB
C
/* $OpenBSD: policy.c,v 1.1.1.1 2006/11/26 10:58:43 matthieu Exp $ */
|
|
/*
|
|
* Copyright (c) 2002 Matthieu Herrb and Niels Provos
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* - Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* - Redistributions in binary form must reproduce the above
|
|
* copyright notice, this list of conditions and the following
|
|
* disclaimer in the documentation and/or other materials provided
|
|
* with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
* COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <sys/param.h>
|
|
|
|
#include <ctype.h>
|
|
#include <err.h>
|
|
#include <libgen.h>
|
|
#include <pwd.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#include "policy.h"
|
|
|
|
#define MAX_SYSCALLARGS 10
|
|
|
|
static char home[MAXPATHLEN]; /* Home directory of user */
|
|
static char username[MAXLOGNAME]; /* Username: predicate match and expansion */
|
|
|
|
static struct policy_list *
|
|
alloc_policy(char *p)
|
|
{
|
|
struct policy_list *np;
|
|
|
|
np = (struct policy_list *)malloc(sizeof(struct policy_list));
|
|
if (np == NULL)
|
|
errx(1, "alloc_policy: cannot allocate memory");
|
|
np->line = strdup(p);
|
|
if (np->line == NULL)
|
|
errx(1, "alloc_policy: cannot allocate memory");
|
|
return (np);
|
|
}
|
|
|
|
void
|
|
free_policy(struct policy_list *p)
|
|
{
|
|
free(p->line);
|
|
free(p);
|
|
}
|
|
|
|
static char *
|
|
strrpl(char *str, size_t size, char *match, char *value)
|
|
{
|
|
char *p, *e;
|
|
int len, rlen;
|
|
|
|
p = str;
|
|
e = p + strlen(p);
|
|
len = strlen(match);
|
|
|
|
/* Try to match against the variable */
|
|
while ((p = strchr(p, match[0])) != NULL) {
|
|
if (!strncmp(p, match, len) && !isalnum(p[len]))
|
|
break;
|
|
p += len;
|
|
|
|
if (p >= e)
|
|
return (NULL);
|
|
}
|
|
|
|
if (p == NULL)
|
|
return (NULL);
|
|
|
|
rlen = strlen(value);
|
|
|
|
if (strlen(str) - len + rlen > size)
|
|
return (NULL);
|
|
|
|
memmove(p + rlen, p + len, strlen(p + len) + 1);
|
|
memcpy(p, value, rlen);
|
|
|
|
return (p);
|
|
}
|
|
|
|
void
|
|
parameters(void)
|
|
{
|
|
struct passwd *pw;
|
|
uid_t uid = getuid();
|
|
|
|
/* Find out current username. */
|
|
if ((pw = getpwuid(uid)) == NULL)
|
|
snprintf(username, sizeof(username), "uid %u", uid);
|
|
else
|
|
snprintf(username, sizeof(username), "%s", pw->pw_name);
|
|
|
|
strlcpy(home, pw->pw_dir, sizeof(home));
|
|
}
|
|
|
|
static int
|
|
make_policy(char **type, char **data, int count, char **presult, int derive)
|
|
{
|
|
static char result[4096];
|
|
char one[2048];
|
|
int i;
|
|
int nfilename, isfilename;
|
|
|
|
result[0] = '\0';
|
|
nfilename = 0;
|
|
for (i = 0; i < count; i++) {
|
|
isfilename = 0;
|
|
/* Special case for non existing filenames */
|
|
if (strstr(data[i], "<non-existent filename>") != NULL) {
|
|
snprintf(result, sizeof(result),
|
|
"filename%s sub \"<non-existent filename>\" then deny[enoent]", i ? "[1]" : "");
|
|
break;
|
|
}
|
|
|
|
if (!strcmp(type[i], "uid") || !strcmp(type[i], "gid") ||
|
|
!strcmp(type[i], "argv"))
|
|
continue;
|
|
|
|
/* Special case for system calls with more than one filename */
|
|
if (!strcmp(type[i], "filename")) {
|
|
isfilename = 1;
|
|
nfilename++;
|
|
}
|
|
|
|
if (strlen(result)) {
|
|
if (strlcat(result, " and ",
|
|
sizeof(result)) >= sizeof(result))
|
|
return (-1);
|
|
}
|
|
|
|
/* Special treatment for filenames */
|
|
if (isfilename) {
|
|
char filename[2048];
|
|
char *operator = "eq";
|
|
|
|
if (derive) {
|
|
operator = "match";
|
|
|
|
snprintf(filename, sizeof(filename),
|
|
"%s/*", dirname(data[i]));
|
|
} else
|
|
strlcpy(filename, data[i], sizeof(filename));
|
|
|
|
/* Make useful replacements */
|
|
while (strrpl(filename, sizeof(filename),
|
|
home, "$HOME") != NULL)
|
|
;
|
|
while (strrpl(filename, sizeof(filename),
|
|
username, "$USER") != NULL)
|
|
;
|
|
|
|
snprintf(one, sizeof(one), "%s%s %s \"%s\"",
|
|
type[i], isfilename && nfilename == 2 ? "[1]" : "",
|
|
operator, filename);
|
|
} else {
|
|
snprintf(one, sizeof(one), "%s eq \"%s\"",
|
|
type[i], data[i]);
|
|
}
|
|
|
|
if (strlcat(result, one, sizeof(result)) >= sizeof(result))
|
|
return (-1);;
|
|
}
|
|
|
|
if (!strlen(result))
|
|
return (-1);
|
|
|
|
/* Normal termination */
|
|
if (i == count)
|
|
strlcat(result, " then permit", sizeof(result));
|
|
|
|
*presult = result;
|
|
return (nfilename);
|
|
}
|
|
|
|
struct plist *
|
|
make_policy_suggestion(char *info)
|
|
{
|
|
char line[4096], *next, *p, *syscall;
|
|
char *type[MAX_SYSCALLARGS], *data[MAX_SYSCALLARGS];
|
|
int count = 0, res;
|
|
struct plist *items;
|
|
struct policy_list *np;
|
|
|
|
items = (struct plist *)malloc(sizeof(struct plist));
|
|
if (items == NULL)
|
|
errx(1, "make_policy_suggestion: cannot allocate memory");
|
|
SIMPLEQ_INIT(items);
|
|
|
|
/* Prepare parsing of info line */
|
|
strlcpy(line, info, sizeof(line));
|
|
|
|
next = line;
|
|
syscall = strsep(&next, ",");
|
|
|
|
/* See if we can make a suggestion for this system call */
|
|
if (next == NULL)
|
|
goto out;
|
|
next++;
|
|
if (!strncmp(next, "args: ", 6)) {
|
|
count = -1;
|
|
goto out;
|
|
}
|
|
|
|
while (next != NULL) {
|
|
p = next;
|
|
|
|
next = strstr(next, ", ");
|
|
if (next != NULL) {
|
|
*next = '\0';
|
|
next += 2;
|
|
}
|
|
|
|
type[count] = strsep(&p, ":");
|
|
data[count] = p + 1;
|
|
|
|
count++;
|
|
}
|
|
|
|
res = make_policy(type, data, count, &p, 0);
|
|
if (res != -1) {
|
|
np = alloc_policy(p);
|
|
SIMPLEQ_INSERT_TAIL(items, np, next);
|
|
}
|
|
|
|
if (res > 0) {
|
|
res = make_policy(type, data, count, &p, 1);
|
|
if (res != -1) {
|
|
np = alloc_policy(p);
|
|
SIMPLEQ_INSERT_TAIL(items, np, next);
|
|
}
|
|
}
|
|
|
|
out:
|
|
/* Simples policy */
|
|
p = count == -1 ? "permit" : "true then permit";
|
|
np = alloc_policy(p);
|
|
SIMPLEQ_INSERT_TAIL(items, np, next);
|
|
|
|
return (items);
|
|
}
|