]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/bus-proxyd/stdio-bridge.c
tree-wide: sort includes
[thirdparty/systemd.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 <errno.h>
25 #include <getopt.h>
26 #include <stddef.h>
27 #include <string.h>
28 #include <unistd.h>
29
30 #include "sd-bus.h"
31 #include "sd-daemon.h"
32
33 #include "alloc-util.h"
34 #include "bus-internal.h"
35 #include "bus-util.h"
36 #include "def.h"
37 #include "formats-util.h"
38 #include "log.h"
39 #include "proxy.h"
40 #include "strv.h"
41 #include "user-util.h"
42 #include "util.h"
43
44 static char *arg_address = NULL;
45 static char *arg_command_line_buffer = NULL;
46
47 static int help(void) {
48
49 printf("%s [OPTIONS...]\n\n"
50 "Connect STDIO to a given bus address.\n\n"
51 " -h --help Show this help\n"
52 " --version Show package version\n"
53 " --machine=MACHINE Connect to specified machine\n"
54 " --address=ADDRESS Connect to the bus specified by ADDRESS\n"
55 " (default: " DEFAULT_SYSTEM_BUS_ADDRESS ")\n",
56 program_invocation_short_name);
57
58 return 0;
59 }
60
61 static int parse_argv(int argc, char *argv[]) {
62
63 enum {
64 ARG_VERSION = 0x100,
65 ARG_ADDRESS,
66 ARG_MACHINE,
67 };
68
69 static const struct option options[] = {
70 { "help", no_argument, NULL, 'h' },
71 { "version", no_argument, NULL, ARG_VERSION },
72 { "address", required_argument, NULL, ARG_ADDRESS },
73 { "machine", required_argument, NULL, ARG_MACHINE },
74 {},
75 };
76
77 int c;
78
79 assert(argc >= 0);
80 assert(argv);
81
82 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
83
84 switch (c) {
85
86 case 'h':
87 help();
88 return 0;
89
90 case ARG_VERSION:
91 return version();
92
93 case ARG_ADDRESS: {
94 char *a;
95
96 a = strdup(optarg);
97 if (!a)
98 return log_oom();
99
100 free(arg_address);
101 arg_address = a;
102 break;
103 }
104
105 case ARG_MACHINE: {
106 _cleanup_free_ char *e = NULL;
107 char *a;
108
109 e = bus_address_escape(optarg);
110 if (!e)
111 return log_oom();
112
113 a = strjoin("x-machine-kernel:machine=", e, ";x-machine-unix:machine=", e, NULL);
114 if (!a)
115 return log_oom();
116
117 free(arg_address);
118 arg_address = a;
119
120 break;
121 }
122
123 case '?':
124 return -EINVAL;
125
126 default:
127 assert_not_reached("Unhandled option");
128 }
129
130 /* If the first command line argument is only "x" characters
131 * we'll write who we are talking to into it, so that "ps" is
132 * explanatory */
133 arg_command_line_buffer = argv[optind];
134 if (argc > optind + 1 || (arg_command_line_buffer && !in_charset(arg_command_line_buffer, "x"))) {
135 log_error("Too many arguments");
136 return -EINVAL;
137 }
138
139 if (!arg_address) {
140 arg_address = strdup(DEFAULT_SYSTEM_BUS_ADDRESS);
141 if (!arg_address)
142 return log_oom();
143 }
144
145 return 1;
146 }
147
148 static int rename_service(sd_bus *a, sd_bus *b) {
149 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
150 _cleanup_free_ char *p = NULL, *name = NULL;
151 const char *comm;
152 char **cmdline;
153 uid_t uid;
154 pid_t pid;
155 int r;
156
157 assert(a);
158 assert(b);
159
160 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);
161 if (r < 0)
162 return r;
163
164 r = sd_bus_creds_get_euid(creds, &uid);
165 if (r < 0)
166 return r;
167
168 r = sd_bus_creds_get_pid(creds, &pid);
169 if (r < 0)
170 return r;
171
172 r = sd_bus_creds_get_cmdline(creds, &cmdline);
173 if (r < 0)
174 return r;
175
176 r = sd_bus_creds_get_comm(creds, &comm);
177 if (r < 0)
178 return r;
179
180 name = uid_to_name(uid);
181 if (!name)
182 return -ENOMEM;
183
184 p = strv_join(cmdline, " ");
185 if (!p)
186 return -ENOMEM;
187
188 /* The status string gets the full command line ... */
189 sd_notifyf(false,
190 "STATUS=Processing requests from client PID "PID_FMT" (%s); UID "UID_FMT" (%s)",
191 pid, p,
192 uid, name);
193
194 /* ... and the argv line only the short comm */
195 if (arg_command_line_buffer) {
196 size_t m, w;
197
198 m = strlen(arg_command_line_buffer);
199 w = snprintf(arg_command_line_buffer, m,
200 "[PID "PID_FMT"/%s; UID "UID_FMT"/%s]",
201 pid, comm,
202 uid, name);
203
204 if (m > w)
205 memzero(arg_command_line_buffer + w, m - w);
206 }
207
208 log_debug("Running on behalf of PID "PID_FMT" (%s), UID "UID_FMT" (%s), %s",
209 pid, p,
210 uid, name,
211 a->unique_name);
212
213 return 0;
214 }
215
216 int main(int argc, char *argv[]) {
217 _cleanup_(proxy_freep) Proxy *p = NULL;
218 int r;
219
220 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
221 log_parse_environment();
222 log_open();
223
224 r = parse_argv(argc, argv);
225 if (r <= 0)
226 goto finish;
227
228 r = proxy_new(&p, STDIN_FILENO, STDOUT_FILENO, arg_address);
229 if (r < 0)
230 goto finish;
231
232 r = rename_service(p->destination_bus, p->local_bus);
233 if (r < 0)
234 log_debug_errno(r, "Failed to rename process: %m");
235
236 r = proxy_run(p);
237
238 finish:
239 sd_notify(false,
240 "STOPPING=1\n"
241 "STATUS=Shutting down.");
242
243 free(arg_address);
244
245 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
246 }