Merge lp:~jamesodhunt/upstart/upstart-local-bridge into lp:upstart
- upstart-local-bridge
- Merge into trunk
Status: | Merged |
---|---|
Merged at revision: | 1515 |
Proposed branch: | lp:~jamesodhunt/upstart/upstart-local-bridge |
Merge into: | lp:upstart |
Diff against target: |
1012 lines (+964/-1) 4 files modified
ChangeLog (+22/-0) extra/Makefile.am (+14/-1) extra/man/upstart-local-bridge.8 (+123/-0) extra/upstart-local-bridge.c (+805/-0) |
To merge this branch: | bzr merge lp:~jamesodhunt/upstart/upstart-local-bridge |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Dimitri John Ledkov | Approve | ||
Review via email: mp+177027@code.launchpad.net |
Commit message
Description of the change
This branch introduces a new bridge (the upstart-
This bridge is extremely simple and as a result suffers from some limitations...
= Limitations =
- Only Local sockets are supported.
- The data is read in line-oriented fashion from the socket and only a single name=value pair is read / line
(meaning that the event can only have a single variable added by the client).
- Only a single client connection is serviced at any one time.
= Security =
By default, the bridge will only accept connections from clients running under the same uid as the bridge, the expectation being that the bridge will run as root and only accept connections from root clients).
The bridge does nothing to prevent a possible DoS should a client send an arbitrarily large amount of data in the single name=value pair.
- 1514. By James Hunt
-
* extra/upstart-
local-bridge. c: Cruft removal.
Dimitri John Ledkov (xnox) : | # |
Preview Diff
1 | === modified file 'ChangeLog' | |||
2 | --- ChangeLog 2013-07-24 09:40:15 +0000 | |||
3 | +++ ChangeLog 2013-07-25 19:58:24 +0000 | |||
4 | @@ -1,8 +1,30 @@ | |||
5 | 1 | 2013-07-25 James Hunt <james.hunt@ubuntu.com> | ||
6 | 2 | |||
7 | 3 | * extra/Makefile.am: Renamed to upstart-local-bridge. | ||
8 | 4 | * extra/man/upstart-local-bridge.8: Removed inet type details. | ||
9 | 5 | * extra/upstart-local-bridge.c: | ||
10 | 6 | - Removed inet socket handling. | ||
11 | 7 | - General clean-up. | ||
12 | 8 | |||
13 | 9 | 2013-07-24 James Hunt <james.hunt@ubuntu.com> | ||
14 | 10 | |||
15 | 11 | * extra/man/upstart-text-bridge.8: Added extra variables. | ||
16 | 12 | * extra/upstart-text-bridge.c: socket_reader(): | ||
17 | 13 | - Fixed assertion failure caused by passing invalid address of fd. | ||
18 | 14 | - Added new standard environment variables to event. | ||
19 | 15 | |||
20 | 1 | 2013-07-24 James Hunt <james.hunt@ubuntu.com> | 16 | 2013-07-24 James Hunt <james.hunt@ubuntu.com> |
21 | 2 | 17 | ||
22 | 3 | * extra/upstart-dbus-bridge.c: signal_filter(): Use inttype | 18 | * extra/upstart-dbus-bridge.c: signal_filter(): Use inttype |
23 | 4 | macros to ensure portability. | 19 | macros to ensure portability. |
24 | 5 | 20 | ||
25 | 21 | 2013-07-23 James Hunt <james.hunt@ubuntu.com> | ||
26 | 22 | |||
27 | 23 | * extra/upstart-text-bridge.c: New bridge. | ||
28 | 24 | * extra/Makefile.am: Updated for new bridge. | ||
29 | 25 | * extra/man/upstart-text-bridge.8: New man page. | ||
30 | 26 | * extra/Makefile.am: Added man page for text-bridge. | ||
31 | 27 | |||
32 | 6 | 2013-07-19 Dmitrijs Ledkovs <xnox@ubuntu.com> | 28 | 2013-07-19 Dmitrijs Ledkovs <xnox@ubuntu.com> |
33 | 7 | 29 | ||
34 | 8 | * init/session.c: fix a bug in session_from_index to handle more | 30 | * init/session.c: fix a bug in session_from_index to handle more |
35 | 9 | 31 | ||
36 | === modified file 'extra/Makefile.am' | |||
37 | --- extra/Makefile.am 2013-07-24 04:41:18 +0000 | |||
38 | +++ extra/Makefile.am 2013-07-25 19:58:24 +0000 | |||
39 | @@ -28,7 +28,8 @@ | |||
40 | 28 | upstart-socket-bridge \ | 28 | upstart-socket-bridge \ |
41 | 29 | upstart-event-bridge \ | 29 | upstart-event-bridge \ |
42 | 30 | upstart-file-bridge \ | 30 | upstart-file-bridge \ |
44 | 31 | upstart-dbus-bridge | 31 | upstart-dbus-bridge \ |
45 | 32 | upstart-local-bridge | ||
46 | 32 | 33 | ||
47 | 33 | dist_init_DATA = \ | 34 | dist_init_DATA = \ |
48 | 34 | conf/upstart-socket-bridge.conf \ | 35 | conf/upstart-socket-bridge.conf \ |
49 | @@ -41,6 +42,7 @@ | |||
50 | 41 | man/upstart-event-bridge.8 \ | 42 | man/upstart-event-bridge.8 \ |
51 | 42 | man/upstart-file-bridge.8 \ | 43 | man/upstart-file-bridge.8 \ |
52 | 43 | man/upstart-dbus-bridge.8 \ | 44 | man/upstart-dbus-bridge.8 \ |
53 | 45 | man/upstart-local-bridge.8 \ | ||
54 | 44 | man/socket-event.7 \ | 46 | man/socket-event.7 \ |
55 | 45 | man/file-event.7 \ | 47 | man/file-event.7 \ |
56 | 46 | man/dbus-event.7 | 48 | man/dbus-event.7 |
57 | @@ -89,6 +91,17 @@ | |||
58 | 89 | $(NIH_DBUS_LIBS) \ | 91 | $(NIH_DBUS_LIBS) \ |
59 | 90 | $(DBUS_LIBS) | 92 | $(DBUS_LIBS) |
60 | 91 | 93 | ||
61 | 94 | upstart_local_bridge_SOURCES = \ | ||
62 | 95 | upstart-local-bridge.c | ||
63 | 96 | nodist_upstart_local_bridge_SOURCES = \ | ||
64 | 97 | $(com_ubuntu_Upstart_OUTPUTS) \ | ||
65 | 98 | $(com_ubuntu_Upstart_Job_OUTPUTS) | ||
66 | 99 | upstart_local_bridge_LDADD = \ | ||
67 | 100 | $(LTLIBINTL) \ | ||
68 | 101 | $(NIH_LIBS) \ | ||
69 | 102 | $(NIH_DBUS_LIBS) \ | ||
70 | 103 | $(DBUS_LIBS) | ||
71 | 104 | |||
72 | 92 | if HAVE_UDEV | 105 | if HAVE_UDEV |
73 | 93 | dist_init_DATA += \ | 106 | dist_init_DATA += \ |
74 | 94 | conf/upstart-udev-bridge.conf | 107 | conf/upstart-udev-bridge.conf |
75 | 95 | 108 | ||
76 | === added file 'extra/man/upstart-local-bridge.8' | |||
77 | --- extra/man/upstart-local-bridge.8 1970-01-01 00:00:00 +0000 | |||
78 | +++ extra/man/upstart-local-bridge.8 2013-07-25 19:58:24 +0000 | |||
79 | @@ -0,0 +1,123 @@ | |||
80 | 1 | .TH upstart\-local\-bridge 8 2013-07-23 upstart | ||
81 | 2 | .\" | ||
82 | 3 | .SH NAME | ||
83 | 4 | upstart\-local\-bridge \- Bridge between Upstart and a local client socket | ||
84 | 5 | connection. | ||
85 | 6 | .\" | ||
86 | 7 | .SH SYNOPSIS | ||
87 | 8 | .B upstart\-local\-bridge | ||
88 | 9 | .RI [ OPTIONS ]... | ||
89 | 10 | .\" | ||
90 | 11 | .SH DESCRIPTION | ||
91 | 12 | .B upstart\-local\-bridge | ||
92 | 13 | listens on a local domain socket for name=value pairs and creates | ||
93 | 14 | .BR init (8) | ||
94 | 15 | events for them. | ||
95 | 16 | |||
96 | 17 | The local unix domain socket can be either named or abstract. | ||
97 | 18 | .\" | ||
98 | 19 | .SH OPTIONS | ||
99 | 20 | .\" | ||
100 | 21 | .TP | ||
101 | 22 | .B \-\-any\-user | ||
102 | 23 | By default the bridge will only accept connections from clients running | ||
103 | 24 | under the same user ID as the bridge itself. This option allows | ||
104 | 25 | connections from any user. | ||
105 | 26 | .\" | ||
106 | 27 | .TP | ||
107 | 28 | .B \-\-daemon | ||
108 | 29 | Detach and run in the background. | ||
109 | 30 | .\" | ||
110 | 31 | .TP | ||
111 | 32 | .B \-\-debug | ||
112 | 33 | Enable debugging output. | ||
113 | 34 | .\" | ||
114 | 35 | .TP | ||
115 | 36 | .B \-\-event \fIevent\fP | ||
116 | 37 | Specify name of event to emit on receipt of a name=value pair. | ||
117 | 38 | .\" | ||
118 | 39 | .TP | ||
119 | 40 | .B \-\-help | ||
120 | 41 | Show brief usage summary. | ||
121 | 42 | .\" | ||
122 | 43 | .TP | ||
123 | 44 | .B \-\-path \fIpath\fP | ||
124 | 45 | Specify path for local/abstract socket to listen on. If the first byte of | ||
125 | 46 | .I path | ||
126 | 47 | is an \(aq\fI@\fP\(aq, the socket will be created as an abstract socket. | ||
127 | 48 | .\" | ||
128 | 49 | .TP | ||
129 | 50 | .B \-\-verbose | ||
130 | 51 | Enable verbose output. | ||
131 | 52 | .\" | ||
132 | 53 | .SH EVENT DETAILS | ||
133 | 54 | |||
134 | 55 | The following environment variables are added automatically to the event | ||
135 | 56 | to be emitted, with the name=value pair being added as the last variable. | ||
136 | 57 | .P | ||
137 | 58 | .IP \(bu 4 | ||
138 | 59 | SOCKET_TYPE=unix | ||
139 | 60 | .IP \(bu 4 | ||
140 | 61 | SOCKET_VARIANT=[\fInamed\fP|\fIabstract\fP] | ||
141 | 62 | Sub-type of socket. | ||
142 | 63 | .IP \(bu 4 | ||
143 | 64 | CLIENT_UID=\fIUID\fP | ||
144 | 65 | User ID of connected client. | ||
145 | 66 | .IP \(bu 4 | ||
146 | 67 | CLIENT_GID=\fIGID\fP | ||
147 | 68 | Group ID of connected client. | ||
148 | 69 | .IP \(bu 4 | ||
149 | 70 | CLIENT_PID=\fIPID\fP | ||
150 | 71 | Process ID of connected client. | ||
151 | 72 | .IP \(bu 4 | ||
152 | 73 | PATH=\fIPATH\fP | ||
153 | 74 | .P | ||
154 | 75 | .\" | ||
155 | 76 | .SH EXAMPLES | ||
156 | 77 | .IP "upstart\-local\-bridge \-\-event=foo \-\-path=/var/foo/bar" 0.4i | ||
157 | 78 | Listen on local socket | ||
158 | 79 | .I /var/foo/bar | ||
159 | 80 | and when a name=value pair is read, emit an event of the form: | ||
160 | 81 | |||
161 | 82 | .RS | ||
162 | 83 | .nf | ||
163 | 84 | foo SOCKET_TYPE=unix SOCKET_VARIANT=named PATH=/var/foo/bar name=value | ||
164 | 85 | .fi | ||
165 | 86 | .RE | ||
166 | 87 | .IP "upstart\-local\-bridge \-\-event=bar \-\-path=@/var/foo/bar" 0.4i | ||
167 | 88 | Listen on abstract socket | ||
168 | 89 | .I @/var/foo/bar | ||
169 | 90 | and when a name=value pair is read, emit an event of the form: | ||
170 | 91 | |||
171 | 92 | .RS | ||
172 | 93 | .nf | ||
173 | 94 | bar SOCKET_TYPE=unix SOCKET_VARIANT=abstract PATH=@/var/foo/bar name=value | ||
174 | 95 | .fi | ||
175 | 96 | .RE | ||
176 | 97 | .\" | ||
177 | 98 | .SH NOTES | ||
178 | 99 | .IP \(bu 4 | ||
179 | 100 | If a named local socket is specified, all path elements except | ||
180 | 101 | for the last must already exist before the bridge starts. | ||
181 | 102 | .\" | ||
182 | 103 | .SH LIMITATIONS | ||
183 | 104 | |||
184 | 105 | .IP \(bu 4 | ||
185 | 106 | Only a single client connection is serviced at any one time. | ||
186 | 107 | .\" | ||
187 | 108 | .SH AUTHOR | ||
188 | 109 | Written by James Hunt | ||
189 | 110 | .RB < james.hunt@canonical.com > | ||
190 | 111 | .\" | ||
191 | 112 | .SH BUGS | ||
192 | 113 | Report bugs at | ||
193 | 114 | .RB < https://launchpad.net/ubuntu/+source/upstart/+bugs > | ||
194 | 115 | .\" | ||
195 | 116 | .SH COPYRIGHT | ||
196 | 117 | Copyright \(co 2013 Canonical Ltd. | ||
197 | 118 | .PP | ||
198 | 119 | This is free software; see the source for copying conditions. There is NO | ||
199 | 120 | warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
200 | 121 | .SH SEE ALSO | ||
201 | 122 | .BR init (5) | ||
202 | 123 | .BR init (8) | ||
203 | 0 | 124 | ||
204 | === added file 'extra/upstart-local-bridge.c' | |||
205 | --- extra/upstart-local-bridge.c 1970-01-01 00:00:00 +0000 | |||
206 | +++ extra/upstart-local-bridge.c 2013-07-25 19:58:24 +0000 | |||
207 | @@ -0,0 +1,805 @@ | |||
208 | 1 | /* upstart | ||
209 | 2 | * | ||
210 | 3 | * Copyright © 2013 Canonical Ltd. | ||
211 | 4 | * Author: James Hunt <james.hunt@canonical.com> | ||
212 | 5 | * | ||
213 | 6 | * This program is free software; you can redistribute it and/or modify | ||
214 | 7 | * it under the terms of the GNU General Public License version 2, as | ||
215 | 8 | * published by the Free Software Foundation. | ||
216 | 9 | * | ||
217 | 10 | * This program is distributed in the hope that it will be useful, | ||
218 | 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
219 | 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
220 | 13 | * GNU General Public License for more details. | ||
221 | 14 | * | ||
222 | 15 | * You should have received a copy of the GNU General Public License along | ||
223 | 16 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
224 | 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
225 | 18 | */ | ||
226 | 19 | |||
227 | 20 | #ifdef HAVE_CONFIG_H | ||
228 | 21 | # include <config.h> | ||
229 | 22 | #endif /* HAVE_CONFIG_H */ | ||
230 | 23 | |||
231 | 24 | #include <sys/types.h> | ||
232 | 25 | #include <sys/socket.h> | ||
233 | 26 | #include <sys/un.h> | ||
234 | 27 | |||
235 | 28 | #include <errno.h> | ||
236 | 29 | #include <stdlib.h> | ||
237 | 30 | #include <string.h> | ||
238 | 31 | #include <syslog.h> | ||
239 | 32 | #include <unistd.h> | ||
240 | 33 | |||
241 | 34 | #include <nih/macros.h> | ||
242 | 35 | #include <nih/alloc.h> | ||
243 | 36 | #include <nih/list.h> | ||
244 | 37 | #include <nih/hash.h> | ||
245 | 38 | #include <nih/string.h> | ||
246 | 39 | #include <nih/io.h> | ||
247 | 40 | #include <nih/option.h> | ||
248 | 41 | #include <nih/main.h> | ||
249 | 42 | #include <nih/logging.h> | ||
250 | 43 | #include <nih/error.h> | ||
251 | 44 | |||
252 | 45 | #include <nih-dbus/dbus_connection.h> | ||
253 | 46 | #include <nih-dbus/dbus_proxy.h> | ||
254 | 47 | |||
255 | 48 | #include "dbus/upstart.h" | ||
256 | 49 | #include "com.ubuntu.Upstart.h" | ||
257 | 50 | #include "com.ubuntu.Upstart.Job.h" | ||
258 | 51 | |||
259 | 52 | /** | ||
260 | 53 | * Job: | ||
261 | 54 | * | ||
262 | 55 | * @entry: list header, | ||
263 | 56 | * @path: D-Bus path for a job. | ||
264 | 57 | * | ||
265 | 58 | * Representation of an Upstart Job. | ||
266 | 59 | * | ||
267 | 60 | **/ | ||
268 | 61 | typedef struct job { | ||
269 | 62 | NihList entry; | ||
270 | 63 | char *path; | ||
271 | 64 | } Job; | ||
272 | 65 | |||
273 | 66 | /** | ||
274 | 67 | * Socket: | ||
275 | 68 | * | ||
276 | 69 | * @addr/sun_addr: socket address, | ||
277 | 70 | * @addrlen: length of sun_addr, | ||
278 | 71 | * @sock: file descriptor of socket, | ||
279 | 72 | * @watch: IO Watch used to detect client activity. | ||
280 | 73 | * | ||
281 | 74 | * Representation of a socket(2). | ||
282 | 75 | **/ | ||
283 | 76 | typedef struct socket { | ||
284 | 77 | union { | ||
285 | 78 | struct sockaddr addr; /* Generic type */ | ||
286 | 79 | struct sockaddr_un sun_addr; /* local/domain/unix/abstract socket */ | ||
287 | 80 | }; | ||
288 | 81 | socklen_t addrlen; | ||
289 | 82 | |||
290 | 83 | int sock; | ||
291 | 84 | NihIoWatch *watch; | ||
292 | 85 | } Socket; | ||
293 | 86 | |||
294 | 87 | /** | ||
295 | 88 | * ClientConnection: | ||
296 | 89 | * | ||
297 | 90 | * @sock: socket client connected via, | ||
298 | 91 | * @fd: file descriptor client connected on, | ||
299 | 92 | * @ucred: client credentials. | ||
300 | 93 | * | ||
301 | 94 | * Representation of a connected client. | ||
302 | 95 | **/ | ||
303 | 96 | typedef struct client_connection { | ||
304 | 97 | Socket *sock; | ||
305 | 98 | int fd; | ||
306 | 99 | struct ucred ucred; | ||
307 | 100 | } ClientConnection; | ||
308 | 101 | |||
309 | 102 | static void upstart_job_added (void *data, NihDBusMessage *message, | ||
310 | 103 | const char *job); | ||
311 | 104 | static void upstart_job_removed (void *data, NihDBusMessage *message, | ||
312 | 105 | const char *job); | ||
313 | 106 | static void upstart_connect (void); | ||
314 | 107 | static void upstart_disconnected (DBusConnection *connection); | ||
315 | 108 | |||
316 | 109 | static Socket *create_socket (void *parent); | ||
317 | 110 | |||
318 | 111 | static void socket_watcher (Socket *sock, NihIoWatch *watch, | ||
319 | 112 | NihIoEvents events); | ||
320 | 113 | |||
321 | 114 | static void socket_reader (ClientConnection *client, NihIo *io, | ||
322 | 115 | const char *buf, size_t len); | ||
323 | 116 | |||
324 | 117 | static void close_handler (ClientConnection *client, NihIo *io); | ||
325 | 118 | |||
326 | 119 | static void emit_event_error (void *data, NihDBusMessage *message); | ||
327 | 120 | |||
328 | 121 | static void signal_handler (void *data, NihSignal *signal); | ||
329 | 122 | |||
330 | 123 | static void cleanup (void); | ||
331 | 124 | |||
332 | 125 | /** | ||
333 | 126 | * daemonise: | ||
334 | 127 | * | ||
335 | 128 | * Set to TRUE if we should become a daemon, rather than just running | ||
336 | 129 | * in the foreground. | ||
337 | 130 | **/ | ||
338 | 131 | static int daemonise = FALSE; | ||
339 | 132 | |||
340 | 133 | /** | ||
341 | 134 | * jobs: | ||
342 | 135 | * | ||
343 | 136 | * Jobs that we're monitoring. | ||
344 | 137 | **/ | ||
345 | 138 | static NihHash *jobs = NULL; | ||
346 | 139 | |||
347 | 140 | /** | ||
348 | 141 | * upstart: | ||
349 | 142 | * | ||
350 | 143 | * Proxy to Upstart daemon. | ||
351 | 144 | **/ | ||
352 | 145 | static NihDBusProxy *upstart = NULL; | ||
353 | 146 | |||
354 | 147 | /** | ||
355 | 148 | * event_name: | ||
356 | 149 | * | ||
357 | 150 | * Name of event this bridge emits. | ||
358 | 151 | **/ | ||
359 | 152 | static char *event_name = NULL; | ||
360 | 153 | |||
361 | 154 | /** | ||
362 | 155 | * Unix (local) domain socket path. | ||
363 | 156 | * | ||
364 | 157 | * Abstract sockets will have '@' as first character. | ||
365 | 158 | **/ | ||
366 | 159 | static char *socket_path = NULL; | ||
367 | 160 | |||
368 | 161 | /** | ||
369 | 162 | * socket_type: | ||
370 | 163 | * | ||
371 | 164 | * Type of socket supported by this bridge. | ||
372 | 165 | **/ | ||
373 | 166 | static char *socket_type = "unix"; | ||
374 | 167 | |||
375 | 168 | /** | ||
376 | 169 | * socket_name: | ||
377 | 170 | * | ||
378 | 171 | * Human-readable socket name in form: | ||
379 | 172 | * | ||
380 | 173 | * unix:[@]/some/path | ||
381 | 174 | **/ | ||
382 | 175 | static char *socket_name = NULL; | ||
383 | 176 | |||
384 | 177 | /** | ||
385 | 178 | * sock: | ||
386 | 179 | * | ||
387 | 180 | * Socket this bridge listens on. | ||
388 | 181 | **/ | ||
389 | 182 | static Socket *sock = NULL; | ||
390 | 183 | |||
391 | 184 | /** | ||
392 | 185 | * any_user: | ||
393 | 186 | * | ||
394 | 187 | * If FALSE, only accept connections from the same uid as | ||
395 | 188 | * user the bridge runs as. | ||
396 | 189 | * If TRUE, accept connections from any user. | ||
397 | 190 | **/ | ||
398 | 191 | static int any_user = FALSE; | ||
399 | 192 | |||
400 | 193 | /** | ||
401 | 194 | * options: | ||
402 | 195 | * | ||
403 | 196 | * Command-line options accepted by this program. | ||
404 | 197 | **/ | ||
405 | 198 | static NihOption options[] = { | ||
406 | 199 | { 0, "daemon", N_("Detach and run in the background"), | ||
407 | 200 | NULL, NULL, &daemonise, NULL }, | ||
408 | 201 | |||
409 | 202 | { 0, "event", N_("specify name of event to emit on receipt of name=value pair"), | ||
410 | 203 | NULL, "EVENT", &event_name, NULL }, | ||
411 | 204 | |||
412 | 205 | { 0, "any-user", N_("allow any user to connect"), | ||
413 | 206 | NULL, NULL, &any_user, NULL }, | ||
414 | 207 | |||
415 | 208 | { 0, "path", N_("specify path for local/abstract socket to use"), | ||
416 | 209 | NULL, "PATH", &socket_path, NULL }, | ||
417 | 210 | |||
418 | 211 | NIH_OPTION_LAST | ||
419 | 212 | }; | ||
420 | 213 | |||
421 | 214 | |||
422 | 215 | /** | ||
423 | 216 | * signal_handler: | ||
424 | 217 | * @data: unused, | ||
425 | 218 | * @signal: signal caught. | ||
426 | 219 | * | ||
427 | 220 | * Called when we receive the TERM/INT signal. | ||
428 | 221 | **/ | ||
429 | 222 | static void | ||
430 | 223 | signal_handler (void *data, | ||
431 | 224 | NihSignal *signal) | ||
432 | 225 | { | ||
433 | 226 | nih_assert (signal != NULL); | ||
434 | 227 | |||
435 | 228 | cleanup (); | ||
436 | 229 | |||
437 | 230 | nih_main_loop_exit (0); | ||
438 | 231 | } | ||
439 | 232 | |||
440 | 233 | /** | ||
441 | 234 | * cleanup: | ||
442 | 235 | * | ||
443 | 236 | * Perform final operations before exit. | ||
444 | 237 | **/ | ||
445 | 238 | static void | ||
446 | 239 | cleanup (void) | ||
447 | 240 | { | ||
448 | 241 | nih_assert (sock); | ||
449 | 242 | |||
450 | 243 | close (sock->sock); | ||
451 | 244 | |||
452 | 245 | if (sock->sun_addr.sun_path[0] != '@') | ||
453 | 246 | unlink (sock->sun_addr.sun_path); | ||
454 | 247 | } | ||
455 | 248 | |||
456 | 249 | int | ||
457 | 250 | main (int argc, | ||
458 | 251 | char *argv[]) | ||
459 | 252 | { | ||
460 | 253 | char **args; | ||
461 | 254 | int ret; | ||
462 | 255 | |||
463 | 256 | nih_main_init (argv[0]); | ||
464 | 257 | |||
465 | 258 | nih_option_set_synopsis (_("Local socket Upstart Bridge")); | ||
466 | 259 | nih_option_set_help ( | ||
467 | 260 | _("By default, this bridge does not detach from the " | ||
468 | 261 | "console and remains in the foreground. Use the --daemon " | ||
469 | 262 | "option to have it detach.")); | ||
470 | 263 | |||
471 | 264 | args = nih_option_parser (NULL, argc, argv, options, FALSE); | ||
472 | 265 | if (! args) | ||
473 | 266 | exit (1); | ||
474 | 267 | |||
475 | 268 | if (! event_name) { | ||
476 | 269 | nih_fatal ("%s", _("Must specify event name")); | ||
477 | 270 | exit (1); | ||
478 | 271 | } | ||
479 | 272 | |||
480 | 273 | /* Allocate jobs hash table */ | ||
481 | 274 | jobs = NIH_MUST (nih_hash_string_new (NULL, 0)); | ||
482 | 275 | |||
483 | 276 | sock = create_socket (NULL); | ||
484 | 277 | if (! sock) { | ||
485 | 278 | nih_fatal ("%s %s", | ||
486 | 279 | _("Failed to create socket"), | ||
487 | 280 | socket_name); | ||
488 | 281 | exit (1); | ||
489 | 282 | } | ||
490 | 283 | |||
491 | 284 | nih_debug ("Connected to socket '%s' on fd %d", socket_name, sock->sock); | ||
492 | 285 | |||
493 | 286 | upstart_connect (); | ||
494 | 287 | |||
495 | 288 | /* Become daemon */ | ||
496 | 289 | if (daemonise) { | ||
497 | 290 | if (nih_main_daemonise () < 0) { | ||
498 | 291 | NihError *err; | ||
499 | 292 | |||
500 | 293 | err = nih_error_get (); | ||
501 | 294 | nih_fatal ("%s: %s", _("Unable to become daemon"), | ||
502 | 295 | err->message); | ||
503 | 296 | nih_free (err); | ||
504 | 297 | |||
505 | 298 | exit (1); | ||
506 | 299 | } | ||
507 | 300 | |||
508 | 301 | /* Send all logging output to syslog */ | ||
509 | 302 | openlog (program_name, LOG_PID, LOG_DAEMON); | ||
510 | 303 | nih_log_set_logger (nih_logger_syslog); | ||
511 | 304 | } | ||
512 | 305 | |||
513 | 306 | nih_signal_set_handler (SIGTERM, nih_signal_handler); | ||
514 | 307 | NIH_MUST (nih_signal_add_handler (NULL, SIGTERM, signal_handler, NULL)); | ||
515 | 308 | |||
516 | 309 | nih_signal_set_handler (SIGINT, nih_signal_handler); | ||
517 | 310 | NIH_MUST (nih_signal_add_handler (NULL, SIGINT, signal_handler, NULL)); | ||
518 | 311 | |||
519 | 312 | /* Handle TERM and INT signals gracefully */ | ||
520 | 313 | nih_signal_set_handler (SIGTERM, nih_signal_handler); | ||
521 | 314 | NIH_MUST (nih_signal_add_handler (NULL, SIGTERM, nih_main_term_signal, NULL)); | ||
522 | 315 | |||
523 | 316 | if (! daemonise) { | ||
524 | 317 | nih_signal_set_handler (SIGINT, nih_signal_handler); | ||
525 | 318 | NIH_MUST (nih_signal_add_handler (NULL, SIGINT, nih_main_term_signal, NULL)); | ||
526 | 319 | } | ||
527 | 320 | |||
528 | 321 | ret = nih_main_loop (); | ||
529 | 322 | |||
530 | 323 | return ret; | ||
531 | 324 | } | ||
532 | 325 | |||
533 | 326 | static void | ||
534 | 327 | upstart_job_added (void *data, | ||
535 | 328 | NihDBusMessage *message, | ||
536 | 329 | const char *job_class_path) | ||
537 | 330 | { | ||
538 | 331 | nih_local NihDBusProxy *job_class = NULL; | ||
539 | 332 | nih_local char ***start_on = NULL; | ||
540 | 333 | nih_local char ***stop_on = NULL; | ||
541 | 334 | Job *job; | ||
542 | 335 | |||
543 | 336 | nih_assert (job_class_path != NULL); | ||
544 | 337 | |||
545 | 338 | /* Obtain a proxy to the job */ | ||
546 | 339 | job_class = nih_dbus_proxy_new (NULL, upstart->connection, | ||
547 | 340 | upstart->name, job_class_path, | ||
548 | 341 | NULL, NULL); | ||
549 | 342 | if (! job_class) { | ||
550 | 343 | NihError *err; | ||
551 | 344 | |||
552 | 345 | err = nih_error_get (); | ||
553 | 346 | nih_error ("Could not create proxy for job %s: %s", | ||
554 | 347 | job_class_path, err->message); | ||
555 | 348 | nih_free (err); | ||
556 | 349 | |||
557 | 350 | return; | ||
558 | 351 | } | ||
559 | 352 | |||
560 | 353 | job_class->auto_start = FALSE; | ||
561 | 354 | |||
562 | 355 | /* Obtain the start_on and stop_on properties of the job */ | ||
563 | 356 | if (job_class_get_start_on_sync (NULL, job_class, &start_on) < 0) { | ||
564 | 357 | NihError *err; | ||
565 | 358 | |||
566 | 359 | err = nih_error_get (); | ||
567 | 360 | nih_error ("Could not obtain job start condition %s: %s", | ||
568 | 361 | job_class_path, err->message); | ||
569 | 362 | nih_free (err); | ||
570 | 363 | |||
571 | 364 | return; | ||
572 | 365 | } | ||
573 | 366 | |||
574 | 367 | if (job_class_get_stop_on_sync (NULL, job_class, &stop_on) < 0) { | ||
575 | 368 | NihError *err; | ||
576 | 369 | |||
577 | 370 | err = nih_error_get (); | ||
578 | 371 | nih_error ("Could not obtain job stop condition %s: %s", | ||
579 | 372 | job_class_path, err->message); | ||
580 | 373 | nih_free (err); | ||
581 | 374 | |||
582 | 375 | return; | ||
583 | 376 | } | ||
584 | 377 | |||
585 | 378 | /* Free any existing record for the job (should never happen, | ||
586 | 379 | * but worth being safe). | ||
587 | 380 | */ | ||
588 | 381 | job = (Job *)nih_hash_lookup (jobs, job_class_path); | ||
589 | 382 | if (job) | ||
590 | 383 | nih_free (job); | ||
591 | 384 | |||
592 | 385 | /* Create new record for the job */ | ||
593 | 386 | job = NIH_MUST (nih_new (NULL, Job)); | ||
594 | 387 | job->path = NIH_MUST (nih_strdup (job, job_class_path)); | ||
595 | 388 | |||
596 | 389 | nih_list_init (&job->entry); | ||
597 | 390 | |||
598 | 391 | nih_debug ("Job got added %s", job_class_path); | ||
599 | 392 | |||
600 | 393 | nih_alloc_set_destructor (job, nih_list_destroy); | ||
601 | 394 | |||
602 | 395 | /* Add all jobs */ | ||
603 | 396 | nih_hash_add (jobs, &job->entry); | ||
604 | 397 | } | ||
605 | 398 | |||
606 | 399 | static void | ||
607 | 400 | upstart_job_removed (void *data, | ||
608 | 401 | NihDBusMessage *message, | ||
609 | 402 | const char *job_path) | ||
610 | 403 | { | ||
611 | 404 | Job *job; | ||
612 | 405 | |||
613 | 406 | nih_assert (job_path != NULL); | ||
614 | 407 | |||
615 | 408 | job = (Job *)nih_hash_lookup (jobs, job_path); | ||
616 | 409 | if (job) { | ||
617 | 410 | nih_debug ("Job went away %s", job_path); | ||
618 | 411 | nih_free (job); | ||
619 | 412 | } | ||
620 | 413 | } | ||
621 | 414 | |||
622 | 415 | static void | ||
623 | 416 | upstart_connect (void) | ||
624 | 417 | { | ||
625 | 418 | DBusConnection *connection; | ||
626 | 419 | char **job_class_paths; | ||
627 | 420 | |||
628 | 421 | /* Initialise the connection to Upstart */ | ||
629 | 422 | connection = NIH_SHOULD (nih_dbus_connect (DBUS_ADDRESS_UPSTART, upstart_disconnected)); | ||
630 | 423 | if (! connection) { | ||
631 | 424 | NihError *err; | ||
632 | 425 | |||
633 | 426 | err = nih_error_get (); | ||
634 | 427 | nih_fatal ("%s: %s", _("Could not connect to Upstart"), | ||
635 | 428 | err->message); | ||
636 | 429 | nih_free (err); | ||
637 | 430 | |||
638 | 431 | exit (1); | ||
639 | 432 | } | ||
640 | 433 | |||
641 | 434 | upstart = NIH_SHOULD (nih_dbus_proxy_new (NULL, connection, | ||
642 | 435 | NULL, DBUS_PATH_UPSTART, | ||
643 | 436 | NULL, NULL)); | ||
644 | 437 | if (! upstart) { | ||
645 | 438 | NihError *err; | ||
646 | 439 | |||
647 | 440 | err = nih_error_get (); | ||
648 | 441 | nih_fatal ("%s: %s", _("Could not create Upstart proxy"), | ||
649 | 442 | err->message); | ||
650 | 443 | nih_free (err); | ||
651 | 444 | |||
652 | 445 | exit (1); | ||
653 | 446 | } | ||
654 | 447 | |||
655 | 448 | nih_debug ("Connected to Upstart"); | ||
656 | 449 | |||
657 | 450 | /* Connect signals to be notified when jobs come and go */ | ||
658 | 451 | if (! nih_dbus_proxy_connect (upstart, &upstart_com_ubuntu_Upstart0_6, "JobAdded", | ||
659 | 452 | (NihDBusSignalHandler)upstart_job_added, NULL)) { | ||
660 | 453 | NihError *err; | ||
661 | 454 | |||
662 | 455 | err = nih_error_get (); | ||
663 | 456 | nih_fatal ("%s: %s", _("Could not create JobAdded signal connection"), | ||
664 | 457 | err->message); | ||
665 | 458 | nih_free (err); | ||
666 | 459 | |||
667 | 460 | exit (1); | ||
668 | 461 | } | ||
669 | 462 | |||
670 | 463 | if (! nih_dbus_proxy_connect (upstart, &upstart_com_ubuntu_Upstart0_6, "JobRemoved", | ||
671 | 464 | (NihDBusSignalHandler)upstart_job_removed, NULL)) { | ||
672 | 465 | NihError *err; | ||
673 | 466 | |||
674 | 467 | err = nih_error_get (); | ||
675 | 468 | nih_fatal ("%s: %s", _("Could not create JobRemoved signal connection"), | ||
676 | 469 | err->message); | ||
677 | 470 | nih_free (err); | ||
678 | 471 | |||
679 | 472 | exit (1); | ||
680 | 473 | } | ||
681 | 474 | |||
682 | 475 | /* Request a list of all current jobs */ | ||
683 | 476 | if (upstart_get_all_jobs_sync (NULL, upstart, &job_class_paths) < 0) { | ||
684 | 477 | NihError *err; | ||
685 | 478 | |||
686 | 479 | err = nih_error_get (); | ||
687 | 480 | nih_fatal ("%s: %s", _("Could not obtain job list"), | ||
688 | 481 | err->message); | ||
689 | 482 | nih_free (err); | ||
690 | 483 | |||
691 | 484 | exit (1); | ||
692 | 485 | } | ||
693 | 486 | |||
694 | 487 | for (char **job_class_path = job_class_paths; | ||
695 | 488 | job_class_path && *job_class_path; job_class_path++) | ||
696 | 489 | upstart_job_added (NULL, NULL, *job_class_path); | ||
697 | 490 | |||
698 | 491 | nih_free (job_class_paths); | ||
699 | 492 | } | ||
700 | 493 | |||
701 | 494 | static void | ||
702 | 495 | upstart_disconnected (DBusConnection *connection) | ||
703 | 496 | { | ||
704 | 497 | nih_fatal (_("Disconnected from Upstart")); | ||
705 | 498 | nih_main_loop_exit (1); | ||
706 | 499 | } | ||
707 | 500 | |||
708 | 501 | /** | ||
709 | 502 | * socket_watcher: | ||
710 | 503 | * | ||
711 | 504 | * @sock: Socket, | ||
712 | 505 | * @watch: IO watch, | ||
713 | 506 | * @event: events that occurred. | ||
714 | 507 | * | ||
715 | 508 | * Called when activity is received for socket fd. | ||
716 | 509 | **/ | ||
717 | 510 | static void | ||
718 | 511 | socket_watcher (Socket *sock, | ||
719 | 512 | NihIoWatch *watch, | ||
720 | 513 | NihIoEvents events) | ||
721 | 514 | { | ||
722 | 515 | struct sockaddr client_addr; | ||
723 | 516 | socklen_t client_len; | ||
724 | 517 | nih_local char *buffer = NULL; | ||
725 | 518 | ClientConnection *client; | ||
726 | 519 | size_t len; | ||
727 | 520 | |||
728 | 521 | nih_assert (sock); | ||
729 | 522 | nih_assert (watch); | ||
730 | 523 | |||
731 | 524 | client = NIH_MUST (nih_new (NULL, ClientConnection)); | ||
732 | 525 | memset (client, 0, sizeof (ClientConnection)); | ||
733 | 526 | client->sock = sock; | ||
734 | 527 | |||
735 | 528 | client_len = sizeof (struct sockaddr); | ||
736 | 529 | |||
737 | 530 | client->fd = accept (sock->sock, (struct sockaddr *)&client_addr, &client_len); | ||
738 | 531 | |||
739 | 532 | if (client->fd < 0) { | ||
740 | 533 | nih_fatal ("%s %s %s", _("Failed to accept socket"), | ||
741 | 534 | socket_name, strerror (errno)); | ||
742 | 535 | return; | ||
743 | 536 | } | ||
744 | 537 | |||
745 | 538 | len = sizeof (client->ucred); | ||
746 | 539 | |||
747 | 540 | /* Establish who is connected to the other end */ | ||
748 | 541 | if (getsockopt (client->fd, SOL_SOCKET, SO_PEERCRED, &client->ucred, &len) < 0) | ||
749 | 542 | goto error; | ||
750 | 543 | |||
751 | 544 | if (! any_user && client->ucred.uid != geteuid ()) { | ||
752 | 545 | nih_warn ("Ignoring request from uid %u (gid %u, pid %u)", | ||
753 | 546 | (unsigned int)client->ucred.uid, | ||
754 | 547 | (unsigned int)client->ucred.gid, | ||
755 | 548 | (unsigned int)client->ucred.pid); | ||
756 | 549 | close (client->fd); | ||
757 | 550 | return; | ||
758 | 551 | } | ||
759 | 552 | |||
760 | 553 | nih_debug ("Client connected via local socket to %s: " | ||
761 | 554 | "pid %d (uid %d, gid %d)", | ||
762 | 555 | socket_name, | ||
763 | 556 | client->ucred.pid, | ||
764 | 557 | client->ucred.uid, | ||
765 | 558 | client->ucred.gid); | ||
766 | 559 | |||
767 | 560 | /* Wait for remote end to send data */ | ||
768 | 561 | NIH_MUST (nih_io_reopen (sock, client->fd, | ||
769 | 562 | NIH_IO_STREAM, | ||
770 | 563 | (NihIoReader)socket_reader, | ||
771 | 564 | (NihIoCloseHandler)close_handler, | ||
772 | 565 | NULL, | ||
773 | 566 | client)); | ||
774 | 567 | return; | ||
775 | 568 | |||
776 | 569 | error: | ||
777 | 570 | nih_warn ("%s %s: %s", | ||
778 | 571 | _("Cannot establish peer credentials for socket"), | ||
779 | 572 | socket_name, strerror (errno)); | ||
780 | 573 | } | ||
781 | 574 | |||
782 | 575 | /** | ||
783 | 576 | * socket_reader: | ||
784 | 577 | * | ||
785 | 578 | * @client: client connection, | ||
786 | 579 | * @io: NihIo, | ||
787 | 580 | * @buf: data read from client, | ||
788 | 581 | * @len: length of @buf. | ||
789 | 582 | * | ||
790 | 583 | * NihIoReader function called when data has been read from the | ||
791 | 584 | * connected client. | ||
792 | 585 | **/ | ||
793 | 586 | static void | ||
794 | 587 | socket_reader (ClientConnection *client, | ||
795 | 588 | NihIo *io, | ||
796 | 589 | const char *buf, | ||
797 | 590 | size_t len) | ||
798 | 591 | { | ||
799 | 592 | DBusPendingCall *pending_call; | ||
800 | 593 | nih_local char **env = NULL; | ||
801 | 594 | nih_local char *var = NULL; | ||
802 | 595 | size_t used_len = 0; | ||
803 | 596 | int i; | ||
804 | 597 | |||
805 | 598 | nih_assert (sock); | ||
806 | 599 | nih_assert (client); | ||
807 | 600 | nih_assert (io); | ||
808 | 601 | nih_assert (buf); | ||
809 | 602 | |||
810 | 603 | /* Ignore messages that are too short */ | ||
811 | 604 | if (len < 2) | ||
812 | 605 | goto error; | ||
813 | 606 | |||
814 | 607 | /* Ensure the data is a name=value pair */ | ||
815 | 608 | if (! strchr (buf, '=') || buf[0] == '=') | ||
816 | 609 | goto error; | ||
817 | 610 | |||
818 | 611 | /* Remove line endings */ | ||
819 | 612 | for (i = 0, used_len = len; i < 2; i++) { | ||
820 | 613 | if (buf[used_len-1] == '\n' || buf[used_len-1] == '\r') | ||
821 | 614 | used_len--; | ||
822 | 615 | else | ||
823 | 616 | break; | ||
824 | 617 | } | ||
825 | 618 | |||
826 | 619 | /* Second check to ensure overly short messages are ignored */ | ||
827 | 620 | if (used_len < 2) | ||
828 | 621 | goto error; | ||
829 | 622 | |||
830 | 623 | /* Construct the event environment. | ||
831 | 624 | * | ||
832 | 625 | * Note that although the client could conceivably specify one | ||
833 | 626 | * of the variables below _itself_, if the intent is malicious | ||
834 | 627 | * it will be thwarted since although the following example | ||
835 | 628 | * event is valid... | ||
836 | 629 | * | ||
837 | 630 | * foo BAR=BAZ BAR=MALICIOUS | ||
838 | 631 | * | ||
839 | 632 | * ... environment variable matching only happens for the first | ||
840 | 633 | * occurence of a variable. In summary, a malicious client | ||
841 | 634 | * cannot spoof the standard variables we set. | ||
842 | 635 | */ | ||
843 | 636 | env = NIH_MUST (nih_str_array_new (NULL)); | ||
844 | 637 | |||
845 | 638 | /* Specify type to allow for other types to be added in the future */ | ||
846 | 639 | var = NIH_MUST (nih_sprintf (NULL, "SOCKET_TYPE=%s", socket_type)); | ||
847 | 640 | NIH_MUST (nih_str_array_addp (&env, NULL, NULL, var)); | ||
848 | 641 | |||
849 | 642 | var = NIH_MUST (nih_sprintf (NULL, "SOCKET_VARIANT=%s", | ||
850 | 643 | sock->sun_addr.sun_path[0] ? "named" : "abstract")); | ||
851 | 644 | NIH_MUST (nih_str_array_addp (&env, NULL, NULL, var)); | ||
852 | 645 | |||
853 | 646 | var = NIH_MUST (nih_sprintf (NULL, "CLIENT_UID=%u", (unsigned int)client->ucred.uid)); | ||
854 | 647 | NIH_MUST (nih_str_array_addp (&env, NULL, NULL, var)); | ||
855 | 648 | |||
856 | 649 | var = NIH_MUST (nih_sprintf (NULL, "CLIENT_GID=%u", (unsigned int)client->ucred.gid)); | ||
857 | 650 | NIH_MUST (nih_str_array_addp (&env, NULL, NULL, var)); | ||
858 | 651 | |||
859 | 652 | var = NIH_MUST (nih_sprintf (NULL, "CLIENT_PID=%u", (unsigned int)client->ucred.pid)); | ||
860 | 653 | NIH_MUST (nih_str_array_addp (&env, NULL, NULL, var)); | ||
861 | 654 | |||
862 | 655 | var = NIH_MUST (nih_sprintf (NULL, "PATH=%s", socket_path)); | ||
863 | 656 | NIH_MUST (nih_str_array_addp (&env, NULL, NULL, var)); | ||
864 | 657 | |||
865 | 658 | /* Add the name=value pair */ | ||
866 | 659 | NIH_MUST (nih_str_array_addn (&env, NULL, NULL, buf, used_len)); | ||
867 | 660 | |||
868 | 661 | pending_call = upstart_emit_event (upstart, | ||
869 | 662 | event_name, env, FALSE, | ||
870 | 663 | NULL, emit_event_error, NULL, | ||
871 | 664 | NIH_DBUS_TIMEOUT_NEVER); | ||
872 | 665 | |||
873 | 666 | if (! pending_call) { | ||
874 | 667 | NihError *err; | ||
875 | 668 | err = nih_error_get (); | ||
876 | 669 | nih_warn ("%s", err->message); | ||
877 | 670 | nih_free (err); | ||
878 | 671 | } | ||
879 | 672 | |||
880 | 673 | /* Consume the entire length */ | ||
881 | 674 | nih_io_buffer_shrink (io->recv_buf, len); | ||
882 | 675 | |||
883 | 676 | dbus_pending_call_unref (pending_call); | ||
884 | 677 | |||
885 | 678 | return; | ||
886 | 679 | |||
887 | 680 | error: | ||
888 | 681 | nih_debug ("ignoring invalid input of length %lu", | ||
889 | 682 | (unsigned long int)len); | ||
890 | 683 | |||
891 | 684 | /* Consume the entire length */ | ||
892 | 685 | nih_io_buffer_shrink (io->recv_buf, len); | ||
893 | 686 | } | ||
894 | 687 | |||
895 | 688 | static void | ||
896 | 689 | close_handler (ClientConnection *client, NihIo *io) | ||
897 | 690 | { | ||
898 | 691 | nih_assert (client); | ||
899 | 692 | nih_assert (io); | ||
900 | 693 | |||
901 | 694 | nih_debug ("Remote end closed connection"); | ||
902 | 695 | |||
903 | 696 | close (client->fd); | ||
904 | 697 | nih_free (client); | ||
905 | 698 | nih_free (io); | ||
906 | 699 | } | ||
907 | 700 | |||
908 | 701 | /** | ||
909 | 702 | * create_socket: | ||
910 | 703 | * @parent: Parent pointer. | ||
911 | 704 | * | ||
912 | 705 | * Create a Socket object, listen on it and arrange for NIH to monitor | ||
913 | 706 | * it. | ||
914 | 707 | * | ||
915 | 708 | * Returns: Newly-allocated Socket on success, or NULL on error. | ||
916 | 709 | **/ | ||
917 | 710 | static Socket * | ||
918 | 711 | create_socket (void *parent) | ||
919 | 712 | { | ||
920 | 713 | Socket *sock = NULL; | ||
921 | 714 | int opt = 1; | ||
922 | 715 | size_t len; | ||
923 | 716 | |||
924 | 717 | if (! socket_path) { | ||
925 | 718 | nih_fatal ("%s", _("Must specify socket path")); | ||
926 | 719 | exit (1); | ||
927 | 720 | } | ||
928 | 721 | |||
929 | 722 | NIH_MUST (nih_strcat_sprintf (&socket_name, NULL, "%s:%s", | ||
930 | 723 | socket_type, socket_path)); | ||
931 | 724 | |||
932 | 725 | sock = NIH_MUST (nih_new (NULL, Socket)); | ||
933 | 726 | memset (sock, 0, sizeof (Socket)); | ||
934 | 727 | sock->sock = -1; | ||
935 | 728 | |||
936 | 729 | sock->sun_addr.sun_family = AF_UNIX; | ||
937 | 730 | |||
938 | 731 | if (! *socket_path || (socket_path[0] != '/' && socket_path[0] != '@')) { | ||
939 | 732 | nih_fatal ("%s %s", _("Invalid path"), socket_path); | ||
940 | 733 | goto error; | ||
941 | 734 | } | ||
942 | 735 | |||
943 | 736 | len = strlen (socket_path); | ||
944 | 737 | |||
945 | 738 | if (len > sizeof (sock->sun_addr.sun_path)) { | ||
946 | 739 | nih_fatal ("%s %s", _("Path too long"), socket_path); | ||
947 | 740 | goto error; | ||
948 | 741 | } | ||
949 | 742 | |||
950 | 743 | strncpy (sock->sun_addr.sun_path, socket_path, | ||
951 | 744 | sizeof (sock->sun_addr.sun_path)); | ||
952 | 745 | |||
953 | 746 | sock->addrlen = sizeof (sock->sun_addr.sun_family) + len; | ||
954 | 747 | |||
955 | 748 | /* Handle abstract names */ | ||
956 | 749 | if (sock->sun_addr.sun_path[0] == '@') | ||
957 | 750 | sock->sun_addr.sun_path[0] = '\0'; | ||
958 | 751 | |||
959 | 752 | sock->sock = socket (sock->addr.sa_family, SOCK_STREAM, 0); | ||
960 | 753 | if (sock->sock < 0) { | ||
961 | 754 | nih_fatal ("%s %s %s", _("Failed to create socket"), | ||
962 | 755 | socket_name, strerror (errno)); | ||
963 | 756 | goto error; | ||
964 | 757 | } | ||
965 | 758 | |||
966 | 759 | if (setsockopt (sock->sock, SOL_SOCKET, SO_REUSEADDR, | ||
967 | 760 | &opt, sizeof (opt)) < 0) { | ||
968 | 761 | nih_fatal ("%s %s %s", _("Failed to set socket reuse"), | ||
969 | 762 | socket_name, strerror (errno)); | ||
970 | 763 | goto error; | ||
971 | 764 | } | ||
972 | 765 | |||
973 | 766 | if (setsockopt (sock->sock, SOL_SOCKET, SO_PASSCRED, | ||
974 | 767 | &opt, sizeof (opt)) < 0) { | ||
975 | 768 | nih_fatal ("%s %s %s", _("Failed to set socket credential-passing"), | ||
976 | 769 | socket_name, strerror (errno)); | ||
977 | 770 | goto error; | ||
978 | 771 | } | ||
979 | 772 | |||
980 | 773 | if (bind (sock->sock, &sock->addr, sock->addrlen) < 0) { | ||
981 | 774 | nih_fatal ("%s %s %s", _("Failed to bind socket"), | ||
982 | 775 | socket_name, strerror (errno)); | ||
983 | 776 | goto error; | ||
984 | 777 | } | ||
985 | 778 | |||
986 | 779 | if (listen (sock->sock, SOMAXCONN) < 0) { | ||
987 | 780 | nih_fatal ("%s %s %s", _("Failed to listen on socket"), | ||
988 | 781 | socket_name, strerror (errno)); | ||
989 | 782 | goto error; | ||
990 | 783 | } | ||
991 | 784 | |||
992 | 785 | sock->watch = NIH_MUST (nih_io_add_watch (sock, sock->sock, | ||
993 | 786 | NIH_IO_READ, | ||
994 | 787 | (NihIoWatcher)socket_watcher, sock)); | ||
995 | 788 | |||
996 | 789 | return sock; | ||
997 | 790 | |||
998 | 791 | error: | ||
999 | 792 | nih_free (sock); | ||
1000 | 793 | return NULL; | ||
1001 | 794 | } | ||
1002 | 795 | |||
1003 | 796 | static void | ||
1004 | 797 | emit_event_error (void *data, | ||
1005 | 798 | NihDBusMessage *message) | ||
1006 | 799 | { | ||
1007 | 800 | NihError *err; | ||
1008 | 801 | |||
1009 | 802 | err = nih_error_get (); | ||
1010 | 803 | nih_warn ("%s", err->message); | ||
1011 | 804 | nih_free (err); | ||
1012 | 805 | } |