2013-07-31 09:05:51 -07:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2013
|
|
|
|
* Canonical, Ltd. (All rights reserved)
|
|
|
|
*
|
|
|
|
* 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. or Canonical
|
|
|
|
* Ltd.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
Move public mediation class types and perms to apparmor.h
Now that the parser links against libapparmor, it makes sense to move
all public permission types and flags to libapparmor's apparmor.h. This
prevents duplication across header files for the parser and libapparmor.
Additionally, this patch breaks the connection between
AA_DBUS_{SEND,RECEIVE,BIND} and AA_MAY_{WRITE,READ,BIND} by using raw
values when defining the AA_DBUS_{SEND,RECEIVE,BIND} macros. This makes
sense because the two sets of permission flags are from two distinctly
different mediation types (AA_CLASS_DBUS and AA_CLASS_FILE). While it is
nice that they share some of the same values, the macros don't need to
be linked together. In other words, when you're creating a D-Bus rule,
it would be incorrect to use permission flags from the AA_CLASS_FILE
type.
The change mentioned above allows the AA_MAY_{WRITE,READ,BIND} macros
to be removed from public-facing apparmor.h header.
Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
Acked-by: Seth Arnold <seth.arnold@canonical.com>
2013-12-06 11:20:06 -08:00
|
|
|
#include <apparmor.h>
|
2013-07-31 09:05:51 -07:00
|
|
|
|
|
|
|
#include "parser.h"
|
2013-09-27 16:16:37 -07:00
|
|
|
#include "profile.h"
|
2013-07-31 09:05:51 -07:00
|
|
|
#include "parser_yacc.h"
|
|
|
|
#include "dbus.h"
|
|
|
|
|
|
|
|
void free_dbus_entry(struct dbus_entry *ent)
|
|
|
|
{
|
|
|
|
if (!ent)
|
|
|
|
return;
|
|
|
|
free(ent->bus);
|
|
|
|
free(ent->name);
|
|
|
|
free(ent->peer_label);
|
|
|
|
free(ent->path);
|
|
|
|
free(ent->interface);
|
|
|
|
free(ent->member);
|
|
|
|
|
|
|
|
free(ent);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int list_len(struct value_list *v)
|
|
|
|
{
|
|
|
|
int len = 0;
|
|
|
|
struct value_list *tmp;
|
|
|
|
|
|
|
|
list_for_each(v, tmp)
|
|
|
|
len++;
|
|
|
|
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void move_conditional_value(char **dst_ptr, struct cond_entry *cond_ent)
|
|
|
|
{
|
|
|
|
if (*dst_ptr)
|
|
|
|
yyerror("dbus conditional \"%s\" can only be specified once\n",
|
|
|
|
cond_ent->name);
|
|
|
|
|
|
|
|
*dst_ptr = cond_ent->vals->value;
|
|
|
|
cond_ent->vals->value = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void move_conditionals(struct dbus_entry *ent, struct cond_entry *conds)
|
|
|
|
{
|
|
|
|
struct cond_entry *cond_ent;
|
|
|
|
|
|
|
|
list_for_each(conds, cond_ent) {
|
|
|
|
/* for now disallow keyword 'in' (list) */
|
|
|
|
if (!cond_ent->eq)
|
|
|
|
yyerror("keyword \"in\" is not allowed in dbus rules\n");
|
|
|
|
if (list_len(cond_ent->vals) > 1)
|
|
|
|
yyerror("dbus conditional \"%s\" only supports a single value\n",
|
|
|
|
cond_ent->name);
|
|
|
|
|
|
|
|
if (strcmp(cond_ent->name, "bus") == 0) {
|
|
|
|
move_conditional_value(&ent->bus, cond_ent);
|
|
|
|
} else if (strcmp(cond_ent->name, "name") == 0) {
|
|
|
|
move_conditional_value(&ent->name, cond_ent);
|
|
|
|
} else if (strcmp(cond_ent->name, "label") == 0) {
|
|
|
|
move_conditional_value(&ent->peer_label, cond_ent);
|
|
|
|
} else if (strcmp(cond_ent->name, "path") == 0) {
|
|
|
|
move_conditional_value(&ent->path, cond_ent);
|
|
|
|
} else if (strcmp(cond_ent->name, "interface") == 0) {
|
|
|
|
move_conditional_value(&ent->interface, cond_ent);
|
|
|
|
} else if (strcmp(cond_ent->name, "member") == 0) {
|
|
|
|
move_conditional_value(&ent->member, cond_ent);
|
|
|
|
} else {
|
|
|
|
yyerror("invalid dbus conditional \"%s\"\n",
|
|
|
|
cond_ent->name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct dbus_entry *new_dbus_entry(int mode, struct cond_entry *conds,
|
|
|
|
struct cond_entry *peer_conds)
|
|
|
|
{
|
|
|
|
struct dbus_entry *ent;
|
|
|
|
int name_is_subject_cond = 0, message_rule = 0, service_rule = 0;
|
|
|
|
|
|
|
|
ent = (struct dbus_entry*) calloc(1, sizeof(struct dbus_entry));
|
|
|
|
if (!ent)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
/* Move the global/subject conditionals over & check the results */
|
|
|
|
move_conditionals(ent, conds);
|
|
|
|
if (ent->name)
|
|
|
|
name_is_subject_cond = 1;
|
|
|
|
if (ent->peer_label)
|
|
|
|
yyerror("dbus \"label\" conditional can only be used inside of the \"peer=()\" grouping\n");
|
|
|
|
|
|
|
|
/* Move the peer conditionals */
|
|
|
|
move_conditionals(ent, peer_conds);
|
|
|
|
|
|
|
|
if (ent->path || ent->interface || ent->member || ent->peer_label ||
|
|
|
|
(ent->name && !name_is_subject_cond))
|
|
|
|
message_rule = 1;
|
|
|
|
|
|
|
|
if (ent->name && name_is_subject_cond)
|
|
|
|
service_rule = 1;
|
|
|
|
|
|
|
|
if (message_rule && service_rule)
|
|
|
|
yyerror("dbus rule contains message conditionals and service conditionals\n");
|
|
|
|
|
|
|
|
/* Copy mode. If no mode was specified, assign an implied mode. */
|
|
|
|
if (mode) {
|
|
|
|
ent->mode = mode;
|
|
|
|
if (ent->mode & ~AA_VALID_DBUS_PERMS)
|
|
|
|
yyerror("mode contains unknown dbus accesss\n");
|
|
|
|
else if (message_rule && (ent->mode & AA_DBUS_BIND))
|
|
|
|
yyerror("dbus \"bind\" access cannot be used with message rule conditionals\n");
|
|
|
|
else if (service_rule && (ent->mode & (AA_DBUS_SEND | AA_DBUS_RECEIVE)))
|
|
|
|
yyerror("dbus \"send\" and/or \"receive\" accesses cannot be used with service rule conditionals\n");
|
parser: Add dbus eavesdrop permission support to apparmor_parser
Allows for the policy writer to grant permission to eavesdrop on the
specified bus. Some example rules for granting the eavesdrop permission
are:
# Grant send, receive, bind, and eavesdrop
dbus,
# Grant send, receive, bind, and eavesdrop on the session bus
dbus bus=session,
# Grant send and eavesdrop on the system bus
dbus (send eavesdrop) bus=system,
# Grant eavesdrop on any bus
dbus eavesdrop,
Eavesdropping rules can contain the bus conditional. Any other
conditionals are not compatible with eavesdropping rules and the parser
will return an error.
Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
Acked-by: Seth Arnold <seth.arnold@canonical.com>
2013-12-06 11:17:43 -08:00
|
|
|
else if (ent->mode & AA_DBUS_EAVESDROP &&
|
|
|
|
(ent->path || ent->interface || ent->member ||
|
|
|
|
ent->peer_label || ent->name)) {
|
|
|
|
yyerror("dbus \"eavesdrop\" access can only contain a bus conditional\n");
|
|
|
|
}
|
2013-07-31 09:05:51 -07:00
|
|
|
} else {
|
|
|
|
if (message_rule)
|
parser: Add dbus eavesdrop permission support to apparmor_parser
Allows for the policy writer to grant permission to eavesdrop on the
specified bus. Some example rules for granting the eavesdrop permission
are:
# Grant send, receive, bind, and eavesdrop
dbus,
# Grant send, receive, bind, and eavesdrop on the session bus
dbus bus=session,
# Grant send and eavesdrop on the system bus
dbus (send eavesdrop) bus=system,
# Grant eavesdrop on any bus
dbus eavesdrop,
Eavesdropping rules can contain the bus conditional. Any other
conditionals are not compatible with eavesdropping rules and the parser
will return an error.
Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
Acked-by: Seth Arnold <seth.arnold@canonical.com>
2013-12-06 11:17:43 -08:00
|
|
|
ent->mode = (AA_DBUS_SEND | AA_DBUS_RECEIVE);
|
2013-07-31 09:05:51 -07:00
|
|
|
else if (service_rule)
|
parser: Add dbus eavesdrop permission support to apparmor_parser
Allows for the policy writer to grant permission to eavesdrop on the
specified bus. Some example rules for granting the eavesdrop permission
are:
# Grant send, receive, bind, and eavesdrop
dbus,
# Grant send, receive, bind, and eavesdrop on the session bus
dbus bus=session,
# Grant send and eavesdrop on the system bus
dbus (send eavesdrop) bus=system,
# Grant eavesdrop on any bus
dbus eavesdrop,
Eavesdropping rules can contain the bus conditional. Any other
conditionals are not compatible with eavesdropping rules and the parser
will return an error.
Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
Acked-by: Seth Arnold <seth.arnold@canonical.com>
2013-12-06 11:17:43 -08:00
|
|
|
ent->mode = (AA_DBUS_BIND);
|
|
|
|
else
|
|
|
|
ent->mode = AA_VALID_DBUS_PERMS;
|
2013-07-31 09:05:51 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
|
|
|
free_cond_list(conds);
|
2013-09-06 13:41:03 -07:00
|
|
|
free_cond_list(peer_conds);
|
2013-07-31 09:05:51 -07:00
|
|
|
return ent;
|
|
|
|
}
|
|
|
|
|
2013-08-29 12:34:13 -07:00
|
|
|
struct dbus_entry *dup_dbus_entry(struct dbus_entry *orig)
|
|
|
|
{
|
|
|
|
struct dbus_entry *ent = NULL;
|
|
|
|
ent = (struct dbus_entry *) calloc(1, sizeof(struct dbus_entry));
|
|
|
|
if (!ent)
|
|
|
|
return NULL;
|
|
|
|
|
2013-09-06 13:39:41 -07:00
|
|
|
DUP_STRING(orig, ent, bus, err);
|
|
|
|
DUP_STRING(orig, ent, name, err);
|
|
|
|
DUP_STRING(orig, ent, peer_label, err);
|
|
|
|
DUP_STRING(orig, ent, path, err);
|
|
|
|
DUP_STRING(orig, ent, interface, err);
|
|
|
|
DUP_STRING(orig, ent, member, err);
|
2013-08-29 12:34:13 -07:00
|
|
|
ent->mode = orig->mode;
|
|
|
|
ent->audit = orig->audit;
|
|
|
|
ent->deny = orig->deny;
|
|
|
|
|
|
|
|
ent->next = orig->next;
|
|
|
|
|
|
|
|
return ent;
|
2013-09-06 13:39:41 -07:00
|
|
|
|
|
|
|
err:
|
|
|
|
free_dbus_entry(ent);
|
|
|
|
return NULL;
|
2013-08-29 12:34:13 -07:00
|
|
|
}
|
2013-07-31 09:05:51 -07:00
|
|
|
|
|
|
|
void print_dbus_entry(struct dbus_entry *ent)
|
|
|
|
{
|
|
|
|
if (ent->audit)
|
|
|
|
fprintf(stderr, "audit ");
|
|
|
|
if (ent->deny)
|
|
|
|
fprintf(stderr, "deny ");
|
|
|
|
|
|
|
|
fprintf(stderr, "dbus ( ");
|
|
|
|
|
|
|
|
if (ent->mode & AA_DBUS_SEND)
|
|
|
|
fprintf(stderr, "send ");
|
|
|
|
if (ent->mode & AA_DBUS_RECEIVE)
|
|
|
|
fprintf(stderr, "receive ");
|
|
|
|
if (ent->mode & AA_DBUS_BIND)
|
|
|
|
fprintf(stderr, "bind ");
|
parser: Add dbus eavesdrop permission support to apparmor_parser
Allows for the policy writer to grant permission to eavesdrop on the
specified bus. Some example rules for granting the eavesdrop permission
are:
# Grant send, receive, bind, and eavesdrop
dbus,
# Grant send, receive, bind, and eavesdrop on the session bus
dbus bus=session,
# Grant send and eavesdrop on the system bus
dbus (send eavesdrop) bus=system,
# Grant eavesdrop on any bus
dbus eavesdrop,
Eavesdropping rules can contain the bus conditional. Any other
conditionals are not compatible with eavesdropping rules and the parser
will return an error.
Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
Acked-by: Seth Arnold <seth.arnold@canonical.com>
2013-12-06 11:17:43 -08:00
|
|
|
if (ent->mode & AA_DBUS_EAVESDROP)
|
|
|
|
fprintf(stderr, "eavesdrop ");
|
2013-07-31 09:05:51 -07:00
|
|
|
fprintf(stderr, ")");
|
|
|
|
|
|
|
|
if (ent->bus)
|
|
|
|
fprintf(stderr, " bus=\"%s\"", ent->bus);
|
|
|
|
if ((ent->mode & AA_DBUS_BIND) && ent->name)
|
|
|
|
fprintf(stderr, " name=\"%s\"", ent->name);
|
|
|
|
if (ent->path)
|
|
|
|
fprintf(stderr, " path=\"%s\"", ent->path);
|
|
|
|
if (ent->interface)
|
|
|
|
fprintf(stderr, " interface=\"%s\"", ent->interface);
|
|
|
|
if (ent->member)
|
|
|
|
fprintf(stderr, " member=\"%s\"", ent->member);
|
|
|
|
|
|
|
|
if (!(ent->mode & AA_DBUS_BIND) && (ent->peer_label || ent->name)) {
|
|
|
|
fprintf(stderr, " peer=( ");
|
|
|
|
if (ent->peer_label)
|
|
|
|
fprintf(stderr, "label=\"%s\" ", ent->peer_label);
|
|
|
|
if (ent->name)
|
|
|
|
fprintf(stderr, "name=\"%s\" ", ent->name);
|
|
|
|
fprintf(stderr, ")");
|
|
|
|
}
|
|
|
|
|
|
|
|
fprintf(stderr, ",\n");
|
|
|
|
}
|