chiark / gitweb /
434a989bfcc814790c2a4037dc89b4e4f957b4cf
[elogind.git] / src / bus-proxyd / stdio-bridge.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
10   systemd is free software; you can redistribute it and/or modify it
11   under the terms of the GNU Lesser General Public License as published by
12   the Free Software Foundation; either version 2.1 of the License, or
13   (at your option) any later version.
14
15   systemd is distributed in the hope that it will be useful, but
16   WITHOUT ANY WARRANTY; without even the implied warranty of
17   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18   Lesser General Public License for more details.
19
20   You should have received a copy of the GNU Lesser General Public License
21   along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 ***/
23
24 #include <sys/socket.h>
25 #include <sys/un.h>
26 #include <sys/types.h>
27 #include <fcntl.h>
28 #include <unistd.h>
29 #include <string.h>
30 #include <errno.h>
31 #include <poll.h>
32 #include <stddef.h>
33 #include <getopt.h>
34
35 #include "log.h"
36 #include "util.h"
37 #include "socket-util.h"
38 #include "sd-daemon.h"
39 #include "sd-bus.h"
40 #include "bus-internal.h"
41 #include "bus-message.h"
42 #include "bus-util.h"
43 #include "build.h"
44 #include "strv.h"
45 #include "def.h"
46 #include "capability.h"
47 #include "bus-control.h"
48 #include "smack-util.h"
49 #include "set.h"
50 #include "bus-xml-policy.h"
51 #include "driver.h"
52 #include "proxy.h"
53 #include "synthesize.h"
54
55 static char *arg_address = NULL;
56 static char *arg_command_line_buffer = NULL;
57
58 static int help(void) {
59
60         printf("%s [OPTIONS...]\n\n"
61                "Connect STDIO to a given bus address.\n\n"
62                "  -h --help               Show this help\n"
63                "     --version            Show package version\n"
64                "     --machine=MACHINE    Connect to specified machine\n"
65                "     --address=ADDRESS    Connect to the bus specified by ADDRESS\n"
66                "                          (default: " DEFAULT_SYSTEM_BUS_ADDRESS ")\n",
67                program_invocation_short_name);
68
69         return 0;
70 }
71
72 static int parse_argv(int argc, char *argv[]) {
73
74         enum {
75                 ARG_VERSION = 0x100,
76                 ARG_ADDRESS,
77                 ARG_MACHINE,
78         };
79
80         static const struct option options[] = {
81                 { "help",            no_argument,       NULL, 'h'                 },
82                 { "version",         no_argument,       NULL, ARG_VERSION         },
83                 { "address",         required_argument, NULL, ARG_ADDRESS         },
84                 { "machine",         required_argument, NULL, ARG_MACHINE         },
85                 {},
86         };
87
88         int c;
89
90         assert(argc >= 0);
91         assert(argv);
92
93         while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
94
95                 switch (c) {
96
97                 case 'h':
98                         help();
99                         return 0;
100
101                 case ARG_VERSION:
102                         puts(PACKAGE_STRING);
103                         puts(SYSTEMD_FEATURES);
104                         return 0;
105
106                 case ARG_ADDRESS: {
107                         char *a;
108
109                         a = strdup(optarg);
110                         if (!a)
111                                 return log_oom();
112
113                         free(arg_address);
114                         arg_address = a;
115                         break;
116                 }
117
118                 case ARG_MACHINE: {
119                         _cleanup_free_ char *e = NULL;
120                         char *a;
121
122                         e = bus_address_escape(optarg);
123                         if (!e)
124                                 return log_oom();
125
126 #ifdef ENABLE_KDBUS
127                         a = strjoin("x-machine-kernel:machine=", e, ";x-machine-unix:machine=", e, NULL);
128 #else
129                         a = strjoin("x-machine-unix:machine=", e, NULL);
130 #endif
131                         if (!a)
132                                 return log_oom();
133
134                         free(arg_address);
135                         arg_address = a;
136
137                         break;
138                 }
139
140                 case '?':
141                         return -EINVAL;
142
143                 default:
144                         assert_not_reached("Unhandled option");
145                 }
146
147         /* If the first command line argument is only "x" characters
148          * we'll write who we are talking to into it, so that "ps" is
149          * explanatory */
150         arg_command_line_buffer = argv[optind];
151         if (argc > optind + 1 || (arg_command_line_buffer && !in_charset(arg_command_line_buffer, "x"))) {
152                 log_error("Too many arguments");
153                 return -EINVAL;
154         }
155
156         if (!arg_address) {
157                 arg_address = strdup(DEFAULT_SYSTEM_BUS_ADDRESS);
158                 if (!arg_address)
159                         return log_oom();
160         }
161
162         return 1;
163 }
164
165 static int rename_service(sd_bus *a, sd_bus *b) {
166         _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
167         _cleanup_free_ char *p = NULL, *name = NULL;
168         const char *comm;
169         char **cmdline;
170         uid_t uid;
171         pid_t pid;
172         int r;
173
174         assert(a);
175         assert(b);
176
177         r = sd_bus_get_owner_creds(b, SD_BUS_CREDS_EUID|SD_BUS_CREDS_PID|SD_BUS_CREDS_CMDLINE|SD_BUS_CREDS_COMM|SD_BUS_CREDS_AUGMENT, &creds);
178         if (r < 0)
179                 return r;
180
181         r = sd_bus_creds_get_euid(creds, &uid);
182         if (r < 0)
183                 return r;
184
185         r = sd_bus_creds_get_pid(creds, &pid);
186         if (r < 0)
187                 return r;
188
189         r = sd_bus_creds_get_cmdline(creds, &cmdline);
190         if (r < 0)
191                 return r;
192
193         r = sd_bus_creds_get_comm(creds, &comm);
194         if (r < 0)
195                 return r;
196
197         name = uid_to_name(uid);
198         if (!name)
199                 return -ENOMEM;
200
201         p = strv_join(cmdline, " ");
202         if (!p)
203                 return -ENOMEM;
204
205         /* The status string gets the full command line ... */
206         sd_notifyf(false,
207                    "STATUS=Processing requests from client PID "PID_FMT" (%s); UID "UID_FMT" (%s)",
208                    pid, p,
209                    uid, name);
210
211         /* ... and the argv line only the short comm */
212         if (arg_command_line_buffer) {
213                 size_t m, w;
214
215                 m = strlen(arg_command_line_buffer);
216                 w = snprintf(arg_command_line_buffer, m,
217                              "[PID "PID_FMT"/%s; UID "UID_FMT"/%s]",
218                              pid, comm,
219                              uid, name);
220
221                 if (m > w)
222                         memzero(arg_command_line_buffer + w, m - w);
223         }
224
225         log_debug("Running on behalf of PID "PID_FMT" (%s), UID "UID_FMT" (%s), %s",
226                   pid, p,
227                   uid, name,
228                   a->unique_name);
229
230         return 0;
231 }
232
233 int main(int argc, char *argv[]) {
234         _cleanup_(proxy_freep) Proxy *p = NULL;
235         int r;
236
237         log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
238         log_parse_environment();
239         log_open();
240
241         r = parse_argv(argc, argv);
242         if (r <= 0)
243                 goto finish;
244
245         r = proxy_new(&p, STDIN_FILENO, STDOUT_FILENO, arg_address);
246         if (r < 0)
247                 goto finish;
248
249         r = rename_service(p->dest_bus, p->local_bus);
250         if (r < 0)
251                 log_debug_errno(r, "Failed to rename process: %m");
252
253         r = proxy_run(p);
254
255 finish:
256         sd_notify(false,
257                   "STOPPING=1\n"
258                   "STATUS=Shutting down.");
259
260         free(arg_address);
261
262         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
263 }