Merge lp:~jamesodhunt/upstart/remove-basic-user-sessions into lp:upstart
- remove-basic-user-sessions
- Merge into trunk
Status: | Merged |
---|---|
Merged at revision: | 1431 |
Proposed branch: | lp:~jamesodhunt/upstart/remove-basic-user-sessions |
Merge into: | lp:upstart |
Diff against target: |
2363 lines (+321/-1503) 14 files modified
ChangeLog (+48/-0) dbus/Upstart.conf (+36/-6) init/control.c (+135/-37) init/job.c (+1/-1) init/job_class.c (+9/-32) init/job_process.c (+2/-91) init/man/init.5 (+16/-53) init/session.c (+50/-168) init/session.h (+12/-14) init/state.h (+3/-3) init/tests/test_conf.c (+2/-0) init/tests/test_state.c (+4/-7) util/tests/test_initctl.c (+3/-0) util/tests/test_user_sessions.sh (+0/-1091) |
To merge this branch: | bzr merge lp:~jamesodhunt/upstart/remove-basic-user-sessions |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Colin Watson (community) | Approve | ||
Steve Langasek | Needs Fixing | ||
Review via email: mp+144873@code.launchpad.net |
Commit message
Description of the change
= Removal of Simple Sessions =
This branch removes the existing 'User Jobs' code since we are in the process of replacing that facility entirely by 'User Sessions' [1].
= D-Bus =
The branch reverts the D-Bus policy changes introduced to allow any user to manipulate any property and method (since with User Jobs, all commands were namespaced off by default.
Checks have been added to all control interfaces to disallow non-priv users from manipulating PID 1 properties and methods.
Note however that this branch does _not_ provide the same checks on job and job instance method calls (or log-priority method): we are reliant on D-Bus policy to police these for now. This is consistent with old pre-session behaviour but we should review this approach in a follow-on branch to make the internal D-Bus border checks fully consistent.
[1] - https:/
- 1430. By James Hunt
-
* init/control.c: More careful uid checking.
James Hunt (jamesodhunt) wrote : | # |
Hi Steve,
Good catch! Fixed.
- 1431. By James Hunt
-
* init/control.c:
- Typos.
- Improved uid checks.
- Replaced direct call to control_get_origin_ uid() with call to new
control_check_permissio n() (as early as possible) for clarity and
to confine policy to one location.
- control_set_log_ prioity( ): Added missing call to
control_check_permissio n().
- control_get_origin_ uid(): Check message contents before allowing
D-Bus calls.
* init/control.h: Added missing prototypes.
James Hunt (jamesodhunt) wrote : | # |
Reworked branch D-Bus permission checking to simplify code and confine policy to a single location.
Colin Watson (cjwatson) wrote : | # |
Looks better now, though I'd add a comment to control_
- 1432. By James Hunt
-
* init/control.c: Comments.
James Hunt (jamesodhunt) wrote : | # |
Fixed. Thanks for reviewing.
Preview Diff
1 | === modified file 'ChangeLog' |
2 | --- ChangeLog 2013-01-24 08:37:53 +0000 |
3 | +++ ChangeLog 2013-01-30 16:15:24 +0000 |
4 | @@ -1,3 +1,51 @@ |
5 | +2013-01-30 James Hunt <james.hunt@ubuntu.com> |
6 | + |
7 | + * init/control.c: |
8 | + - Typos. |
9 | + - Improved uid checks. |
10 | + - Replaced direct call to control_get_origin_uid() with call to new |
11 | + control_check_permission() (as early as possible) for clarity and |
12 | + to confine policy to one location. |
13 | + - control_set_log_prioity(): Added missing call to |
14 | + control_check_permission(). |
15 | + - control_get_origin_uid(): Check message contents before allowing |
16 | + D-Bus calls. |
17 | + |
18 | +2013-01-29 James Hunt <james.hunt@ubuntu.com> |
19 | + |
20 | + * init/control.c: More careful uid checking. |
21 | + |
22 | +2013-01-25 James Hunt <james.hunt@ubuntu.com> |
23 | + |
24 | + * init/control.c: |
25 | + - control_reload_configuration(): Added missing permission checks. |
26 | + - control_emit_event_with_file(): Added missing permission checks. |
27 | + - Added calls to new function control_get_origin_uid() to allow |
28 | + D-Bus methods to be policed by filtering on uid, rather than |
29 | + relying on the same information that used to be stored in the |
30 | + old Session object. |
31 | + * init/job.c: Typo. |
32 | + * init/job_class.c: |
33 | + - job_class_new(): Removed user elements from session code. |
34 | + - job_class_serialise(): Comments. |
35 | + - job_class_deserialise(): Comments. |
36 | + * init/job_process.c: job_process_spawn(): Removed user session |
37 | + handling. |
38 | + * init/session.c: Removed user session handling since it is |
39 | + about to be replaced by the ability to run Upstart as a |
40 | + non-privileged user (aka a 'Session Init'). |
41 | + * init/session.h: Updated prototypes. |
42 | + * init/state.h: Comments. |
43 | + * init/tests/test_conf.c: test_source_reload_job_dir(): Added missing |
44 | + check. |
45 | + * init/tests/test_state.c: |
46 | + - session_diff(): Removed user check. |
47 | + - Updated all calls to session_new(). |
48 | + * util/tests/test_initctl.c: test_notify_disk_writeable(): Ensure this |
49 | + test is not run as root. |
50 | + * util/tests/test_user_sessions.sh: Removed. |
51 | + * init/man/init.5: Updated to reflect removal of user jobs. |
52 | + |
53 | 2013-01-21 Dmitrijs Ledkovs <xnox@ubuntu.com> |
54 | |
55 | * init/xdg.[ch]: add xdg_get_cache_home and get_user_log_dir |
56 | |
57 | === modified file 'dbus/Upstart.conf' |
58 | --- dbus/Upstart.conf 2010-12-10 03:02:57 +0000 |
59 | +++ dbus/Upstart.conf 2013-01-30 16:15:24 +0000 |
60 | @@ -9,14 +9,12 @@ |
61 | <allow own="com.ubuntu.Upstart" /> |
62 | </policy> |
63 | |
64 | - <!-- Allow any user to invoke all of the methods on Upstart, its jobs |
65 | - or their instances, and to get and set properties - since Upstart |
66 | - isolates commands by user. --> |
67 | - <policy context="default"> |
68 | - <allow send_destination="com.ubuntu.Upstart" |
69 | - send_interface="org.freedesktop.DBus.Introspectable" /> |
70 | + <!-- Permit the root user to invoke all of the methods on Upstart, its jobs |
71 | + or their instances, and to get and set properties. --> |
72 | + <policy user="root"> |
73 | <allow send_destination="com.ubuntu.Upstart" |
74 | send_interface="org.freedesktop.DBus.Properties" /> |
75 | + |
76 | <allow send_destination="com.ubuntu.Upstart" |
77 | send_interface="com.ubuntu.Upstart0_6" /> |
78 | <allow send_destination="com.ubuntu.Upstart" |
79 | @@ -24,4 +22,36 @@ |
80 | <allow send_destination="com.ubuntu.Upstart" |
81 | send_interface="com.ubuntu.Upstart0_6.Instance" /> |
82 | </policy> |
83 | + |
84 | + <!-- Allow any user to introspect Upstart's interfaces, to obtain the |
85 | + values of properties (but not set them) and to invoke selected |
86 | + methods on Upstart and its jobs that are used to walk information. --> |
87 | + <policy context="default"> |
88 | + <allow send_destination="com.ubuntu.Upstart" |
89 | + send_interface="org.freedesktop.DBus.Introspectable" /> |
90 | + |
91 | + <allow send_destination="com.ubuntu.Upstart" |
92 | + send_interface="org.freedesktop.DBus.Properties" |
93 | + send_type="method_call" send_member="Get" /> |
94 | + <allow send_destination="com.ubuntu.Upstart" |
95 | + send_interface="org.freedesktop.DBus.Properties" |
96 | + send_type="method_call" send_member="GetAll" /> |
97 | + |
98 | + <allow send_destination="com.ubuntu.Upstart" |
99 | + send_interface="com.ubuntu.Upstart0_6" |
100 | + send_type="method_call" send_member="GetJobByName" /> |
101 | + <allow send_destination="com.ubuntu.Upstart" |
102 | + send_interface="com.ubuntu.Upstart0_6" |
103 | + send_type="method_call" send_member="GetAllJobs" /> |
104 | + |
105 | + <allow send_destination="com.ubuntu.Upstart" |
106 | + send_interface="com.ubuntu.Upstart0_6.Job" |
107 | + send_type="method_call" send_member="GetInstance" /> |
108 | + <allow send_destination="com.ubuntu.Upstart" |
109 | + send_interface="com.ubuntu.Upstart0_6.Job" |
110 | + send_type="method_call" send_member="GetInstanceByName" /> |
111 | + <allow send_destination="com.ubuntu.Upstart" |
112 | + send_interface="com.ubuntu.Upstart0_6.Job" |
113 | + send_type="method_call" send_member="GetAllInstances" /> |
114 | + </policy> |
115 | </busconfig> |
116 | |
117 | === modified file 'init/control.c' |
118 | --- init/control.c 2013-01-23 12:56:00 +0000 |
119 | +++ init/control.c 2013-01-30 16:15:24 +0000 |
120 | @@ -2,7 +2,7 @@ |
121 | * |
122 | * control.c - D-Bus connections, objects and methods |
123 | * |
124 | - * Copyright © 2009-2011 Canonical Ltd. |
125 | + * Copyright 2009-2011 Canonical Ltd. |
126 | * Author: Scott James Remnant <scott@netsplit.com>. |
127 | * |
128 | * This program is free software; you can redistribute it and/or modify |
129 | @@ -60,11 +60,15 @@ |
130 | #include "com.ubuntu.Upstart.h" |
131 | |
132 | /* Prototypes for static functions */ |
133 | -static int control_server_connect (DBusServer *server, DBusConnection *conn); |
134 | -static void control_disconnected (DBusConnection *conn); |
135 | -static void control_register_all (DBusConnection *conn); |
136 | +static int control_server_connect (DBusServer *server, DBusConnection *conn); |
137 | +static void control_disconnected (DBusConnection *conn); |
138 | +static void control_register_all (DBusConnection *conn); |
139 | |
140 | -static void control_bus_flush (void); |
141 | +static void control_bus_flush (void); |
142 | +static int control_get_origin_uid (NihDBusMessage *message, uid_t *uid) |
143 | + __attribute__ ((warn_unused_result)); |
144 | +static int control_check_permission (NihDBusMessage *message) |
145 | + __attribute__ ((warn_unused_result)); |
146 | |
147 | /** |
148 | * use_session_bus: |
149 | @@ -378,6 +382,8 @@ |
150 | * Called to request that Upstart reloads its configuration from disk, |
151 | * useful when inotify is not available or the user is generally paranoid. |
152 | * |
153 | + * Notes: chroot sessions are permitted to make this call. |
154 | + * |
155 | * Returns: zero on success, negative value on raised error. |
156 | **/ |
157 | int |
158 | @@ -386,6 +392,13 @@ |
159 | { |
160 | nih_assert (message != NULL); |
161 | |
162 | + if (! control_check_permission (message)) { |
163 | + nih_dbus_error_raise_printf ( |
164 | + DBUS_INTERFACE_UPSTART ".Error.PermissionDenied", |
165 | + _("You do not have permission to reload configuration")); |
166 | + return -1; |
167 | + } |
168 | + |
169 | nih_info (_("Reloading configuration")); |
170 | |
171 | /* This can only be called after deserialisation */ |
172 | @@ -574,13 +587,20 @@ |
173 | int wait, |
174 | int file) |
175 | { |
176 | - Event *event; |
177 | - Blocked *blocked; |
178 | + Event *event; |
179 | + Blocked *blocked; |
180 | |
181 | nih_assert (message != NULL); |
182 | nih_assert (name != NULL); |
183 | nih_assert (env != NULL); |
184 | |
185 | + if (! control_check_permission (message)) { |
186 | + nih_dbus_error_raise_printf ( |
187 | + DBUS_INTERFACE_UPSTART ".Error.PermissionDenied", |
188 | + _("You do not have permission to emit an event")); |
189 | + return -1; |
190 | + } |
191 | + |
192 | /* Verify that the name is valid */ |
193 | if (! strlen (name)) { |
194 | nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS, |
195 | @@ -741,6 +761,13 @@ |
196 | nih_assert (message != NULL); |
197 | nih_assert (log_priority != NULL); |
198 | |
199 | + if (! control_check_permission (message)) { |
200 | + nih_dbus_error_raise_printf ( |
201 | + DBUS_INTERFACE_UPSTART ".Error.PermissionDenied", |
202 | + _("You do not have permission to set log priority")); |
203 | + return -1; |
204 | + } |
205 | + |
206 | if (! strcmp (log_priority, "debug")) { |
207 | nih_log_set_priority (NIH_LOG_DEBUG); |
208 | |
209 | @@ -793,6 +820,11 @@ |
210 | * Called to flush the job logs for all jobs that ended before the log |
211 | * disk became writeable. |
212 | * |
213 | + * Notes: Session Inits are permitted to make this call. In the common |
214 | + * case of starting a Session Init as a child of a Display Manager this |
215 | + * is somewhat meaningless, but it does mean that if a Session Init were |
216 | + * started from a system job, behaviour would be as expected. |
217 | + * |
218 | * Returns: zero on success, negative value on raised error. |
219 | **/ |
220 | int |
221 | @@ -804,16 +836,16 @@ |
222 | |
223 | nih_assert (message != NULL); |
224 | |
225 | - /* Get the relevant session */ |
226 | - session = session_from_dbus (NULL, message); |
227 | - |
228 | - if (session && session->user) { |
229 | + if (! control_check_permission (message)) { |
230 | nih_dbus_error_raise_printf ( |
231 | DBUS_INTERFACE_UPSTART ".Error.PermissionDenied", |
232 | _("You do not have permission to notify disk is writeable")); |
233 | return -1; |
234 | } |
235 | |
236 | + /* Get the relevant session */ |
237 | + session = session_from_dbus (NULL, message); |
238 | + |
239 | /* "nop" when run from a chroot */ |
240 | if (session && session->chroot) |
241 | return 0; |
242 | @@ -978,13 +1010,17 @@ |
243 | char **state) |
244 | { |
245 | Session *session; |
246 | - uid_t uid; |
247 | size_t len; |
248 | |
249 | nih_assert (message); |
250 | nih_assert (state); |
251 | |
252 | - uid = getuid (); |
253 | + if (! control_check_permission (message)) { |
254 | + nih_dbus_error_raise_printf ( |
255 | + DBUS_INTERFACE_UPSTART ".Error.PermissionDenied", |
256 | + _("You do not have permission to request state")); |
257 | + return -1; |
258 | + } |
259 | |
260 | /* Get the relevant session */ |
261 | session = session_from_dbus (NULL, message); |
262 | @@ -999,17 +1035,6 @@ |
263 | return 0; |
264 | } |
265 | |
266 | - /* Disallow users from obtaining state details, unless they |
267 | - * happen to own this process (which they may do in the test |
268 | - * scenario and when running Upstart as a non-privileged user). |
269 | - */ |
270 | - if (session && session->user != uid) { |
271 | - nih_dbus_error_raise_printf ( |
272 | - DBUS_INTERFACE_UPSTART ".Error.PermissionDenied", |
273 | - _("You do not have permission to request state")); |
274 | - return -1; |
275 | - } |
276 | - |
277 | if (state_to_string (state, &len) < 0) |
278 | goto error; |
279 | |
280 | @@ -1041,11 +1066,15 @@ |
281 | NihDBusMessage *message) |
282 | { |
283 | Session *session; |
284 | - uid_t uid; |
285 | |
286 | nih_assert (message != NULL); |
287 | |
288 | - uid = getuid (); |
289 | + if (! control_check_permission (message)) { |
290 | + nih_dbus_error_raise_printf ( |
291 | + DBUS_INTERFACE_UPSTART ".Error.PermissionDenied", |
292 | + _("You do not have permission to request restart")); |
293 | + return -1; |
294 | + } |
295 | |
296 | /* Get the relevant session */ |
297 | session = session_from_dbus (NULL, message); |
298 | @@ -1061,17 +1090,6 @@ |
299 | return 0; |
300 | } |
301 | |
302 | - /* Disallow users from restarting Upstart, unless they happen to |
303 | - * own this process (which they may do in the test scenario and |
304 | - * when running Upstart as a non-privileged user). |
305 | - */ |
306 | - if (session && session->user != uid) { |
307 | - nih_dbus_error_raise_printf ( |
308 | - DBUS_INTERFACE_UPSTART ".Error.PermissionDenied", |
309 | - _("You do not have permission to request restart")); |
310 | - return -1; |
311 | - } |
312 | - |
313 | nih_info (_("Restarting")); |
314 | |
315 | stateful_reexec (); |
316 | @@ -1117,3 +1135,83 @@ |
317 | NIH_ZERO (control_emit_restarted (conn, DBUS_PATH_UPSTART)); |
318 | } |
319 | } |
320 | + |
321 | +/** |
322 | + * control_get_origin_uid: |
323 | + * @message: D-Bus connection and message received, |
324 | + * @uid: returned uid value. |
325 | + * |
326 | + * Returns TRUE: if @uid now contains uid corresponding to @message, |
327 | + * else FALSE. |
328 | + **/ |
329 | +static int |
330 | +control_get_origin_uid (NihDBusMessage *message, uid_t *uid) |
331 | +{ |
332 | + DBusError dbus_error; |
333 | + unsigned long unix_user = 0; |
334 | + const char *sender; |
335 | + |
336 | + nih_assert (message); |
337 | + nih_assert (uid); |
338 | + |
339 | + dbus_error_init (&dbus_error); |
340 | + |
341 | + if (! message->message || ! message->connection) |
342 | + return FALSE; |
343 | + |
344 | + sender = dbus_message_get_sender (message->message); |
345 | + if (sender) { |
346 | + unix_user = dbus_bus_get_unix_user (message->connection, sender, |
347 | + &dbus_error); |
348 | + if (unix_user == (unsigned long)-1) { |
349 | + dbus_error_free (&dbus_error); |
350 | + return FALSE; |
351 | + } |
352 | + } else { |
353 | + if (! dbus_connection_get_unix_user (message->connection, |
354 | + &unix_user)) { |
355 | + return FALSE; |
356 | + } |
357 | + } |
358 | + |
359 | + *uid = (uid_t)unix_user; |
360 | + |
361 | + return TRUE; |
362 | +} |
363 | + |
364 | +/** |
365 | + * control_check_permission: |
366 | + * |
367 | + * @message: D-Bus connection and message received. |
368 | + * |
369 | + * Determine if caller should be allowed to make a control request. |
370 | + * |
371 | + * Note that these permission checks rely on D-Bus to limit |
372 | + * session bus access to the same user. |
373 | + * |
374 | + * Returns: TRUE if permission is granted, else FALSE. |
375 | + **/ |
376 | +static int |
377 | +control_check_permission (NihDBusMessage *message) |
378 | +{ |
379 | + int ret; |
380 | + uid_t uid; |
381 | + pid_t pid; |
382 | + uid_t origin_uid = 0; |
383 | + |
384 | + nih_assert (message); |
385 | + |
386 | + uid = getuid (); |
387 | + pid = getpid (); |
388 | + |
389 | + ret = control_get_origin_uid (message, &origin_uid); |
390 | + |
391 | + /* Its possible that D-Bus might be unable to determine the user |
392 | + * making the request. In this case, deny the request unless |
393 | + * we're running as a Session Init or via the test harness. |
394 | + */ |
395 | + if ((ret && origin_uid == uid) || user_mode || (uid && pid != 1)) |
396 | + return TRUE; |
397 | + |
398 | + return FALSE; |
399 | +} |
400 | |
401 | === modified file 'init/job.c' |
402 | --- init/job.c 2012-11-07 11:56:33 +0000 |
403 | +++ init/job.c 2013-01-30 16:15:24 +0000 |
404 | @@ -1701,7 +1701,7 @@ |
405 | /** |
406 | * job_serialise_all: |
407 | * |
408 | - * Convert existing Session objects to JSON representation. |
409 | + * Convert existing Job objects to JSON representation. |
410 | * |
411 | * Returns: JSON object containing array of Job objects, or NULL on error. |
412 | **/ |
413 | |
414 | === modified file 'init/job_class.c' |
415 | --- init/job_class.c 2012-12-14 20:55:41 +0000 |
416 | +++ init/job_class.c 2013-01-30 16:15:24 +0000 |
417 | @@ -142,40 +142,17 @@ |
418 | goto error; |
419 | |
420 | class->session = session; |
421 | - if (class->session |
422 | - && class->session->chroot |
423 | - && class->session->user) { |
424 | - nih_local char *uid = NULL; |
425 | - |
426 | - uid = nih_sprintf (NULL, "%d", class->session->user); |
427 | - if (! uid) |
428 | - goto error; |
429 | - |
430 | - class->path = nih_dbus_path (class, DBUS_PATH_UPSTART, "jobs", |
431 | - session->chroot, uid, |
432 | - class->name, NULL); |
433 | - |
434 | - } else if (class->session |
435 | - && class->session->chroot) { |
436 | + |
437 | + if (class->session && class->session->chroot) { |
438 | class->path = nih_dbus_path (class, DBUS_PATH_UPSTART, "jobs", |
439 | session->chroot, |
440 | class->name, NULL); |
441 | |
442 | - } else if (class->session |
443 | - && class->session->user) { |
444 | - nih_local char *uid = NULL; |
445 | - |
446 | - uid = nih_sprintf (NULL, "%d", class->session->user); |
447 | - if (! uid) |
448 | - goto error; |
449 | - |
450 | - class->path = nih_dbus_path (class, DBUS_PATH_UPSTART, "jobs", |
451 | - uid, class->name, NULL); |
452 | - |
453 | } else { |
454 | class->path = nih_dbus_path (class, DBUS_PATH_UPSTART, "jobs", |
455 | class->name, NULL); |
456 | } |
457 | + |
458 | if (! class->path) |
459 | goto error; |
460 | |
461 | @@ -1595,12 +1572,12 @@ |
462 | if (! json) |
463 | return NULL; |
464 | |
465 | - /* XXX: user and chroot jobs are not currently supported |
466 | + /* XXX: chroot jobs are not currently supported |
467 | * due to ConfSources not currently being serialised. |
468 | */ |
469 | if (class->session) { |
470 | - nih_info ("WARNING: serialisation of user jobs and " |
471 | - "chroot sessions not currently supported"); |
472 | + nih_info ("WARNING: serialisation of chroot " |
473 | + "sessions not currently supported"); |
474 | goto error; |
475 | } |
476 | |
477 | @@ -1828,12 +1805,12 @@ |
478 | |
479 | session = session_from_index (session_index); |
480 | |
481 | - /* XXX: user and chroot jobs are not currently supported |
482 | + /* XXX: chroot jobs are not currently supported |
483 | * due to ConfSources not currently being serialised. |
484 | */ |
485 | if (session) { |
486 | - nih_info ("WARNING: deserialisation of user jobs and " |
487 | - "chroot sessions not currently supported"); |
488 | + nih_info ("WARNING: deserialisation of chroot " |
489 | + "sessions not currently supported"); |
490 | goto error; |
491 | } |
492 | |
493 | |
494 | === modified file 'init/job_process.c' |
495 | --- init/job_process.c 2013-01-23 12:40:36 +0000 |
496 | +++ init/job_process.c 2013-01-30 16:15:24 +0000 |
497 | @@ -420,8 +420,6 @@ |
498 | char pts_name[PATH_MAX]; |
499 | char filename[PATH_MAX]; |
500 | FILE *fd; |
501 | - int user_job = FALSE; |
502 | - nih_local char *user_dir = NULL; |
503 | nih_local char *log_path = NULL; |
504 | JobClass *class; |
505 | uid_t job_setuid = -1; |
506 | @@ -439,20 +437,14 @@ |
507 | |
508 | nih_assert (class != NULL); |
509 | |
510 | - if (class && class->session && class->session->user) |
511 | - user_job = TRUE; |
512 | - |
513 | /* Create a pipe to communicate with the child process until it |
514 | * execs so we know whether that was successful or an error occurred. |
515 | */ |
516 | if (pipe (fds) < 0) |
517 | nih_return_system_error (-1); |
518 | |
519 | - /* Logging of user job output is not currently possible */ |
520 | - if (class->console == CONSOLE_LOG) { |
521 | - if (disable_job_logging || user_job) |
522 | + if (class->console == CONSOLE_LOG && disable_job_logging) |
523 | class->console = CONSOLE_NONE; |
524 | - } |
525 | |
526 | if (class->console == CONSOLE_LOG) { |
527 | NihError *err; |
528 | @@ -655,87 +647,6 @@ |
529 | /* Set the process environment from the function parameters. */ |
530 | environ = (char **)env; |
531 | |
532 | - /* Handle unprivileged user job by dropping privileges to |
533 | - * their level as soon as possible to avoid privilege |
534 | - * escalations when we set resource limits. |
535 | - */ |
536 | - if (user_job) { |
537 | - uid_t uid = class->session->user; |
538 | - struct passwd *pw = NULL; |
539 | - |
540 | - /* D-Bus does not expose a public API call to allow |
541 | - * us to query a users primary group. |
542 | - * _dbus_user_info_fill_uid () seems to exist for this |
543 | - * purpose, but is a "secret" API. It is unclear why |
544 | - * D-Bus neglects the gid when it allows the uid |
545 | - * to be queried directly. |
546 | - * |
547 | - * Our only recourse is to disallow user sessions in a |
548 | - * chroot and assume that all other user sessions |
549 | - * originate from the local system. In this way, we can |
550 | - * bypass D-Bus and use getpwuid (). |
551 | - */ |
552 | - |
553 | - if (class->session->chroot) { |
554 | - /* We cannot determine the group id of the user |
555 | - * session in the chroot via D-Bus, so disallow |
556 | - * all jobs in such an environment. |
557 | - */ |
558 | - nih_error_raise (EPERM, "user jobs not supported in chroots"); |
559 | - job_process_error_abort (fds[1], JOB_PROCESS_ERROR_CHROOT, 0); |
560 | - } |
561 | - |
562 | - pw = getpwuid (uid); |
563 | - |
564 | - if (!pw) { |
565 | - nih_error_raise_system (); |
566 | - job_process_error_abort (fds[1], JOB_PROCESS_ERROR_GETPWUID, 0); |
567 | - } |
568 | - |
569 | - nih_assert (pw->pw_uid == uid); |
570 | - |
571 | - if (! pw->pw_dir) { |
572 | - nih_error_raise_printf (ENOENT, |
573 | - "no home directory for user with uid %d", uid); |
574 | - job_process_error_abort (fds[1], JOB_PROCESS_ERROR_GETPWUID, 0); |
575 | - |
576 | - } |
577 | - |
578 | - /* Note we don't use NIH_MUST since this could result in a |
579 | - * DoS for a (low priority) user job in low-memory scenarios. |
580 | - */ |
581 | - user_dir = nih_strdup (NULL, pw->pw_dir); |
582 | - |
583 | - if (! user_dir) { |
584 | - nih_error_raise_no_memory (); |
585 | - job_process_error_abort (fds[1], JOB_PROCESS_ERROR_ALLOC, 0); |
586 | - } |
587 | - |
588 | - /* Ensure the file associated with fd 9 |
589 | - * (/proc/self/fd/9) is owned by the user we're about to |
590 | - * become to avoid EPERM. |
591 | - */ |
592 | - if (script_fd != -1 && fchown (script_fd, pw->pw_uid, pw->pw_gid) < 0) { |
593 | - nih_error_raise_system (); |
594 | - job_process_error_abort (fds[1], JOB_PROCESS_ERROR_CHOWN, 0); |
595 | - } |
596 | - |
597 | - if (geteuid () == 0 && initgroups (pw->pw_name, pw->pw_gid) < 0) { |
598 | - nih_error_raise_system (); |
599 | - job_process_error_abort (fds[1], JOB_PROCESS_ERROR_INITGROUPS, 0); |
600 | - } |
601 | - |
602 | - if (pw->pw_gid && setgid (pw->pw_gid) < 0) { |
603 | - nih_error_raise_system (); |
604 | - job_process_error_abort (fds[1], JOB_PROCESS_ERROR_SETGID, 0); |
605 | - } |
606 | - |
607 | - if (pw->pw_uid && setuid (pw->pw_uid) < 0) { |
608 | - nih_error_raise_system (); |
609 | - job_process_error_abort (fds[1], JOB_PROCESS_ERROR_SETUID, 0); |
610 | - } |
611 | - } |
612 | - |
613 | /* Set the standard file descriptors to an output of our chosing; |
614 | * any other open descriptor must be intended for the child, or have |
615 | * the FD_CLOEXEC flag so it's automatically closed when we exec() |
616 | @@ -854,7 +765,7 @@ |
617 | * configured in the job, or to the root directory of the filesystem |
618 | * (or at least relative to the chroot). |
619 | */ |
620 | - if (chdir (class->chdir ? class->chdir : user_job ? user_dir : "/") < 0) { |
621 | + if (chdir (class->chdir ? class->chdir : "/") < 0) { |
622 | nih_error_raise_system (); |
623 | job_process_error_abort (fds[1], JOB_PROCESS_ERROR_CHDIR, 0); |
624 | } |
625 | |
626 | === modified file 'init/man/init.5' |
627 | --- init/man/init.5 2013-01-23 12:40:36 +0000 |
628 | +++ init/man/init.5 2013-01-30 16:15:24 +0000 |
629 | @@ -1,4 +1,4 @@ |
630 | -.TH init 5 2012-12-18 "Upstart" |
631 | +.TH init 5 2013-01-25 "Upstart" |
632 | .\" |
633 | .SH NAME |
634 | init \- Upstart init daemon job configuration |
635 | @@ -9,13 +9,14 @@ |
636 | Default location of system job configuration files. |
637 | .\" |
638 | .TP |
639 | -.B $HOME/.init/ |
640 | -Default location of user job configuration files. |
641 | -.\" |
642 | -.TP |
643 | .B $XDG_CONFIG_HOME/upstart/, $XDG_CONFIG_DIRS/upstart/ |
644 | Default locations of user session job configuration files. |
645 | .\" |
646 | +.TP |
647 | +.B $HOME/.init/ |
648 | +Deprecated location of user job configuration files (still |
649 | +honoured by User Session Mode). |
650 | +.\" |
651 | .SH DESCRIPTION |
652 | On startup, the Upstart |
653 | .BR init (8) |
654 | @@ -24,11 +25,6 @@ |
655 | directory, and watches for future changes to these files using |
656 | .BR inotify (7). |
657 | |
658 | -If D\-Bus has been configured to allow non\-privileged users to invoke all |
659 | -Upstart D\-Bus methods, Upstart is also able to manage User Jobs. See |
660 | -.B User Jobs |
661 | -for further details. |
662 | - |
663 | If Upstart was invoked as a user process with \-\-user option, it will |
664 | run in User Session mode. See |
665 | .B User Session Mode |
666 | @@ -85,33 +81,6 @@ |
667 | |
668 | Configuration files are plain text and should not be executable. |
669 | .\" |
670 | -.SS User Jobs |
671 | - |
672 | -A User Job is a job configuration file created by a non\-privileged user |
673 | -in their |
674 | -.B $HOME/.init/ |
675 | -directory. Job configuration files in this directory have the same |
676 | -syntax as system job configuration files. |
677 | -Files in this directory will be read and an |
678 | -.BR inotify (7) |
679 | -watch created the first time a user runs |
680 | -.BR initctl (8) "." |
681 | - |
682 | -Any user can create user jobs, but that user can control |
683 | -.I only |
684 | -jobs they create. |
685 | - |
686 | -Users are able to manage their jobs using the standard |
687 | -.BR initctl (8) |
688 | -facility. |
689 | - |
690 | -Note that stanzas which manipulate resources limits may cause a job to |
691 | -fail to start should the value provided to such a stanza attempt to |
692 | -exceed the maximum value the users privilege level allows. |
693 | - |
694 | -Note that a user job configuration file cannot have the same name as a |
695 | -system job configuration file. |
696 | -.\" |
697 | .SS Chroot Support |
698 | |
699 | Upstart is able to manage jobs within a \fBchroot\fP(2). To control jobs |
700 | @@ -124,10 +93,6 @@ |
701 | .B Process environment |
702 | below). |
703 | |
704 | -Note that User Jobs |
705 | -.B cannot |
706 | -be used within a chroot environment. |
707 | - |
708 | .\" |
709 | .SS User Session Mode |
710 | |
711 | @@ -447,9 +412,10 @@ |
712 | .BR initctl (8) |
713 | utility to default to acting on the job the commands are called from. |
714 | |
715 | -When running in a user session, the additional UPSTART_SESSION environment |
716 | -variable is also set and contains the DBus path to the private bus used by |
717 | -the upstart instance daemon. |
718 | +When running in a user session, the additional |
719 | +.B UPSTART_SESSION |
720 | +environment variable is also set and contains the DBus path to the |
721 | +private bus used by the upstart instance daemon. |
722 | |
723 | .TP |
724 | .B env \fIKEY\fR[=\fIVALUE\fR] |
725 | @@ -667,12 +633,7 @@ |
726 | .B log |
727 | .RS |
728 | .B |
729 | -Only applies to system and user session jobs: |
730 | -if specified by user jobs, the job will be considered to have specified |
731 | -the value |
732 | -.BR none "." |
733 | - |
734 | -For system and user session jobs jobs, if \fBlog\fR is specified, standard input is connected |
735 | +If \fBlog\fR is specified, standard input is connected |
736 | to |
737 | .IR /dev/null "," |
738 | and standard output and standard error are connected to a pseudo-tty |
739 | @@ -881,7 +842,7 @@ |
740 | block is used for all job processes. If both stanzas are unspecified, |
741 | all job processes will run with its group ID set to 0 in the case of |
742 | system jobs, and as the primary group of the user in the case of User |
743 | -Jobs. |
744 | +Session jobs. |
745 | .\" |
746 | .SS Override File Handling |
747 | Override files allow a jobs environment to be changed without modifying |
748 | @@ -1025,11 +986,13 @@ |
749 | . |
750 | .TP |
751 | .I $HOME/.init/*.conf |
752 | -User job configuration files. |
753 | +User job configuration files |
754 | +.BR (deprecated) . |
755 | . |
756 | .TP |
757 | .I $HOME/.init/*.override |
758 | User job override files. |
759 | +.BR (deprecated) . |
760 | . |
761 | .TP |
762 | .I $XDG_CONFIG_HOME/upstart/*.conf |
763 | @@ -1063,7 +1026,7 @@ |
764 | .RB < https://launchpad.net/upstart/+bugs > |
765 | .\" |
766 | .SH COPYRIGHT |
767 | -Copyright \(co 2009-2011 Canonical Ltd. |
768 | +Copyright \(co 2009-2013 Canonical Ltd. |
769 | .br |
770 | This is free software; see the source for copying conditions. There is NO |
771 | warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
772 | |
773 | === modified file 'init/session.c' |
774 | --- init/session.c 2012-11-14 14:47:19 +0000 |
775 | +++ init/session.c 2013-01-30 16:15:24 +0000 |
776 | @@ -68,7 +68,7 @@ |
777 | /** |
778 | * disable_sessions: |
779 | * |
780 | - * If TRUE, disable user and chroot sessions, resulting in a |
781 | + * If TRUE, disable chroot sessions, resulting in a |
782 | * "traditional" (pre-session support) system. |
783 | **/ |
784 | int disable_sessions = FALSE; |
785 | @@ -93,21 +93,19 @@ |
786 | /** |
787 | * session_new: |
788 | * @parent: parent, |
789 | - * @chroot: full chroot path, |
790 | - * @user: user id. |
791 | + * @chroot: full chroot path. |
792 | * |
793 | - * Create a new session. |
794 | + * Create a new chroot session. |
795 | * |
796 | * Returns: new Session, or NULL on error. |
797 | **/ |
798 | Session * |
799 | session_new (const void *parent, |
800 | - const char *chroot, |
801 | - uid_t user) |
802 | + const char *chroot) |
803 | { |
804 | Session *session; |
805 | |
806 | - nih_assert ((chroot != NULL) || (user != 0)); |
807 | + nih_assert (chroot); |
808 | |
809 | session_init (); |
810 | |
811 | @@ -117,18 +115,12 @@ |
812 | |
813 | nih_list_init (&session->entry); |
814 | |
815 | - if (chroot) { |
816 | - session->chroot = nih_strdup (session, chroot); |
817 | - if (! session->chroot) { |
818 | - nih_free (session); |
819 | - return NULL; |
820 | - } |
821 | - } else { |
822 | - session->chroot = NULL; |
823 | + session->chroot = nih_strdup (session, chroot); |
824 | + if (! session->chroot) { |
825 | + nih_free (session); |
826 | + return NULL; |
827 | } |
828 | |
829 | - session->user = user; |
830 | - |
831 | session->conf_path = NULL; |
832 | |
833 | nih_alloc_set_destructor (session, nih_list_destroy); |
834 | @@ -151,14 +143,13 @@ |
835 | session_from_dbus (const void *parent, |
836 | NihDBusMessage *message) |
837 | { |
838 | - const char *sender; |
839 | - DBusError dbus_error; |
840 | - unsigned long unix_user; |
841 | - unsigned long unix_process_id; |
842 | - char root[PATH_MAX]; |
843 | - Session *session; |
844 | - struct passwd *pwd; |
845 | - nih_local char *conf_path = NULL; |
846 | + DBusError dbus_error; |
847 | + unsigned long unix_process_id; |
848 | + char root[PATH_MAX]; |
849 | + Session *session; |
850 | + nih_local char *conf_path = NULL; |
851 | + nih_local char *symlink = NULL; |
852 | + ssize_t len; |
853 | |
854 | nih_assert (message != NULL); |
855 | |
856 | @@ -170,126 +161,43 @@ |
857 | |
858 | session_init (); |
859 | |
860 | - /* Ask D-Bus nicely for the origin uid and/or pid of the caller; |
861 | - * sadly we can't ask the bus daemon for the origin pid, so that |
862 | - * one will just have to stay user-session only. |
863 | - */ |
864 | dbus_error_init (&dbus_error); |
865 | |
866 | - sender = dbus_message_get_sender (message->message); |
867 | - if (sender) { |
868 | - unix_user = dbus_bus_get_unix_user (message->connection, sender, |
869 | - &dbus_error); |
870 | - if (unix_user == (unsigned long)-1) { |
871 | - dbus_error_free (&dbus_error); |
872 | - unix_user = 0; |
873 | - } |
874 | - |
875 | - unix_process_id = 0; |
876 | - |
877 | - } else { |
878 | - if (! dbus_connection_get_unix_user (message->connection, |
879 | - &unix_user)) |
880 | - unix_process_id = 0; |
881 | - |
882 | - if (! dbus_connection_get_unix_process_id (message->connection, |
883 | - &unix_process_id)) |
884 | - unix_process_id = 0; |
885 | - } |
886 | - |
887 | - /* If we retrieved a process id, look up the root path for it; |
888 | - * if it's just '/' don't worry so much about it. |
889 | - */ |
890 | - if (unix_process_id) { |
891 | - nih_local char *symlink = NULL; |
892 | - ssize_t len; |
893 | - |
894 | - symlink = NIH_MUST (nih_sprintf (NULL, "/proc/%lu/root", |
895 | - unix_process_id)); |
896 | - len = readlink (symlink, root, sizeof root); |
897 | - if (len < 0) |
898 | - return NULL; |
899 | - |
900 | - root[len] = '\0'; |
901 | - |
902 | - if (! strcmp (root, "/")) { |
903 | - unix_process_id = 0; |
904 | - if (! unix_user) |
905 | - return NULL; |
906 | - } |
907 | - |
908 | - } else if (! unix_user) { |
909 | - /* No process id or user id found, return the NULL session */ |
910 | - return NULL; |
911 | - } |
912 | - |
913 | - if (unix_user) { |
914 | - pwd = getpwuid (unix_user); |
915 | - |
916 | - if (! pwd || ! pwd->pw_dir) { |
917 | - nih_error ("%lu: %s: %s", unix_user, |
918 | - _("Unable to lookup home directory"), |
919 | - strerror (errno)); |
920 | - return NULL; |
921 | - } |
922 | - |
923 | - NIH_MUST (nih_strcat_sprintf (&conf_path, NULL, "%s/%s", |
924 | - pwd->pw_dir, USERCONFDIR)); |
925 | - } |
926 | - |
927 | + /* Query origin pid of the caller */ |
928 | + if (! dbus_connection_get_unix_process_id (message->connection, |
929 | + &unix_process_id)) { |
930 | + return NULL; |
931 | + } |
932 | + |
933 | + /* Look up the root path for retrieved pid */ |
934 | + symlink = NIH_MUST (nih_sprintf (NULL, "/proc/%lu/root", |
935 | + unix_process_id)); |
936 | + len = readlink (symlink, root, sizeof root); |
937 | + if (len < 0) |
938 | + return NULL; |
939 | + |
940 | + root[len] = '\0'; |
941 | + |
942 | + /* Path is not inside a chroot */ |
943 | + if (! strcmp (root, "/")) |
944 | + return NULL; |
945 | |
946 | /* Now find in the existing Sessions list */ |
947 | NIH_LIST_FOREACH_SAFE (sessions, iter) { |
948 | Session *session = (Session *)iter; |
949 | |
950 | - if (unix_process_id) { |
951 | - if (! session->chroot) |
952 | - continue; |
953 | - |
954 | + if (strcmp (session->chroot, root)) |
955 | /* ignore sessions relating to other chroots */ |
956 | - if (strcmp (session->chroot, root)) |
957 | - continue; |
958 | - } |
959 | - |
960 | - /* ignore sessions relating to other users */ |
961 | - if (unix_user != session->user) |
962 | continue; |
963 | |
964 | - /* Found a user with the same uid but different |
965 | - * conf_path to the existing session user. Either the |
966 | - * original user has been deleted and a new user created |
967 | - * with the same uid, or the original users home |
968 | - * directory has changed since they first started |
969 | - * running jobs. Whatever the reason, we (can only) honour |
970 | - * the new value. |
971 | - * |
972 | - * Since multiple users with the same uid are considered |
973 | - * to be "the same user", invalidate the old path, |
974 | - * allowing the correct new path to be set below. |
975 | - * |
976 | - * Note that there may be a possibility of trouble if |
977 | - * the scenario relates to a deleted user and that original |
978 | - * user still has jobs running. However, if that were the |
979 | - * case, those jobs would likely fail anyway since they |
980 | - * would have no working directory due to the original |
981 | - * users home directory being deleted/changed/made inaccessible. |
982 | - */ |
983 | - if (unix_user && conf_path && session->conf_path && |
984 | - strcmp (conf_path, session->conf_path)) { |
985 | - nih_free (session->conf_path); |
986 | - session->conf_path = NULL; |
987 | - } |
988 | - |
989 | if (! session->conf_path) |
990 | session_create_conf_source (session, FALSE); |
991 | |
992 | return session; |
993 | } |
994 | |
995 | - |
996 | /* Didn't find one, make a new one */ |
997 | - session = NIH_MUST (session_new (parent, unix_process_id ? root : NULL, |
998 | - unix_user)); |
999 | + session = NIH_MUST (session_new (parent, root)); |
1000 | session_create_conf_source (session, FALSE); |
1001 | |
1002 | return session; |
1003 | @@ -317,27 +225,8 @@ |
1004 | session_init (); |
1005 | |
1006 | if (! deserialised) { |
1007 | - if (session->chroot) |
1008 | - session->conf_path = NIH_MUST (nih_strdup (NULL, session->chroot)); |
1009 | - if (session->user) { |
1010 | - struct passwd *pwd; |
1011 | - |
1012 | - pwd = getpwuid (session->user); |
1013 | - if (! pwd) { |
1014 | - nih_error ("%d: %s: %s", session->user, |
1015 | - _("Unable to lookup home directory"), |
1016 | - strerror (errno)); |
1017 | - |
1018 | - nih_free (session->conf_path); |
1019 | - session->conf_path = NULL; |
1020 | - return; |
1021 | - } |
1022 | - |
1023 | - NIH_MUST (nih_strcat_sprintf (&session->conf_path, NULL, "%s/%s", |
1024 | - pwd->pw_dir, USERCONFDIR)); |
1025 | - } else { |
1026 | - NIH_MUST (nih_strcat (&session->conf_path, NULL, CONFDIR)); |
1027 | - } |
1028 | + session->conf_path = NIH_MUST (nih_strdup (NULL, session->chroot)); |
1029 | + NIH_MUST (nih_strcat (&session->conf_path, NULL, CONFDIR)); |
1030 | } |
1031 | |
1032 | source = NIH_MUST (conf_source_new (session, session->conf_path, |
1033 | @@ -375,9 +264,10 @@ |
1034 | json_object *json; |
1035 | json_object *conf_path = NULL; |
1036 | json_object *chroot = NULL; |
1037 | - json_object *user; |
1038 | |
1039 | nih_assert (session); |
1040 | + nih_assert (session->chroot); |
1041 | + nih_assert (session->conf_path); |
1042 | |
1043 | session_init (); |
1044 | |
1045 | @@ -385,26 +275,16 @@ |
1046 | if (! json) |
1047 | return NULL; |
1048 | |
1049 | - if (session->chroot) { |
1050 | - chroot = json_object_new_string (session->chroot); |
1051 | - if (! chroot) |
1052 | - goto error; |
1053 | - } |
1054 | + chroot = json_object_new_string (session->chroot); |
1055 | + if (! chroot) |
1056 | + goto error; |
1057 | |
1058 | json_object_object_add (json, "chroot", chroot); |
1059 | |
1060 | - user = state_new_json_int (session->user); |
1061 | - if (! user) |
1062 | + conf_path = json_object_new_string (session->conf_path); |
1063 | + if (! conf_path) |
1064 | goto error; |
1065 | |
1066 | - json_object_object_add (json, "user", user); |
1067 | - |
1068 | - if (session->conf_path) { |
1069 | - conf_path = json_object_new_string (session->conf_path); |
1070 | - if (! conf_path) |
1071 | - goto error; |
1072 | - } |
1073 | - |
1074 | json_object_object_add (json, "conf_path", conf_path); |
1075 | |
1076 | return json; |
1077 | @@ -459,6 +339,9 @@ |
1078 | * |
1079 | * Convert @json into a Session object. |
1080 | * |
1081 | + * NOTE: Any user sessions seen when re-execing from an older version |
1082 | + * of Upstart are implicitly ignored. |
1083 | + * |
1084 | * Returns: Session object, or NULL on error. |
1085 | **/ |
1086 | static Session * |
1087 | @@ -466,7 +349,6 @@ |
1088 | { |
1089 | Session *session = NULL; |
1090 | nih_local const char *chroot = NULL; |
1091 | - uid_t user; |
1092 | |
1093 | nih_assert (json); |
1094 | |
1095 | @@ -477,11 +359,11 @@ |
1096 | if (! state_get_json_string_var (json, "chroot", NULL, chroot)) |
1097 | return NULL; |
1098 | |
1099 | - if (! state_get_json_int_var (json, "user", user)) |
1100 | + if (! chroot) |
1101 | return NULL; |
1102 | |
1103 | /* Create a new session */ |
1104 | - session = NIH_MUST (session_new (NULL, chroot, user)); |
1105 | + session = NIH_MUST (session_new (NULL, chroot)); |
1106 | |
1107 | if (! state_get_json_string_var_to_obj (json, session, conf_path)) |
1108 | goto error; |
1109 | |
1110 | === modified file 'init/session.h' |
1111 | --- init/session.h 2012-11-22 16:32:36 +0000 |
1112 | +++ init/session.h 2013-01-30 16:15:24 +0000 |
1113 | @@ -33,14 +33,11 @@ |
1114 | * Session: |
1115 | * @entry: list header, |
1116 | * @chroot: path all jobs are chrooted to, |
1117 | - * @user: uid all jobs are switched to, |
1118 | - * @conf_path: configuration path (either full path to chroot root, or |
1119 | - * full path to users job directory (which may itself be prepended |
1120 | - * with a chroot path)). |
1121 | + * @conf_path: configuration path (full path to chroot root). |
1122 | * |
1123 | * This structure is used to identify collections of jobs |
1124 | - * that share either a common @chroot and/or common @user. Note that |
1125 | - * @conf_path is unique across all sessions. |
1126 | + * that share a common @chroot (*). Note that @conf_path is |
1127 | + * unique across all sessions. |
1128 | * |
1129 | * Summary of Session values for different environments: |
1130 | * |
1131 | @@ -50,27 +47,28 @@ |
1132 | * | user | PID | chroot | uid | Object contents | |
1133 | * +------+------+--------+-----+-----------------------------------+ |
1134 | * | 0 | >0 | no | 0 | NULL (*1) | |
1135 | - * | >0 | "0" | no | >0 | uid + conf_path set to "~/.init". | |
1136 | * | 0 | >0 | yes | 0 | chroot + conf_path set | |
1137 | - * | >0 | ?? | yes | >0 | XXX: fails (*2) | |
1138 | + * | >0 | ?? | yes | >0 | Not permitted (*2) | |
1139 | * +------+------+--------+-----+-----------------------------------+ |
1140 | * |
1141 | * Notes: |
1142 | * |
1143 | + * (*) - this structure used to also store user session details (hence |
1144 | + * the name), but the functionality was removed with the advent of |
1145 | + * a true user mode. |
1146 | + * |
1147 | * (*1) - The "NULL session" represents the "traditional" environment |
1148 | * before sessions were introduced (namely a non-chroot environment |
1149 | * where all job and event operations were handled by uid 0 (root)). |
1150 | * |
1151 | - * (*2) - error is: |
1152 | + * (*2) - User lookup is not reliable since the user to query exists |
1153 | + * within the chroot, but the only possible lookup is outside the |
1154 | + * chroot. |
1155 | * |
1156 | - * initctl: Unable to connect to system bus: Failed to connect to socket |
1157 | - * /var/run/dbus/system_bus_socket: No such file or directory |
1158 | - * |
1159 | **/ |
1160 | typedef struct session { |
1161 | NihList entry; |
1162 | char * chroot; |
1163 | - uid_t user; |
1164 | char * conf_path; |
1165 | } Session; |
1166 | |
1167 | @@ -81,7 +79,7 @@ |
1168 | |
1169 | void session_init (void); |
1170 | |
1171 | -Session * session_new (const void *parent, const char *chroot, uid_t user) |
1172 | +Session * session_new (const void *parent, const char *chroot) |
1173 | __attribute__ ((malloc, warn_unused_result)); |
1174 | |
1175 | Session * session_from_dbus (const void *parent, NihDBusMessage *message); |
1176 | |
1177 | === modified file 'init/state.h' |
1178 | --- init/state.h 2012-12-04 16:09:18 +0000 |
1179 | +++ init/state.h 2013-01-30 16:15:24 +0000 |
1180 | @@ -28,10 +28,10 @@ |
1181 | * detect that is *has* changed filesystem context. |
1182 | * |
1183 | * - Since ConfSources are NOT serialised, it is currently not possible |
1184 | - * to support user jobs and chroot jobs (because the only ConfSource |
1185 | + * to support chroot jobs (because the only ConfSource |
1186 | * objects created are those at startup (for '/etc/init/'): any |
1187 | - * pre-existing ConfSources with non-NULL sessions representing |
1188 | - * user jobs will be ignored). |
1189 | + * pre-existing ConfSources with non-NULL Session objects will |
1190 | + * be ignored). |
1191 | * |
1192 | * - parent/child timeout handling: we won't support down-grading initially. |
1193 | * |
1194 | |
1195 | === modified file 'init/tests/test_conf.c' |
1196 | --- init/tests/test_conf.c 2013-01-04 13:03:47 +0000 |
1197 | +++ init/tests/test_conf.c 2013-01-30 16:15:24 +0000 |
1198 | @@ -1404,6 +1404,8 @@ |
1199 | fclose (f); |
1200 | |
1201 | source = conf_source_new (NULL, dirname, CONF_JOB_DIR); |
1202 | + TEST_NE_P (source, NULL); |
1203 | + |
1204 | ret = conf_source_reload (source); |
1205 | |
1206 | TEST_EQ (ret, 0); |
1207 | |
1208 | === modified file 'init/tests/test_state.c' |
1209 | --- init/tests/test_state.c 2012-12-07 21:38:17 +0000 |
1210 | +++ init/tests/test_state.c 2013-01-30 16:15:24 +0000 |
1211 | @@ -217,9 +217,6 @@ |
1212 | if (obj_string_check (a, b, chroot)) |
1213 | goto fail; |
1214 | |
1215 | - if (obj_num_check (a, b, user)) |
1216 | - goto fail; |
1217 | - |
1218 | if (obj_string_check (a, b, conf_path)) |
1219 | goto fail; |
1220 | |
1221 | @@ -871,12 +868,12 @@ |
1222 | TEST_NE_P (json, NULL); |
1223 | |
1224 | /* Create a couple of sessions */ |
1225 | - session1 = session_new (NULL, "/abc", getuid ()); |
1226 | + session1 = session_new (NULL, "/abc"); |
1227 | TEST_NE_P (session1, NULL); |
1228 | session1->conf_path = NIH_MUST (nih_strdup (session1, "/def/ghi")); |
1229 | TEST_LIST_NOT_EMPTY (sessions); |
1230 | |
1231 | - session2 = session_new (NULL, "/foo", 0); |
1232 | + session2 = session_new (NULL, "/foo"); |
1233 | TEST_NE_P (session2, NULL); |
1234 | session2->conf_path = NIH_MUST (nih_strdup (session2, "/bar/baz")); |
1235 | |
1236 | @@ -1264,7 +1261,7 @@ |
1237 | TEST_LIST_EMPTY (conf_sources); |
1238 | TEST_HASH_EMPTY (job_classes); |
1239 | |
1240 | - session = session_new (NULL, "/my/session", getuid ()); |
1241 | + session = session_new (NULL, "/my/session"); |
1242 | TEST_NE_P (session, NULL); |
1243 | session->conf_path = NIH_MUST (nih_strdup (session, "/lives/here")); |
1244 | TEST_LIST_NOT_EMPTY (sessions); |
1245 | @@ -1659,7 +1656,7 @@ |
1246 | TEST_NE_P (env, NULL); |
1247 | TEST_NE_P (environ_add (&env, NULL, &len, TRUE, "FOO=BAR"), NULL); |
1248 | |
1249 | - session = session_new (NULL, "/abc", getuid ()); |
1250 | + session = session_new (NULL, "/abc"); |
1251 | TEST_NE_P (session, NULL); |
1252 | session->conf_path = NIH_MUST (nih_strdup (session, "/def/ghi")); |
1253 | TEST_LIST_NOT_EMPTY (sessions); |
1254 | |
1255 | === modified file 'util/tests/test_initctl.c' |
1256 | --- util/tests/test_initctl.c 2013-01-22 18:17:04 +0000 |
1257 | +++ util/tests/test_initctl.c 2013-01-30 16:15:24 +0000 |
1258 | @@ -12490,6 +12490,9 @@ |
1259 | /* Ensure again that no log file written */ |
1260 | TEST_LT (stat (logfile_name, &statbuf), 0); |
1261 | |
1262 | + /* Must not be run as root */ |
1263 | + TEST_TRUE (getuid ()); |
1264 | + |
1265 | cmd = nih_sprintf (NULL, "%s notify-disk-writeable 2>&1", INITCTL_BINARY); |
1266 | TEST_NE_P (cmd, NULL); |
1267 | RUN_COMMAND (NULL, cmd, &output, &lines); |
1268 | |
1269 | === removed file 'util/tests/test_user_sessions.sh' |
1270 | --- util/tests/test_user_sessions.sh 2012-01-26 08:59:08 +0000 |
1271 | +++ util/tests/test_user_sessions.sh 1970-01-01 00:00:00 +0000 |
1272 | @@ -1,1091 +0,0 @@ |
1273 | -#!/bin/sh |
1274 | -#--------------------------------------------------------------------- |
1275 | -# Script to run minimal Upstart user session tests. |
1276 | -# |
1277 | -# Note that this script _cannot_ be run as part of the "make check" |
1278 | -# tests since those tests stimulate functions and features of the |
1279 | -# as-yet-uninstalled version of Upstart. However, this script needs to |
1280 | -# run on a system where the version of Upstart under test has _already_ |
1281 | -# been fully installed. |
1282 | -#--------------------------------------------------------------------- |
1283 | -# |
1284 | -# Copyright (C) 2011 Canonical Ltd. |
1285 | -# |
1286 | -# Author: James Hunt <james.hunt@canonical.com> |
1287 | -# |
1288 | -# This program is free software: you can redistribute it and/or modify |
1289 | -# it under the terms of the GNU General Public License as published by |
1290 | -# the Free Software Foundation, version 3 of the License. |
1291 | -# |
1292 | -# This program is distributed in the hope that it will be useful, |
1293 | -# but WITHOUT ANY WARRANTY; without even the implied warranty of |
1294 | -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1295 | -# GNU General Public License for more details. |
1296 | -# |
1297 | -# You should have received a copy of the GNU General Public License |
1298 | -# along with this program. If not, see <http://www.gnu.org/licenses/>. |
1299 | -# |
1300 | -#--------------------------------------------------------------------- |
1301 | - |
1302 | -script_name=${0##*/} |
1303 | -sys_job_dir="/etc/init" |
1304 | -user_job_dir="$HOME/.init" |
1305 | -user_log_dir="$HOME/.cache/upstart/log" |
1306 | -sys_log_dir="/var/log/upstart" |
1307 | -bug_url="https://bugs.launchpad.net/upstart/+filebug" |
1308 | -test_dir= |
1309 | -test_dir_suffix= |
1310 | -user_to_create= |
1311 | -uid= |
1312 | -gid= |
1313 | -opt= |
1314 | -OPTARG= |
1315 | -debug_enabled=0 |
1316 | -feature= |
1317 | - |
1318 | -# allow non-priv users to find 'initctl' |
1319 | -export PATH=$PATH:/sbin |
1320 | - |
1321 | -# for assertions |
1322 | -die() |
1323 | -{ |
1324 | - msg="$*" |
1325 | - echo "ERROR: $msg" >&2 |
1326 | - exit 1 |
1327 | -} |
1328 | - |
1329 | -debug() |
1330 | -{ |
1331 | - str="$1" |
1332 | - [ "$debug_enabled" = 1 ] && echo "DEBUG: $str" |
1333 | -} |
1334 | - |
1335 | -get_job_pid() |
1336 | -{ |
1337 | - job="$1" |
1338 | - [ -z "$job" ] && die "need job" |
1339 | - |
1340 | - pid=$(initctl status "$job"|grep process|awk '{print $NF}') |
1341 | - [ -z "$pid" ] && die "job $job has no pid" |
1342 | - |
1343 | - echo "$pid" |
1344 | -} |
1345 | - |
1346 | -# take a string and convert it into a valid job name |
1347 | -make_job_name() |
1348 | -{ |
1349 | - str="$1" |
1350 | - |
1351 | - echo "$str" |\ |
1352 | - sed -e 's/>/ gt /g' -e 's/</ lt /g' -e 's/+/ and /g' |\ |
1353 | - sed -e 's/[[:punct:]]//g' -e 's/ */ /g' |\ |
1354 | - tr ' ' '-' |
1355 | -} |
1356 | - |
1357 | -upstart_encode() |
1358 | -{ |
1359 | - str="$1" |
1360 | - |
1361 | - echo "$str" | sed 's!/!_!g' |
1362 | -} |
1363 | - |
1364 | -# take a string and convert it into a valid job log file name |
1365 | -make_log_name() |
1366 | -{ |
1367 | - str="$1" |
1368 | - upstart_encode "$str" |
1369 | -} |
1370 | - |
1371 | -TEST_FAILED() |
1372 | -{ |
1373 | - args="$*" |
1374 | - |
1375 | - [ -z "$args" ] && die "need args" |
1376 | - |
1377 | - echo |
1378 | - echo "ERROR: TEST FAILED ('$feature')" |
1379 | - echo |
1380 | - printf "BAD: ${args}\n" |
1381 | - printf "\nPlease report a bug at $bug_url including the following details:\n" |
1382 | - printf "\nUpstart:\n" |
1383 | - /sbin/init --version|head -n1 |
1384 | - /sbin/initctl --version|head -n1 |
1385 | - echo |
1386 | - printf "cmdline:\n" |
1387 | - cat /proc/cmdline |
1388 | - echo |
1389 | - printf "Upstart Env:\n" |
1390 | - set|grep UPSTART_ |
1391 | - echo |
1392 | - printf "lsb:\n" |
1393 | - lsb_release -a |
1394 | - printf "\nuname:\n" |
1395 | - uname -a |
1396 | - echo |
1397 | - sync |
1398 | - echo "ERROR: TEST FAILED ('$feature')" |
1399 | - echo |
1400 | - exit 1 |
1401 | -} |
1402 | - |
1403 | -TEST_GROUP() |
1404 | -{ |
1405 | - name="$1" |
1406 | - |
1407 | - [ -z "$name" ] && die "need name" |
1408 | - |
1409 | - printf "Testing %s\n" "$name" |
1410 | -} |
1411 | - |
1412 | -TEST_FEATURE() |
1413 | -{ |
1414 | - feature="$1" |
1415 | - |
1416 | - [ -z "$feature" ] && die "need feature" |
1417 | - |
1418 | - printf "...%s\n" "$feature" |
1419 | -} |
1420 | - |
1421 | -TEST_NE() |
1422 | -{ |
1423 | - cmd="$1" |
1424 | - value="$2" |
1425 | - expected="$3" |
1426 | - |
1427 | - # XXX: no checks on value or expected since they might be blank |
1428 | - [ -z "$cmd" ] && die "need cmd" |
1429 | - |
1430 | - [ "$value" = "$expected" ] && TEST_FAILED \ |
1431 | - "wrong value for '$cmd', expected $expected got $value" |
1432 | -} |
1433 | - |
1434 | -TEST_EQ() |
1435 | -{ |
1436 | - cmd="$1" |
1437 | - value="$2" |
1438 | - expected="$3" |
1439 | - |
1440 | - # XXX: no checks on value or expected since they might be blank |
1441 | - [ -z "$cmd" ] && die "need cmd" |
1442 | - |
1443 | - [ "$value" != "$expected" ] && TEST_FAILED \ |
1444 | - "wrong value for '$cmd', expected '$expected' got '$value'" |
1445 | -} |
1446 | - |
1447 | -checks() |
1448 | -{ |
1449 | - cmd=initctl |
1450 | - [ -z "$(command -v $cmd)" ] && die "cannot find command $cmd" |
1451 | - |
1452 | - [ "$(id -u)" = 0 ] && die "ERROR: should not run this function as root" |
1453 | - |
1454 | - # This will fail for a non-root user unless D-Bus is correctly |
1455 | - # configured |
1456 | - $cmd emit foo || die \ |
1457 | - "You do not appear to have configured D-Bus for Upstart user sessions. See usage." |
1458 | -} |
1459 | - |
1460 | -setup() |
1461 | -{ |
1462 | - uid=$(id -u) |
1463 | - gid=$(id -g) |
1464 | - |
1465 | - if [ "$uid" = 0 ] |
1466 | - then |
1467 | - [ -z "$user_to_create" ] && die "need '-u' option when running as root" |
1468 | - |
1469 | - getent passwd "$user_to_create" && \ |
1470 | - die "user '$user_to_create' already exists" |
1471 | - |
1472 | - echo "Creating user '$user_to_create'" |
1473 | - cmd="useradd -mU -c 'Upstart Test User' $user_to_create" |
1474 | - eval "$cmd" |
1475 | - TEST_EQ "$cmd" $? 0 |
1476 | - |
1477 | - echo "Locking account for user '$user_to_create'" |
1478 | - cmd="usermod -L $user_to_create" |
1479 | - eval "$cmd" |
1480 | - TEST_EQ "$cmd" $? 0 |
1481 | - |
1482 | - # Run ourselves again as the new user |
1483 | - su -c "$0 -a" "$user_to_create" |
1484 | - test_run_rc=$? |
1485 | - |
1486 | - if [ $test_run_rc -eq 0 ] |
1487 | - then |
1488 | - echo "Deleting user '$user_to_create'" |
1489 | - cmd="userdel -r \"$user_to_create\"" |
1490 | - eval "$cmd" |
1491 | - TEST_EQ "$cmd" $? 0 |
1492 | - fi |
1493 | - |
1494 | - exit $test_run_rc |
1495 | - fi |
1496 | - |
1497 | - checks |
1498 | - |
1499 | - # setup |
1500 | - if [ ! -d "$user_job_dir" ] |
1501 | - then |
1502 | - cmd="mkdir -p \"$user_job_dir\"" |
1503 | - eval $cmd |
1504 | - TEST_EQ "$cmd" $? 0 |
1505 | - |
1506 | - cmd="chmod 755 \"$user_job_dir\"" |
1507 | - eval "$cmd" |
1508 | - TEST_EQ "$cmd" $? 0 |
1509 | - fi |
1510 | - |
1511 | - # create somewhere to store user jobs |
1512 | - cmd="mktemp -d --tmpdir=\"$user_job_dir\"" |
1513 | - test_dir=$(eval "$cmd") |
1514 | - TEST_EQ "$cmd" $? 0 |
1515 | - TEST_NE "$test_dir" "$test_dir" "" |
1516 | - test_dir_suffix=${test_dir#${user_job_dir}/} |
1517 | - |
1518 | - # ensure files in this directory are accessible since |
1519 | - # mktemp sets directory perms to 0700 regardless of umask. |
1520 | - cmd="chmod 755 \"$test_dir\"" |
1521 | - eval "$cmd" |
1522 | - TEST_EQ "$cmd" $? 0 |
1523 | - |
1524 | - TEST_NE "HOME" "$HOME" "" |
1525 | -} |
1526 | - |
1527 | -cleanup() |
1528 | -{ |
1529 | - if [ -d "$test_dir" ] |
1530 | - then |
1531 | - echo "Removing test directory '$test_dir'" |
1532 | - cmd="rmdir \"$test_dir\"" |
1533 | - eval "$cmd" |
1534 | - TEST_EQ "$cmd" $? 0 |
1535 | - fi |
1536 | -} |
1537 | - |
1538 | -ensure_job_known() |
1539 | -{ |
1540 | - job="$1" |
1541 | - job_name="$2" |
1542 | - |
1543 | - [ -z "$job" ] && die "no job" |
1544 | - [ -z "$job_name" ] && die "no job name" |
1545 | - |
1546 | - TEST_FEATURE "ensure 'initctl' recognises job" |
1547 | - initctl list|grep -q "^$job " || \ |
1548 | - TEST_FAILED "job $job_name not known to initctl" |
1549 | - |
1550 | - TEST_FEATURE "ensure 'status' recognises job" |
1551 | - cmd="status ${job}" |
1552 | - eval "$cmd" >/dev/null 2>&1 |
1553 | - rc=$? |
1554 | - TEST_EQ "$cmd" $rc 0 |
1555 | -} |
1556 | - |
1557 | -# Note that if the specified job is *not* as task, it is expected to run |
1558 | -# indefinately. This allows us to perform PID checks, etc. |
1559 | -run_user_job_tests() |
1560 | -{ |
1561 | - job_name="$1" |
1562 | - job_file="$2" |
1563 | - task="$3" |
1564 | - env="$4" |
1565 | - |
1566 | - # XXX: env can be empty |
1567 | - [ -z "$job_name" ] && die "no job name" |
1568 | - [ -z "$job_file" ] && die "no job file" |
1569 | - [ -z "$task" ] && die "no task value" |
1570 | - |
1571 | - job="${test_dir_suffix}/${job_name}" |
1572 | - |
1573 | - [ -f "$job_file" ] || TEST_FAILED "job file '$job_file' does not exist" |
1574 | - |
1575 | - ensure_job_known "$job" "$job_name" |
1576 | - |
1577 | - TEST_FEATURE "ensure job can be started" |
1578 | - cmd="start ${job} ${env}" |
1579 | - output=$(eval "$cmd") |
1580 | - rc=$? |
1581 | - TEST_EQ "$cmd" $rc 0 |
1582 | - |
1583 | - if [ "$task" = no ] |
1584 | - then |
1585 | - TEST_FEATURE "ensure 'start' shows job pid" |
1586 | - pid=$(echo "$output"|awk '{print $4}') |
1587 | - TEST_NE "pid" "$pid" "" |
1588 | - |
1589 | - TEST_FEATURE "ensure 'initctl' shows job is running with pid" |
1590 | - initctl list|grep -q "^$job start/running, process $pid" || \ |
1591 | - TEST_FAILED "job $job_name did not start" |
1592 | - |
1593 | - TEST_FEATURE "ensure 'status' shows job is running with pid" |
1594 | - cmd="status ${job}" |
1595 | - output=$(eval "$cmd") |
1596 | - echo "$output"|while read job_tmp state ignored status_pid |
1597 | - do |
1598 | - state=$(echo $state|tr -d ',') |
1599 | - TEST_EQ "job name" "$job_tmp" "$job" |
1600 | - TEST_EQ "job state" "$state" "start/running" |
1601 | - TEST_EQ "job pid" "$status_pid" "$pid" |
1602 | - done |
1603 | - |
1604 | - TEST_FEATURE "ensure job pid is running with correct uids" |
1605 | - pid_uids=$(ps --no-headers -p $pid -o euid,ruid) |
1606 | - for pid_uid in $pid_uids |
1607 | - do |
1608 | - TEST_EQ "pid uid" "$pid_uid" "$uid" |
1609 | - done |
1610 | - |
1611 | - TEST_FEATURE "ensure job pid is running with correct gids" |
1612 | - pid_gids=$(ps --no-headers -p $pid -o egid,rgid) |
1613 | - for pid_gid in $pid_gids |
1614 | - do |
1615 | - TEST_EQ "pid gid" "$pid_gid" "$gid" |
1616 | - done |
1617 | - |
1618 | - TEST_FEATURE "ensure process is running in correct directory" |
1619 | - cwd=$(readlink /proc/$pid/cwd) |
1620 | - TEST_EQ "cwd" "$cwd" "$HOME" |
1621 | - |
1622 | - TEST_FEATURE "ensure job can be stopped" |
1623 | - cmd="stop ${job}" |
1624 | - output=$(eval "$cmd") |
1625 | - rc=$? |
1626 | - TEST_EQ "$cmd" $rc 0 |
1627 | - |
1628 | - TEST_FEATURE "ensure job pid no longer exists" |
1629 | - pid_ids=$(ps --no-headers -p $pid -o euid,ruid,egid,rgid) |
1630 | - TEST_EQ "pid uids+gids" "$pid_ids" "" |
1631 | - fi |
1632 | - |
1633 | - remove_job_file "$job_file" |
1634 | - ensure_job_gone "$job" "$job_name" "$env" |
1635 | -} |
1636 | - |
1637 | -remove_job_file() |
1638 | -{ |
1639 | - job_file="$1" |
1640 | - |
1641 | - [ -z "$job_file" ] && die "no job file" |
1642 | - [ ! -f "$job_file" ] && TEST_FAILED "job file '$job_file' does not exist" |
1643 | - |
1644 | - cmd="rm $job_file" |
1645 | - eval "$cmd" |
1646 | - TEST_EQ "$cmd" $? 0 |
1647 | -} |
1648 | - |
1649 | -ensure_job_gone() |
1650 | -{ |
1651 | - job="$1" |
1652 | - job_name="$2" |
1653 | - env="$3" |
1654 | - |
1655 | - # XXX: no check on env since it can be empty |
1656 | - [ -z "$job" ] && die "no job" |
1657 | - [ -z "$job_name" ] && die "no job name" |
1658 | - |
1659 | - TEST_FEATURE "ensure 'initctl' no longer recognises job" |
1660 | - initctl list|grep -q "^$job " && \ |
1661 | - TEST_FAILED "deleted job $job_name still known to initctl" |
1662 | - |
1663 | - TEST_FEATURE "ensure 'status' no longer recognises job" |
1664 | - cmd="status ${job}" |
1665 | - eval "$cmd" >/dev/null 2>&1 |
1666 | - rc=$? |
1667 | - TEST_NE "$cmd" $rc 0 |
1668 | -} |
1669 | - |
1670 | -test_user_job() |
1671 | -{ |
1672 | - test_group="$1" |
1673 | - job_name="$2" |
1674 | - script="$3" |
1675 | - task="$4" |
1676 | - env="$5" |
1677 | - |
1678 | - # XXX: no test on script or env since they might be empty |
1679 | - [ -z "$test_group" ] && die "no test group" |
1680 | - [ -z "$job_name" ] && die "no job name" |
1681 | - [ -z "$task" ] && die "no task" |
1682 | - |
1683 | - TEST_GROUP "$test_group" |
1684 | - |
1685 | - job_file="${test_dir}/${job_name}.conf" |
1686 | - |
1687 | - echo "$script" > $job_file |
1688 | - |
1689 | - run_user_job_tests "$job_name" "$job_file" "$task" "$env" |
1690 | -} |
1691 | - |
1692 | -test_user_job_binary() |
1693 | -{ |
1694 | - group="user job running a binary" |
1695 | - job_name="binary_test" |
1696 | - script="exec sleep 999" |
1697 | - test_user_job "$group" "$job_name" "$script" no "" |
1698 | -} |
1699 | - |
1700 | -test_user_job_binary_task() |
1701 | -{ |
1702 | - group="user job running a binary task" |
1703 | - job_name="binary_task_test" |
1704 | - OUTFILE=$(mktemp) |
1705 | - |
1706 | - script="\ |
1707 | -task |
1708 | -exec /bin/true > $OUTFILE" |
1709 | - |
1710 | - test_user_job "$group" "$job_name" "$script" yes "OUTFILE=$OUTFILE" |
1711 | - rm -f $OUTFILE |
1712 | -} |
1713 | - |
1714 | -test_user_job_single_line_script() |
1715 | -{ |
1716 | - group="user job running a single-line script" |
1717 | - job_name="single_line_script_test" |
1718 | - script="\ |
1719 | -script |
1720 | - sleep 999 |
1721 | -end script" |
1722 | - test_user_job "$group" "$job_name" "$script" no "" |
1723 | -} |
1724 | - |
1725 | -test_user_job_single_line_script_task() |
1726 | -{ |
1727 | - group="user job running a single-line script task" |
1728 | - job_name="single_line_script_task_test" |
1729 | - OUTFILE=$(mktemp) |
1730 | - |
1731 | - script="\ |
1732 | -task |
1733 | -script |
1734 | - exec /bin/true > $OUTFILE |
1735 | -end script" |
1736 | - test_user_job "$group" "$job_name" "$script" yes "OUTFILE=$OUTFILE" |
1737 | - rm -f $OUTFILE |
1738 | -} |
1739 | - |
1740 | -test_user_job_multi_line_script() |
1741 | -{ |
1742 | - group="user job running a multi-line script" |
1743 | - job_name="multi_line_script_test" |
1744 | - script="\ |
1745 | -script |
1746 | - |
1747 | - /bin/true |
1748 | - /bin/true;/bin/true |
1749 | - sleep 999 |
1750 | - |
1751 | -end script" |
1752 | - test_user_job "$group" "$job_name" "$script" no "" |
1753 | -} |
1754 | - |
1755 | -test_user_job_multi_line_script_task() |
1756 | -{ |
1757 | - group="user job running a multi-line script task" |
1758 | - job_name="multi_line_script_task_test" |
1759 | - OUTFILE=$(mktemp) |
1760 | - |
1761 | - script="\ |
1762 | -task |
1763 | -script |
1764 | - |
1765 | - /bin/true |
1766 | - /bin/true |
1767 | - /bin/true |
1768 | - |
1769 | -end script" |
1770 | - test_user_job "$group" "$job_name" "$script" yes "OUTFILE=$OUTFILE" |
1771 | - rm -f $OUTFILE |
1772 | -} |
1773 | - |
1774 | -test_user_emit_events() |
1775 | -{ |
1776 | - job_name="start_on_foo" |
1777 | - |
1778 | - TEST_GROUP "user emitting an event" |
1779 | - initctl emit foo || TEST_FAILED "failed to emit event as user" |
1780 | - |
1781 | - TEST_GROUP "user emitting an event to start a job" |
1782 | - script="\ |
1783 | - start on foo BAR=2 |
1784 | - stop on baz cow=moo or hello |
1785 | - exec sleep 999" |
1786 | - |
1787 | - job_file="${test_dir}/${job_name}.conf" |
1788 | - job="${test_dir_suffix}/${job_name}" |
1789 | - |
1790 | - echo "$script" > $job_file |
1791 | - |
1792 | - ensure_job_known "$job" "$job_name" |
1793 | - |
1794 | - initctl list|grep -q "^$job stop/waiting" || \ |
1795 | - TEST_FAILED "job $job_name not stopped" |
1796 | - |
1797 | - TEST_FEATURE "ensure job can be started with event" |
1798 | - initctl emit foo BAR=2 || \ |
1799 | - TEST_FAILED "failed to emit event for user job" |
1800 | - |
1801 | - initctl status "$job"|grep -q "^$job start/running" || \ |
1802 | - TEST_FAILED "job $job_name failed to start" |
1803 | - |
1804 | - TEST_FEATURE "ensure job can be stopped with event" |
1805 | - initctl emit baz cow=moo || \ |
1806 | - TEST_FAILED "failed to emit event for user job" |
1807 | - |
1808 | - initctl list|grep -q "^$job stop/waiting" || \ |
1809 | - TEST_FAILED "job $job_name not stopped" |
1810 | - |
1811 | - rm -f "$job_file" |
1812 | -} |
1813 | - |
1814 | -test_user_job_setuid_setgid() |
1815 | -{ |
1816 | - group="user job with setuid and setgid me" |
1817 | - job_name="setuid_setgid_me_test" |
1818 | - script="\ |
1819 | -setuid $(id -un) |
1820 | -setgid $(id -gn) |
1821 | -exec sleep 999" |
1822 | - test_user_job "$group" "$job_name" "$script" no "" |
1823 | - |
1824 | - TEST_GROUP "user job with setuid and setgid root" |
1825 | - script="\ |
1826 | -setuid root |
1827 | -setgid root |
1828 | -exec sleep 999" |
1829 | - |
1830 | - job_name="setuid_setgid_root_test" |
1831 | - job_file="${test_dir}/${job_name}.conf" |
1832 | - job="${test_dir_suffix}/${job_name}" |
1833 | - |
1834 | - echo "$script" > $job_file |
1835 | - |
1836 | - ensure_job_known "$job" "$job_name" |
1837 | - |
1838 | - TEST_FEATURE "ensure job fails to start as root" |
1839 | - cmd="start ${job}" |
1840 | - output=$(eval "$cmd" 2>&1) |
1841 | - rc=$? |
1842 | - TEST_EQ "$cmd" $rc 1 |
1843 | - |
1844 | - TEST_FEATURE "ensure 'start' indicates job failure" |
1845 | - error=$(echo "$output"|grep failed) |
1846 | - TEST_NE "error" "$error" "" |
1847 | - |
1848 | - TEST_FEATURE "ensure 'initctl' does not list job" |
1849 | - initctl list|grep -q "^$job stop/waiting" || \ |
1850 | - TEST_FAILED "job $job_name not listed as stopped" |
1851 | - |
1852 | - delete_job "$job_name" |
1853 | -} |
1854 | - |
1855 | -get_job_file() |
1856 | -{ |
1857 | - job_name="$1" |
1858 | - |
1859 | - [ -z "$job_name" ] && die "no job name" |
1860 | - echo "${test_dir}/${job_name}.conf" |
1861 | -} |
1862 | - |
1863 | -ensure_no_output() |
1864 | -{ |
1865 | - job_name="$1" |
1866 | - script="$2" |
1867 | - instance="$3" |
1868 | - |
1869 | - job="${test_dir_suffix}/${job_name}" |
1870 | - |
1871 | - create_job "$job_name" "$script" |
1872 | - start_job "$job" "$job_name" "$instance" |
1873 | - |
1874 | - check_job_output "$job_name" |
1875 | - delete_job "$job_name" |
1876 | -} |
1877 | - |
1878 | -create_job() |
1879 | -{ |
1880 | - job_name="$1" |
1881 | - script="$2" |
1882 | - |
1883 | - # XXX: script could be empty |
1884 | - [ -z "$job_name" ] && die "no job name" |
1885 | - |
1886 | - debug "create_job: job_name='$job_name'" |
1887 | - debug "create_job: script='$script'" |
1888 | - |
1889 | - # Not currently possible to have a user job with the |
1890 | - # same name as a system job. |
1891 | - # |
1892 | - # XXX: Note that this test assumes that user has *not* specified |
1893 | - # XXX: an alternate configuration directory using the |
1894 | - # XXX: '--confdir' option. |
1895 | - [ -e "${sys_job_dir}/${job_name}.conf" ] && \ |
1896 | - die "job '$job_name' already exists as a system job" |
1897 | - |
1898 | - job_file="${test_dir}/${job_name}.conf" |
1899 | - job="${test_dir_suffix}/${job_name}" |
1900 | - |
1901 | - echo "$script" > "$job_file" |
1902 | - sync |
1903 | -} |
1904 | - |
1905 | -delete_job() |
1906 | -{ |
1907 | - job_name="$1" |
1908 | - |
1909 | - [ -z "$job_name" ] && die "no job name" |
1910 | - |
1911 | - job_file="$(get_job_file $job_name)" |
1912 | - |
1913 | - rm "$job_file" || TEST_FAILED "unable to remove job file '$job_file'" |
1914 | -} |
1915 | - |
1916 | -check_job_output() |
1917 | -{ |
1918 | - job_name="$1" |
1919 | - |
1920 | - [ ! -z "$(ls $user_log_dir 2>/dev/null)" ] && \ |
1921 | - TEST_FAILED "job $job_name created logfile unexpectedly in '$user_log_dir'" |
1922 | - |
1923 | - # XXX: note that it might appear that checking in $sys_log_dir |
1924 | - # could result in false positives, but this isn't so since |
1925 | - # (currently) it is not possible for a user job to have the |
1926 | - # same name as a system job. start_job() will detect this |
1927 | - # scenario. |
1928 | - for dir in "$user_log_dir" "$sys_log_dir" |
1929 | - do |
1930 | - log_file="${dir}/${job_name}.log" |
1931 | - [ -f "$log_file" ] && \ |
1932 | - TEST_FAILED "job $job_name created logfile unexpectedly as '$log_file'" |
1933 | - done |
1934 | -} |
1935 | - |
1936 | -start_job() |
1937 | -{ |
1938 | - job="$1" |
1939 | - job_file="$2" |
1940 | - instance="$3" |
1941 | - allow_failure="$4" |
1942 | - |
1943 | - # XXX: instance may be blank |
1944 | - [ -z "$job" ] && die "no job" |
1945 | - [ -z "$job_file" ] && die "no job file" |
1946 | - |
1947 | - debug "start_job: job='$job'" |
1948 | - debug "start_job: job_file='$job_file'" |
1949 | - debug "start_job: instance='$instance'" |
1950 | - debug "start_job: allow_failure='$allow_failure'" |
1951 | - |
1952 | - eval output=$(mktemp) |
1953 | - |
1954 | - # XXX: Don't quote instance as we don't want to pass a null instance to |
1955 | - # start(8). |
1956 | - cmd="start \"$job\" $instance >${output} 2>&1" |
1957 | - debug "start_job: running '$cmd'" |
1958 | - eval "$cmd" |
1959 | - rc=$? |
1960 | - |
1961 | - if [ $rc -ne 0 -a -z "$allow_failure" ] |
1962 | - then |
1963 | - TEST_FAILED "job $job_file not started: $(cat $output)" |
1964 | - fi |
1965 | - |
1966 | - rm -f "$output" |
1967 | -} |
1968 | - |
1969 | -get_job_logfile_name() |
1970 | -{ |
1971 | - job_name="$1" |
1972 | - instance_value="$2" |
1973 | - |
1974 | - # XXX: instance may be null |
1975 | - [ -z "$job_name" ] && die "no job name" |
1976 | - |
1977 | - encoded_test_dir_suffix=$(upstart_encode "${test_dir_suffix}/") |
1978 | - file_name="${encoded_test_dir_suffix}$(make_log_name $job_name)" |
1979 | - |
1980 | - if [ ! -z "$instance_value" ] |
1981 | - then |
1982 | - log_file="${user_log_dir}/${file_name}-${instance_value}.log" |
1983 | - else |
1984 | - log_file="${user_log_dir}/${file_name}.log" |
1985 | - fi |
1986 | - |
1987 | - echo "$log_file" |
1988 | -} |
1989 | - |
1990 | -run_job() |
1991 | -{ |
1992 | - job="$1" |
1993 | - job_name="$2" |
1994 | - script="$3" |
1995 | - instance="$4" |
1996 | - |
1997 | - # XXX: script, instance might be blank |
1998 | - [ -z "$job" ] && die "no job" |
1999 | - [ -z "$job_name" ] && die "no job name" |
2000 | - |
2001 | - debug "run_job: job='$job'" |
2002 | - debug "run_job: job_name='$job_name'" |
2003 | - debug "run_job: script='$script'" |
2004 | - debug "run_job: instance='$instance'" |
2005 | - |
2006 | - create_job "$job_name" "$script" |
2007 | - start_job "$job" "$job_name" "$instance" |
2008 | -} |
2009 | - |
2010 | -ensure_file_meta() |
2011 | -{ |
2012 | - file="$1" |
2013 | - expected_owner="$2" |
2014 | - expected_group="$3" |
2015 | - expected_perms="$4" |
2016 | - |
2017 | - [ -z "$file" ] && die "no file" |
2018 | - [ -z "$expected_owner" ] && die "no expected owner" |
2019 | - [ -z "$expected_group" ] && die "no expected group" |
2020 | - [ -z "$expected_perms" ] && die "no expected perms" |
2021 | - |
2022 | - [ ! -f "$file" ] && die "file $file does not exist" |
2023 | - |
2024 | - expected_perms="640" |
2025 | - umask_value=$(umask) |
2026 | - umask_expected=0022 |
2027 | - |
2028 | - if [ "$umask_value" != "$umask_expected" ] |
2029 | - then |
2030 | - msg="umask value is $umask_value -" |
2031 | - msg="${msg} changing it to $umask_expected." |
2032 | - echo "WARNING: $msg" |
2033 | - umask "$umask_expected" || TEST_FAILED "unable to change umask" |
2034 | - fi |
2035 | - |
2036 | - owner=$(ls -l "$file"|awk '{print $3}') |
2037 | - group=$(ls -l "$file"|awk '{print $4}') |
2038 | - perms=$(stat --printf "%a\n" "$file") |
2039 | - |
2040 | - [ "$owner" = "$expected_owner" ] || TEST_FAILED \ |
2041 | - "file $file has wrong owner (expected $expected_owner, got $owner)" |
2042 | - |
2043 | - [ "$group" = "$expected_group" ] || TEST_FAILED \ |
2044 | - "file $file has wrong group (expected $expected_group, got $group)" |
2045 | - |
2046 | - [ "$perms" = "$expected_perms" ] || TEST_FAILED \ |
2047 | - "file $file has wrong group (expected $expected_perms, got $perms)" |
2048 | -} |
2049 | - |
2050 | - |
2051 | -ensure_output() |
2052 | -{ |
2053 | - job_name="$1" |
2054 | - script="$2" |
2055 | - expected_output="$3" |
2056 | - instance="$4" |
2057 | - instance_value="$5" |
2058 | - options="$6" |
2059 | - |
2060 | - # XXX: remaining args could be null |
2061 | - [ -z "$job_name" ] && die "no job name" |
2062 | - |
2063 | - debug "ensure_output: job_name='$job_name'" |
2064 | - debug "ensure_output: script='$script'" |
2065 | - debug "ensure_output: expected_ouput='$expected_ouput'" |
2066 | - debug "ensure_output: instance='$instance'" |
2067 | - debug "ensure_output: instance_value='$instance_value'" |
2068 | - debug "ensure_output: options='$options'" |
2069 | - |
2070 | - regex=n |
2071 | - retain=n |
2072 | - unique="" |
2073 | - use_od=n |
2074 | - |
2075 | - for opt in $options |
2076 | - do |
2077 | - case "$opt" in |
2078 | - regex) |
2079 | - regex=y |
2080 | - ;; |
2081 | - retain) |
2082 | - retain=y |
2083 | - ;; |
2084 | - unique) |
2085 | - unique='|sort -u' |
2086 | - ;; |
2087 | - use_od) |
2088 | - use_od=y |
2089 | - ;; |
2090 | - esac |
2091 | - done |
2092 | - |
2093 | - debug "ensure_output: regex='$regex'" |
2094 | - debug "ensure_output: retain='$retain'" |
2095 | - debug "ensure_output: unique='$unique'" |
2096 | - debug "ensure_output: use_od='$use_od'" |
2097 | - |
2098 | - expected_owner=$(id -un) |
2099 | - expected_group=$(id -gn) |
2100 | - expected_perms="640" |
2101 | - |
2102 | - job="${test_dir_suffix}/${job_name}" |
2103 | - |
2104 | - run_job "$job" "$job_name" "$script" "$instance" |
2105 | - |
2106 | - debug "ensure_output: user_log_dir='$user_log_dir'" |
2107 | - debug "ensure_output: test_dir='$test_dir'" |
2108 | - debug "ensure_output: test_dir_suffix='$test_dir_suffix'" |
2109 | - |
2110 | - log_file=$(get_job_logfile_name "$job_name" "$instance_value") |
2111 | - |
2112 | - debug "ensure_output: log_file='$log_file'" |
2113 | - |
2114 | - # Give Upstart a chance to parse the file |
2115 | - count=1 |
2116 | - while ! status "$job" >/dev/null 2>&1 |
2117 | - do |
2118 | - sleep 1 |
2119 | - count=$((count+1)) |
2120 | - [ "$count" -eq 5 ] && break |
2121 | - done |
2122 | - |
2123 | - # give job a chance to start |
2124 | - count=1 |
2125 | - while [ ! -f "$log_file" ] |
2126 | - do |
2127 | - sleep 1 |
2128 | - count=$((count+1)) |
2129 | - [ "$count" -eq 5 ] && break |
2130 | - done |
2131 | - |
2132 | - [ ! -f "$log_file" ] && \ |
2133 | - TEST_FAILED "job '$job_name' failed to create logfile" |
2134 | - |
2135 | - ensure_file_meta \ |
2136 | - "$log_file" \ |
2137 | - "$expected_owner" \ |
2138 | - "$expected_group" \ |
2139 | - "$expected_perms" |
2140 | - |
2141 | - # XXX: note we have to remove carriage returns added by the line |
2142 | - # discipline |
2143 | - if [ "$regex" = y ] |
2144 | - then |
2145 | - log=$(eval "cat $log_file|tr -d '\r' $unique") |
2146 | - msg="job '$job_name' failed to log correct data\n" |
2147 | - msg="${msg}\texpected regex: '$expected_output'\n" |
2148 | - msg="${msg}\tgot : '$log'" |
2149 | - cat "$log_file" | egrep "$expected_output" || TEST_FAILED "$msg" |
2150 | - elif [ "$use_od" = y ] |
2151 | - then |
2152 | - log=$(eval "cat $log_file|tr -d '\r' $unique|od -x") |
2153 | - msg="job '$job_name' failed to log correct data\n" |
2154 | - msg="${msg}\texpected hex: '$expected_output'\n" |
2155 | - msg="${msg}\tgot : '$log'" |
2156 | - [ "$expected_output" != "$log" ] && TEST_FAILED "$msg" |
2157 | - else |
2158 | - log=$(eval "cat $log_file|tr -d '\r' $unique") |
2159 | - msg="job '$job_name' failed to log correct data\n" |
2160 | - msg="${msg}\texpected text: '$expected_output'\n" |
2161 | - msg="${msg}\tgot : '$log'" |
2162 | - [ "$expected_output" != "$log" ] && TEST_FAILED "$msg" |
2163 | - fi |
2164 | - |
2165 | - if [ "$retain" = n ] |
2166 | - then |
2167 | - delete_job "$job_name" |
2168 | - rm "$log_file" || TEST_FAILED "unable to remove log file '$log_file'" |
2169 | - fi |
2170 | -} |
2171 | - |
2172 | -test_ensure_no_unexpected_output() |
2173 | -{ |
2174 | - #--------------------------------------------------------------------- |
2175 | - feature="ensure command job does not create log file with no console" |
2176 | - TEST_FEATURE "$feature" |
2177 | - |
2178 | - job_name=$(make_job_name "$feature") |
2179 | - |
2180 | - script="\ |
2181 | - console none |
2182 | - exec echo hello world" |
2183 | - |
2184 | - ensure_no_output "$job_name" "$script" "" |
2185 | - |
2186 | - #--------------------------------------------------------------------- |
2187 | - feature="ensure 1-line script job does not create log file with no console" |
2188 | - TEST_FEATURE "$feature" |
2189 | - |
2190 | - job_name=$(make_job_name "$feature") |
2191 | - |
2192 | - script="\ |
2193 | - console none |
2194 | - script |
2195 | - echo hello world |
2196 | - end script |
2197 | - " |
2198 | - |
2199 | - ensure_no_output "$job_name" "$script" "" |
2200 | - |
2201 | - #--------------------------------------------------------------------- |
2202 | - feature="ensure multi-line script job does not create log file with no console" |
2203 | - TEST_FEATURE "$feature" |
2204 | - |
2205 | - job_name=$(make_job_name "$feature") |
2206 | - |
2207 | - script="\ |
2208 | - console none |
2209 | - script |
2210 | - /bin/true |
2211 | - echo hello world |
2212 | - end script |
2213 | - " |
2214 | - |
2215 | - ensure_no_output "$job_name" "$script" "" |
2216 | - |
2217 | - #--------------------------------------------------------------------- |
2218 | - feature="ensure no output if log directory does not exist" |
2219 | - TEST_FEATURE "$feature" |
2220 | - |
2221 | - rmdir "${user_log_dir}" || \ |
2222 | - TEST_FAILED "unable to delete log directory '$user_log_dir'" |
2223 | - |
2224 | - job_name=$(make_job_name "$feature") |
2225 | - string="hello world" |
2226 | - script="\ |
2227 | - console log |
2228 | - script |
2229 | - /bin/true |
2230 | - /bin/echo hello world |
2231 | - end script |
2232 | - " |
2233 | - |
2234 | - ensure_no_output "$job_name" "$script" "" |
2235 | - |
2236 | - mkdir "${user_log_dir}" || \ |
2237 | - TEST_FAILED "unable to recreate log directory '$user_log_dir'" |
2238 | - |
2239 | - #--------------------------------------------------------------------- |
2240 | - feature="ensure command job does not create log file with invalid command" |
2241 | - TEST_FEATURE "$feature" |
2242 | - |
2243 | - job_name=$(make_job_name "$feature") |
2244 | - |
2245 | - script="\ |
2246 | - console log |
2247 | - exec /this/command/does/not/exist" |
2248 | - |
2249 | - job="${test_dir_suffix}/${job_name}" |
2250 | - create_job "$job_name" "$script" |
2251 | - start_job "$job" "$job_name" "" 1 |
2252 | - check_job_output "$job_name" |
2253 | - delete_job "$job_name" |
2254 | -} |
2255 | - |
2256 | -test_output_logged() |
2257 | -{ |
2258 | - # XXX: upstart won't create this |
2259 | - mkdir -p "$user_log_dir" |
2260 | - |
2261 | - test_ensure_no_unexpected_output |
2262 | -} |
2263 | - |
2264 | -test_user_jobs() |
2265 | -{ |
2266 | - test_user_job_binary |
2267 | - test_user_job_single_line_script |
2268 | - test_user_job_multi_line_script |
2269 | - |
2270 | - test_user_job_binary_task |
2271 | - test_user_job_single_line_script_task |
2272 | - test_user_job_multi_line_script_task |
2273 | - |
2274 | - test_user_job_setuid_setgid |
2275 | - |
2276 | - test_user_emit_events |
2277 | - |
2278 | - test_output_logged |
2279 | -} |
2280 | - |
2281 | -tests() |
2282 | -{ |
2283 | - echo |
2284 | - echo -n "Running Upstart user session tests as user '`whoami`'" |
2285 | - echo " (uid $uid, gid $gid) in directory '$test_dir'" |
2286 | - echo |
2287 | - |
2288 | - test_user_jobs |
2289 | - |
2290 | - echo |
2291 | - echo "All tests completed successfully" |
2292 | - echo |
2293 | -} |
2294 | - |
2295 | -usage() |
2296 | -{ |
2297 | -cat <<EOT |
2298 | -USAGE: $script_name [options] |
2299 | - |
2300 | -OPTIONS: |
2301 | - |
2302 | - -a : Actually run this script. |
2303 | - -h : Show this help. |
2304 | - -u <user> : Specify name of test user to create. |
2305 | - |
2306 | -DESCRIPTION: |
2307 | - |
2308 | -Run simple set of Upstart user session tests. |
2309 | - |
2310 | -PREREQUISITE: |
2311 | - |
2312 | -For this test to run, non-root users must be allowed to invoke all D-Bus |
2313 | -methods on Upstart via configuration file: |
2314 | - |
2315 | - /etc/dbus-1/system.d/Upstart.conf |
2316 | - |
2317 | -See dbus-daemon(1) for further details. |
2318 | - |
2319 | -WARNING: Note that this script is unavoidably invasive, so read what |
2320 | -WARNING: follows before running! |
2321 | - |
2322 | -If run as a non-root user, this script will create a uniquely-named |
2323 | -subdirectory below "\$HOME/.init/" to run its tests in. On successful |
2324 | -completion of these tests, the unique subdirectory and its contents will |
2325 | -be removed. |
2326 | - |
2327 | -If however, this script is invoked as the root user, the script will |
2328 | -refuse to run until given the name of a test user to create via the "-u" |
2329 | -option. If the user specified to this option already exists, this script |
2330 | -will exit with an error. If the user does not already exist, it will be |
2331 | -created, the script then run *as that user* and assuming successful |
2332 | -completion of the tests, the test user and their home directory will |
2333 | -then be deleted. |
2334 | - |
2335 | -EOT |
2336 | -} |
2337 | - |
2338 | -#--------------------------------------------------------------------- |
2339 | -# main |
2340 | -#--------------------------------------------------------------------- |
2341 | - |
2342 | -while getopts "dhu:" opt |
2343 | -do |
2344 | - case "$opt" in |
2345 | - d) |
2346 | - debug_enabled=1 |
2347 | - ;; |
2348 | - |
2349 | - h) |
2350 | - usage |
2351 | - exit 0 |
2352 | - ;; |
2353 | - |
2354 | - u) |
2355 | - user_to_create="$OPTARG" |
2356 | - ;; |
2357 | - esac |
2358 | -done |
2359 | - |
2360 | -setup |
2361 | -tests |
2362 | -cleanup |
2363 | -exit 0 |
Several places in the code, you're using this construction:
if (control_ get_origin_ uid (message, &origin_uid) && origin_uid != uid) {
// EPERM
So if the control_ get_origin_ uid() function fails, access is granted. This seems like a bad idea, as it means anyone who can figure out a way to break the function can get access. I think it's probably better to do:
if (!control_ get_origin_ uid (message, &origin_uid) || origin_uid != uid) {
// EPERM
Otherwise, this looks good to me.