1 /***
2   This file is part of avahi.
3 
4   avahi is free software; you can redistribute it and/or modify it
5   under the terms of the GNU Lesser General Public License as
6   published by the Free Software Foundation; either version 2.1 of the
7   License, or (at your option) any later version.
8 
9   avahi is distributed in the hope that it will be useful, but WITHOUT
10   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11   or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
12   Public License for more details.
13 
14   You should have received a copy of the GNU Lesser General Public
15   License along with avahi; if not, write to the Free Software
16   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
17   USA.
18 ***/
19 
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23 
24 #include <string.h>
25 #include <sys/ioctl.h>
26 #include <sys/types.h>
27 #include <sys/socket.h>
28 #include <netinet/in.h>
29 #include <net/if.h>
30 #include <errno.h>
31 #include <unistd.h>
32 #include <assert.h>
33 #include <sys/stat.h>
34 #include <fcntl.h>
35 #include <stdio.h>
36 #include <signal.h>
37 #include <stdlib.h>
38 
39 #include <dbus/dbus.h>
40 
41 #include <avahi-common/dbus.h>
42 #include <avahi-common/llist.h>
43 #include <avahi-common/malloc.h>
44 #include <avahi-common/dbus-watch-glue.h>
45 #include <avahi-common/alternative.h>
46 #include <avahi-common/error.h>
47 #include <avahi-common/domain.h>
48 #include <avahi-common/timeval.h>
49 
50 #include <avahi-core/log.h>
51 #include <avahi-core/core.h>
52 #include <avahi-core/lookup.h>
53 #include <avahi-core/publish.h>
54 
55 #include "dbus-protocol.h"
56 #include "dbus-util.h"
57 #include "dbus-internal.h"
58 #include "main.h"
59 
60 /* #define VALGRIND_WORKAROUND 1 */
61 
62 #define RECONNECT_MSEC 3000
63 
64 Server *server = NULL;
65 
66 static int dbus_connect(void);
67 static void dbus_disconnect(void);
68 
client_free(Client * c)69 static void client_free(Client *c) {
70 
71     assert(server);
72     assert(c);
73 
74     while (c->entry_groups)
75         avahi_dbus_entry_group_free(c->entry_groups);
76 
77     while (c->sync_host_name_resolvers)
78         avahi_dbus_sync_host_name_resolver_free(c->sync_host_name_resolvers);
79 
80     while (c->async_host_name_resolvers)
81         avahi_dbus_async_host_name_resolver_free(c->async_host_name_resolvers);
82 
83     while (c->sync_address_resolvers)
84         avahi_dbus_sync_address_resolver_free(c->sync_address_resolvers);
85 
86     while (c->async_address_resolvers)
87         avahi_dbus_async_address_resolver_free(c->async_address_resolvers);
88 
89     while (c->domain_browsers)
90         avahi_dbus_domain_browser_free(c->domain_browsers);
91 
92     while (c->service_type_browsers)
93         avahi_dbus_service_type_browser_free(c->service_type_browsers);
94 
95     while (c->service_browsers)
96         avahi_dbus_service_browser_free(c->service_browsers);
97 
98     while (c->sync_service_resolvers)
99         avahi_dbus_sync_service_resolver_free(c->sync_service_resolvers);
100 
101     while (c->async_service_resolvers)
102         avahi_dbus_async_service_resolver_free(c->async_service_resolvers);
103 
104     while (c->record_browsers)
105         avahi_dbus_record_browser_free(c->record_browsers);
106 
107     assert(c->n_objects == 0);
108 
109     avahi_free(c->name);
110     AVAHI_LLIST_REMOVE(Client, clients, server->clients, c);
111     avahi_free(c);
112 
113     assert(server->n_clients >= 1);
114     server->n_clients --;
115 }
116 
client_get(const char * name,int create)117 static Client *client_get(const char *name, int create) {
118     Client *client;
119 
120     assert(server);
121     assert(name);
122 
123     for (client = server->clients; client; client = client->clients_next)
124         if (!strcmp(name, client->name))
125             return client;
126 
127     if (!create)
128         return NULL;
129 
130     if (server->n_clients >= server->n_clients_max)
131         return NULL;
132 
133     /* If not existent yet, create a new entry */
134     client = avahi_new(Client, 1);
135     client->id = server->current_id++;
136     client->name = avahi_strdup(name);
137     client->current_id = 0;
138     client->n_objects = 0;
139 
140     AVAHI_LLIST_HEAD_INIT(EntryGroupInfo, client->entry_groups);
141     AVAHI_LLIST_HEAD_INIT(SyncHostNameResolverInfo, client->sync_host_name_resolvers);
142     AVAHI_LLIST_HEAD_INIT(AsyncHostNameResolverInfo, client->async_host_name_resolvers);
143     AVAHI_LLIST_HEAD_INIT(SyncAddressResolverInfo, client->sync_address_resolvers);
144     AVAHI_LLIST_HEAD_INIT(AsyncAddressResolverInfo, client->async_address_resolvers);
145     AVAHI_LLIST_HEAD_INIT(DomainBrowserInfo, client->domain_browsers);
146     AVAHI_LLIST_HEAD_INIT(ServiceTypeBrowserInfo, client->service_type_browsers);
147     AVAHI_LLIST_HEAD_INIT(ServiceBrowserInfo, client->service_browsers);
148     AVAHI_LLIST_HEAD_INIT(SyncServiceResolverInfo, client->sync_service_resolvers);
149     AVAHI_LLIST_HEAD_INIT(AsyncServiceResolverInfo, client->async_service_resolvers);
150     AVAHI_LLIST_HEAD_INIT(RecordBrowserInfo, client->record_browsers);
151 
152     AVAHI_LLIST_PREPEND(Client, clients, server->clients, client);
153 
154     server->n_clients++;
155     assert(server->n_clients > 0);
156 
157     return client;
158 }
159 
reconnect_callback(AvahiTimeout * t,AVAHI_GCC_UNUSED void * userdata)160 static void reconnect_callback(AvahiTimeout *t, AVAHI_GCC_UNUSED void *userdata) {
161     assert(!server->bus);
162 
163     if (dbus_connect() < 0) {
164         struct timeval tv;
165         avahi_log_debug(__FILE__": Connection failed, retrying in %ims...", RECONNECT_MSEC);
166         avahi_elapse_time(&tv, RECONNECT_MSEC, 0);
167         server->poll_api->timeout_update(t, &tv);
168     } else {
169         avahi_log_debug(__FILE__": Successfully reconnected.");
170         server->poll_api->timeout_update(t, NULL);
171     }
172 }
173 
dbus_parsing_error(const char * txt,DBusError * error)174 static DBusHandlerResult dbus_parsing_error(const char *txt, DBusError *error) {
175     avahi_log_warn("%s",txt);
176     if (dbus_error_is_set(error))
177         dbus_error_free(error);
178 
179     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
180 }
181 
msg_signal_filter_impl(AVAHI_GCC_UNUSED DBusConnection * c,DBusMessage * m,AVAHI_GCC_UNUSED void * userdata)182 static DBusHandlerResult msg_signal_filter_impl(AVAHI_GCC_UNUSED DBusConnection *c, DBusMessage *m, AVAHI_GCC_UNUSED void *userdata) {
183     DBusError error;
184 
185     dbus_error_init(&error);
186 
187 /*     avahi_log_debug(__FILE__": interface=%s, path=%s, member=%s", */
188 /*                     dbus_message_get_interface(m), */
189 /*                     dbus_message_get_path(m), */
190 /*                     dbus_message_get_member(m)); */
191 
192     if (dbus_message_is_signal(m, DBUS_INTERFACE_LOCAL, "Disconnected")) {
193         struct timeval tv;
194 
195         if (server->reconnect) {
196             avahi_log_warn("Disconnected from D-Bus, trying to reconnect in %ims...", RECONNECT_MSEC);
197 
198             dbus_disconnect();
199 
200             avahi_elapse_time(&tv, RECONNECT_MSEC, 0);
201 
202             if (server->reconnect_timeout)
203                 server->poll_api->timeout_update(server->reconnect_timeout, &tv);
204             else
205                 server->reconnect_timeout = server->poll_api->timeout_new(server->poll_api, &tv, reconnect_callback, NULL);
206         } else {
207             avahi_log_warn("Disconnected from D-Bus, exiting.");
208             raise(SIGTERM);
209         }
210 
211         return DBUS_HANDLER_RESULT_HANDLED;
212 
213     } else if (dbus_message_is_signal(m, DBUS_INTERFACE_DBUS, "NameAcquired")) {
214         char *name;
215 
216         if (!dbus_message_get_args(m, &error, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID)) {
217             return dbus_parsing_error("Error parsing NameAcquired message", &error);
218         }
219 
220 /*         avahi_log_info(__FILE__": name acquired (%s)", name); */
221         return DBUS_HANDLER_RESULT_HANDLED;
222 
223     } else if (dbus_message_is_signal(m, DBUS_INTERFACE_DBUS, "NameOwnerChanged")) {
224         char *name, *old, *new;
225 
226         if (!dbus_message_get_args(m, &error, DBUS_TYPE_STRING, &name, DBUS_TYPE_STRING, &old, DBUS_TYPE_STRING, &new, DBUS_TYPE_INVALID)) {
227             return dbus_parsing_error("Error parsing NameOwnerChanged message", &error);
228         }
229 
230         if (!*new) {
231             Client *client;
232 
233             if ((client = client_get(name, FALSE))) {
234                 avahi_log_debug(__FILE__": client %s vanished.", name);
235                 client_free(client);
236             }
237         }
238     }
239 
240     if (dbus_error_is_set(&error))
241         dbus_error_free(&error);
242 
243     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
244 }
245 
dbus_get_host_name(DBusConnection * c,DBusMessage * m,DBusError * error)246 static DBusHandlerResult dbus_get_host_name(DBusConnection *c, DBusMessage *m, DBusError *error) {
247     if (!dbus_message_get_args(m, error, DBUS_TYPE_INVALID)) {
248         return dbus_parsing_error("Error parsing Server::GetHostName message", error);
249     }
250 
251     return avahi_dbus_respond_string(c, m, avahi_server_get_host_name(avahi_server));
252 }
253 
dbus_set_host_name(DBusConnection * c,DBusMessage * m,DBusError * error)254 static DBusHandlerResult dbus_set_host_name(DBusConnection *c, DBusMessage *m, DBusError *error) {
255     char *name;
256 
257     if (!dbus_message_get_args(m, error, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID)) {
258         return dbus_parsing_error("Error parsing Server::SetHostName message", error);
259     }
260 
261     if (avahi_server_set_host_name(avahi_server, name) < 0)
262         return avahi_dbus_respond_error(c, m, avahi_server_errno(avahi_server), NULL);
263 
264     avahi_log_info("Changing host name to '%s'.", name);
265 
266     return avahi_dbus_respond_ok(c, m);
267 }
268 
dbus_get_domain_name(DBusConnection * c,DBusMessage * m,DBusError * error)269 static DBusHandlerResult dbus_get_domain_name(DBusConnection *c, DBusMessage *m, DBusError *error) {
270     if (!dbus_message_get_args(m, error, DBUS_TYPE_INVALID)) {
271         return dbus_parsing_error("Error parsing Server::GetDomainName message", error);
272     }
273 
274     return avahi_dbus_respond_string(c, m, avahi_server_get_domain_name(avahi_server));
275 }
276 
dbus_get_host_name_fqdn(DBusConnection * c,DBusMessage * m,DBusError * error)277 static DBusHandlerResult dbus_get_host_name_fqdn(DBusConnection *c, DBusMessage *m, DBusError *error) {
278     if (!(dbus_message_get_args(m, error, DBUS_TYPE_INVALID))) {
279         return dbus_parsing_error("Error parsing Server::GetHostNameFqdn message", error);
280     }
281 
282     return avahi_dbus_respond_string(c, m, avahi_server_get_host_name_fqdn(avahi_server));
283 }
284 
dbus_is_ns_support_available(DBusConnection * c,DBusMessage * m,DBusError * error)285 static DBusHandlerResult dbus_is_ns_support_available(DBusConnection *c, DBusMessage *m, DBusError *error) {
286     if (!(dbus_message_get_args(m, error, DBUS_TYPE_INVALID))) {
287         return dbus_parsing_error("Error parsing Server::IsNSSSupportAvailable message", error);
288     }
289 
290     return avahi_dbus_respond_boolean(c, m, nss_support);
291 }
292 
dbus_get_version_string(DBusConnection * c,DBusMessage * m,DBusError * error)293 static DBusHandlerResult dbus_get_version_string(DBusConnection *c, DBusMessage *m, DBusError *error) {
294     if (!(dbus_message_get_args(m, error, DBUS_TYPE_INVALID))) {
295         return dbus_parsing_error("Error parsing Server::GetVersionString message", error);
296     }
297 
298     return avahi_dbus_respond_string(c, m, PACKAGE_STRING);
299 }
300 
dbus_get_api_version(DBusConnection * c,DBusMessage * m,DBusError * error)301 static DBusHandlerResult dbus_get_api_version(DBusConnection *c, DBusMessage *m, DBusError *error) {
302     if (!(dbus_message_get_args(m, error, DBUS_TYPE_INVALID))) {
303         return dbus_parsing_error("Error parsing Server::GetAPIVersion message", error);
304     }
305 
306     return avahi_dbus_respond_uint32(c, m, AVAHI_DBUS_API_VERSION);
307 }
308 
dbus_get_state(DBusConnection * c,DBusMessage * m,DBusError * error)309 static DBusHandlerResult dbus_get_state(DBusConnection *c, DBusMessage *m, DBusError *error) {
310     AvahiServerState state;
311 
312     if (!(dbus_message_get_args(m, error, DBUS_TYPE_INVALID))) {
313         return dbus_parsing_error("Error parsing Server::GetState message", error);
314     }
315 
316     state = avahi_server_get_state(avahi_server);
317     return avahi_dbus_respond_int32(c, m, (int32_t) state);
318 }
319 
dbus_get_local_service_cookie(DBusConnection * c,DBusMessage * m,DBusError * error)320 static DBusHandlerResult dbus_get_local_service_cookie(DBusConnection *c, DBusMessage *m, DBusError *error) {
321     if (!(dbus_message_get_args(m, error, DBUS_TYPE_INVALID))) {
322         return dbus_parsing_error("Error parsing Server::GetLocalServiceCookie message", error);
323     }
324 
325     return avahi_dbus_respond_uint32(c, m, avahi_server_get_local_service_cookie(avahi_server));
326 }
327 
dbus_get_net_if_by_index(DBusConnection * c,DBusMessage * m,DBusError * error)328 static DBusHandlerResult dbus_get_net_if_by_index(DBusConnection *c, DBusMessage *m, DBusError *error) {
329     int32_t idx;
330     char name[IF_NAMESIZE];
331 
332     if (!(dbus_message_get_args(m, error, DBUS_TYPE_INT32, &idx, DBUS_TYPE_INVALID))) {
333         return dbus_parsing_error("Error parsing Server::GetNetworkInterfaceNameByIndex message", error);
334     }
335 
336 #ifdef VALGRIND_WORKAROUND
337     return respond_string(c, m, "blah");
338 #else
339     if ((!if_indextoname(idx, name))) {
340         char txt[256];
341         snprintf(txt, sizeof(txt), "OS Error: %s", strerror(errno));
342         return avahi_dbus_respond_error(c, m, AVAHI_ERR_OS, txt);
343     }
344 
345     return avahi_dbus_respond_string(c, m, name);
346 #endif
347 }
348 
dbus_get_net_if_by_name(DBusConnection * c,DBusMessage * m,DBusError * error)349 static DBusHandlerResult dbus_get_net_if_by_name(DBusConnection *c, DBusMessage *m, DBusError *error) {
350     char *n;
351     int32_t idx;
352 
353     if (!(dbus_message_get_args(m, error, DBUS_TYPE_STRING, &n, DBUS_TYPE_INVALID)) || !n) {
354         return dbus_parsing_error("Error parsing Server::GetNetworkInterfaceIndexByName message", error);
355     }
356 
357 #ifdef VALGRIND_WORKAROUND
358     return respond_int32(c, m, 1);
359 #else
360     if (!(idx = if_nametoindex(n))) {
361         char txt[256];
362         snprintf(txt, sizeof(txt), "OS Error: %s", strerror(errno));
363         return avahi_dbus_respond_error(c, m, AVAHI_ERR_OS, txt);
364     }
365 
366     return avahi_dbus_respond_int32(c, m, idx);
367 #endif
368 }
369 
dbus_get_alternative_host_name(DBusConnection * c,DBusMessage * m,DBusError * error)370 static DBusHandlerResult dbus_get_alternative_host_name(DBusConnection *c, DBusMessage *m, DBusError *error) {
371     char *n, * t;
372 
373     if (!(dbus_message_get_args(m, error, DBUS_TYPE_STRING, &n, DBUS_TYPE_INVALID)) || !n) {
374         return dbus_parsing_error("Error parsing Server::GetAlternativeHostName message", error);
375     }
376 
377     t = avahi_alternative_host_name(n);
378     avahi_dbus_respond_string(c, m, t);
379     avahi_free(t);
380 
381     return DBUS_HANDLER_RESULT_HANDLED;
382 }
383 
dbus_get_alternative_service_name(DBusConnection * c,DBusMessage * m,DBusError * error)384 static DBusHandlerResult dbus_get_alternative_service_name(DBusConnection *c, DBusMessage *m, DBusError *error) {
385     char *n, *t;
386 
387     if (!(dbus_message_get_args(m, error, DBUS_TYPE_STRING, &n, DBUS_TYPE_INVALID)) || !n) {
388         return dbus_parsing_error("Error parsing Server::GetAlternativeServiceName message", error);
389     }
390 
391     t = avahi_alternative_service_name(n);
392     avahi_dbus_respond_string(c, m, t);
393     avahi_free(t);
394 
395     return DBUS_HANDLER_RESULT_HANDLED;
396 }
397 
dbus_create_new_entry_group(DBusConnection * c,DBusMessage * m,DBusError * error)398 static DBusHandlerResult dbus_create_new_entry_group(DBusConnection *c, DBusMessage *m, DBusError *error) {
399     Client *client;
400     EntryGroupInfo *i;
401     static const DBusObjectPathVTable vtable = {
402         NULL,
403         avahi_dbus_msg_entry_group_impl,
404         NULL,
405         NULL,
406         NULL,
407         NULL
408     };
409 
410     if (!dbus_message_get_args(m, error, DBUS_TYPE_INVALID)) {
411         return dbus_parsing_error("Error parsing Server::EntryGroupNew message", error);
412     }
413 
414     if (server->disable_user_service_publishing)
415         return avahi_dbus_respond_error(c, m, AVAHI_ERR_NOT_PERMITTED, NULL);
416 
417     if (!(client = client_get(dbus_message_get_sender(m), TRUE))) {
418         avahi_log_warn("Too many clients, client request failed.");
419         return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_CLIENTS, NULL);
420     }
421 
422     if (client->n_objects >= server->n_objects_per_client_max) {
423         avahi_log_warn("Too many objects for client '%s', client request failed.", client->name);
424         return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_OBJECTS, NULL);
425     }
426 
427     i = avahi_new(EntryGroupInfo, 1);
428     i->id = ++client->current_id;
429     i->client = client;
430     i->path = NULL;
431     i->n_entries = 0;
432     AVAHI_LLIST_PREPEND(EntryGroupInfo, entry_groups, client->entry_groups, i);
433     client->n_objects++;
434 
435     if (!(i->entry_group = avahi_s_entry_group_new(avahi_server, avahi_dbus_entry_group_callback, i))) {
436         avahi_dbus_entry_group_free(i);
437         return avahi_dbus_respond_error(c, m, avahi_server_errno(avahi_server), NULL);
438     }
439 
440     i->path = avahi_strdup_printf("/Client%u/EntryGroup%u", client->id, i->id);
441     dbus_connection_register_object_path(c, i->path, &vtable, i);
442     return avahi_dbus_respond_path(c, m, i->path);
443 }
444 
dbus_prepare_domain_browser_object(DomainBrowserInfo ** dbi,DBusConnection * c,DBusMessage * m,DBusError * error)445 static DBusHandlerResult dbus_prepare_domain_browser_object(DomainBrowserInfo **dbi, DBusConnection *c, DBusMessage *m, DBusError *error) {
446     Client *client;
447     DomainBrowserInfo *i;
448     static const DBusObjectPathVTable vtable = {
449         NULL,
450         avahi_dbus_msg_domain_browser_impl,
451         NULL,
452         NULL,
453         NULL,
454         NULL
455     };
456     int32_t interface, protocol, type;
457     uint32_t flags;
458     char *domain;
459 
460     if (!dbus_message_get_args(
461             m, error,
462             DBUS_TYPE_INT32, &interface,
463             DBUS_TYPE_INT32, &protocol,
464             DBUS_TYPE_STRING, &domain,
465             DBUS_TYPE_INT32, &type,
466             DBUS_TYPE_UINT32, &flags,
467             DBUS_TYPE_INVALID) || type < 0 || type >= AVAHI_DOMAIN_BROWSER_MAX) {
468         return dbus_parsing_error("Error parsing Server::DomainBrowserNew message", error);
469     }
470 
471     if (!(client = client_get(dbus_message_get_sender(m), TRUE))) {
472         avahi_log_warn("Too many clients, client request failed.");
473         return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_CLIENTS, NULL);
474     }
475 
476     if (client->n_objects >= server->n_objects_per_client_max) {
477         avahi_log_warn("Too many objects for client '%s', client request failed.", client->name);
478         return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_OBJECTS, NULL);
479     }
480 
481     if (!*domain)
482         domain = NULL;
483 
484     i = avahi_new(DomainBrowserInfo, 1);
485     i->id = ++client->current_id;
486     i->client = client;
487     i->path = NULL;
488     i->delay_timeout = NULL;
489     AVAHI_LLIST_PREPEND(DomainBrowserInfo, domain_browsers, client->domain_browsers, i);
490     client->n_objects++;
491 
492     if (!(i->domain_browser = avahi_s_domain_browser_prepare(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, domain, (AvahiDomainBrowserType) type, (AvahiLookupFlags) flags, avahi_dbus_domain_browser_callback, i))) {
493         avahi_dbus_domain_browser_free(i);
494         return avahi_dbus_respond_error(c, m, avahi_server_errno(avahi_server), NULL);
495     }
496 
497     i->path = avahi_strdup_printf("/Client%u/DomainBrowser%u", client->id, i->id);
498     dbus_connection_register_object_path(c, i->path, &vtable, i);
499     *dbi = i;
500     return avahi_dbus_respond_path(c, m, i->path);
501 }
502 
503 
dbus_prepare_service_type_browser_object(ServiceTypeBrowserInfo ** stbi,DBusConnection * c,DBusMessage * m,DBusError * error)504 static DBusHandlerResult dbus_prepare_service_type_browser_object(ServiceTypeBrowserInfo **stbi, DBusConnection *c, DBusMessage *m, DBusError *error) {
505     Client *client;
506     ServiceTypeBrowserInfo *i;
507     static const DBusObjectPathVTable vtable = {
508         NULL,
509         avahi_dbus_msg_service_type_browser_impl,
510         NULL,
511         NULL,
512         NULL,
513         NULL
514     };
515     int32_t interface, protocol;
516     uint32_t flags;
517     char *domain;
518 
519     if (!dbus_message_get_args(
520             m, error,
521             DBUS_TYPE_INT32, &interface,
522             DBUS_TYPE_INT32, &protocol,
523             DBUS_TYPE_STRING, &domain,
524             DBUS_TYPE_UINT32, &flags,
525             DBUS_TYPE_INVALID)) {
526         return dbus_parsing_error("Error parsing Server::ServiceTypeBrowserNew message", error);
527     }
528 
529     if (!(client = client_get(dbus_message_get_sender(m), TRUE))) {
530         avahi_log_warn("Too many clients, client request failed.");
531         return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_CLIENTS, NULL);
532     }
533 
534     if (client->n_objects >= server->n_objects_per_client_max) {
535         avahi_log_warn("Too many objects for client '%s', client request failed.", client->name);
536         return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_OBJECTS, NULL);
537     }
538 
539     if (!*domain)
540         domain = NULL;
541 
542     i = avahi_new(ServiceTypeBrowserInfo, 1);
543     i->id = ++client->current_id;
544     i->client = client;
545     i->path = NULL;
546     i->delay_timeout = NULL;
547     AVAHI_LLIST_PREPEND(ServiceTypeBrowserInfo, service_type_browsers, client->service_type_browsers, i);
548     client->n_objects++;
549 
550     if (!(i->service_type_browser = avahi_s_service_type_browser_prepare(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, domain, (AvahiLookupFlags) flags, avahi_dbus_service_type_browser_callback, i))) {
551         avahi_dbus_service_type_browser_free(i);
552         return avahi_dbus_respond_error(c, m, avahi_server_errno(avahi_server), NULL);
553     }
554 
555     i->path = avahi_strdup_printf("/Client%u/ServiceTypeBrowser%u", client->id, i->id);
556     dbus_connection_register_object_path(c, i->path, &vtable, i);
557     *stbi = i;
558     return avahi_dbus_respond_path(c, m, i->path);
559 }
560 
561 
dbus_prepare_service_browser_object(ServiceBrowserInfo ** sbi,DBusConnection * c,DBusMessage * m,DBusError * error)562 static DBusHandlerResult dbus_prepare_service_browser_object(ServiceBrowserInfo **sbi, DBusConnection *c, DBusMessage *m, DBusError *error) {
563     Client *client;
564     ServiceBrowserInfo *i;
565     static const DBusObjectPathVTable vtable = {
566         NULL,
567         avahi_dbus_msg_service_browser_impl,
568         NULL,
569         NULL,
570         NULL,
571         NULL
572     };
573     int32_t interface, protocol;
574     uint32_t flags;
575     char *domain, *type;
576 
577     if (!dbus_message_get_args(
578             m, error,
579             DBUS_TYPE_INT32, &interface,
580             DBUS_TYPE_INT32, &protocol,
581             DBUS_TYPE_STRING, &type,
582             DBUS_TYPE_STRING, &domain,
583             DBUS_TYPE_UINT32, &flags,
584             DBUS_TYPE_INVALID) || !type) {
585         return dbus_parsing_error("Error parsing Server::ServiceBrowserNew message", error);
586     }
587 
588     if (!(client = client_get(dbus_message_get_sender(m), TRUE))) {
589         avahi_log_warn("Too many clients, client request failed.");
590         return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_CLIENTS, NULL);
591     }
592 
593     if (client->n_objects >= server->n_objects_per_client_max) {
594         avahi_log_warn("Too many objects for client '%s', client request failed.", client->name);
595         return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_OBJECTS, NULL);
596     }
597 
598     if (!*domain)
599         domain = NULL;
600 
601     i = avahi_new(ServiceBrowserInfo, 1);
602     i->id = ++client->current_id;
603     i->client = client;
604     i->path = NULL;
605     i->delay_timeout = NULL;
606     AVAHI_LLIST_PREPEND(ServiceBrowserInfo, service_browsers, client->service_browsers, i);
607     client->n_objects++;
608 
609     if (!(i->service_browser = avahi_s_service_browser_prepare(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, type, domain, (AvahiLookupFlags) flags, avahi_dbus_service_browser_callback, i))) {
610         avahi_dbus_service_browser_free(i);
611         return avahi_dbus_respond_error(c, m, avahi_server_errno(avahi_server), NULL);
612     }
613 
614     i->path = avahi_strdup_printf("/Client%u/ServiceBrowser%u", client->id, i->id);
615     dbus_connection_register_object_path(c, i->path, &vtable, i);
616     *sbi = i;
617     return avahi_dbus_respond_path(c, m, i->path);
618 }
619 
dbus_create_sync_service_resolver_object(DBusConnection * c,DBusMessage * m,DBusError * error)620 static DBusHandlerResult dbus_create_sync_service_resolver_object(DBusConnection *c, DBusMessage *m, DBusError *error) {
621     Client *client;
622     int32_t interface, protocol, aprotocol;
623     uint32_t flags;
624     char *name, *type, *domain;
625     SyncServiceResolverInfo *i;
626 
627     if (!dbus_message_get_args(
628             m, error,
629             DBUS_TYPE_INT32, &interface,
630             DBUS_TYPE_INT32, &protocol,
631             DBUS_TYPE_STRING, &name,
632             DBUS_TYPE_STRING, &type,
633             DBUS_TYPE_STRING, &domain,
634             DBUS_TYPE_INT32, &aprotocol,
635             DBUS_TYPE_UINT32, &flags,
636             DBUS_TYPE_INVALID) || !type) {
637         return dbus_parsing_error("Error parsing Server::ResolveService message", error);
638     }
639 
640     if (!(client = client_get(dbus_message_get_sender(m), TRUE))) {
641         avahi_log_warn("Too many clients, client request failed.");
642         return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_CLIENTS, NULL);
643     }
644 
645     if (client->n_objects >= server->n_objects_per_client_max) {
646         avahi_log_warn("Too many objects for client '%s', client request failed.", client->name);
647         return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_OBJECTS, NULL);
648     }
649 
650     if (!*domain)
651         domain = NULL;
652 
653     if (!*name)
654         name = NULL;
655 
656     i = avahi_new(SyncServiceResolverInfo, 1);
657     i->client = client;
658     i->message = dbus_message_ref(m);
659     AVAHI_LLIST_PREPEND(SyncServiceResolverInfo, sync_service_resolvers, client->sync_service_resolvers, i);
660     client->n_objects++;
661 
662     if (!(i->service_resolver = avahi_s_service_resolver_new(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, name, type, domain, (AvahiProtocol) aprotocol, (AvahiLookupFlags) flags, avahi_dbus_sync_service_resolver_callback, i))) {
663         avahi_dbus_sync_service_resolver_free(i);
664         return avahi_dbus_respond_error(c, m, avahi_server_errno(avahi_server), NULL);
665     }
666 
667     return DBUS_HANDLER_RESULT_HANDLED;
668 }
669 
dbus_prepare_async_service_resolver_object(AsyncServiceResolverInfo ** sri,DBusConnection * c,DBusMessage * m,DBusError * error)670 static DBusHandlerResult dbus_prepare_async_service_resolver_object(AsyncServiceResolverInfo **sri, DBusConnection *c, DBusMessage *m, DBusError *error) {
671     Client *client;
672     int32_t interface, protocol, aprotocol;
673     uint32_t flags;
674     char *name, *type, *domain;
675     AsyncServiceResolverInfo *i;
676     static const DBusObjectPathVTable vtable = {
677         NULL,
678         avahi_dbus_msg_async_service_resolver_impl,
679         NULL,
680         NULL,
681         NULL,
682         NULL
683     };
684 
685     if (!dbus_message_get_args(
686             m, error,
687             DBUS_TYPE_INT32, &interface,
688             DBUS_TYPE_INT32, &protocol,
689             DBUS_TYPE_STRING, &name,
690             DBUS_TYPE_STRING, &type,
691             DBUS_TYPE_STRING, &domain,
692             DBUS_TYPE_INT32, &aprotocol,
693             DBUS_TYPE_UINT32, &flags,
694             DBUS_TYPE_INVALID) || !type) {
695         return dbus_parsing_error("Error parsing Server::ServiceResolverNew message", error);
696     }
697 
698     if (!(client = client_get(dbus_message_get_sender(m), TRUE))) {
699         avahi_log_warn(__FILE__": Too many clients, client request failed.");
700         return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_CLIENTS, NULL);
701     }
702 
703     if (client->n_objects >= server->n_objects_per_client_max) {
704         avahi_log_warn(__FILE__": Too many objects for client '%s', client request failed.", client->name);
705         return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_OBJECTS, NULL);
706     }
707 
708     if (!*domain)
709         domain = NULL;
710 
711     if (!*name)
712         name = NULL;
713 
714     i = avahi_new(AsyncServiceResolverInfo, 1);
715     i->id = ++client->current_id;
716     i->client = client;
717     i->path = NULL;
718     i->delay_timeout = NULL;
719     AVAHI_LLIST_PREPEND(AsyncServiceResolverInfo, async_service_resolvers, client->async_service_resolvers, i);
720     client->n_objects++;
721 
722     if (!(i->service_resolver = avahi_s_service_resolver_prepare(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, name, type, domain, (AvahiProtocol) aprotocol, (AvahiLookupFlags) flags, avahi_dbus_async_service_resolver_callback, i))) {
723         avahi_dbus_async_service_resolver_free(i);
724         return avahi_dbus_respond_error(c, m, avahi_server_errno(avahi_server), NULL);
725     }
726 
727 /* avahi_log_debug(__FILE__": [%s], new service resolver for <%s.%s.%s>", i->path, name, type, domain); */
728 
729     i->path = avahi_strdup_printf("/Client%u/ServiceResolver%u", client->id, i->id);
730     dbus_connection_register_object_path(c, i->path, &vtable, i);
731     *sri = i;
732     return avahi_dbus_respond_path(c, m, i->path);
733 }
734 
dbus_create_sync_host_name_resolver_object(DBusConnection * c,DBusMessage * m,DBusError * error)735 static DBusHandlerResult dbus_create_sync_host_name_resolver_object(DBusConnection *c, DBusMessage *m, DBusError *error) {
736     Client *client;
737     int32_t interface, protocol, aprotocol;
738     uint32_t flags;
739     char *name;
740     SyncHostNameResolverInfo *i;
741 
742     if (!dbus_message_get_args(
743             m, error,
744             DBUS_TYPE_INT32, &interface,
745             DBUS_TYPE_INT32, &protocol,
746             DBUS_TYPE_STRING, &name,
747             DBUS_TYPE_INT32, &aprotocol,
748             DBUS_TYPE_UINT32, &flags,
749             DBUS_TYPE_INVALID) || !name) {
750         return dbus_parsing_error("Error parsing Server::ResolveHostName message", error);
751     }
752 
753     if (!(client = client_get(dbus_message_get_sender(m), TRUE))) {
754         avahi_log_warn("Too many clients, client request failed.");
755         return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_CLIENTS, NULL);
756     }
757 
758     if (client->n_objects >= server->n_objects_per_client_max) {
759         avahi_log_warn("Too many objects for client '%s', client request failed.", client->name);
760         return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_OBJECTS, NULL);
761     }
762 
763     i = avahi_new(SyncHostNameResolverInfo, 1);
764     i->client = client;
765     i->message = dbus_message_ref(m);
766     AVAHI_LLIST_PREPEND(SyncHostNameResolverInfo, sync_host_name_resolvers, client->sync_host_name_resolvers, i);
767     client->n_objects++;
768 
769     if (!(i->host_name_resolver = avahi_s_host_name_resolver_new(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, name, (AvahiProtocol) aprotocol, (AvahiLookupFlags) flags, avahi_dbus_sync_host_name_resolver_callback, i))) {
770         avahi_dbus_sync_host_name_resolver_free(i);
771         return avahi_dbus_respond_error(c, m, avahi_server_errno(avahi_server), NULL);
772     }
773 
774     return DBUS_HANDLER_RESULT_HANDLED;
775 }
776 
dbus_prepare_async_host_name_resolver_object(AsyncHostNameResolverInfo ** hri,DBusConnection * c,DBusMessage * m,DBusError * error)777 static DBusHandlerResult dbus_prepare_async_host_name_resolver_object(AsyncHostNameResolverInfo **hri, DBusConnection *c, DBusMessage *m, DBusError *error) {
778     Client *client;
779     int32_t interface, protocol, aprotocol;
780     uint32_t flags;
781     char *name;
782     AsyncHostNameResolverInfo *i;
783     static const DBusObjectPathVTable vtable = {
784         NULL,
785         avahi_dbus_msg_async_host_name_resolver_impl,
786         NULL,
787         NULL,
788         NULL,
789         NULL
790     };
791 
792     if (!dbus_message_get_args(
793             m, error,
794             DBUS_TYPE_INT32, &interface,
795             DBUS_TYPE_INT32, &protocol,
796             DBUS_TYPE_STRING, &name,
797             DBUS_TYPE_INT32, &aprotocol,
798             DBUS_TYPE_UINT32, &flags,
799             DBUS_TYPE_INVALID) || !name) {
800         return dbus_parsing_error("Error parsing Server::HostNameResolverNew message", error);
801     }
802 
803     if (!(client = client_get(dbus_message_get_sender(m), TRUE))) {
804         avahi_log_warn(__FILE__": Too many clients, client request failed.");
805         return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_CLIENTS, NULL);
806     }
807 
808     if (client->n_objects >= server->n_objects_per_client_max) {
809         avahi_log_warn(__FILE__": Too many objects for client '%s', client request failed.", client->name);
810         return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_OBJECTS, NULL);
811     }
812 
813     i = avahi_new(AsyncHostNameResolverInfo, 1);
814     i->id = ++client->current_id;
815     i->client = client;
816     i->path = NULL;
817     i->delay_timeout = NULL;
818     AVAHI_LLIST_PREPEND(AsyncHostNameResolverInfo, async_host_name_resolvers, client->async_host_name_resolvers, i);
819     client->n_objects++;
820 
821     if (!(i->host_name_resolver = avahi_s_host_name_resolver_prepare(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, name, aprotocol, (AvahiLookupFlags) flags, avahi_dbus_async_host_name_resolver_callback, i))) {
822         avahi_dbus_async_host_name_resolver_free(i);
823         return avahi_dbus_respond_error(c, m, avahi_server_errno(avahi_server), NULL);
824     }
825 
826     i->path = avahi_strdup_printf("/Client%u/HostNameResolver%u", client->id, i->id);
827     dbus_connection_register_object_path(c, i->path, &vtable, i);
828     *hri = i;
829     return avahi_dbus_respond_path(c, m, i->path);
830 }
831 
dbus_create_sync_address_resolver_object(DBusConnection * c,DBusMessage * m,DBusError * error)832 static DBusHandlerResult dbus_create_sync_address_resolver_object(DBusConnection *c, DBusMessage *m, DBusError *error) {
833     Client *client;
834     int32_t interface, protocol;
835     uint32_t flags;
836     char *address;
837     SyncAddressResolverInfo *i;
838     AvahiAddress a;
839 
840     if (!dbus_message_get_args(
841             m, error,
842             DBUS_TYPE_INT32, &interface,
843             DBUS_TYPE_INT32, &protocol,
844             DBUS_TYPE_STRING, &address,
845             DBUS_TYPE_UINT32, &flags,
846             DBUS_TYPE_INVALID) || !address) {
847         return dbus_parsing_error("Error parsing Server::ResolveAddress message", error);
848     }
849 
850     if (!avahi_address_parse(address, AVAHI_PROTO_UNSPEC, &a))
851         return avahi_dbus_respond_error(c, m, AVAHI_ERR_INVALID_ADDRESS, NULL);
852 
853     if (!(client = client_get(dbus_message_get_sender(m), TRUE))) {
854         avahi_log_warn("Too many clients, client request failed.");
855         return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_CLIENTS, NULL);
856     }
857 
858     if (client->n_objects >= server->n_objects_per_client_max) {
859         avahi_log_warn("Too many objects for client '%s', client request failed.", client->name);
860         return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_OBJECTS, NULL);
861     }
862 
863     i = avahi_new(SyncAddressResolverInfo, 1);
864     i->client = client;
865     i->message = dbus_message_ref(m);
866     AVAHI_LLIST_PREPEND(SyncAddressResolverInfo, sync_address_resolvers, client->sync_address_resolvers, i);
867     client->n_objects++;
868 
869     if (!(i->address_resolver = avahi_s_address_resolver_new(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, &a, (AvahiLookupFlags) flags, avahi_dbus_sync_address_resolver_callback, i))) {
870         avahi_dbus_sync_address_resolver_free(i);
871         return avahi_dbus_respond_error(c, m, avahi_server_errno(avahi_server), NULL);
872     }
873 
874     return DBUS_HANDLER_RESULT_HANDLED;
875 }
876 
dbus_prepare_async_address_resolver_object(AsyncAddressResolverInfo ** ari,DBusConnection * c,DBusMessage * m,DBusError * error)877 static DBusHandlerResult dbus_prepare_async_address_resolver_object(AsyncAddressResolverInfo **ari, DBusConnection *c, DBusMessage *m, DBusError *error) {
878     Client *client;
879     int32_t interface, protocol;
880     uint32_t flags;
881     char *address;
882     AsyncAddressResolverInfo *i;
883     AvahiAddress a;
884     static const DBusObjectPathVTable vtable = {
885         NULL,
886         avahi_dbus_msg_async_address_resolver_impl,
887         NULL,
888         NULL,
889         NULL,
890         NULL
891     };
892 
893     if (!dbus_message_get_args(
894             m, error,
895             DBUS_TYPE_INT32, &interface,
896             DBUS_TYPE_INT32, &protocol,
897             DBUS_TYPE_STRING, &address,
898             DBUS_TYPE_UINT32, &flags,
899             DBUS_TYPE_INVALID) || !address) {
900         return dbus_parsing_error("Error parsing Server::AddressResolverNew message", error);
901     }
902 
903     if (!avahi_address_parse(address, AVAHI_PROTO_UNSPEC, &a))
904         return avahi_dbus_respond_error(c, m, AVAHI_ERR_INVALID_ADDRESS, NULL);
905 
906     if (!(client = client_get(dbus_message_get_sender(m), TRUE))) {
907         avahi_log_warn(__FILE__": Too many clients, client request failed.");
908         return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_CLIENTS, NULL);
909     }
910 
911     if (client->n_objects >= server->n_objects_per_client_max) {
912         avahi_log_warn(__FILE__": Too many objects for client '%s', client request failed.", client->name);
913         return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_OBJECTS, NULL);
914     }
915 
916     i = avahi_new(AsyncAddressResolverInfo, 1);
917     i->id = ++client->current_id;
918     i->client = client;
919     i->path = NULL;
920     i->delay_timeout = NULL;
921     AVAHI_LLIST_PREPEND(AsyncAddressResolverInfo, async_address_resolvers, client->async_address_resolvers, i);
922     client->n_objects++;
923 
924     if (!(i->address_resolver = avahi_s_address_resolver_prepare(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, &a, (AvahiLookupFlags) flags, avahi_dbus_async_address_resolver_callback, i))) {
925         avahi_dbus_async_address_resolver_free(i);
926         return avahi_dbus_respond_error(c, m, avahi_server_errno(avahi_server), NULL);
927     }
928 
929     i->path = avahi_strdup_printf("/Client%u/AddressResolver%u", client->id, i->id);
930     dbus_connection_register_object_path(c, i->path, &vtable, i);
931     *ari = i;
932     return avahi_dbus_respond_path(c, m, i->path);
933 }
934 
dbus_prepare_record_browser_object(RecordBrowserInfo ** rbi,DBusConnection * c,DBusMessage * m,DBusError * error)935 static DBusHandlerResult dbus_prepare_record_browser_object(RecordBrowserInfo **rbi, DBusConnection *c, DBusMessage *m, DBusError *error) {
936     Client *client;
937     RecordBrowserInfo *i;
938     static const DBusObjectPathVTable vtable = {
939         NULL,
940         avahi_dbus_msg_record_browser_impl,
941         NULL,
942         NULL,
943         NULL,
944         NULL
945     };
946     int32_t interface, protocol;
947     uint32_t flags;
948     char *name;
949     uint16_t type, clazz;
950     AvahiKey *key;
951 
952     if (!dbus_message_get_args(
953             m, error,
954             DBUS_TYPE_INT32, &interface,
955             DBUS_TYPE_INT32, &protocol,
956             DBUS_TYPE_STRING, &name,
957             DBUS_TYPE_UINT16, &clazz,
958             DBUS_TYPE_UINT16, &type,
959             DBUS_TYPE_UINT32, &flags,
960             DBUS_TYPE_INVALID) || !name) {
961         return dbus_parsing_error("Error parsing Server::RecordBrowserNew message", error);
962     }
963 
964     if (!avahi_is_valid_domain_name(name))
965         return avahi_dbus_respond_error(c, m, AVAHI_ERR_INVALID_DOMAIN_NAME, NULL);
966 
967     if (!(client = client_get(dbus_message_get_sender(m), TRUE))) {
968         avahi_log_warn("Too many clients, client request failed.");
969         return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_CLIENTS, NULL);
970     }
971 
972     if (client->n_objects >= server->n_objects_per_client_max) {
973         avahi_log_warn("Too many objects for client '%s', client request failed.", client->name);
974         return avahi_dbus_respond_error(c, m, AVAHI_ERR_TOO_MANY_OBJECTS, NULL);
975     }
976 
977     i = avahi_new(RecordBrowserInfo, 1);
978     i->id = ++client->current_id;
979     i->client = client;
980     i->path = NULL;
981     i->delay_timeout = NULL;
982     AVAHI_LLIST_PREPEND(RecordBrowserInfo, record_browsers, client->record_browsers, i);
983     client->n_objects++;
984 
985     key = avahi_key_new(name, clazz, type);
986     assert(key);
987 
988     if (!(i->record_browser = avahi_s_record_browser_prepare(avahi_server, (AvahiIfIndex) interface, (AvahiProtocol) protocol, key, (AvahiLookupFlags) flags, avahi_dbus_record_browser_callback, i))) {
989         avahi_key_unref(key);
990         avahi_dbus_record_browser_free(i);
991         return avahi_dbus_respond_error(c, m, avahi_server_errno(avahi_server), NULL);
992     }
993 
994     avahi_key_unref(key);
995 
996     i->path = avahi_strdup_printf("/Client%u/RecordBrowser%u", client->id, i->id);
997     dbus_connection_register_object_path(c, i->path, &vtable, i);
998     *rbi = i;
999     return avahi_dbus_respond_path(c, m, i->path);
1000 }
1001 
dbus_select_common_methods(DBusConnection * c,DBusMessage * m,AVAHI_GCC_UNUSED void * userdata,const char * iface,DBusError * error)1002 static DBusHandlerResult dbus_select_common_methods(DBusConnection *c, DBusMessage *m, AVAHI_GCC_UNUSED void *userdata, const char *iface, DBusError *error) {
1003     if (dbus_message_is_method_call(m, DBUS_INTERFACE_INTROSPECTABLE, "Introspect"))
1004         return avahi_dbus_handle_introspect(c, m, "org.freedesktop.Avahi.Server.xml");
1005 
1006     else if (dbus_message_is_method_call(m, iface, "GetHostName")) {
1007         return dbus_get_host_name(c, m, error);
1008 
1009     } else if (dbus_message_is_method_call(m, iface, "SetHostName")) {
1010         return dbus_set_host_name(c, m, error);
1011 
1012     } else if (dbus_message_is_method_call(m, iface, "GetDomainName")) {
1013         return dbus_get_domain_name(c, m, error);
1014 
1015     } else if (dbus_message_is_method_call(m, iface, "GetHostNameFqdn")) {
1016         return dbus_get_host_name_fqdn(c, m, error);
1017 
1018     } else if (dbus_message_is_method_call(m, iface, "IsNSSSupportAvailable")) {
1019         return dbus_is_ns_support_available(c, m, error);
1020 
1021     } else if (dbus_message_is_method_call(m, iface, "GetVersionString")) {
1022         return dbus_get_version_string(c, m, error);
1023 
1024     } else if (dbus_message_is_method_call(m, iface, "GetAPIVersion")) {
1025         return dbus_get_api_version(c, m, error);
1026 
1027     } else if (dbus_message_is_method_call(m, iface, "GetState")) {
1028         return dbus_get_state(c, m, error);
1029 
1030     } else if (dbus_message_is_method_call(m, iface, "GetLocalServiceCookie")) {
1031         return dbus_get_local_service_cookie(c, m, error);
1032 
1033     } else if (dbus_message_is_method_call(m, iface, "GetNetworkInterfaceNameByIndex")) {
1034         return dbus_get_net_if_by_index(c, m, error);
1035 
1036     } else if (dbus_message_is_method_call(m, iface, "GetNetworkInterfaceIndexByName")) {
1037         return dbus_get_net_if_by_name(c, m, error);
1038 
1039     } else if (dbus_message_is_method_call(m, iface, "GetAlternativeHostName")) {
1040         return dbus_get_alternative_host_name(c, m, error);
1041 
1042     } else if (dbus_message_is_method_call(m, iface, "GetAlternativeServiceName")) {
1043         return dbus_get_alternative_service_name(c, m, error);
1044 
1045     } else if (dbus_message_is_method_call(m, iface, "EntryGroupNew")) {
1046         return dbus_create_new_entry_group(c, m, error);
1047 
1048     } else if (dbus_message_is_method_call(m, iface, "ResolveHostName")) {
1049         return dbus_create_sync_host_name_resolver_object(c, m, error);
1050 
1051     } else if (dbus_message_is_method_call(m, iface, "ResolveAddress")) {
1052         return dbus_create_sync_address_resolver_object(c, m, error);
1053 
1054     } else if (dbus_message_is_method_call(m, iface, "ResolveService")) {
1055         return dbus_create_sync_service_resolver_object(c, m, error);
1056     }
1057 
1058     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1059 }
1060 
CREATE_DBUS_DELAY_FUNC(DomainBrowserInfo,domain_browser,avahi_s_domain_browser_start)1061 CREATE_DBUS_DELAY_FUNC(DomainBrowserInfo, domain_browser, avahi_s_domain_browser_start)
1062 CREATE_DBUS_DELAY_FUNC(ServiceTypeBrowserInfo, service_type_browser, avahi_s_service_type_browser_start)
1063 CREATE_DBUS_DELAY_FUNC(ServiceBrowserInfo, service_browser, avahi_s_service_browser_start)
1064 CREATE_DBUS_DELAY_FUNC(AsyncServiceResolverInfo, service_resolver, avahi_s_service_resolver_start)
1065 CREATE_DBUS_DELAY_FUNC(AsyncHostNameResolverInfo, host_name_resolver, avahi_s_host_name_resolver_start)
1066 CREATE_DBUS_DELAY_FUNC(AsyncAddressResolverInfo, address_resolver, avahi_s_address_resolver_start)
1067 CREATE_DBUS_DELAY_FUNC(RecordBrowserInfo, record_browser, avahi_s_record_browser_start_query)
1068 
1069 static DBusHandlerResult dbus_select_browser(DBusConnection *c, DBusMessage *m, AVAHI_GCC_UNUSED void *userdata, const char *iface, DBusError *error) {
1070     DBusHandlerResult r;
1071     const AvahiPoll *poll_api = NULL;
1072     struct timeval tv;
1073 
1074     poll_api = avahi_simple_poll_get(simple_poll_api);
1075     avahi_elapse_time(&tv, DEFAULT_START_DELAY_MS, 0);
1076 
1077     if (dbus_message_is_method_call(m, iface, "DomainBrowserNew")) {
1078         DomainBrowserInfo *db = NULL;
1079         r = dbus_prepare_domain_browser_object(&db, c, m, error);
1080         if (db)
1081             db->delay_timeout = poll_api->timeout_new(poll_api, &tv, GET_DBUS_DELAY_FUNC(DomainBrowserInfo, domain_browser), db);
1082         return r;
1083 
1084     } else if (dbus_message_is_method_call(m, iface, "ServiceTypeBrowserNew")) {
1085         ServiceTypeBrowserInfo *stbi = NULL;
1086         r = dbus_prepare_service_type_browser_object(&stbi, c, m, error);
1087         if (stbi)
1088             stbi->delay_timeout = poll_api->timeout_new(poll_api, &tv, GET_DBUS_DELAY_FUNC(ServiceTypeBrowserInfo, service_type_browser), stbi);
1089         return r;
1090 
1091     } else if (dbus_message_is_method_call(m, iface, "ServiceBrowserNew")) {
1092         ServiceBrowserInfo *sbi = NULL;
1093         r = dbus_prepare_service_browser_object(&sbi, c, m, error);
1094         if (sbi)
1095             sbi->delay_timeout = poll_api->timeout_new(poll_api, &tv, GET_DBUS_DELAY_FUNC(ServiceBrowserInfo, service_browser), sbi);
1096         return r;
1097 
1098     } else if (dbus_message_is_method_call(m, iface, "ServiceResolverNew")) {
1099         AsyncServiceResolverInfo *sri = NULL;
1100         r = dbus_prepare_async_service_resolver_object(&sri, c, m, error);
1101         if (sri)
1102             sri->delay_timeout = poll_api->timeout_new(poll_api, &tv, GET_DBUS_DELAY_FUNC(AsyncServiceResolverInfo, service_resolver), sri);
1103         return r;
1104 
1105     } else if (dbus_message_is_method_call(m, iface, "HostNameResolverNew")) {
1106         AsyncHostNameResolverInfo *hri = NULL;
1107         r = dbus_prepare_async_host_name_resolver_object(&hri, c, m, error);
1108         if (hri)
1109             hri->delay_timeout = poll_api->timeout_new(poll_api, &tv, GET_DBUS_DELAY_FUNC(AsyncHostNameResolverInfo, host_name_resolver), hri);
1110         return r;
1111 
1112     } else if (dbus_message_is_method_call(m, iface, "AddressResolverNew")) {
1113         AsyncAddressResolverInfo *ari = NULL;
1114         r = dbus_prepare_async_address_resolver_object(&ari, c, m, error);
1115         if (ari)
1116             ari->delay_timeout = poll_api->timeout_new(poll_api, &tv, GET_DBUS_DELAY_FUNC(AsyncAddressResolverInfo, address_resolver), ari);
1117         return r;
1118 
1119     } else if (dbus_message_is_method_call(m, iface, "RecordBrowserNew")) {
1120         RecordBrowserInfo *rbi = NULL;
1121         r = dbus_prepare_record_browser_object(&rbi, c, m, error);
1122         if (rbi)
1123             rbi->delay_timeout = poll_api->timeout_new(poll_api, &tv, GET_DBUS_DELAY_FUNC(RecordBrowserInfo, record_browser), rbi);
1124         return r;
1125     }
1126 
1127     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1128 }
1129 
dbus_select_prepare_browser(DBusConnection * c,DBusMessage * m,AVAHI_GCC_UNUSED void * userdata,const char * iface,DBusError * error)1130 static DBusHandlerResult dbus_select_prepare_browser(DBusConnection *c, DBusMessage *m, AVAHI_GCC_UNUSED void *userdata, const char *iface, DBusError *error) {
1131     DBusHandlerResult r;
1132 
1133     if (dbus_message_is_method_call(m, iface, "DomainBrowserPrepare")) {
1134         DomainBrowserInfo *db = NULL;
1135         r = dbus_prepare_domain_browser_object(&db, c, m, error);
1136         return r;
1137 
1138     } else if (dbus_message_is_method_call(m, iface, "ServiceTypeBrowserPrepare")) {
1139         ServiceTypeBrowserInfo *stbi = NULL;
1140         r = dbus_prepare_service_type_browser_object(&stbi, c, m, error);
1141         return r;
1142 
1143     } else if (dbus_message_is_method_call(m, iface, "ServiceBrowserPrepare")) {
1144         ServiceBrowserInfo *sbi = NULL;
1145         r = dbus_prepare_service_browser_object(&sbi, c, m, error);
1146         return r;
1147 
1148     } else if (dbus_message_is_method_call(m, iface, "ServiceResolverPrepare")) {
1149         AsyncServiceResolverInfo *sri = NULL;
1150         r = dbus_prepare_async_service_resolver_object(&sri, c, m, error);
1151         return r;
1152 
1153     } else if (dbus_message_is_method_call(m, iface, "HostNameResolverPrepare")) {
1154         AsyncHostNameResolverInfo *hri = NULL;
1155         r = dbus_prepare_async_host_name_resolver_object(&hri, c, m, error);
1156         return r;
1157 
1158     } else if (dbus_message_is_method_call(m, iface, "AddressResolverPrepare")) {
1159         AsyncAddressResolverInfo *ari = NULL;
1160         r = dbus_prepare_async_address_resolver_object(&ari, c, m, error);
1161         return r;
1162 
1163     } else if (dbus_message_is_method_call(m, iface, "RecordBrowserPrepare")) {
1164         RecordBrowserInfo *rbi = NULL;
1165         r = dbus_prepare_record_browser_object(&rbi, c, m, error);
1166         return r;
1167     }
1168 
1169     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1170 }
1171 
msg_server_impl(DBusConnection * c,DBusMessage * m,AVAHI_GCC_UNUSED void * userdata)1172 static DBusHandlerResult msg_server_impl(DBusConnection *c, DBusMessage *m, AVAHI_GCC_UNUSED void *userdata) {
1173     DBusHandlerResult r;
1174     DBusError error;
1175 
1176     dbus_error_init(&error);
1177 
1178     avahi_log_debug(__FILE__": interface=%s, path=%s, member=%s",
1179                     dbus_message_get_interface(m),
1180                     dbus_message_get_path(m),
1181                     dbus_message_get_member(m));
1182 
1183     r = dbus_select_common_methods(c,m,userdata, AVAHI_DBUS_INTERFACE_SERVER, &error);
1184     if( r != DBUS_HANDLER_RESULT_NOT_YET_HANDLED)
1185         return r;
1186 
1187     r = dbus_select_browser(c,m,userdata, AVAHI_DBUS_INTERFACE_SERVER, &error);
1188     if( r != DBUS_HANDLER_RESULT_NOT_YET_HANDLED)
1189         return r;
1190 
1191     r = dbus_select_common_methods(c,m,userdata, AVAHI_DBUS_INTERFACE_SERVER2, &error);
1192     if( r != DBUS_HANDLER_RESULT_NOT_YET_HANDLED)
1193         return r;
1194 
1195     r = dbus_select_browser(c,m,userdata, AVAHI_DBUS_INTERFACE_SERVER2, &error);
1196     if( r != DBUS_HANDLER_RESULT_NOT_YET_HANDLED)
1197         return r;
1198 
1199     r = dbus_select_prepare_browser(c,m,userdata, AVAHI_DBUS_INTERFACE_SERVER2, &error);
1200     if( r != DBUS_HANDLER_RESULT_NOT_YET_HANDLED)
1201         return r;
1202 
1203 
1204     avahi_log_warn("Missed message %s::%s()", dbus_message_get_interface(m), dbus_message_get_member(m));
1205     if (dbus_error_is_set(&error))
1206         dbus_error_free(&error);
1207 
1208     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1209 }
1210 
dbus_protocol_server_state_changed(AvahiServerState state)1211 void dbus_protocol_server_state_changed(AvahiServerState state) {
1212     DBusMessage *m;
1213     int32_t t;
1214     const char *e;
1215 
1216     if (!server || !server->bus)
1217         return;
1218 
1219     m = dbus_message_new_signal(AVAHI_DBUS_PATH_SERVER, AVAHI_DBUS_INTERFACE_SERVER, "StateChanged");
1220 
1221     if (!m) {
1222         avahi_log_error("Failed allocate message");
1223         return;
1224     }
1225 
1226     t = (int32_t) state;
1227 
1228     if (state == AVAHI_SERVER_COLLISION)
1229         e = AVAHI_DBUS_ERR_COLLISION;
1230     else if (state == AVAHI_SERVER_FAILURE)
1231         e = avahi_error_number_to_dbus(avahi_server_errno(avahi_server));
1232     else
1233         e = AVAHI_DBUS_ERR_OK;
1234 
1235     dbus_message_append_args(m, DBUS_TYPE_INT32, &t, DBUS_TYPE_STRING, &e, DBUS_TYPE_INVALID);
1236     dbus_connection_send(server->bus, m, NULL);
1237     dbus_message_unref(m);
1238 }
1239 
dbus_connect(void)1240 static int dbus_connect(void) {
1241     DBusError error;
1242 
1243     static const DBusObjectPathVTable server_vtable = {
1244         NULL,
1245         msg_server_impl,
1246         NULL,
1247         NULL,
1248         NULL,
1249         NULL
1250     };
1251 
1252     assert(server);
1253     assert(!server->bus);
1254 
1255     dbus_error_init(&error);
1256 
1257 #ifdef HAVE_DBUS_BUS_GET_PRIVATE
1258     if (!(server->bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error))) {
1259         assert(dbus_error_is_set(&error));
1260         avahi_log_error("dbus_bus_get_private(): %s", error.message);
1261         goto fail;
1262     }
1263 #else
1264     {
1265         const char *a;
1266 
1267         if (!(a = getenv("DBUS_SYSTEM_BUS_ADDRESS")) || !*a)
1268             a = DBUS_SYSTEM_BUS_DEFAULT_ADDRESS;
1269 
1270         if (!(server->bus = dbus_connection_open_private(a, &error))) {
1271             assert(dbus_error_is_set(&error));
1272             avahi_log_error("dbus_bus_open_private(): %s", error.message);
1273             goto fail;
1274         }
1275 
1276         if (!dbus_bus_register(server->bus, &error)) {
1277             assert(dbus_error_is_set(&error));
1278             avahi_log_error("dbus_bus_register(): %s", error.message);
1279             goto fail;
1280         }
1281     }
1282 #endif
1283 
1284     if (avahi_dbus_connection_glue(server->bus, server->poll_api) < 0) {
1285         avahi_log_error("avahi_dbus_connection_glue() failed");
1286         goto fail;
1287     }
1288 
1289     dbus_connection_set_exit_on_disconnect(server->bus, FALSE);
1290 
1291     if (dbus_bus_request_name(
1292             server->bus,
1293             AVAHI_DBUS_NAME,
1294 #if (DBUS_VERSION_MAJOR == 0) && (DBUS_VERSION_MINOR < 60)
1295             DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT,
1296 #else
1297             DBUS_NAME_FLAG_DO_NOT_QUEUE,
1298 #endif
1299             &error) != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
1300         if (dbus_error_is_set(&error)) {
1301             avahi_log_error("dbus_bus_request_name(): %s", error.message);
1302             goto fail;
1303         }
1304 
1305         avahi_log_error("Failed to acquire D-Bus name '"AVAHI_DBUS_NAME"'");
1306         goto fail;
1307     }
1308 
1309     if (!(dbus_connection_add_filter(server->bus, msg_signal_filter_impl, (void*) server->poll_api, NULL))) {
1310         avahi_log_error("dbus_connection_add_filter() failed");
1311         goto fail;
1312     }
1313 
1314     dbus_bus_add_match(server->bus, "type='signal',""interface='" DBUS_INTERFACE_DBUS  "'", &error);
1315 
1316     if (dbus_error_is_set(&error)) {
1317         avahi_log_error("dbus_bus_add_match(): %s", error.message);
1318         goto fail;
1319     }
1320 
1321     if (!(dbus_connection_register_object_path(server->bus, AVAHI_DBUS_PATH_SERVER, &server_vtable, NULL))) {
1322         avahi_log_error("dbus_connection_register_object_path() failed");
1323         goto fail;
1324     }
1325 
1326     return 0;
1327 fail:
1328 
1329     if (dbus_error_is_set(&error))
1330         dbus_error_free(&error);
1331 
1332     if (server->bus) {
1333 #ifdef HAVE_DBUS_CONNECTION_CLOSE
1334         dbus_connection_close(server->bus);
1335 #else
1336         dbus_connection_disconnect(server->bus);
1337 #endif
1338         dbus_connection_unref(server->bus);
1339         server->bus = NULL;
1340     }
1341 
1342     return -1;
1343 }
1344 
dbus_disconnect(void)1345 static void dbus_disconnect(void) {
1346     assert(server);
1347 
1348     while (server->clients)
1349         client_free(server->clients);
1350 
1351     assert(server->n_clients == 0);
1352 
1353     if (server->bus) {
1354 #ifdef HAVE_DBUS_CONNECTION_CLOSE
1355         dbus_connection_close(server->bus);
1356 #else
1357         dbus_connection_disconnect(server->bus);
1358 #endif
1359         dbus_connection_unref(server->bus);
1360         server->bus = NULL;
1361     }
1362 }
1363 
dbus_protocol_setup(const AvahiPoll * poll_api,int _disable_user_service_publishing,int _n_clients_max,int _n_objects_per_client_max,int _n_entries_per_entry_group_max,int force)1364 int dbus_protocol_setup(const AvahiPoll *poll_api,
1365                         int _disable_user_service_publishing,
1366                         int _n_clients_max,
1367                         int _n_objects_per_client_max,
1368                         int _n_entries_per_entry_group_max,
1369                         int force) {
1370 
1371 
1372     server = avahi_new(Server, 1);
1373     AVAHI_LLIST_HEAD_INIT(Clients, server->clients);
1374     server->current_id = 0;
1375     server->n_clients = 0;
1376     server->bus = NULL;
1377     server->poll_api = poll_api;
1378     server->reconnect_timeout = NULL;
1379     server->reconnect = force;
1380     server->disable_user_service_publishing = _disable_user_service_publishing;
1381     server->n_clients_max = _n_clients_max > 0 ? _n_clients_max : DEFAULT_CLIENTS_MAX;
1382     server->n_objects_per_client_max = _n_objects_per_client_max > 0 ? _n_objects_per_client_max : DEFAULT_OBJECTS_PER_CLIENT_MAX;
1383     server->n_entries_per_entry_group_max = _n_entries_per_entry_group_max > 0 ? _n_entries_per_entry_group_max : DEFAULT_ENTRIES_PER_ENTRY_GROUP_MAX;
1384 
1385     if (dbus_connect() < 0) {
1386         struct timeval tv;
1387 
1388         if (!force)
1389             goto fail;
1390 
1391         avahi_log_warn("WARNING: Failed to contact D-Bus daemon, retrying in %ims.", RECONNECT_MSEC);
1392 
1393         avahi_elapse_time(&tv, RECONNECT_MSEC, 0);
1394         server->reconnect_timeout = server->poll_api->timeout_new(server->poll_api, &tv, reconnect_callback, NULL);
1395     }
1396 
1397     return 0;
1398 
1399 fail:
1400     if (server->bus) {
1401 #ifdef HAVE_DBUS_CONNECTION_CLOSE
1402         dbus_connection_close(server->bus);
1403 #else
1404         dbus_connection_disconnect(server->bus);
1405 #endif
1406 
1407         dbus_connection_unref(server->bus);
1408     }
1409 
1410     avahi_free(server);
1411     server = NULL;
1412     return -1;
1413 }
1414 
dbus_protocol_shutdown(void)1415 void dbus_protocol_shutdown(void) {
1416 
1417     if (server) {
1418         dbus_disconnect();
1419 
1420         if (server->reconnect_timeout)
1421             server->poll_api->timeout_free(server->reconnect_timeout);
1422 
1423         avahi_free(server);
1424         server = NULL;
1425     }
1426 }
1427