]> git.proxmox.com Git - systemd.git/blob - src/bus-proxyd/bus-proxyd.c
Imported Upstream version 221
[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 <sys/socket.h>
26 #include <unistd.h>
27 #include <string.h>
28 #include <errno.h>
29 #include <sys/prctl.h>
30 #include <stddef.h>
31 #include <getopt.h>
32 #include <pthread.h>
33
34 #include "log.h"
35 #include "util.h"
36 #include "sd-daemon.h"
37 #include "bus-internal.h"
38 #include "build.h"
39 #include "strv.h"
40 #include "def.h"
41 #include "capability.h"
42 #include "bus-xml-policy.h"
43 #include "proxy.h"
44 #include "formats-util.h"
45
46 static char *arg_address = NULL;
47 static char **arg_configuration = NULL;
48
49 typedef struct {
50 int fd;
51 SharedPolicy *policy;
52 uid_t bus_uid;
53 } ClientContext;
54
55 static ClientContext *client_context_free(ClientContext *c) {
56 if (!c)
57 return NULL;
58
59 safe_close(c->fd);
60 free(c);
61
62 return NULL;
63 }
64
65 DEFINE_TRIVIAL_CLEANUP_FUNC(ClientContext*, client_context_free);
66
67 static int client_context_new(ClientContext **out) {
68 _cleanup_(client_context_freep) ClientContext *c = NULL;
69
70 c = new0(ClientContext, 1);
71 if (!c)
72 return -ENOMEM;
73
74 c->fd = -1;
75
76 *out = c;
77 c = NULL;
78 return 0;
79 }
80
81 static void *run_client(void *userdata) {
82 _cleanup_(client_context_freep) ClientContext *c = userdata;
83 _cleanup_(proxy_freep) Proxy *p = NULL;
84 char comm[16];
85 int r;
86
87 r = proxy_new(&p, c->fd, c->fd, arg_address);
88 if (r < 0)
89 goto exit;
90
91 c->fd = -1;
92
93 /* set comm to "p$PIDu$UID" and suffix with '*' if truncated */
94 r = snprintf(comm, sizeof(comm), "p" PID_FMT "u" UID_FMT, p->local_creds.pid, p->local_creds.uid);
95 if (r >= (ssize_t)sizeof(comm))
96 comm[sizeof(comm) - 2] = '*';
97 (void) prctl(PR_SET_NAME, comm);
98
99 r = proxy_set_policy(p, c->policy, arg_configuration);
100 if (r < 0)
101 goto exit;
102
103 r = proxy_hello_policy(p, c->bus_uid);
104 if (r < 0)
105 goto exit;
106
107 r = proxy_run(p);
108
109 exit:
110 return NULL;
111 }
112
113 static int loop_clients(int accept_fd, uid_t bus_uid) {
114 _cleanup_(shared_policy_freep) SharedPolicy *sp = NULL;
115 pthread_attr_t attr;
116 int r;
117
118 r = pthread_attr_init(&attr);
119 if (r < 0) {
120 return log_error_errno(errno, "Cannot initialize pthread attributes: %m");
121 }
122
123 r = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
124 if (r < 0) {
125 r = log_error_errno(errno, "Cannot mark pthread attributes as detached: %m");
126 goto finish;
127 }
128
129 r = shared_policy_new(&sp);
130 if (r < 0)
131 goto finish;
132
133 for (;;) {
134 ClientContext *c;
135 pthread_t tid;
136 int fd;
137
138 fd = accept4(accept_fd, NULL, NULL, SOCK_NONBLOCK | SOCK_CLOEXEC);
139 if (fd < 0) {
140 if (errno == EAGAIN || errno == EINTR)
141 continue;
142
143 r = log_error_errno(errno, "accept4() failed: %m");
144 goto finish;
145 }
146
147 r = client_context_new(&c);
148 if (r < 0) {
149 log_oom();
150 close(fd);
151 continue;
152 }
153
154 c->fd = fd;
155 c->policy = sp;
156 c->bus_uid = bus_uid;
157
158 r = pthread_create(&tid, &attr, run_client, c);
159 if (r < 0) {
160 log_error("Cannot spawn thread: %m");
161 client_context_free(c);
162 continue;
163 }
164 }
165
166 finish:
167 pthread_attr_destroy(&attr);
168 return r;
169 }
170
171 static int help(void) {
172
173 printf("%s [OPTIONS...]\n\n"
174 "DBus proxy server.\n\n"
175 " -h --help Show this help\n"
176 " --version Show package version\n"
177 " --configuration=PATH Configuration file or directory\n"
178 " --machine=MACHINE Connect to specified machine\n"
179 " --address=ADDRESS Connect to the bus specified by ADDRESS\n"
180 " (default: " DEFAULT_SYSTEM_BUS_ADDRESS ")\n",
181 program_invocation_short_name);
182
183 return 0;
184 }
185
186 static int parse_argv(int argc, char *argv[]) {
187
188 enum {
189 ARG_VERSION = 0x100,
190 ARG_ADDRESS,
191 ARG_CONFIGURATION,
192 ARG_MACHINE,
193 };
194
195 static const struct option options[] = {
196 { "help", no_argument, NULL, 'h' },
197 { "version", no_argument, NULL, ARG_VERSION },
198 { "address", required_argument, NULL, ARG_ADDRESS },
199 { "configuration", required_argument, NULL, ARG_CONFIGURATION },
200 { "machine", required_argument, NULL, ARG_MACHINE },
201 {},
202 };
203
204 int c, r;
205
206 assert(argc >= 0);
207 assert(argv);
208
209 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
210
211 switch (c) {
212
213 case 'h':
214 help();
215 return 0;
216
217 case ARG_VERSION:
218 puts(PACKAGE_STRING);
219 puts(SYSTEMD_FEATURES);
220 return 0;
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 }