[doc][daemon-fix][daemon-opt] Known limitations updated, code fixes, clean-ups, optim...
[platform/upstream/dbus.git] / bus / kdbus-d.c
1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2 /* kdbus-d.c  kdbus related daemon functions
3  *
4  * Copyright (C) 2013  Samsung Electronics
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 and under the terms of the GNU
12  * Lesser General Public License as published by the
13  * Free Software Foundation; either version 2.1 of the License, or (at
14  * your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
24  *
25  */
26
27 #include <dbus/dbus-connection-internal.h>
28 #include "kdbus-d.h"
29 #include <dbus/kdbus.h>
30 #include <dbus/dbus-bus.h>
31 #include "dispatch.h"
32 #include <dbus/kdbus-common.h>
33 #include <dbus/dbus-transport.h>
34 #include <dbus/dbus-transport-kdbus.h>
35 #include "connection.h"
36 #include "activation.h"
37 #include "services.h"
38
39 #include <utils.h>
40 #include <stdlib.h>
41 #include <stdio.h>
42 #include <fcntl.h>
43 #include <unistd.h>
44 #include <errno.h>
45
46 /*
47  * Converts string with unique name into __u64 id number. If the name is not unique, sets error.
48  */
49 __u64 sender_name_to_id(const char* name, DBusError* error)
50 {
51         __u64 sender_id = 0;
52
53         if(!strncmp(name, ":1.", 3)) /*if name is unique name it must be converted to unique id*/
54                 sender_id = strtoull(&name[3], NULL, 10);
55         else
56                 dbus_set_error (error, DBUS_ERROR_INVALID_ARGS, "Could not convert sender of the message into kdbus unique id");
57
58         return sender_id;
59 }
60
61 /*
62  * Creates kdbus bus of given type.
63  */
64 char* make_kdbus_bus(DBusBusType type, DBusError *error)
65 {
66     struct {
67         struct kdbus_cmd_bus_make head;
68         uint64_t n_size;
69         uint64_t n_type;
70         char name[64];
71     } __attribute__ ((__aligned__(8))) bus_make;
72
73     int fdc, ret;
74     char *bus;
75
76     _dbus_verbose("Opening /dev/kdbus/control\n");
77     fdc = open("/dev/kdbus/control", O_RDWR|O_CLOEXEC);
78     if (fdc < 0)
79     {
80         _dbus_verbose("--- error %d (%m)\n", fdc);
81         dbus_set_error(error, DBUS_ERROR_FAILED, "Opening /dev/kdbus/control failed: %d (%m)", fdc);
82         return NULL;
83     }
84
85     memset(&bus_make, 0, sizeof(bus_make));
86     bus_make.head.bloom_size = 64;
87     bus_make.head.flags = KDBUS_MAKE_ACCESS_WORLD;
88
89     if(type == DBUS_BUS_SYSTEM)
90         snprintf(bus_make.name, sizeof(bus_make.name), "%u-kdbus-%s", getuid(), "system");
91     else if(type == DBUS_BUS_SESSION)
92         snprintf(bus_make.name, sizeof(bus_make.name), "%u-kdbus", getuid());
93     else
94         snprintf(bus_make.name, sizeof(bus_make.name), "%u-kdbus-%u", getuid(), getpid());
95
96     bus_make.n_type = KDBUS_MAKE_NAME;
97     bus_make.n_size = KDBUS_PART_HEADER_SIZE + strlen(bus_make.name) + 1;
98     bus_make.head.size = sizeof(struct kdbus_cmd_bus_make) + bus_make.n_size;
99
100     _dbus_verbose("Creating bus '%s'\n", bus_make.name);
101     ret = ioctl(fdc, KDBUS_CMD_BUS_MAKE, &bus_make);
102     if (ret)
103     {
104         _dbus_verbose("--- error %d (%m)\n", ret);
105         dbus_set_error(error, DBUS_ERROR_FAILED, "Creating bus '%s' failed: %d (%m)", bus_make.name, fdc);
106         return NULL;
107     }
108
109     if (asprintf(&bus, "kdbus:path=/dev/kdbus/%s/bus", bus_make.name) < 0)
110     {
111         BUS_SET_OOM (error);
112         return NULL;
113     }
114
115     _dbus_verbose("Return value '%s'\n", bus);
116         return bus;
117 }
118
119 /*
120  * Minimal server init needed by context to go further.
121  */
122 DBusServer* empty_server_init(char* address)
123 {
124         return dbus_server_init_mini(address);
125 }
126
127 /*
128  * Connects daemon to bus created by him and adds matches for "system" broadcasts.
129  * Do not requests org.freedesktop.DBus name, because it's to early
130  * (some structures of BusContext are not ready yet).
131  */
132 DBusConnection* daemon_as_client(DBusBusType type, char* address, DBusError *error)
133 {
134         DBusConnection* connection;
135
136         dbus_bus_set_bus_connection_address(type, address);
137
138         connection = dbus_bus_get_private(type, error);  /*todo possibly could be optimised by using lower functions*/
139         if(connection == NULL)
140                 return NULL;
141
142         if(!add_match_kdbus (dbus_connection_get_transport(connection), 1, "member='IdRemoved'"))
143     {
144           dbus_set_error (error, _dbus_error_from_errno (errno), "Could not add match for id:1, %s", _dbus_strerror_from_errno ());
145           goto failed;
146     }
147     if(!add_match_kdbus (dbus_connection_get_transport(connection), 1, "member='NameChanged'"))
148     {
149           dbus_set_error (error, _dbus_error_from_errno (errno), "Could not add match for id:1, %s", _dbus_strerror_from_errno ());
150           goto failed;
151     }
152     if(!add_match_kdbus (dbus_connection_get_transport(connection), 1, "member='NameLost'"))
153     {
154           dbus_set_error (error, _dbus_error_from_errno (errno), "Could not add match for id:1, %s", _dbus_strerror_from_errno ());
155           goto failed;
156     }
157     if(!add_match_kdbus (dbus_connection_get_transport(connection), 1, "member='NameAcquired'"))
158     {
159           dbus_set_error (error, _dbus_error_from_errno (errno), "Could not add match for id:1, %s", _dbus_strerror_from_errno ());
160           goto failed;
161     }
162
163         if(dbus_error_is_set(error))
164         {
165 failed:
166                 _dbus_connection_close_possibly_shared (connection);
167                 dbus_connection_unref (connection);
168                 connection = NULL;
169         }
170         else
171                 _dbus_verbose ("Daemon connected as kdbus client.\n");
172
173         return connection;
174 }
175
176 /*
177  * Asks bus for org.freedesktop.DBus well-known name.
178  */
179 dbus_bool_t register_daemon_name(DBusConnection* connection)
180 {
181     DBusString daemon_name;
182     dbus_bool_t retval = FALSE;
183     BusTransaction *transaction;
184
185     _dbus_string_init_const(&daemon_name, DBUS_SERVICE_DBUS);
186     if(!kdbus_register_policy (&daemon_name, connection))
187         return FALSE;
188
189     if(kdbus_request_name(connection, &daemon_name, 0, 0) != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
190        return FALSE;
191
192     transaction = bus_transaction_new (bus_connection_get_context(connection));
193     if (transaction == NULL)
194     {
195         kdbus_release_name(connection, &daemon_name, 0);
196         goto out;
197     }
198
199     if(!bus_registry_ensure (bus_connection_get_registry (connection), &daemon_name, connection, 0, transaction, NULL))
200     {
201         kdbus_release_name(connection, &daemon_name, 0);
202         goto out;
203     }
204
205     retval = TRUE;
206
207 out:
208         bus_transaction_cancel_and_free(transaction);
209     return retval;
210 }
211
212 dbus_bool_t kdbus_register_policy (const DBusString *service_name, DBusConnection* connection)
213 {
214         int fd;
215
216         _dbus_transport_get_socket_fd(dbus_connection_get_transport(connection), &fd);
217
218         return register_kdbus_policy(_dbus_string_get_const_data(service_name), fd);
219 }
220
221 dbus_uint32_t kdbus_request_name(DBusConnection* connection, const DBusString *service_name, dbus_uint32_t flags, __u64 sender_id)
222 {
223         int fd;
224
225         _dbus_transport_get_socket_fd(dbus_connection_get_transport(connection), &fd);
226
227         return request_kdbus_name(fd, _dbus_string_get_const_data(service_name), flags, sender_id);
228 }
229
230 dbus_uint32_t kdbus_release_name(DBusConnection* connection, const DBusString *service_name, __u64 sender_id)
231 {
232         int fd;
233
234         _dbus_transport_get_socket_fd(dbus_connection_get_transport(connection), &fd);
235
236         return release_kdbus_name(fd, _dbus_string_get_const_data(service_name), sender_id);
237 }
238
239 /*
240  * Asks kdbus for well-known names registered on the bus
241  */
242 dbus_bool_t kdbus_list_services (DBusConnection* connection, char ***listp, int *array_len)
243 {
244         int fd;
245         struct kdbus_cmd_names* pCmd;
246         __u64 cmd_size;
247         dbus_bool_t ret_val = FALSE;
248         char** list;
249         int list_len = 0;
250         int i = 0;
251         int j;
252
253         cmd_size = sizeof(struct kdbus_cmd_names) + KDBUS_ITEM_SIZE(1);
254         pCmd = malloc(cmd_size);
255         if(pCmd == NULL)
256                 goto out;
257         pCmd->size = cmd_size;
258
259         _dbus_transport_get_socket_fd(dbus_connection_get_transport(connection), &fd);
260
261 again:
262         cmd_size = 0;
263         if(ioctl(fd, KDBUS_CMD_NAME_LIST, pCmd))
264         {
265                 if(errno == EINTR)
266                         goto again;
267                 if(errno == ENOBUFS)                    //buffer to small to put all names into it
268                         cmd_size = pCmd->size;          //here kernel tells how much memory it needs
269                 else
270                 {
271                         _dbus_verbose("kdbus error asking for name list: err %d (%m)\n",errno);
272                         goto out;
273                 }
274         }
275         if(cmd_size)  //kernel needs more memory
276         {
277                 pCmd = realloc(pCmd, cmd_size);  //prepare memory
278                 if(pCmd == NULL)
279                         return FALSE;
280                 goto again;                                             //and try again
281         }
282         else
283         {
284                 struct kdbus_cmd_name* pCmd_name;
285
286                 for (pCmd_name = pCmd->names; (uint8_t *)(pCmd_name) < (uint8_t *)(pCmd) + pCmd->size; pCmd_name = KDBUS_PART_NEXT(pCmd_name))
287                         list_len++;
288
289                 list = malloc(sizeof(char*) * (list_len + 1));
290                 if(list == NULL)
291                         goto out;
292
293                 for (pCmd_name = pCmd->names; (uint8_t *)(pCmd_name) < (uint8_t *)(pCmd) + pCmd->size; pCmd_name = KDBUS_PART_NEXT(pCmd_name))
294                 {
295                         list[i] = strdup(pCmd_name->name);
296                         if(list[i] == NULL)
297                         {
298                                 for(j=0; j<i; j++)
299                                         free(list[j]);
300                                 free(list);
301                                 goto out;
302                         }
303                         _dbus_verbose ("Name %d: %s\n", i, list[i]);
304                         ++i;
305                 }
306                 list[i] = NULL;
307         }
308
309         *array_len = list_len;
310         *listp = list;
311         ret_val = TRUE;
312
313 out:
314         if(pCmd)
315                 free(pCmd);
316         return ret_val;
317 }
318
319 /*
320  *  Register match rule in kdbus on behalf of sender of the message
321  */
322 dbus_bool_t kdbus_add_match_rule (DBusConnection* connection, DBusMessage* message, const char* text, DBusError* error)
323 {
324         __u64 sender_id;
325
326         sender_id = sender_name_to_id(dbus_message_get_sender(message), error);
327         if(dbus_error_is_set(error))
328                 return FALSE;
329
330         if(!add_match_kdbus (dbus_connection_get_transport(connection), sender_id, text))
331         {
332               dbus_set_error (error, _dbus_error_from_errno (errno), "Could not add match for id:%d, %s",
333                               sender_id, _dbus_strerror_from_errno ());
334               return FALSE;
335         }
336
337         return TRUE;
338 }
339
340 /*
341  *  Removes match rule in kdbus on behalf of sender of the message
342  */
343 dbus_bool_t kdbus_remove_match (DBusConnection* connection, DBusMessage* message, DBusError* error)
344 {
345         __u64 sender_id;
346
347         sender_id = sender_name_to_id(dbus_message_get_sender(message), error);
348         if(dbus_error_is_set(error))
349                 return FALSE;
350
351         if(!remove_match_kdbus (dbus_connection_get_transport(connection), sender_id))
352         {
353               dbus_set_error (error, _dbus_error_from_errno (errno), "Could not remove match rules for id:%d", sender_id);
354               return FALSE;
355         }
356
357         return TRUE;
358 }
359
360 int kdbus_get_name_owner(DBusConnection* connection, const char* name, char* owner)
361 {
362   int ret;
363   struct nameInfo info;
364
365   ret = kdbus_NameQuery(name, dbus_connection_get_transport(connection), &info);
366   if(ret == 0) //unique id of the name
367   {
368     sprintf(owner, ":1.%llu", (unsigned long long int)info.uniqueId);
369     _dbus_verbose("Unique name discovered:%s\n", owner);
370   }
371   else if(ret != -ENOENT)
372     _dbus_verbose("kdbus error sending name query: err %d (%m)\n", errno);
373
374   return ret;
375 }
376
377 /*
378  *  Asks kdbus for uid of the owner of the name given in the message
379  */
380 dbus_bool_t kdbus_get_connection_unix_user(DBusConnection* connection, const char* name, unsigned long* uid, DBusError* error)
381 {
382         struct nameInfo info;
383         int inter_ret;
384         dbus_bool_t ret = FALSE;
385
386         inter_ret = kdbus_NameQuery(name, dbus_connection_get_transport(connection), &info);
387         if(inter_ret == 0) //name found
388         {
389                 _dbus_verbose("User id:%llu\n", (unsigned long long) info.userId);
390                 *uid = info.userId;
391                 return TRUE;
392         }
393         else if(inter_ret == -ENOENT)  //name has no owner
394                 dbus_set_error (error, DBUS_ERROR_FAILED, "Could not get UID of name '%s': no such name", name);
395         else
396         {
397                 _dbus_verbose("kdbus error determining UID: err %d (%m)\n", errno);
398                 dbus_set_error (error, DBUS_ERROR_FAILED, "Could not determine UID for '%s'", name);
399         }
400
401         return ret;
402 }
403
404 /*
405  *  Asks kdbus for pid of the owner of the name given in the message
406  */
407 dbus_bool_t kdbus_get_connection_unix_process_id(DBusConnection* connection, const char* name, unsigned long* pid, DBusError* error)
408 {
409         struct nameInfo info;
410         int inter_ret;
411         dbus_bool_t ret = FALSE;
412
413         inter_ret = kdbus_NameQuery(name, dbus_connection_get_transport(connection), &info);
414         if(inter_ret == 0) //name found
415         {
416                 _dbus_verbose("Process id:%llu\n", (unsigned long long) info.processId);
417                 *pid = info.processId;
418                 return TRUE;
419         }
420         else if(inter_ret == -ENOENT)  //name has no owner
421                 dbus_set_error (error, DBUS_ERROR_FAILED, "Could not get PID of name '%s': no such name", name);
422         else
423         {
424                 _dbus_verbose("kdbus error determining PID: err %d (%m)\n", errno);
425                 dbus_set_error (error, DBUS_ERROR_FAILED, "Could not determine PID for '%s'", name);
426         }
427
428         return ret;
429 }
430
431 /*
432  *  Asks kdbus for selinux_security_context of the owner of the name given in the message
433  */
434 dbus_bool_t kdbus_get_connection_unix_selinux_security_context(DBusConnection* connection, DBusMessage* message, DBusMessage* reply, DBusError* error)
435 {
436         char* name = NULL;
437         struct nameInfo info;
438         int inter_ret;
439         dbus_bool_t ret = FALSE;
440
441         dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID);
442         inter_ret = kdbus_NameQuery(name, dbus_connection_get_transport(connection), &info);
443         if(inter_ret == -ENOENT)  //name has no owner
444                 dbus_set_error (error, DBUS_ERROR_FAILED, "Could not get security context of name '%s': no such name", name);
445         else if(inter_ret < 0)
446         {
447                 _dbus_verbose("kdbus error determining security context: err %d (%m)\n", errno);
448                 dbus_set_error (error, DBUS_ERROR_FAILED, "Could not determine security context for '%s'", name);
449         }
450         else
451         {
452                 if (!dbus_message_append_args (reply, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &info.sec_label, info.sec_label_len, DBUS_TYPE_INVALID))
453                 {
454                       _DBUS_SET_OOM (error);
455                       return FALSE;
456                 }
457                 ret = TRUE;
458         }
459
460         return ret;
461 }
462
463 /**
464  * Gets the UNIX user ID of the connection from kdbus, if known. Returns #TRUE if
465  * the uid is filled in.  Always returns #FALSE on non-UNIX platforms
466  * for now., though in theory someone could hook Windows to NIS or
467  * something.  Always returns #FALSE prior to authenticating the
468  * connection.
469  *
470  * The UID of is only read by bus daemon from kdbus. You can not
471  * call this function from client side of the connection.
472  *
473  * You can ask the bus to tell you the UID of another connection though
474  * if you like; this is done with dbus_bus_get_unix_user().
475  *
476  * @param connection the connection
477  * @param uid return location for the user ID
478  * @returns #TRUE if uid is filled in with a valid user ID
479  */
480 dbus_bool_t
481 dbus_connection_get_unix_user (DBusConnection *connection,
482                                unsigned long  *uid)
483 {
484   _dbus_return_val_if_fail (connection != NULL, FALSE);
485   _dbus_return_val_if_fail (uid != NULL, FALSE);
486
487   return kdbus_get_connection_unix_user(connection, bus_connection_get_name(connection), uid, NULL);
488 }
489
490 /**
491  * Gets the process ID of the connection if any.
492  * Returns #TRUE if the pid is filled in.
493  *
494  * @param connection the connection
495  * @param pid return location for the process ID
496  * @returns #TRUE if uid is filled in with a valid process ID
497  */
498 dbus_bool_t
499 dbus_connection_get_unix_process_id (DBusConnection *connection,
500              unsigned long  *pid)
501 {
502   _dbus_return_val_if_fail (connection != NULL, FALSE);
503   _dbus_return_val_if_fail (pid != NULL, FALSE);
504
505   return kdbus_get_connection_unix_process_id(connection, bus_connection_get_name(connection), pid, NULL);
506 }
507
508 /*
509  * Create connection structure for given name. It is needed to control starters - activatable services
510  * and for ListQueued method (as long as kdbus is not supporting it). This connections don't have it's own
511  * fd so it is set up on the basis of daemon's transport. Functionality of such connection is limited.
512  */
513 DBusConnection* create_phantom_connection(DBusConnection* connection, const char* name, DBusError* error)
514 {
515     DBusConnection *phantom_connection;
516     DBusString Sname;
517
518     _dbus_string_init_const(&Sname, name);
519
520     phantom_connection = _dbus_connection_new_for_used_transport (dbus_connection_get_transport(connection));
521     if(phantom_connection == NULL)
522         return FALSE;
523     if(!bus_connections_setup_connection(bus_connection_get_connections(connection), phantom_connection))
524     {
525         dbus_connection_unref_phantom(phantom_connection);
526         phantom_connection = NULL;
527         dbus_set_error (error, DBUS_ERROR_FAILED , "Name \"%s\" could not be acquired", name);
528         goto out;
529     }
530     if(!bus_connection_complete(phantom_connection, &Sname, error))
531     {
532         bus_connection_disconnected(phantom_connection);
533         phantom_connection = NULL;
534         goto out;
535     }
536
537     _dbus_verbose ("Created phantom connection for %s\n", bus_connection_get_name(phantom_connection));
538
539 out:
540     return phantom_connection;
541 }
542
543 /*
544  * Registers activatable services as kdbus starters.
545  */
546 dbus_bool_t register_kdbus_starters(DBusConnection* connection)
547 {
548     int i,j, len;
549     char **services;
550     dbus_bool_t retval = FALSE;
551     int fd;
552     BusTransaction *transaction;
553     DBusString name;
554
555     transaction = bus_transaction_new (bus_connection_get_context(connection));
556     if (transaction == NULL)
557         return FALSE;
558
559     if (!bus_activation_list_services (bus_connection_get_activation (connection), &services, &len))
560         return FALSE;
561
562     _dbus_transport_get_socket_fd (dbus_connection_get_transport(connection), &fd);
563     _dbus_string_init(&name);
564
565     for(i=0; i<len; i++)
566     {
567         if(!register_kdbus_policy(services[i], fd))
568             goto out;
569
570         if (request_kdbus_name(fd, services[i], (DBUS_NAME_FLAG_ALLOW_REPLACEMENT | KDBUS_NAME_STARTER) , 0) < 0)
571             goto out;
572
573         if(!_dbus_string_append(&name, services[i]))
574                 goto out;
575         if(!bus_registry_ensure (bus_connection_get_registry (connection), &name, connection,
576                         (DBUS_NAME_FLAG_ALLOW_REPLACEMENT | KDBUS_NAME_STARTER), transaction, NULL))
577                 goto out;
578         if(!_dbus_string_set_length(&name, 0))
579                 goto out;
580     }
581     retval = TRUE;
582
583 out:
584     if(retval == FALSE)
585     {
586         for(j=0; j<i; j++)
587             release_kdbus_name(fd, services[j], 0);
588     }
589     dbus_free_string_array (services);
590     _dbus_string_free(&name);
591     bus_transaction_cancel_and_free(transaction);
592     return retval;
593 }
594
595 /*
596  * Updates kdbus starters (activatable services) after configuration was reloaded.
597  * It releases all previous starters and registers all new.
598  */
599 dbus_bool_t update_kdbus_starters(DBusConnection* connection)
600 {
601     dbus_bool_t retval = FALSE;
602     DBusList **services_old;
603     DBusList *link;
604     BusService *service = NULL;
605     BusTransaction *transaction;
606     int fd;
607
608     transaction = bus_transaction_new (bus_connection_get_context(connection));
609     if (transaction == NULL)
610         return FALSE;
611
612     if(!_dbus_transport_get_socket_fd(dbus_connection_get_transport(connection), &fd))
613         goto out;
614
615     services_old = bus_connection_get_services_owned(connection);
616     link = _dbus_list_get_first_link(services_old);
617     link = _dbus_list_get_next_link (services_old, link); //skip org.freedesktop.DBus which is not starter
618
619     while (link != NULL)
620     {
621         int ret;
622
623         service = (BusService*) link->data;
624         if(service == NULL)
625             goto out;
626
627         ret = release_kdbus_name(fd, bus_service_get_name(service), 0);
628
629         if (ret == DBUS_RELEASE_NAME_REPLY_RELEASED)
630         {
631             if(!bus_service_remove_owner(service, connection, transaction, NULL))
632                 _dbus_verbose ("Unable to remove\n");
633         }
634         else if(ret < 0)
635             goto out;
636
637         link = _dbus_list_get_next_link (services_old, link);
638     }
639
640     if(!register_kdbus_starters(connection))
641     {
642         _dbus_verbose ("Registering kdbus starters for dbus activatable names failed!\n");
643         goto out;
644     }
645     retval = TRUE;
646
647 out:
648         bus_transaction_cancel_and_free(transaction);
649     return retval;
650 }
651
652 /*
653  * Analyzes system broadcasts about id and name changes.
654  * Basing on this it sends NameAcquired and NameLost signals and clear phantom connections.
655  */
656 void handleNameOwnerChanged(DBusMessage *msg, BusTransaction *transaction, DBusConnection *connection)
657 {
658     const char *name, *old, *new;
659
660     if(!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &name, DBUS_TYPE_STRING, &old, DBUS_TYPE_STRING, &new, DBUS_TYPE_INVALID))
661     {
662         _dbus_verbose ("Couldn't get args of NameOwnerChanged signal: .\n");//, error.message);
663         return;
664     }
665
666     _dbus_verbose ("Got NameOwnerChanged signal:\nName: %s\nOld: %s\nNew: %s\n", name, old, new);
667
668     if(!strncmp(name, ":1.", 3))/*if it starts from :1. it is unique name - this might be IdRemoved info*/
669     {
670         if(!strcmp(name, old))  //yes it is - someone has disconnected
671         {
672             DBusConnection* conn;
673
674             conn = bus_connections_find_conn_by_name(bus_connection_get_connections(connection), name);
675             if(conn)
676                 bus_connection_disconnected(conn);
677         }
678     }
679     else //it is well-known name
680     {
681         if((*old != 0) && (strcmp(old, ":1.1")))
682         {
683             DBusMessage *message;
684
685             if(bus_connections_find_conn_by_name(bus_connection_get_connections(connection), old) == NULL)
686                 goto next;
687
688             _dbus_verbose ("Owner '%s' lost name '%s'. Sending NameLost.\n", old, name);
689
690             message = dbus_message_new_signal (DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "NameLost");
691             if (message == NULL)
692                 goto next;
693
694             if (!dbus_message_set_destination (message, old) || !dbus_message_append_args (message,
695                                                                  DBUS_TYPE_STRING, &name,
696                                                                  DBUS_TYPE_INVALID))
697             {
698                 dbus_message_unref (message);
699                 goto next;
700             }
701
702             bus_transaction_send_from_driver (transaction, connection, message);
703             dbus_message_unref (message);
704         }
705     next:
706         if((*new != 0) && (strcmp(new, ":1.1")))
707         {
708             DBusMessage *message;
709
710             _dbus_verbose ("Owner '%s' acquired name '%s'. Sending NameAcquired.\n", new, name);
711
712             message = dbus_message_new_signal (DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "NameAcquired");
713             if (message == NULL)
714                 return;
715
716             if (!dbus_message_set_destination (message, new) || !dbus_message_append_args (message,
717                                                                  DBUS_TYPE_STRING, &name,
718                                                                  DBUS_TYPE_INVALID))
719             {
720                 dbus_message_unref (message);
721                 return;
722             }
723
724             bus_transaction_send_from_driver (transaction, connection, message);
725             dbus_message_unref (message);
726         }
727     }
728 }