/* $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 #include #include #include #include #include #include #include #include #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], "") != NULL) { snprintf(result, sizeof(result), "filename%s sub \"\" 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); }