chiark / gitweb /
pam_systemd: Ignore vtnr when seat != seat0
[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\n"
70                         "[Service]\n"
71                         "ExecStart=%s\n"
72                         "Type=dbus\n"
73                         "BusName=%s\n",
74                         path,
75                         name,
76                         exec,
77                         name);
78
79                 if (user)
80                         fprintf(f, "User=%s\n", user);
81
82
83                 if (type) {
84                         fprintf(f, "Environment=DBUS_STARTER_BUS_TYPE=%s\n", type);
85
86                         if (streq(type, "system"))
87                                 fprintf(f, "Environment=DBUS_STARTER_ADDRESS=" DEFAULT_SYSTEM_BUS_PATH "\n");
88                         else if (streq(type, "session")) {
89                                 char *run;
90
91                                 run = getenv("XDG_RUNTIME_DIR");
92                                 if (!run) {
93                                         log_error("XDG_RUNTIME_DIR not set.");
94                                         return -EINVAL;
95                                 }
96
97                                 fprintf(f, "Environment=DBUS_STARTER_ADDRESS="KERNEL_USER_BUS_FMT ";" UNIX_USER_BUS_FMT "\n",
98                                         (unsigned long) getuid(), run);
99                         }
100                 }
101
102                 fflush(f);
103                 if (ferror(f)) {
104                         log_error("Failed to write %s: %m", a);
105                         return -errno;
106                 }
107
108                 service = s;
109         }
110
111         b = strjoin(arg_dest_late, "/", name, ".busname", NULL);
112         if (!b)
113                 return log_oom();
114
115         f = fopen(b, "wxe");
116         if (!f) {
117                 log_error("Failed to create %s: %m", b);
118                 return -errno;
119         }
120
121         fprintf(f,
122                 "# Automatically generated by systemd-dbus1-generator\n\n"
123                 "[Unit]\n"
124                 "SourcePath=%s\n"
125                 "Description=DBUS1: %s\n\n"
126                 "[BusName]\n"
127                 "Name=%s\n"
128                 "Service=%s\n",
129                 path,
130                 name,
131                 name,
132                 service);
133
134         fflush(f);
135         if (ferror(f)) {
136                 log_error("Failed to write %s: %m", b);
137                 return -errno;
138         }
139
140         lnk = strjoin(arg_dest_late, "/" SPECIAL_BUSNAMES_TARGET ".wants/", name, ".busname", NULL);
141         if (!lnk)
142                 return log_oom();
143
144         mkdir_parents_label(lnk, 0755);
145         if (symlink(b, lnk)) {
146                 log_error("Failed to create symlink %s: %m", lnk);
147                 return -errno;
148         }
149
150         return 0;
151 }
152
153 static int add_dbus(const char *path, const char *fname, const char *type) {
154         _cleanup_free_ char *name = NULL, *exec = NULL, *user = NULL, *service = NULL;
155
156         ConfigTableItem table[] = {
157                 { "D-BUS Service", "Name", config_parse_string, 0, &name },
158                 { "D-BUS Service", "Exec", config_parse_string, 0, &exec },
159                 { "D-BUS Service", "User", config_parse_string, 0, &user },
160                 { "D-BUS Service", "SystemdService", config_parse_string, 0, &service },
161         };
162
163         _cleanup_fclose_ FILE *f = NULL;
164         _cleanup_free_ char *p = NULL;
165         int r;
166
167         assert(path);
168         assert(fname);
169
170         p = strjoin(path, "/", fname, NULL);
171         if (!p)
172                 return log_oom();
173
174         f = fopen(p, "re");
175         if (!f) {
176                 if (errno == -ENOENT)
177                         return 0;
178
179                 log_error("Failed to read %s: %m", p);
180                 return -errno;
181         }
182
183         r = config_parse(NULL, p, f, "D-BUS Service\0", config_item_table_lookup, table, true, false, NULL);
184         if (r < 0)
185                 return r;
186
187         if (!name) {
188                 log_warning("Activation file %s lacks name setting, ignoring.", p);
189                 return 0;
190         }
191
192         if (!service_name_is_valid(name)) {
193                 log_warning("Bus service name %s is not valid, ignoring.", name);
194                 return 0;
195         }
196
197         if (streq(name, "org.freedesktop.systemd1")) {
198                 log_debug("Skipping %s, identified as systemd.", p);
199                 return 0;
200         }
201
202         if (service) {
203                 if (!unit_name_is_valid(service, TEMPLATE_INVALID)) {
204                         log_warning("Unit name %s is not valid, ignoring.", service);
205                         return 0;
206                 }
207                 if (!endswith(service, ".service")) {
208                         log_warning("Bus names can only activate services, ignoring %s.", p);
209                         return 0;
210                 }
211         } else {
212                 if (streq(exec, "/bin/false") || !exec) {
213                         log_warning("Neither service name nor binary path specified, ignoring %s.", p);
214                         return 0;
215                 }
216
217                 if (exec[0] != '/') {
218                         log_warning("Exec= in %s does not start with an absolute path, ignoring.", p);
219                         return 0;
220                 }
221         }
222
223         return create_dbus_files(p, name, service, exec, user, type);
224 }
225
226 static int parse_dbus_fragments(const char *path, const char *type) {
227         _cleanup_closedir_ DIR *d = NULL;
228         struct dirent *de;
229         int r;
230
231         assert(path);
232         assert(type);
233
234         d = opendir(path);
235         if (!d) {
236                 if (errno == -ENOENT)
237                         return 0;
238
239                 log_error("Failed to enumerate D-Bus activated services: %m");
240                 return -errno;
241         }
242
243         r = 0;
244         FOREACH_DIRENT(de, d, goto fail) {
245                 int q;
246
247                 if (!endswith(de->d_name, ".service"))
248                         continue;
249
250                 q = add_dbus(path, de->d_name, type);
251                 if (q < 0)
252                         r = q;
253         }
254
255         return r;
256
257 fail:
258         log_error("Failed to read D-Bus services directory: %m");
259         return -errno;
260 }
261
262 static int link_busnames_target(const char *units) {
263         const char *f, *t;
264
265         f = strappenda(units, "/" SPECIAL_BUSNAMES_TARGET);
266         t = strappenda(arg_dest, "/" SPECIAL_BASIC_TARGET ".wants/" SPECIAL_BUSNAMES_TARGET);
267
268         mkdir_parents_label(t, 0755);
269         if (symlink(f, t) < 0) {
270                 log_error("Failed to create symlink %s: %m", t);
271                 return -errno;
272         }
273
274         return 0;
275 }
276
277 static int link_compatibility(const char *units) {
278         const char *f, *t;
279
280         f = strappenda(units, "/systemd-bus-proxyd.socket");
281         t = strappenda(arg_dest, "/" SPECIAL_DBUS_SOCKET);
282         mkdir_parents_label(t, 0755);
283         if (symlink(f, t) < 0) {
284                 log_error("Failed to create symlink %s: %m", t);
285                 return -errno;
286         }
287
288         f = strappenda(units, "/systemd-bus-proxyd.socket");
289         t = strappenda(arg_dest, "/" SPECIAL_SOCKETS_TARGET ".wants/systemd-bus-proxyd.socket");
290         mkdir_parents_label(t, 0755);
291         if (symlink(f, t) < 0) {
292                 log_error("Failed to create symlink %s: %m", t);
293                 return -errno;
294         }
295
296         t = strappenda(arg_dest, "/" SPECIAL_DBUS_SERVICE);
297         if (symlink("/dev/null", t) < 0) {
298                 log_error("Failed to mask %s: %m", t);
299                 return -errno;
300         }
301
302         return 0;
303 }
304
305 int main(int argc, char *argv[]) {
306         const char *path, *type, *units;
307         int r, q;
308
309         if (argc > 1 && argc != 4) {
310                 log_error("This program takes three or no arguments.");
311                 return EXIT_FAILURE;
312         }
313
314         if (argc > 1) {
315                 arg_dest = argv[1];
316                 arg_dest_late = argv[3];
317         }
318
319         log_set_target(LOG_TARGET_SAFE);
320         log_parse_environment();
321         log_open();
322
323         umask(0022);
324
325         if (access("/dev/kdbus/control", F_OK) < 0)
326                 return 0;
327
328         r = cg_pid_get_owner_uid(0, NULL);
329         if (r >= 0) {
330                 path = "/usr/share/dbus-1/services";
331                 type = "session";
332                 units = USER_DATA_UNIT_PATH;
333         } else if (r == -ENOENT) {
334                 path = "/usr/share/dbus-1/system-services";
335                 type = "system";
336                 units = SYSTEM_DATA_UNIT_PATH;
337         } else {
338                 log_error("Failed to determine whether we are running as user or system instance: %s", strerror(-r));
339                 return r;
340         }
341
342         r = parse_dbus_fragments(path, type);
343
344         /* FIXME: One day this should just be pulled in statically from basic.target */
345         q = link_busnames_target(units);
346         if (q < 0)
347                 r = q;
348
349         q = link_compatibility(units);
350         if (q < 0)
351                 r = q;
352
353         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
354 }