chiark / gitweb /
resolved: when there's already somebody listening on the LLMNR ports, simple disable...
[elogind.git] / src / dbus1-generator / dbus1-generator.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2013 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include "util.h"
23 #include "conf-parser.h"
24 #include "special.h"
25 #include "mkdir.h"
26 #include "bus-util.h"
27 #include "bus-internal.h"
28 #include "unit-name.h"
29 #include "cgroup-util.h"
30
31 static const char *arg_dest_late = "/tmp", *arg_dest = "/tmp";
32
33 static int create_dbus_files(
34                 const char *path,
35                 const char *name,
36                 const char *service,
37                 const char *exec,
38                 const char *user,
39                 const char *type) {
40
41         _cleanup_free_ char *b = NULL, *s = NULL, *lnk = NULL;
42         _cleanup_fclose_ FILE *f = NULL;
43
44         assert(path);
45         assert(name);
46         assert(service || exec);
47
48         if (!service) {
49                 _cleanup_free_ char *a = NULL;
50
51                 s = strjoin("dbus-", name, ".service", NULL);
52                 if (!s)
53                         return log_oom();
54
55                 a = strjoin(arg_dest_late, "/", s, NULL);
56                 if (!a)
57                         return log_oom();
58
59                 f = fopen(a, "wxe");
60                 if (!f) {
61                         log_error("Failed to create %s: %m", a);
62                         return -errno;
63                 }
64
65                 fprintf(f,
66                         "# Automatically generated by systemd-dbus1-generator\n\n"
67                         "[Unit]\n"
68                         "SourcePath=%s\n"
69                         "Description=DBUS1: %s\n"
70                         "Documentation=man:systemd-dbus1-generator(8)\n\n"
71                         "[Service]\n"
72                         "ExecStart=%s\n"
73                         "Type=dbus\n"
74                         "BusName=%s\n",
75                         path,
76                         name,
77                         exec,
78                         name);
79
80                 if (user)
81                         fprintf(f, "User=%s\n", user);
82
83
84                 if (type) {
85                         fprintf(f, "Environment=DBUS_STARTER_BUS_TYPE=%s\n", type);
86
87                         if (streq(type, "system"))
88                                 fprintf(f, "Environment=DBUS_STARTER_ADDRESS=" DEFAULT_SYSTEM_BUS_PATH "\n");
89                         else if (streq(type, "session")) {
90                                 char *run;
91
92                                 run = getenv("XDG_RUNTIME_DIR");
93                                 if (!run) {
94                                         log_error("XDG_RUNTIME_DIR not set.");
95                                         return -EINVAL;
96                                 }
97
98                                 fprintf(f, "Environment=DBUS_STARTER_ADDRESS="KERNEL_USER_BUS_FMT ";" UNIX_USER_BUS_FMT "\n",
99                                         getuid(), run);
100                         }
101                 }
102
103                 fflush(f);
104                 if (ferror(f)) {
105                         log_error("Failed to write %s: %m", a);
106                         return -errno;
107                 }
108
109                 service = s;
110         }
111
112         b = strjoin(arg_dest_late, "/", name, ".busname", NULL);
113         if (!b)
114                 return log_oom();
115
116         f = fopen(b, "wxe");
117         if (!f) {
118                 log_error("Failed to create %s: %m", b);
119                 return -errno;
120         }
121
122         fprintf(f,
123                 "# Automatically generated by systemd-dbus1-generator\n\n"
124                 "[Unit]\n"
125                 "SourcePath=%s\n"
126                 "Description=DBUS1: %s\n"
127                 "Documentation=man:systemd-dbus1-generator(8)\n\n"
128                 "[BusName]\n"
129                 "Name=%s\n"
130                 "Service=%s\n"
131                 "AllowWorld=talk\n",
132                 path,
133                 name,
134                 name,
135                 service);
136
137         fflush(f);
138         if (ferror(f)) {
139                 log_error("Failed to write %s: %m", b);
140                 return -errno;
141         }
142
143         lnk = strjoin(arg_dest_late, "/" SPECIAL_BUSNAMES_TARGET ".wants/", name, ".busname", NULL);
144         if (!lnk)
145                 return log_oom();
146
147         mkdir_parents_label(lnk, 0755);
148         if (symlink(b, lnk)) {
149                 log_error("Failed to create symlink %s: %m", lnk);
150                 return -errno;
151         }
152
153         return 0;
154 }
155
156 static int add_dbus(const char *path, const char *fname, const char *type) {
157         _cleanup_free_ char *name = NULL, *exec = NULL, *user = NULL, *service = NULL;
158
159         const ConfigTableItem table[] = {
160                 { "D-BUS Service", "Name", config_parse_string, 0, &name },
161                 { "D-BUS Service", "Exec", config_parse_string, 0, &exec },
162                 { "D-BUS Service", "User", config_parse_string, 0, &user },
163                 { "D-BUS Service", "SystemdService", config_parse_string, 0, &service },
164         };
165
166         char *p;
167         int r;
168
169         assert(path);
170         assert(fname);
171
172         p = strappenda3(path, "/", fname);
173         r = config_parse(NULL, p, NULL,
174                          "D-BUS Service\0",
175                          config_item_table_lookup, table,
176                          true, false, true, NULL);
177         if (r < 0)
178                 return r;
179
180         if (!name) {
181                 log_warning("Activation file %s lacks name setting, ignoring.", p);
182                 return 0;
183         }
184
185         if (!service_name_is_valid(name)) {
186                 log_warning("Bus service name %s is not valid, ignoring.", name);
187                 return 0;
188         }
189
190         if (streq(name, "org.freedesktop.systemd1")) {
191                 log_debug("Skipping %s, identified as systemd.", p);
192                 return 0;
193         }
194
195         if (service) {
196                 if (!unit_name_is_valid(service, TEMPLATE_INVALID)) {
197                         log_warning("Unit name %s is not valid, ignoring.", service);
198                         return 0;
199                 }
200                 if (!endswith(service, ".service")) {
201                         log_warning("Bus names can only activate services, ignoring %s.", p);
202                         return 0;
203                 }
204         } else {
205                 if (streq(exec, "/bin/false") || !exec) {
206                         log_warning("Neither service name nor binary path specified, ignoring %s.", p);
207                         return 0;
208                 }
209
210                 if (exec[0] != '/') {
211                         log_warning("Exec= in %s does not start with an absolute path, ignoring.", p);
212                         return 0;
213                 }
214         }
215
216         return create_dbus_files(p, name, service, exec, user, type);
217 }
218
219 static int parse_dbus_fragments(const char *path, const char *type) {
220         _cleanup_closedir_ DIR *d = NULL;
221         struct dirent *de;
222         int r;
223
224         assert(path);
225         assert(type);
226
227         d = opendir(path);
228         if (!d) {
229                 if (errno == -ENOENT)
230                         return 0;
231
232                 log_error("Failed to enumerate D-Bus activated services: %m");
233                 return -errno;
234         }
235
236         r = 0;
237         FOREACH_DIRENT(de, d, goto fail) {
238                 int q;
239
240                 if (!endswith(de->d_name, ".service"))
241                         continue;
242
243                 q = add_dbus(path, de->d_name, type);
244                 if (q < 0)
245                         r = q;
246         }
247
248         return r;
249
250 fail:
251         log_error("Failed to read D-Bus services directory: %m");
252         return -errno;
253 }
254
255 static int link_busnames_target(const char *units) {
256         const char *f, *t;
257
258         f = strappenda(units, "/" SPECIAL_BUSNAMES_TARGET);
259         t = strappenda(arg_dest, "/" SPECIAL_BASIC_TARGET ".wants/" SPECIAL_BUSNAMES_TARGET);
260
261         mkdir_parents_label(t, 0755);
262         if (symlink(f, t) < 0) {
263                 log_error("Failed to create symlink %s: %m", t);
264                 return -errno;
265         }
266
267         return 0;
268 }
269
270 static int link_compatibility(const char *units) {
271         const char *f, *t;
272
273         f = strappenda(units, "/systemd-bus-proxyd.socket");
274         t = strappenda(arg_dest, "/" SPECIAL_DBUS_SOCKET);
275         mkdir_parents_label(t, 0755);
276         if (symlink(f, t) < 0) {
277                 log_error("Failed to create symlink %s: %m", t);
278                 return -errno;
279         }
280
281         f = strappenda(units, "/systemd-bus-proxyd.socket");
282         t = strappenda(arg_dest, "/" SPECIAL_SOCKETS_TARGET ".wants/systemd-bus-proxyd.socket");
283         mkdir_parents_label(t, 0755);
284         if (symlink(f, t) < 0) {
285                 log_error("Failed to create symlink %s: %m", t);
286                 return -errno;
287         }
288
289         t = strappenda(arg_dest, "/" SPECIAL_DBUS_SERVICE);
290         if (symlink("/dev/null", t) < 0) {
291                 log_error("Failed to mask %s: %m", t);
292                 return -errno;
293         }
294
295         return 0;
296 }
297
298 int main(int argc, char *argv[]) {
299         const char *path, *type, *units;
300         int r, q;
301
302         if (argc > 1 && argc != 4) {
303                 log_error("This program takes three or no arguments.");
304                 return EXIT_FAILURE;
305         }
306
307         if (argc > 1) {
308                 arg_dest = argv[1];
309                 arg_dest_late = argv[3];
310         }
311
312         log_set_target(LOG_TARGET_SAFE);
313         log_parse_environment();
314         log_open();
315
316         umask(0022);
317
318         if (access("/dev/kdbus/control", F_OK) < 0)
319                 return 0;
320
321         r = cg_pid_get_owner_uid(0, NULL);
322         if (r >= 0) {
323                 path = "/usr/share/dbus-1/services";
324                 type = "session";
325                 units = USER_DATA_UNIT_PATH;
326         } else if (r == -ENOENT) {
327                 path = "/usr/share/dbus-1/system-services";
328                 type = "system";
329                 units = SYSTEM_DATA_UNIT_PATH;
330         } else {
331                 log_error("Failed to determine whether we are running as user or system instance: %s", strerror(-r));
332                 return r;
333         }
334
335         r = parse_dbus_fragments(path, type);
336
337         /* FIXME: One day this should just be pulled in statically from basic.target */
338         q = link_busnames_target(units);
339         if (q < 0)
340                 r = q;
341
342         q = link_compatibility(units);
343         if (q < 0)
344                 r = q;
345
346         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
347 }