chiark / gitweb /
build-sys: re-add old symbols for abi compat
[elogind.git] / src / bus-proxyd / bus-proxyd.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2010 Lennart Poettering
7   Copyright 2013 Daniel Mack
8   Copyright 2014 Kay Sievers
9   Copyright 2015 David Herrmann
10
11   systemd is free software; you can redistribute it and/or modify it
12   under the terms of the GNU Lesser General Public License as published by
13   the Free Software Foundation; either version 2.1 of the License, or
14   (at your option) any later version.
15
16   systemd is distributed in the hope that it will be useful, but
17   WITHOUT ANY WARRANTY; without even the implied warranty of
18   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19   Lesser General Public License for more details.
20
21   You should have received a copy of the GNU Lesser General Public License
22   along with systemd; If not, see <http://www.gnu.org/licenses/>.
23 ***/
24
25 #include <sys/socket.h>
26 #include <sys/un.h>
27 #include <sys/types.h>
28 #include <fcntl.h>
29 #include <unistd.h>
30 #include <string.h>
31 #include <errno.h>
32 #include <poll.h>
33 #include <sys/prctl.h>
34 #include <stddef.h>
35 #include <getopt.h>
36 #include <pthread.h>
37
38 #include "log.h"
39 #include "util.h"
40 #include "hashmap.h"
41 #include "socket-util.h"
42 #include "sd-daemon.h"
43 #include "sd-bus.h"
44 #include "bus-internal.h"
45 #include "bus-message.h"
46 #include "bus-util.h"
47 #include "build.h"
48 #include "strv.h"
49 #include "def.h"
50 #include "capability.h"
51 #include "bus-control.h"
52 #include "smack-util.h"
53 #include "set.h"
54 #include "bus-xml-policy.h"
55 #include "driver.h"
56 #include "proxy.h"
57 #include "synthesize.h"
58
59 static char *arg_address = NULL;
60 static char **arg_configuration = NULL;
61
62 typedef struct {
63         int fd;
64         SharedPolicy *policy;
65         uid_t bus_uid;
66 } ClientContext;
67
68 static ClientContext *client_context_free(ClientContext *c) {
69         if (!c)
70                 return NULL;
71
72         safe_close(c->fd);
73         free(c);
74
75         return NULL;
76 }
77
78 DEFINE_TRIVIAL_CLEANUP_FUNC(ClientContext*, client_context_free);
79
80 static int client_context_new(ClientContext **out) {
81         _cleanup_(client_context_freep) ClientContext *c = NULL;
82
83         c = new0(ClientContext, 1);
84         if (!c)
85                 return log_oom();
86
87         c->fd = -1;
88
89         *out = c;
90         c = NULL;
91         return 0;
92 }
93
94 static void *run_client(void *userdata) {
95         _cleanup_(client_context_freep) ClientContext *c = userdata;
96         _cleanup_(proxy_freep) Proxy *p = NULL;
97         char comm[16];
98         int r;
99
100         r = proxy_new(&p, c->fd, c->fd, arg_address);
101         if (r < 0)
102                 goto exit;
103
104         c->fd = -1;
105
106         /* set comm to "p$PIDu$UID" and suffix with '*' if truncated */
107         r = snprintf(comm, sizeof(comm), "p" PID_FMT "u" UID_FMT, p->local_creds.pid, p->local_creds.uid);
108         if (r >= (ssize_t)sizeof(comm))
109                 comm[sizeof(comm) - 2] = '*';
110         (void) prctl(PR_SET_NAME, comm);
111
112         r = proxy_set_policy(p, c->policy, arg_configuration);
113         if (r < 0)
114                 goto exit;
115
116         r = proxy_hello_policy(p, c->bus_uid);
117         if (r < 0)
118                 goto exit;
119
120         r = proxy_run(p);
121
122 exit:
123         return NULL;
124 }
125
126 static int loop_clients(int accept_fd, uid_t bus_uid) {
127         _cleanup_(shared_policy_freep) SharedPolicy *sp = NULL;
128         pthread_attr_t attr;
129         int r;
130
131         r = pthread_attr_init(&attr);
132         if (r < 0) {
133                 return log_error_errno(errno, "Cannot initialize pthread attributes: %m");
134         }
135
136         r = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
137         if (r < 0) {
138                 r = log_error_errno(errno, "Cannot mark pthread attributes as detached: %m");
139                 goto finish;
140         }
141
142         r = shared_policy_new(&sp);
143         if (r < 0)
144                 goto finish;
145
146         for (;;) {
147                 ClientContext *c;
148                 pthread_t tid;
149                 int fd;
150
151                 fd = accept4(accept_fd, NULL, NULL, SOCK_NONBLOCK | SOCK_CLOEXEC);
152                 if (fd < 0) {
153                         if (errno == EAGAIN || errno == EINTR)
154                                 continue;
155
156                         r = log_error_errno(errno, "accept4() failed: %m");
157                         goto finish;
158                 }
159
160                 r = client_context_new(&c);
161                 if (r < 0) {
162                         log_oom();
163                         close(fd);
164                         continue;
165                 }
166
167                 c->fd = fd;
168                 c->policy = sp;
169                 c->bus_uid = bus_uid;
170
171                 r = pthread_create(&tid, &attr, run_client, c);
172                 if (r < 0) {
173                         log_error("Cannot spawn thread: %m");
174                         client_context_free(c);
175                         continue;
176                 }
177         }
178
179 finish:
180         pthread_attr_destroy(&attr);
181         return r;
182 }
183
184 static int help(void) {
185
186         printf("%s [OPTIONS...]\n\n"
187                "DBus proxy server.\n\n"
188                "  -h --help               Show this help\n"
189                "     --version            Show package version\n"
190                "     --configuration=PATH Configuration file or directory\n"
191                "     --machine=MACHINE    Connect to specified machine\n"
192                "     --address=ADDRESS    Connect to the bus specified by ADDRESS\n"
193                "                          (default: " DEFAULT_SYSTEM_BUS_ADDRESS ")\n",
194                program_invocation_short_name);
195
196         return 0;
197 }
198
199 static int parse_argv(int argc, char *argv[]) {
200
201         enum {
202                 ARG_VERSION = 0x100,
203                 ARG_ADDRESS,
204                 ARG_CONFIGURATION,
205                 ARG_MACHINE,
206         };
207
208         static const struct option options[] = {
209                 { "help",            no_argument,       NULL, 'h'                 },
210                 { "version",         no_argument,       NULL, ARG_VERSION         },
211                 { "address",         required_argument, NULL, ARG_ADDRESS         },
212                 { "configuration",   required_argument, NULL, ARG_CONFIGURATION   },
213                 { "machine",         required_argument, NULL, ARG_MACHINE         },
214                 {},
215         };
216
217         int c, r;
218
219         assert(argc >= 0);
220         assert(argv);
221
222         while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
223
224                 switch (c) {
225
226                 case 'h':
227                         help();
228                         return 0;
229
230                 case ARG_VERSION:
231                         puts(PACKAGE_STRING);
232                         puts(SYSTEMD_FEATURES);
233                         return 0;
234
235                 case ARG_ADDRESS:
236                         r = free_and_strdup(&arg_address, optarg);
237                         if (r < 0)
238                                 return log_oom();
239                         break;
240
241                 case ARG_CONFIGURATION:
242                         r = strv_extend(&arg_configuration, optarg);
243                         if (r < 0)
244                                 return log_oom();
245                         break;
246
247                 case ARG_MACHINE: {
248                         _cleanup_free_ char *e = NULL;
249                         char *a;
250
251                         e = bus_address_escape(optarg);
252                         if (!e)
253                                 return log_oom();
254
255 #ifdef ENABLE_KDBUS
256                         a = strjoin("x-machine-kernel:machine=", e, ";x-machine-unix:machine=", e, NULL);
257 #else
258                         a = strjoin("x-machine-unix:machine=", e, NULL);
259 #endif
260                         if (!a)
261                                 return log_oom();
262
263                         free(arg_address);
264                         arg_address = a;
265
266                         break;
267                 }
268
269                 case '?':
270                         return -EINVAL;
271
272                 default:
273                         assert_not_reached("Unhandled option");
274                 }
275
276         if (argc > optind) {
277                 log_error("Too many arguments");
278                 return -EINVAL;
279         }
280
281         if (!arg_address) {
282                 arg_address = strdup(DEFAULT_SYSTEM_BUS_ADDRESS);
283                 if (!arg_address)
284                         return log_oom();
285         }
286
287         return 1;
288 }
289
290 int main(int argc, char *argv[]) {
291         int r, accept_fd;
292         uid_t uid, bus_uid;
293         gid_t gid;
294
295         log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
296         log_parse_environment();
297         log_open();
298
299         bus_uid = getuid();
300
301         if (geteuid() == 0) {
302                 const char *user = "systemd-bus-proxy";
303
304                 r = get_user_creds(&user, &uid, &gid, NULL, NULL);
305                 if (r < 0) {
306                         log_error_errno(r, "Cannot resolve user name %s: %m", user);
307                         goto finish;
308                 }
309
310                 r = drop_privileges(uid, gid, 1ULL << CAP_IPC_OWNER);
311                 if (r < 0) {
312                         log_error_errno(r, "Cannot drop privileges: %m");
313                         goto finish;
314                 }
315         }
316
317         r = parse_argv(argc, argv);
318         if (r <= 0)
319                 goto finish;
320
321         r = sd_listen_fds(0);
322         if (r != 1) {
323                 log_error("Illegal number of file descriptors passed");
324                 goto finish;
325         }
326
327         accept_fd = SD_LISTEN_FDS_START;
328
329         r = fd_nonblock(accept_fd, false);
330         if (r < 0) {
331                 log_error_errno(r, "Cannot mark accept-fd non-blocking: %m");
332                 goto finish;
333         }
334
335         r = loop_clients(accept_fd, bus_uid);
336
337 finish:
338         sd_notify(false,
339                   "STOPPING=1\n"
340                   "STATUS=Shutting down.");
341
342         strv_free(arg_configuration);
343         free(arg_address);
344
345         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
346 }