]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/bus-proxyd/bus-proxyd.c
src/basic: rename audit.[ch] → audit-util.[ch] and capability.[ch] → capability-util...
[thirdparty/systemd.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 <errno.h>
26 #include <getopt.h>
27 #include <pthread.h>
28 #include <stddef.h>
29 #include <string.h>
30 #include <sys/prctl.h>
31 #include <sys/socket.h>
32 #include <unistd.h>
33
34 #include "sd-daemon.h"
35
36 #include "bus-internal.h"
37 #include "bus-xml-policy.h"
38 #include "capability-util.h"
39 #include "def.h"
40 #include "fd-util.h"
41 #include "formats-util.h"
42 #include "log.h"
43 #include "proxy.h"
44 #include "string-util.h"
45 #include "strv.h"
46 #include "user-util.h"
47 #include "util.h"
48
49 static char *arg_address = NULL;
50 static char **arg_configuration = NULL;
51
52 typedef struct {
53 int fd;
54 SharedPolicy *policy;
55 uid_t bus_uid;
56 } ClientContext;
57
58 static ClientContext *client_context_free(ClientContext *c) {
59 if (!c)
60 return NULL;
61
62 safe_close(c->fd);
63 free(c);
64
65 return NULL;
66 }
67
68 DEFINE_TRIVIAL_CLEANUP_FUNC(ClientContext*, client_context_free);
69
70 static int client_context_new(ClientContext **out) {
71 _cleanup_(client_context_freep) ClientContext *c = NULL;
72
73 c = new0(ClientContext, 1);
74 if (!c)
75 return -ENOMEM;
76
77 c->fd = -1;
78
79 *out = c;
80 c = NULL;
81 return 0;
82 }
83
84 static void *run_client(void *userdata) {
85 _cleanup_(client_context_freep) ClientContext *c = userdata;
86 _cleanup_(proxy_freep) Proxy *p = NULL;
87 char comm[16];
88 int r;
89
90 r = proxy_new(&p, c->fd, c->fd, arg_address);
91 c->fd = -1;
92
93 if (r < 0)
94 goto exit;
95
96 /* set comm to "p$PIDu$UID" and suffix with '*' if truncated */
97 r = snprintf(comm, sizeof(comm), "p" PID_FMT "u" UID_FMT, p->local_creds.pid, p->local_creds.uid);
98 if (r >= (ssize_t)sizeof(comm))
99 comm[sizeof(comm) - 2] = '*';
100 (void) prctl(PR_SET_NAME, comm);
101
102 r = proxy_set_policy(p, c->policy, arg_configuration);
103 if (r < 0)
104 goto exit;
105
106 r = proxy_hello_policy(p, c->bus_uid);
107 if (r < 0)
108 goto exit;
109
110 r = proxy_run(p);
111
112 exit:
113 return NULL;
114 }
115
116 static int loop_clients(int accept_fd, uid_t bus_uid) {
117 _cleanup_(shared_policy_freep) SharedPolicy *sp = NULL;
118 pthread_attr_t attr;
119 int r;
120
121 r = pthread_attr_init(&attr);
122 if (r != 0)
123 return log_error_errno(r, "Cannot initialize pthread attributes: %m");
124
125 r = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
126 if (r != 0) {
127 r = log_error_errno(r, "Cannot mark pthread attributes as detached: %m");
128 goto finish;
129 }
130
131 r = shared_policy_new(&sp);
132 if (r < 0)
133 goto finish;
134
135 for (;;) {
136 ClientContext *c;
137 pthread_t tid;
138 int fd;
139
140 fd = accept4(accept_fd, NULL, NULL, SOCK_NONBLOCK | SOCK_CLOEXEC);
141 if (fd < 0) {
142 if (errno == EAGAIN || errno == EINTR)
143 continue;
144
145 r = log_error_errno(errno, "accept4() failed: %m");
146 goto finish;
147 }
148
149 r = client_context_new(&c);
150 if (r < 0) {
151 log_oom();
152 close(fd);
153 continue;
154 }
155
156 c->fd = fd;
157 c->policy = sp;
158 c->bus_uid = bus_uid;
159
160 r = pthread_create(&tid, &attr, run_client, c);
161 if (r != 0) {
162 log_warning_errno(r, "Cannot spawn thread, ignoring: %m");
163 client_context_free(c);
164 continue;
165 }
166 }
167
168 finish:
169 pthread_attr_destroy(&attr);
170 return r;
171 }
172
173 static int help(void) {
174
175 printf("%s [OPTIONS...]\n\n"
176 "DBus proxy server.\n\n"
177 " -h --help Show this help\n"
178 " --version Show package version\n"
179 " --configuration=PATH Configuration file or directory\n"
180 " --machine=MACHINE Connect to specified machine\n"
181 " --address=ADDRESS Connect to the bus specified by ADDRESS\n"
182 " (default: " DEFAULT_SYSTEM_BUS_ADDRESS ")\n",
183 program_invocation_short_name);
184
185 return 0;
186 }
187
188 static int parse_argv(int argc, char *argv[]) {
189
190 enum {
191 ARG_VERSION = 0x100,
192 ARG_ADDRESS,
193 ARG_CONFIGURATION,
194 ARG_MACHINE,
195 };
196
197 static const struct option options[] = {
198 { "help", no_argument, NULL, 'h' },
199 { "version", no_argument, NULL, ARG_VERSION },
200 { "address", required_argument, NULL, ARG_ADDRESS },
201 { "configuration", required_argument, NULL, ARG_CONFIGURATION },
202 { "machine", required_argument, NULL, ARG_MACHINE },
203 {},
204 };
205
206 int c, r;
207
208 assert(argc >= 0);
209 assert(argv);
210
211 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
212
213 switch (c) {
214
215 case 'h':
216 help();
217 return 0;
218
219 case ARG_VERSION:
220 return version();
221
222 case ARG_ADDRESS:
223 r = free_and_strdup(&arg_address, optarg);
224 if (r < 0)
225 return log_oom();
226 break;
227
228 case ARG_CONFIGURATION:
229 r = strv_extend(&arg_configuration, optarg);
230 if (r < 0)
231 return log_oom();
232 break;
233
234 case ARG_MACHINE: {
235 _cleanup_free_ char *e = NULL;
236 char *a;
237
238 e = bus_address_escape(optarg);
239 if (!e)
240 return log_oom();
241
242 a = strjoin("x-machine-kernel:machine=", e, ";x-machine-unix:machine=", e, NULL);
243 if (!a)
244 return log_oom();
245
246 free(arg_address);
247 arg_address = a;
248
249 break;
250 }
251
252 case '?':
253 return -EINVAL;
254
255 default:
256 assert_not_reached("Unhandled option");
257 }
258
259 if (argc > optind) {
260 log_error("Too many arguments");
261 return -EINVAL;
262 }
263
264 if (!arg_address) {
265 arg_address = strdup(DEFAULT_SYSTEM_BUS_ADDRESS);
266 if (!arg_address)
267 return log_oom();
268 }
269
270 return 1;
271 }
272
273 int main(int argc, char *argv[]) {
274 int r, accept_fd;
275 uid_t uid, bus_uid;
276 gid_t gid;
277
278 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
279 log_parse_environment();
280 log_open();
281
282 bus_uid = getuid();
283
284 if (geteuid() == 0) {
285 const char *user = "systemd-bus-proxy";
286
287 r = get_user_creds(&user, &uid, &gid, NULL, NULL);
288 if (r < 0) {
289 log_error_errno(r, "Cannot resolve user name %s: %m", user);
290 goto finish;
291 }
292
293 r = drop_privileges(uid, gid, 1ULL << CAP_IPC_OWNER);
294 if (r < 0) {
295 log_error_errno(r, "Cannot drop privileges: %m");
296 goto finish;
297 }
298 }
299
300 r = parse_argv(argc, argv);
301 if (r <= 0)
302 goto finish;
303
304 r = sd_listen_fds(0);
305 if (r != 1) {
306 log_error("Illegal number of file descriptors passed");
307 goto finish;
308 }
309
310 accept_fd = SD_LISTEN_FDS_START;
311
312 r = fd_nonblock(accept_fd, false);
313 if (r < 0) {
314 log_error_errno(r, "Cannot mark accept-fd non-blocking: %m");
315 goto finish;
316 }
317
318 r = loop_clients(accept_fd, bus_uid);
319
320 finish:
321 sd_notify(false,
322 "STOPPING=1\n"
323 "STATUS=Shutting down.");
324
325 strv_free(arg_configuration);
326 free(arg_address);
327
328 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
329 }