spec: remove unused files
[platform/upstream/dbus.git] / bus / smack.c
1 /* smack.c - Provide interface to query smack context
2  *
3  * Author: Brian McGillion <brian.mcgillion@intel.com>
4  * Copyright © 2011 Intel Corporation
5  *
6  * Licensed under the Academic Free License version 2.1
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21  * 02110-1301 USA
22  */
23
24 #include <config.h>
25 #include "smack.h"
26
27 #include <dbus/dbus-internals.h>
28
29 #include "connection.h"
30 #include "services.h"
31 #include "utils.h"
32 #include "policy.h"
33
34 #ifdef DBUS_ENABLE_SMACK
35 #include <sys/smack.h>
36 #endif
37
38 #define SMACK_WRITE "W"
39 #define SMACK_READ "R"
40 #define SMACK_READ_WRITE "RW"
41
42
43 BusResult
44 bus_smack_handle_get_connection_context (DBusConnection *connection,
45                                          BusTransaction *transaction,
46                                          DBusMessage    *message,
47                                          DBusError      *error)
48 {
49 #ifdef DBUS_ENABLE_SMACK
50   const char *remote_end = NULL;
51   BusRegistry *registry;
52   DBusString remote_end_str;
53   BusService *service;
54   DBusConnection *remote_connection;
55   DBusMessage *reply = NULL;
56   const char *label;
57
58   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
59
60   registry = bus_connection_get_registry (connection);
61
62   if (!dbus_message_get_args (message, error, DBUS_TYPE_STRING, &remote_end,
63                               DBUS_TYPE_INVALID))
64     return BUS_RESULT_FALSE;
65
66   _dbus_verbose ("asked for label of connection %s\n", remote_end);
67
68   _dbus_string_init_const (&remote_end_str, remote_end);
69
70   service = bus_registry_lookup (registry, &remote_end_str);
71   if (service == NULL)
72     {
73       dbus_set_error (error, DBUS_ERROR_NAME_HAS_NO_OWNER,
74                       "Bus name '%s' has no owner", remote_end);
75       return BUS_RESULT_FALSE;
76     }
77
78   remote_connection = bus_service_get_primary_owners_connection (service);
79   if (remote_connection == NULL)
80     goto oom;
81
82   reply = dbus_message_new_method_return (message);
83   if (reply == NULL)
84     goto oom;
85
86   if (!dbus_connection_get_smack_label(remote_connection, &label))
87     {
88       dbus_set_error (error, DBUS_ERROR_FAILED,
89                       "Failed to get the socket fd of the connection",
90                       remote_end);
91       goto err;
92     }
93
94   if (!dbus_message_append_args (reply, DBUS_TYPE_STRING,
95                                  &label, DBUS_TYPE_INVALID))
96     goto oom;
97
98   if (!bus_transaction_send_from_driver (transaction, connection, reply))
99     goto oom;
100
101   dbus_message_unref (reply);
102
103   return BUS_RESULT_TRUE;
104
105 oom:
106   BUS_SET_OOM (error);
107
108 err:
109   if (reply != NULL)
110     dbus_message_unref (reply);
111
112   return BUS_RESULT_FALSE;
113 #else
114   dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED,
115                   "SMACK support is not enabled");
116   return BUS_RESULT_FALSE;
117 #endif
118 }
119
120 #ifdef DBUS_ENABLE_SMACK
121 static dbus_bool_t
122 bus_smack_has_access (const char *subject, const char *object,
123                       const char *access)
124 {
125   return (smack_have_access (subject, object, access) == 1 ? TRUE : FALSE);
126 }
127 #endif
128
129
130 /**
131  * Calculate the list of rules that apply to a connection.
132  *
133  * @param connection The inbound conenction
134  * @param rules_by_smack_label The table of object labels -> rules mapping
135  * @param nomem_err (out) If a nomem situation is encountered this value is set to TRUE.
136  * @returns the list of permitted rules if it exists and no errors were encountered otherwise NULL.
137  */
138 DBusList**
139 bus_smack_generate_allowed_list (DBusConnection *connection,
140                                  DBusHashTable  *rules_by_smack_label,
141                                  dbus_bool_t *nomem_err)
142 {
143 #ifdef DBUS_ENABLE_SMACK
144   const char *subject_label;
145   DBusHashIter iter;
146   dbus_bool_t is_allowed;
147   DBusList **allowed_list;
148
149   /* the label of the subject, is the label on the new connection,
150      either the service itself or one of its clients */
151
152   if (!dbus_connection_get_smack_label(connection, &subject_label))
153     return NULL;
154
155   allowed_list = dbus_new0 (DBusList*, 1);
156   if (allowed_list == NULL)
157     goto nomem;
158
159   /* Iterate over all the smack labels we have parsed from the .conf files */
160   _dbus_hash_iter_init (rules_by_smack_label, &iter);
161   while (_dbus_hash_iter_next (&iter))
162     {
163       DBusList *link;
164       const char *object_label = _dbus_hash_iter_get_string_key (&iter);
165       /* the list here is all the rules that are 'protected'
166          by the SMACK label named $object_label */
167       DBusList **list = _dbus_hash_iter_get_value (&iter);
168
169       link = _dbus_list_get_first_link (list);
170       while (link != NULL)
171         {
172           BusPolicyRule *rule = link->data;
173           link = _dbus_list_get_next_link (list, link);
174           is_allowed = FALSE;
175
176           switch (rule->type)
177             {
178             case BUS_POLICY_RULE_OWN:
179               is_allowed = bus_smack_has_access (subject_label,
180                                                  object_label,
181                                                  SMACK_READ_WRITE);
182               break;
183             case BUS_POLICY_RULE_SEND:
184               is_allowed = bus_smack_has_access (subject_label,
185                                                  object_label,
186                                                  SMACK_WRITE);
187               break;
188             case BUS_POLICY_RULE_RECEIVE:
189               is_allowed = bus_smack_has_access (subject_label,
190                                                  object_label,
191                                                  SMACK_READ);
192               break;
193             default:
194               continue;
195             }
196
197           if (is_allowed)
198             {
199               if (!_dbus_list_append (allowed_list, rule))
200                 goto nomem;
201
202               bus_policy_rule_ref (rule);
203             }
204
205           _dbus_verbose ("permission request subject (%s) -> object (%s) : %s", subject_label, object_label, (is_allowed ? "GRANTED" : "REJECTED"));
206         }
207     }
208
209   return allowed_list;
210
211 nomem:
212   if (allowed_list != NULL) {
213     _dbus_list_clear (allowed_list);
214     dbus_free (allowed_list);
215   }
216
217   *nomem_err = TRUE;
218   return NULL;
219
220 #else
221   return NULL;
222 #endif
223 }