2
0
mirror of https://gitlab.com/apparmor/apparmor synced 2025-08-22 01:57:43 +00:00
apparmor/parser/dbus.c
Steve Beattie dd5145131e Subject: parser - use DUP_STRING more widely and detect strdup errors
This patch moves the DUP_STRING macro to parser.h and modifies
it to accept a goto error target, that will be jumped to if the
call to strdup(3) fails. It also uses it in additional locations
where copying structures occurs, as well as detecting additional
cases where a structure duplication might have failed but not been
propagated outward.

Signed-off-by: Steve Beattie <steve@nxnw.org>
Acked-by: Tyler Hicks <tyhicks@canonical.com>
2013-09-06 13:39:41 -07:00

209 lines
5.6 KiB
C

/*
* 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>
#include "parser.h"
#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");
} else {
ent->mode = AA_VALID_DBUS_PERMS;
if (message_rule)
ent->mode &= ~AA_DBUS_BIND;
else if (service_rule)
ent->mode &= ~(AA_DBUS_SEND | AA_DBUS_RECEIVE);
}
out:
free_cond_list(conds);
return ent;
}
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;
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);
ent->mode = orig->mode;
ent->audit = orig->audit;
ent->deny = orig->deny;
ent->next = orig->next;
return ent;
err:
free_dbus_entry(ent);
return NULL;
}
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 ");
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");
}