2006-04-11 21:52:54 +00:00
|
|
|
%{
|
2006-04-12 03:09:10 +00:00
|
|
|
/* $Id$ */
|
2006-04-11 21:52:54 +00:00
|
|
|
|
|
|
|
/*
|
2007-04-11 08:12:51 +00:00
|
|
|
* Copyright (c) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
|
|
|
|
* NOVELL (All rights reserved)
|
2006-04-11 21:52:54 +00:00
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of version 2 of the GNU General Public
|
|
|
|
* License published by the Free Software Foundation.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, contact Novell, Inc.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define YYERROR_VERBOSE 1
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <getopt.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <libintl.h>
|
|
|
|
#define _(s) gettext(s)
|
|
|
|
|
|
|
|
/* #define DEBUG */
|
|
|
|
|
|
|
|
#include "parser.h"
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
|
|
|
|
#include <linux/capability.h>
|
|
|
|
|
2006-11-20 05:26:25 +00:00
|
|
|
#ifndef CAP_AUDIT_WRITE
|
|
|
|
#define CAP_AUDIT_WRITE 29
|
|
|
|
#endif
|
|
|
|
#ifndef CAP_AUDIT_CONTROL
|
|
|
|
#define CAP_AUDIT_CONTROL 30
|
|
|
|
#endif
|
|
|
|
|
2006-04-11 21:52:54 +00:00
|
|
|
/* A few utility defines */
|
|
|
|
|
|
|
|
#define CIDR_32 htonl(0xffffffff)
|
|
|
|
#define CIDR_24 htonl(0xffffff00)
|
|
|
|
#define CIDR_16 htonl(0xffff0000)
|
|
|
|
#define CIDR_8 htonl(0xff000000)
|
|
|
|
|
|
|
|
#define CAP_TO_MASK(x) (1 << (x))
|
|
|
|
|
|
|
|
static struct flagval force_complain_flags = {0, 1, 0};
|
|
|
|
|
|
|
|
/* from lex_config, for nice error messages */
|
|
|
|
/* extern char *current_file; */
|
|
|
|
extern int current_lineno;
|
|
|
|
|
|
|
|
struct value_list {
|
|
|
|
char *value;
|
|
|
|
struct value_list *next;
|
|
|
|
};
|
|
|
|
|
|
|
|
void free_value_list(struct value_list *list);
|
2007-11-16 09:18:48 +00:00
|
|
|
struct cod_entry *do_file_rule(char *namespace, char *id, int mode);
|
2006-04-11 21:52:54 +00:00
|
|
|
|
|
|
|
%}
|
|
|
|
|
|
|
|
%token TOK_ID
|
|
|
|
%token TOK_SEP
|
|
|
|
%token TOK_OPEN
|
|
|
|
%token TOK_CLOSE
|
|
|
|
%token TOK_MODE
|
|
|
|
%token TOK_END_OF_RULE
|
|
|
|
%token TOK_EQUALS
|
|
|
|
%token TOK_ADD_ASSIGN
|
|
|
|
%token TOK_SET_VAR
|
|
|
|
%token TOK_BOOL_VAR
|
|
|
|
%token TOK_VALUE
|
|
|
|
%token TOK_IF
|
|
|
|
%token TOK_ELSE
|
|
|
|
%token TOK_NOT
|
|
|
|
%token TOK_DEFINED
|
2007-06-26 21:10:28 +00:00
|
|
|
%token TOK_CHANGE_PROFILE
|
2007-07-27 20:29:47 +00:00
|
|
|
%token TOK_NETWORK
|
2007-07-27 20:48:24 +00:00
|
|
|
%token TOK_HAT
|
2007-07-27 20:55:25 +00:00
|
|
|
%token TOK_UNSAFE
|
2006-04-11 21:52:54 +00:00
|
|
|
%token TOK_COLON
|
|
|
|
|
|
|
|
/* capabilities */
|
|
|
|
%token TOK_CAPABILITY
|
|
|
|
|
|
|
|
/* debug flag values */
|
|
|
|
%token TOK_FLAGS
|
|
|
|
%token TOK_FLAG_OPENPAREN
|
|
|
|
%token TOK_FLAG_CLOSEPAREN
|
|
|
|
%token TOK_FLAG_SEP
|
2007-11-16 09:31:33 +00:00
|
|
|
%token TOK_FLAG_ID
|
2006-04-11 21:52:54 +00:00
|
|
|
|
|
|
|
%union {
|
|
|
|
char *id;
|
2007-11-16 09:31:33 +00:00
|
|
|
char *flag_id;
|
2006-04-11 21:52:54 +00:00
|
|
|
char *mode;
|
2007-07-27 20:29:47 +00:00
|
|
|
struct aa_network_entry *network_entry;
|
2006-04-11 21:52:54 +00:00
|
|
|
struct codomain *cod;
|
|
|
|
struct cod_global_entry *entry;
|
|
|
|
struct cod_net_entry *net_entry;
|
|
|
|
struct cod_entry *user_entry;
|
|
|
|
struct flagval flags;
|
2007-07-27 20:47:17 +00:00
|
|
|
int fmode;
|
2006-04-11 21:52:54 +00:00
|
|
|
unsigned int cap;
|
2007-07-27 20:29:47 +00:00
|
|
|
unsigned int allowed_protocol;
|
2006-04-11 21:52:54 +00:00
|
|
|
char *set_var;
|
|
|
|
char *bool_var;
|
|
|
|
char *var_val;
|
|
|
|
struct value_list *val_list;
|
|
|
|
int boolean;
|
|
|
|
}
|
|
|
|
|
|
|
|
%type <id> TOK_ID
|
|
|
|
%type <mode> TOK_MODE
|
2007-07-27 20:47:17 +00:00
|
|
|
%type <fmode> file_mode
|
2006-04-11 21:52:54 +00:00
|
|
|
%type <cod> profile
|
|
|
|
%type <cod> rules
|
|
|
|
%type <cod> hat
|
|
|
|
%type <cod> cond_rule
|
2007-07-27 20:29:47 +00:00
|
|
|
%type <network_entry> network_rule
|
2006-04-11 21:52:54 +00:00
|
|
|
%type <user_entry> rule
|
|
|
|
%type <flags> flags
|
|
|
|
%type <flags> flagvals
|
|
|
|
%type <flags> flagval
|
2007-11-16 09:31:33 +00:00
|
|
|
%type <flag_id> TOK_FLAG_ID
|
2007-11-16 09:32:38 +00:00
|
|
|
%type <cap> caps
|
2006-04-11 21:52:54 +00:00
|
|
|
%type <cap> capability
|
2007-06-26 21:10:28 +00:00
|
|
|
%type <user_entry> change_profile
|
2006-04-11 21:52:54 +00:00
|
|
|
%type <set_var> TOK_SET_VAR
|
|
|
|
%type <bool_var> TOK_BOOL_VAR
|
|
|
|
%type <var_val> TOK_VALUE
|
|
|
|
%type <val_list> valuelist
|
|
|
|
%type <boolean> expr
|
2007-11-16 09:30:08 +00:00
|
|
|
%type <id> id_or_var
|
2006-04-11 21:52:54 +00:00
|
|
|
|
|
|
|
%%
|
|
|
|
|
|
|
|
|
|
|
|
list: varlist profilelist
|
|
|
|
{ /* nothing */ };
|
|
|
|
|
|
|
|
profilelist: { /* nothing */ };
|
|
|
|
|
|
|
|
profilelist: profilelist profile
|
|
|
|
{
|
|
|
|
PDEBUG("Matched: list profile\n");
|
|
|
|
add_to_list($2);
|
|
|
|
};
|
|
|
|
|
|
|
|
profile: TOK_ID flags TOK_OPEN rules TOK_CLOSE
|
|
|
|
{
|
|
|
|
struct codomain *cod = $4;
|
|
|
|
PDEBUG("Matched: id (%s) open rules close\n", $1);
|
|
|
|
if (!cod) {
|
|
|
|
yyerror(_("Memory allocation error."));
|
|
|
|
}
|
2007-11-16 09:18:48 +00:00
|
|
|
|
|
|
|
if ($1[0] != '/')
|
|
|
|
yyerror(_("Profile names must begin with a '/'."));
|
|
|
|
|
2006-04-11 21:52:54 +00:00
|
|
|
cod->name = $1;
|
|
|
|
cod->flags = $2;
|
|
|
|
if (force_complain)
|
|
|
|
cod->flags = force_complain_flags;
|
|
|
|
|
|
|
|
PDEBUG("%s: flags='%s%s'\n",
|
|
|
|
$1,
|
|
|
|
cod->flags.complain ? "complain, " : "",
|
|
|
|
cod->flags.audit ? "audit" : "");
|
|
|
|
|
|
|
|
$$ = cod;
|
|
|
|
};
|
|
|
|
|
2007-11-16 09:18:48 +00:00
|
|
|
profile: TOK_ID TOK_COLON TOK_ID flags TOK_OPEN rules TOK_CLOSE
|
|
|
|
{
|
|
|
|
struct codomain *cod = $6;
|
|
|
|
PDEBUG("Matched: id (%s:%s) open rules close\n", $1, $3);
|
|
|
|
if (!cod) {
|
|
|
|
yyerror(_("Memory allocation error."));
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($3[0] != '/')
|
|
|
|
yyerror(_("Profile names must begin with a '/'."));
|
|
|
|
|
|
|
|
cod->namespace = $1;
|
|
|
|
cod->name = $3;
|
|
|
|
cod->flags = $4;
|
|
|
|
if (force_complain)
|
|
|
|
cod->flags = force_complain_flags;
|
|
|
|
|
|
|
|
PDEBUG("%s: flags='%s%s'\n",
|
|
|
|
$1,
|
|
|
|
cod->flags.complain ? "complain, " : "",
|
|
|
|
cod->flags.audit ? "audit" : "");
|
|
|
|
|
|
|
|
$$ = cod;
|
|
|
|
};
|
|
|
|
|
2006-04-11 21:52:54 +00:00
|
|
|
varlist: { /* nothing */ }
|
|
|
|
|
|
|
|
varlist: varlist varassign
|
|
|
|
{ /* nothing */ }
|
|
|
|
|
|
|
|
varassign: TOK_SET_VAR TOK_EQUALS valuelist
|
|
|
|
{
|
|
|
|
struct value_list *list = $3;
|
|
|
|
char *var_name = process_var($1);
|
|
|
|
int err;
|
|
|
|
if (!list || !list->value)
|
|
|
|
yyerror("Assert: valuelist returned NULL");
|
|
|
|
PDEBUG("Matched: set assignment for (%s)\n", $1);
|
|
|
|
err = new_set_var(var_name, list->value);
|
|
|
|
if (err) {
|
|
|
|
yyerror("variable %s was previously declared", $1);
|
|
|
|
/* FIXME: it'd be handy to report the previous location */
|
|
|
|
}
|
|
|
|
for (list = list->next; list; list = list->next) {
|
|
|
|
err = add_set_value(var_name, list->value);
|
|
|
|
if (err)
|
|
|
|
yyerror("Error adding %s to set var %s",
|
|
|
|
list->value, $1);
|
|
|
|
}
|
|
|
|
free_value_list($3);
|
|
|
|
free(var_name);
|
|
|
|
free($1);
|
|
|
|
}
|
|
|
|
|
|
|
|
varassign: TOK_SET_VAR TOK_ADD_ASSIGN valuelist
|
|
|
|
{
|
|
|
|
struct value_list *list = $3;
|
|
|
|
char *var_name = process_var($1);
|
|
|
|
int err;
|
|
|
|
if (!list || !list->value)
|
|
|
|
yyerror("Assert: valuelist returned NULL");
|
|
|
|
PDEBUG("Matched: additive assignment for (%s)\n", $1);
|
|
|
|
/* do the first one outside the loop, subsequent
|
|
|
|
* failures are indicative of symtab failures */
|
|
|
|
err = add_set_value(var_name, list->value);
|
|
|
|
if (err) {
|
|
|
|
yyerror("variable %s was not previously declared, but is being assigned additional values", $1);
|
|
|
|
}
|
|
|
|
for (list = list->next; list; list = list->next) {
|
|
|
|
err = add_set_value(var_name, list->value);
|
|
|
|
if (err)
|
|
|
|
yyerror("Error adding %s to set var %s",
|
|
|
|
list->value, $1);
|
|
|
|
}
|
|
|
|
free_value_list($3);
|
|
|
|
free(var_name);
|
|
|
|
free($1);
|
|
|
|
}
|
|
|
|
|
|
|
|
varassign: TOK_BOOL_VAR TOK_EQUALS TOK_VALUE
|
|
|
|
{
|
|
|
|
int boolean, err;
|
|
|
|
char *var_name = process_var($1);
|
|
|
|
PDEBUG("Matched: boolean assignment (%s) to %s\n", $1, $3);
|
|
|
|
boolean = str_to_boolean($3);
|
|
|
|
if (boolean == -1) {
|
|
|
|
yyerror("Invalid boolean assignment for (%s): %s is not true or false",
|
|
|
|
$1, $3);
|
|
|
|
}
|
|
|
|
err = add_boolean_var(var_name, boolean);
|
|
|
|
if (err) {
|
|
|
|
yyerror("variable %s was previously declared", $1);
|
|
|
|
/* FIXME: it'd be handy to report the previous location */
|
|
|
|
}
|
|
|
|
free(var_name);
|
|
|
|
free($1);
|
|
|
|
free($3);
|
|
|
|
}
|
|
|
|
|
|
|
|
valuelist: TOK_VALUE
|
|
|
|
{
|
|
|
|
struct value_list *new = malloc(sizeof(struct value_list));
|
|
|
|
if (!new)
|
|
|
|
yyerror(_("Memory allocation error."));
|
|
|
|
PDEBUG("Matched: value (%s)\n", $1);
|
|
|
|
|
|
|
|
new->value = $1;
|
|
|
|
new->next = NULL;
|
|
|
|
$$ = new;
|
|
|
|
}
|
|
|
|
|
|
|
|
valuelist: valuelist TOK_VALUE
|
|
|
|
{
|
|
|
|
struct value_list *new = malloc(sizeof(struct value_list));
|
|
|
|
if (!new)
|
|
|
|
yyerror(_("Memory allocation error."));
|
|
|
|
PDEBUG("Matched: value (%s)\n", $1);
|
|
|
|
|
|
|
|
new->value = $2;
|
|
|
|
new->next = $1;
|
|
|
|
$$ = new;
|
|
|
|
}
|
|
|
|
|
|
|
|
flags: { /* nothing */
|
|
|
|
struct flagval fv = { 0, 0, 0 };
|
|
|
|
|
|
|
|
$$ = fv;
|
|
|
|
};
|
|
|
|
|
|
|
|
flags: TOK_FLAGS TOK_EQUALS TOK_FLAG_OPENPAREN flagvals TOK_FLAG_CLOSEPAREN
|
|
|
|
{
|
|
|
|
$$ = $4;
|
|
|
|
};
|
|
|
|
|
2007-11-16 09:31:33 +00:00
|
|
|
flags: TOK_FLAG_OPENPAREN flagvals TOK_FLAG_CLOSEPAREN
|
|
|
|
{
|
|
|
|
$$ = $2;
|
|
|
|
}
|
|
|
|
|
2006-04-11 21:52:54 +00:00
|
|
|
flagvals: flagvals TOK_FLAG_SEP flagval
|
|
|
|
{
|
|
|
|
$1.complain = $1.complain || $3.complain;
|
|
|
|
$1.audit = $1.audit || $3.audit;
|
|
|
|
|
|
|
|
$$ = $1;
|
|
|
|
};
|
|
|
|
|
|
|
|
flagvals: flagval
|
|
|
|
{
|
|
|
|
$$ = $1;
|
|
|
|
};
|
|
|
|
|
2007-11-16 09:31:33 +00:00
|
|
|
flagval: TOK_FLAG_ID
|
2006-04-11 21:52:54 +00:00
|
|
|
{
|
2007-11-16 09:31:33 +00:00
|
|
|
struct flagval fv = {0, 0, 0};
|
|
|
|
if (strcmp($1, "debug") == 0) {
|
|
|
|
yyerror(_("Profile flag 'debug' is no longer valid."));
|
|
|
|
} else if (strcmp($1, "complain") == 0) {
|
|
|
|
fv.complain = 1;
|
|
|
|
} else if (strcmp($1, "audit") == 0) {
|
|
|
|
fv.audit = 1;
|
|
|
|
} else {
|
|
|
|
yyerror(_("Invalid profile flag: %s."), $1);
|
|
|
|
}
|
|
|
|
free($1);
|
2006-04-11 21:52:54 +00:00
|
|
|
$$ = fv;
|
|
|
|
};
|
|
|
|
|
|
|
|
rules: { /* nothing */
|
|
|
|
struct codomain *cod = NULL;
|
|
|
|
cod = (struct codomain *) calloc(1, sizeof(struct codomain));
|
|
|
|
if (!cod) {
|
|
|
|
yyerror(_("Memory allocation error."));
|
|
|
|
}
|
|
|
|
|
|
|
|
$$ = cod;
|
|
|
|
};
|
|
|
|
|
|
|
|
rules: rules rule
|
|
|
|
{
|
|
|
|
PDEBUG("matched: rules rule\n");
|
|
|
|
PDEBUG("rules rule: (%s)\n", $2->name);
|
|
|
|
if (!$2)
|
|
|
|
yyerror(_("Assert: `rule' returned NULL."));
|
|
|
|
add_entry_to_policy($1, $2);
|
|
|
|
$$ = $1;
|
|
|
|
};
|
|
|
|
|
2007-07-27 20:29:47 +00:00
|
|
|
rules: rules network_rule
|
|
|
|
{
|
|
|
|
struct aa_network_entry *entry, *tmp;
|
|
|
|
|
|
|
|
PDEBUG("Matched: network rule\n");
|
|
|
|
if (!$2)
|
|
|
|
yyerror(_("Assert: `network_rule' return invalid protocol."));
|
|
|
|
if (!$1->network_allowed) {
|
|
|
|
$1->network_allowed = calloc(AF_MAX,
|
|
|
|
sizeof(unsigned int));
|
|
|
|
if (!$1->network_allowed)
|
|
|
|
yyerror(_("Memory allocation error."));
|
|
|
|
}
|
|
|
|
list_for_each_safe($2, entry, tmp) {
|
|
|
|
if (entry->type > SOCK_PACKET) {
|
|
|
|
/* setting mask instead of a bit */
|
|
|
|
$1->network_allowed[entry->family] |= entry->type;
|
|
|
|
} else {
|
|
|
|
$1->network_allowed[entry->family] |= 1 << entry->type;
|
|
|
|
}
|
|
|
|
free(entry);
|
|
|
|
}
|
|
|
|
|
|
|
|
$$ = $1
|
|
|
|
}
|
|
|
|
|
2007-06-26 21:10:28 +00:00
|
|
|
rules: rules change_profile
|
|
|
|
{
|
|
|
|
PDEBUG("matched: rules change_profile\n");
|
|
|
|
PDEBUG("rules change_profile: (%s)\n", $2->name);
|
|
|
|
if (!$2)
|
|
|
|
yyerror(_("Assert: `change_profile' returned NULL."));
|
|
|
|
add_entry_to_policy($1, $2);
|
|
|
|
$$ = $1;
|
|
|
|
};
|
|
|
|
|
2006-04-11 21:52:54 +00:00
|
|
|
rules: rules capability
|
|
|
|
{
|
2007-11-16 09:32:38 +00:00
|
|
|
$1->capabilities = $1->capabilities | $2;
|
2006-04-11 21:52:54 +00:00
|
|
|
$$ = $1;
|
|
|
|
};
|
|
|
|
|
|
|
|
rules: rules hat
|
|
|
|
{
|
|
|
|
PDEBUG("Matched: hat rule\n");
|
|
|
|
if (!$2)
|
|
|
|
yyerror(_("Assert: 'hat rule' returned NULL."));
|
|
|
|
add_hat_to_policy($1, $2);
|
|
|
|
$$ = $1;
|
|
|
|
};
|
|
|
|
|
|
|
|
rules: rules cond_rule
|
|
|
|
{
|
|
|
|
PDEBUG("Matched: conditional rules\n");
|
|
|
|
$$ = merge_policy($1, $2);
|
|
|
|
}
|
|
|
|
|
|
|
|
cond_rule: TOK_IF expr TOK_OPEN rules TOK_CLOSE
|
|
|
|
{
|
|
|
|
struct codomain *ret = NULL;
|
|
|
|
PDEBUG("Matched: found conditional rules\n");
|
|
|
|
if ($2) {
|
|
|
|
ret = $4;
|
|
|
|
} else {
|
|
|
|
free_policy($4);
|
|
|
|
}
|
|
|
|
$$ = ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
cond_rule: TOK_IF expr TOK_OPEN rules TOK_CLOSE TOK_ELSE TOK_OPEN rules TOK_CLOSE
|
|
|
|
{
|
|
|
|
struct codomain *ret = NULL;
|
|
|
|
PDEBUG("Matched: found conditional else rules\n");
|
|
|
|
if ($2) {
|
|
|
|
ret = $4;
|
|
|
|
free_policy($8);
|
|
|
|
} else {
|
|
|
|
ret = $8;
|
|
|
|
free_policy($4);
|
|
|
|
}
|
|
|
|
$$ = ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
cond_rule: TOK_IF expr TOK_OPEN rules TOK_CLOSE TOK_ELSE cond_rule
|
|
|
|
{
|
|
|
|
struct codomain *ret = NULL;
|
|
|
|
PDEBUG("Matched: found conditional else-if rules\n");
|
|
|
|
if ($2) {
|
|
|
|
ret = $4;
|
|
|
|
free_policy($7);
|
|
|
|
} else {
|
|
|
|
ret = $7;
|
|
|
|
free_policy($4);
|
|
|
|
}
|
|
|
|
$$ = ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
expr: TOK_NOT expr
|
|
|
|
{
|
|
|
|
$$ = !$2;
|
|
|
|
}
|
|
|
|
|
|
|
|
expr: TOK_BOOL_VAR
|
|
|
|
{
|
|
|
|
char *var_name = process_var($1);
|
|
|
|
int boolean = get_boolean_var(var_name);
|
|
|
|
PDEBUG("Matched: boolean expr %s value: %d\n", $1, boolean);
|
|
|
|
if (boolean < 0) {
|
|
|
|
/* FIXME check for set var */
|
|
|
|
yyerror(_("Unset boolean variable %s used in if-expression"),
|
|
|
|
$1);
|
|
|
|
}
|
|
|
|
$$ = boolean;
|
|
|
|
free(var_name);
|
|
|
|
free($1);
|
|
|
|
}
|
|
|
|
|
|
|
|
expr: TOK_DEFINED TOK_SET_VAR
|
|
|
|
{
|
|
|
|
char *var_name = process_var($2);
|
|
|
|
void *set_value = get_set_var(var_name);
|
|
|
|
PDEBUG("Matched: defined set expr %s value %lx\n", $2, (long) set_value);
|
|
|
|
$$ = !! (long) set_value;
|
|
|
|
free(var_name);
|
|
|
|
free($2);
|
|
|
|
}
|
|
|
|
|
|
|
|
expr: TOK_DEFINED TOK_BOOL_VAR
|
|
|
|
{
|
|
|
|
char *var_name = process_var($2);
|
|
|
|
int boolean = get_boolean_var(var_name);
|
|
|
|
PDEBUG("Matched: defined set expr %s value %d\n", $2, boolean);
|
|
|
|
$$ = (boolean != -1);
|
|
|
|
free(var_name);
|
|
|
|
free($2);
|
|
|
|
}
|
|
|
|
|
2007-11-16 09:30:08 +00:00
|
|
|
id_or_var: TOK_ID { $$ = $1; }
|
|
|
|
id_or_var: TOK_SET_VAR { $$ = $1; };
|
2006-04-11 21:52:54 +00:00
|
|
|
|
2007-11-16 09:30:08 +00:00
|
|
|
rule: id_or_var file_mode TOK_END_OF_RULE
|
2006-04-11 21:52:54 +00:00
|
|
|
{
|
2007-11-16 09:18:48 +00:00
|
|
|
$$ = do_file_rule(NULL, $1, $2);
|
2007-07-27 20:55:25 +00:00
|
|
|
};
|
|
|
|
|
2007-11-16 09:30:08 +00:00
|
|
|
rule: file_mode id_or_var TOK_END_OF_RULE
|
2007-07-27 20:55:25 +00:00
|
|
|
{
|
2007-11-16 09:18:48 +00:00
|
|
|
$$ = do_file_rule(NULL, $2, $1 & ~AA_EXEC_UNSAFE);
|
2007-07-27 20:55:25 +00:00
|
|
|
};
|
|
|
|
|
2007-11-16 09:30:08 +00:00
|
|
|
rule: TOK_UNSAFE file_mode id_or_var TOK_END_OF_RULE
|
2007-07-27 20:55:25 +00:00
|
|
|
{
|
|
|
|
if (!($2 & AA_MAY_EXEC))
|
|
|
|
yyerror(_("unsafe rule missing exec permissions"));
|
2007-11-16 09:18:48 +00:00
|
|
|
$$ = do_file_rule(NULL, $3, $2 | AA_EXEC_UNSAFE);
|
2007-07-27 20:55:25 +00:00
|
|
|
};
|
|
|
|
|
2007-11-16 09:30:08 +00:00
|
|
|
rule: id_or_var file_mode id_or_var
|
2006-04-11 21:52:54 +00:00
|
|
|
{
|
|
|
|
/* Oopsie, we appear to be missing an EOL marker. If we
|
|
|
|
* were *smart*, we could work around it. Since we're
|
|
|
|
* obviously not smart, we'll just punt with a more
|
|
|
|
* sensible error. */
|
|
|
|
yyerror(_("missing an end of line character? (entry: %s)"), $1);
|
|
|
|
};
|
|
|
|
|
2007-07-27 20:48:24 +00:00
|
|
|
hat: hat_start TOK_ID flags TOK_OPEN rules TOK_CLOSE
|
2006-04-11 21:52:54 +00:00
|
|
|
{
|
|
|
|
struct codomain *cod = $5;
|
|
|
|
PDEBUG("Matched: sep id (%s) open rules close\n", $2);
|
|
|
|
if (!cod) {
|
|
|
|
yyerror(_("Memory allocation error."));
|
|
|
|
}
|
|
|
|
cod->name = $2;
|
|
|
|
cod->flags = $3;
|
|
|
|
if (force_complain)
|
|
|
|
cod->flags = force_complain_flags;
|
|
|
|
PDEBUG("^%s: flags='%s%s'\n",
|
|
|
|
$2,
|
|
|
|
cod->flags.complain ? "complain, " : "",
|
|
|
|
cod->flags.audit ? "audit" : "");
|
|
|
|
$$ = cod;
|
|
|
|
};
|
|
|
|
|
2007-07-27 20:29:47 +00:00
|
|
|
network_rule: TOK_NETWORK TOK_END_OF_RULE
|
|
|
|
{
|
|
|
|
int family;
|
|
|
|
struct aa_network_entry *new_entry, *entry = NULL;
|
|
|
|
for (family = AF_UNSPEC; family < AF_MAX; family++) {
|
|
|
|
new_entry = new_network_ent(family, 0xffffffff,
|
|
|
|
0xffffffff);
|
|
|
|
if (!new_entry)
|
|
|
|
yyerror(_("Memory allocation error."));
|
|
|
|
new_entry->next = entry;
|
|
|
|
entry = new_entry;
|
|
|
|
}
|
|
|
|
$$ = entry;
|
|
|
|
}
|
|
|
|
|
|
|
|
network_rule: TOK_NETWORK TOK_ID TOK_END_OF_RULE
|
|
|
|
{
|
|
|
|
struct aa_network_entry *entry;
|
|
|
|
entry = network_entry($2, NULL, NULL);
|
|
|
|
if (!entry)
|
|
|
|
/* test for short circuiting of family */
|
|
|
|
entry = network_entry(NULL, $2, NULL);
|
|
|
|
if (!entry)
|
|
|
|
yyerror(_("Invalid network entry."));
|
|
|
|
free($2);
|
|
|
|
$$ = entry;
|
|
|
|
}
|
|
|
|
|
|
|
|
network_rule: TOK_NETWORK TOK_ID TOK_ID TOK_END_OF_RULE
|
|
|
|
{
|
|
|
|
struct aa_network_entry *entry;
|
|
|
|
entry = network_entry($2, $3, NULL);
|
|
|
|
if (!entry)
|
|
|
|
yyerror(_("Invalid network entry."));
|
|
|
|
free($2);
|
|
|
|
free($3);
|
|
|
|
$$ = entry;
|
|
|
|
}
|
2006-04-11 21:52:54 +00:00
|
|
|
|
2007-07-27 20:48:24 +00:00
|
|
|
hat_start: TOK_SEP {}
|
|
|
|
| TOK_HAT {}
|
|
|
|
|
2007-07-27 20:47:17 +00:00
|
|
|
file_mode: TOK_MODE
|
|
|
|
{
|
|
|
|
$$ = parse_mode($1);
|
|
|
|
free($1);
|
|
|
|
}
|
2006-04-11 21:52:54 +00:00
|
|
|
|
2007-06-26 21:10:28 +00:00
|
|
|
change_profile: TOK_CHANGE_PROFILE TOK_ID TOK_END_OF_RULE
|
|
|
|
{
|
|
|
|
struct cod_entry *entry;
|
|
|
|
PDEBUG("Matched change_profile: tok_id (%s)\n", $2);
|
2007-11-16 09:18:48 +00:00
|
|
|
entry = new_entry(NULL, $2, AA_CHANGE_PROFILE);
|
|
|
|
if (!entry)
|
|
|
|
yyerror(_("Memory allocation error."));
|
|
|
|
PDEBUG("change_profile.entry: (%s)\n", entry->name);
|
|
|
|
$$ = entry;
|
|
|
|
};
|
|
|
|
|
|
|
|
change_profile: TOK_CHANGE_PROFILE TOK_ID TOK_COLON TOK_ID TOK_END_OF_RULE
|
|
|
|
{
|
|
|
|
struct cod_entry *entry;
|
|
|
|
PDEBUG("Matched change_profile: tok_id (%s:%s)\n", $2, $4);
|
|
|
|
entry = new_entry($2, $4, AA_CHANGE_PROFILE);
|
2007-06-26 21:10:28 +00:00
|
|
|
if (!entry)
|
|
|
|
yyerror(_("Memory allocation error."));
|
|
|
|
PDEBUG("change_profile.entry: (%s)\n", entry->name);
|
|
|
|
$$ = entry;
|
|
|
|
};
|
|
|
|
|
2007-11-16 09:32:38 +00:00
|
|
|
capability: TOK_CAPABILITY caps TOK_END_OF_RULE
|
2006-04-11 21:52:54 +00:00
|
|
|
{
|
|
|
|
$$ = $2;
|
|
|
|
};
|
|
|
|
|
2007-11-16 09:32:38 +00:00
|
|
|
caps: caps TOK_ID
|
|
|
|
{
|
|
|
|
int cap = name_to_capability($2);
|
|
|
|
if (cap == -1)
|
|
|
|
yyerror(_("Invalid capability %s."), $2);
|
|
|
|
$$ = $1 | CAP_TO_MASK(cap);
|
|
|
|
}
|
|
|
|
|
|
|
|
caps: TOK_ID
|
|
|
|
{
|
|
|
|
int cap = name_to_capability($1);
|
|
|
|
if (cap == -1)
|
|
|
|
yyerror(_("Invalid capability %s."), $1);
|
|
|
|
$$ = CAP_TO_MASK(cap);
|
|
|
|
};
|
|
|
|
|
2006-04-11 21:52:54 +00:00
|
|
|
%%
|
|
|
|
#define MAXBUFSIZE 4096
|
|
|
|
|
|
|
|
void yyerror(char *msg, ...)
|
|
|
|
{
|
|
|
|
va_list arg;
|
|
|
|
char buf[MAXBUFSIZE];
|
|
|
|
|
|
|
|
va_start(arg, msg);
|
|
|
|
vsnprintf(buf, sizeof(buf), msg, arg);
|
|
|
|
va_end(arg);
|
|
|
|
|
|
|
|
if (profilename) {
|
|
|
|
PERROR(_("AppArmor parser error in %s at line %d: %s\n"),
|
|
|
|
profilename, current_lineno, buf);
|
|
|
|
} else {
|
|
|
|
PERROR(_("AppArmor parser error, line %d: %s\n"),
|
|
|
|
current_lineno, buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void free_value_list(struct value_list *list)
|
|
|
|
{
|
|
|
|
struct value_list *next;
|
|
|
|
|
|
|
|
while (list) {
|
|
|
|
next = list->next;
|
|
|
|
if (list->value)
|
|
|
|
free(list->value);
|
|
|
|
free(list);
|
|
|
|
list = next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-11-16 09:18:48 +00:00
|
|
|
struct cod_entry *do_file_rule(char *namespace, char *id, int mode)
|
2007-07-27 20:55:25 +00:00
|
|
|
{
|
|
|
|
struct cod_entry *entry;
|
|
|
|
PDEBUG("Matched: tok_id (%s) tok_mode (0x%x)\n", id, mode);
|
2007-11-16 09:18:48 +00:00
|
|
|
entry = new_entry(namespace, id, mode);
|
2007-07-27 20:55:25 +00:00
|
|
|
if (!entry)
|
|
|
|
yyerror(_("Memory allocation error."));
|
|
|
|
PDEBUG("rule.entry: (%s)\n", entry->name);
|
|
|
|
return entry;
|
|
|
|
}
|