b0466ee3d8ba183be5b415eb87246a2d7dddf73a
[platform/upstream/dbus.git] / bus / kdbus-d.c
1 /*
2  * kdbus-d.c
3  *
4  *  Created on: Sep 4, 2013
5  *      Author: r.pajak
6  *
7  *  kdbus add-on to dbus daemon
8  *
9  */
10
11 #include <dbus/dbus-connection-internal.h>
12 #include "kdbus-d.h"
13 #include <dbus/kdbus.h>
14 #include <dbus/dbus-bus.h>
15 #include "dispatch.h"
16 #include <dbus/kdbus-common.h>
17 #include <dbus/dbus-transport.h>
18 #include <dbus/dbus-transport-kdbus.h>
19 #include "connection.h"
20
21 #include <utils.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <fcntl.h>
25 #include <unistd.h>
26 #include <errno.h>
27
28 //todo there should be no include below - needed functions should be moved to kdbus-common
29 #include <dbus/dbus-transport-kdbus.h>
30
31 __u64 sender_name_to_id(const char* name, DBusError* error)
32 {
33         __u64 sender_id = 0;
34
35         if(!strncmp(name, ":1.", 3)) /*if name is unique name it must be converted to unique id*/
36                 sender_id = strtoull(&name[3], NULL, 10);
37         else
38                 dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, "Could not convert sender of the message into kdbus unique id");
39
40         return sender_id;
41 }
42
43 char* make_kdbus_bus(DBusBusType type, DBusError *error)
44 {
45     struct {
46         struct kdbus_cmd_bus_make head;
47         uint64_t n_size;
48         uint64_t n_type;
49         char name[64];
50     } __attribute__ ((__aligned__(8))) bus_make;
51
52     int fdc, ret;
53     char *bus;
54
55     /*TODO Distinguish session and system bus make*/
56     /*TODO Add dbus_set_error(error, DBUS_ERROR_FAILED,  "...") (?)*/
57
58     _dbus_verbose("Opening /dev/kdbus/control\n");
59     fdc = open("/dev/kdbus/control", O_RDWR|O_CLOEXEC);
60     if (fdc < 0)
61     {
62         _dbus_verbose("--- error %d (%m)\n", fdc);
63         return NULL;
64     }
65
66     memset(&bus_make, 0, sizeof(bus_make));
67     bus_make.head.bloom_size = 64;
68     bus_make.head.flags = KDBUS_MAKE_ACCESS_WORLD;
69
70     snprintf(bus_make.name, sizeof(bus_make.name), "%u-kdbus", getuid());
71     bus_make.n_type = KDBUS_MAKE_NAME;
72     bus_make.n_size = KDBUS_PART_HEADER_SIZE + strlen(bus_make.name) + 1;
73     bus_make.head.size = sizeof(struct kdbus_cmd_bus_make) + bus_make.n_size;
74
75     _dbus_verbose("Creating bus '%s'\n", bus_make.name);
76     ret = ioctl(fdc, KDBUS_CMD_BUS_MAKE, &bus_make);
77     if (ret)
78     {
79         _dbus_verbose("--- error %d (%m)\n", ret);
80         return NULL;
81     }
82
83     if (asprintf(&bus, "kdbus:path=/dev/kdbus/%s/bus", bus_make.name) < 0)
84     {
85         BUS_SET_OOM (error);
86         return NULL;
87     }
88
89     _dbus_verbose("Return value '%s'\n", bus);
90         return bus;
91 }
92
93 DBusServer* empty_server_init(char* address)
94 {
95         return dbus_server_init_mini(address);
96 }
97
98 DBusConnection* daemon_as_client(DBusBusType type, char* address, DBusError *error)
99 {
100         DBusConnection* connection;
101         DBusString daemon_name;
102
103         dbus_bus_set_bus_connection_address(type, address);
104
105         connection = dbus_bus_get(type, error);
106         if(connection == NULL)
107                 return NULL;
108
109         _dbus_string_init_const(&daemon_name, DBUS_SERVICE_DBUS);
110         if(!kdbus_register_policy (&daemon_name, connection))
111                 goto failed;
112
113         if(kdbus_request_name(connection, &daemon_name, 0, 0) != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
114                 goto failed;
115
116 //      dbus_bus_add_match(connection, "type='signal', member='NameAcquired'", error);  //not needed if request name ioctled  by daemon not libdbus
117 //      dbus_bus_add_match(connection, "type='signal', member='NameLost'", error);  //todo dispatch and digest this  or ioctl about name where daemon checks name presence
118         if(!add_match_kdbus (dbus_connection_get_transport(connection), 1, "type='signal', member='NameLost'"))
119         {
120               dbus_set_error (error, _dbus_error_from_errno (errno), "Could not add match for id:1, %s", _dbus_strerror_from_errno ());
121               return FALSE;
122         }
123
124         if(dbus_error_is_set(error))
125         {
126 failed:
127                 _dbus_connection_close_possibly_shared (connection);
128                 dbus_connection_unref (connection);
129                 connection = NULL;
130         }
131         else
132                 _dbus_verbose ("Daemon connected as kdbus client.\n");
133
134         return connection;
135 }
136
137 dbus_bool_t kdbus_register_policy (const DBusString *service_name, DBusConnection* connection)
138 {
139         int fd;
140
141         _dbus_transport_get_socket_fd(dbus_connection_get_transport(connection), &fd);
142
143         return register_kdbus_policy(_dbus_string_get_const_data(service_name), fd);
144 }
145
146 dbus_uint32_t kdbus_request_name(DBusConnection* connection, const DBusString *service_name, dbus_uint32_t flags, __u64 sender_id)
147 {
148         int fd;
149
150         _dbus_transport_get_socket_fd(dbus_connection_get_transport(connection), &fd);
151
152         return request_kdbus_name(fd, _dbus_string_get_const_data(service_name), flags, sender_id);
153 }
154
155 dbus_uint32_t kdbus_release_name(DBusConnection* connection, const DBusString *service_name, __u64 sender_id)
156 {
157         int fd;
158
159         _dbus_transport_get_socket_fd(dbus_connection_get_transport(connection), &fd);
160
161         return release_kdbus_name(fd, _dbus_string_get_const_data(service_name), sender_id);
162 }
163
164 dbus_bool_t kdbus_list_services (DBusConnection* connection, char ***listp, int *array_len)
165 {
166         int fd;
167
168         _dbus_transport_get_socket_fd(dbus_connection_get_transport(connection), &fd);
169
170         return list_kdbus_names(fd, listp, array_len);
171 }
172
173 dbus_bool_t kdbus_add_match_rule (DBusConnection* connection, DBusMessage* message, const char* text, DBusError* error)
174 {
175         __u64 sender_id;
176
177         sender_id = sender_name_to_id(dbus_message_get_sender(message), error);
178         if(dbus_error_is_set(error))
179                 return FALSE;
180
181         if(!add_match_kdbus (dbus_connection_get_transport(connection), sender_id, text))
182         {
183               dbus_set_error (error, _dbus_error_from_errno (errno), "Could not add match for id:%d, %s",
184                               sender_id, _dbus_strerror_from_errno ());
185               return FALSE;
186         }
187
188         return TRUE;
189 }
190
191 dbus_bool_t kdbus_remove_match (DBusConnection* connection, DBusMessage* message, DBusError* error)
192 {
193         __u64 sender_id;
194
195         sender_id = sender_name_to_id(dbus_message_get_sender(message), error);
196         if(dbus_error_is_set(error))
197                 return FALSE;
198
199         if(!remove_match_kdbus (dbus_connection_get_transport(connection), sender_id))
200         {
201               dbus_set_error (error, _dbus_error_from_errno (errno), "Could not remove match rules for id:%d", sender_id);
202               return FALSE;
203         }
204
205         return TRUE;
206 }
207
208 dbus_bool_t kdbus_get_connection_unix_user(DBusConnection* connection, DBusMessage* message, unsigned long* uid, DBusError* error)
209 {
210         char* name = NULL;
211         struct nameInfo info;
212         int inter_ret;
213         dbus_bool_t ret = FALSE;
214
215         dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID);
216         inter_ret = kdbus_NameQuery(name, dbus_connection_get_transport(connection), &info);
217         if(inter_ret == 0) //name found
218         {
219                 _dbus_verbose("User id:%llu\n", (unsigned long long) info.userId);
220                 *uid = info.userId;
221                 return TRUE;
222         }
223         else if(inter_ret == -ENOENT)  //name has no owner
224                 dbus_set_error (error, DBUS_ERROR_FAILED, "Could not get UID of name '%s': no such name", name);
225         else
226         {
227                 _dbus_verbose("kdbus error determining UID: err %d (%m)\n", errno);
228                 dbus_set_error (error, DBUS_ERROR_FAILED, "Could not determine UID for '%s'", name);
229         }
230
231         return ret;
232 }
233
234 dbus_bool_t kdbus_get_connection_unix_process_id(DBusConnection* connection, DBusMessage* message, unsigned long* pid, DBusError* error)
235 {
236         char* name = NULL;
237         struct nameInfo info;
238         int inter_ret;
239         dbus_bool_t ret = FALSE;
240
241         dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID);
242         inter_ret = kdbus_NameQuery(name, dbus_connection_get_transport(connection), &info);
243         if(inter_ret == 0) //name found
244         {
245                 _dbus_verbose("Process id:%llu\n", (unsigned long long) info.processId);
246                 *pid = info.processId;
247                 return TRUE;
248         }
249         else if(inter_ret == -ENOENT)  //name has no owner
250                 dbus_set_error (error, DBUS_ERROR_FAILED, "Could not get PID of name '%s': no such name", name);
251         else
252         {
253                 _dbus_verbose("kdbus error determining PID: err %d (%m)\n", errno);
254                 dbus_set_error (error, DBUS_ERROR_FAILED, "Could not determine PID for '%s'", name);
255         }
256
257         return ret;
258 }
259
260 dbus_bool_t kdbus_get_connection_unix_selinux_security_context(DBusConnection* connection, DBusMessage* message, DBusMessage* reply, DBusError* error)
261 {
262         char* name = NULL;
263         struct nameInfo info;
264         int inter_ret;
265         dbus_bool_t ret = FALSE;
266
267         dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID);
268         inter_ret = kdbus_NameQuery(name, dbus_connection_get_transport(connection), &info);
269         if(inter_ret == -ENOENT)  //name has no owner
270                 dbus_set_error (error, DBUS_ERROR_FAILED, "Could not get security context of name '%s': no such name", name);
271         else if(inter_ret < 0)
272         {
273                 _dbus_verbose("kdbus error determining security context: err %d (%m)\n", errno);
274                 dbus_set_error (error, DBUS_ERROR_FAILED, "Could not determine security context for '%s'", name);
275         }
276         else
277         {
278                 if (!dbus_message_append_args (reply, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &info.sec_label, info.sec_label_len, DBUS_TYPE_INVALID))
279                 {
280                       _DBUS_SET_OOM (error);
281                       return FALSE;
282                 }
283                 ret = TRUE;
284         }
285
286         return ret;
287 }
288
289 DBusConnection* create_phantom_connection(DBusConnection* connection, const char* unique_name)
290 {
291     DBusConnection *phantom_connection;
292     DBusString name;
293     DBusError error;
294
295     _dbus_string_init_const(&name, unique_name);
296
297     phantom_connection = _dbus_connection_new_for_used_transport (dbus_connection_get_transport(connection));
298     if(phantom_connection == NULL)
299         return FALSE;
300     if(!bus_connections_setup_connection(bus_connection_get_connections(connection), phantom_connection))
301     {
302         /*todo FIXME something should be done to clean up the phantom connection
303          * but we can't use standard disconnect, unref or last_unref because the transport is taken from connection
304          * so we probably should write own function on the basis of _dbus_connection_last_unref
305          */
306         phantom_connection = NULL;
307     }
308     if(!bus_connection_complete(phantom_connection, &name, &error))
309     {
310         /* todo FIXME exactly the same issue as above */
311         phantom_connection = NULL;
312     }
313
314     _dbus_verbose ("Created phantom connection for %s\n", bus_connection_get_name(phantom_connection));
315
316     return phantom_connection;
317 }