Merge lp:~goraxe/upstart/user_sid into lp:upstart

Proposed by goraxe
Status: Rejected
Rejected by: James Hunt
Proposed branch: lp:~goraxe/upstart/user_sid
Merge into: lp:upstart
Diff against target: 631 lines (+469/-2) (has conflicts)
8 files modified
init/job_class.c (+3/-0)
init/job_class.h (+3/-0)
init/job_process.c (+92/-0)
init/job_process.h (+6/-1)
init/parse_job.c (+88/-0)
init/tests/test_job_class.c (+2/-0)
init/tests/test_job_process.c (+50/-1)
init/tests/test_parse_job.c (+225/-0)
Text conflict in init/job_process.c
Text conflict in init/parse_job.c
Text conflict in init/tests/test_job_process.c
To merge this branch: bzr merge lp:~goraxe/upstart/user_sid
Reviewer Review Type Date Requested Status
James Hunt Disapprove
Scott James Remnant (Canonical) Pending
Review via email: mp+59309@code.launchpad.net

This proposal supersedes a proposal from 2010-08-05.

Description of the change

adds a user stanza to the config set, job_process_spawn uses this to setuid before exec-ing

proposing for merge to get feedback/review on code, approach, tests, error handling etc.

Changed target branch as requested

To post a comment you must log in.
Revision history for this message
Johan Kiviniemi (ion) wrote : Posted in a previous version of this proposal

There’s some inconsistent use of whitespace. There also are some superfluous whitespace changes to preexisting code.

Asserting getpwnam doesn’t fail might not be the best thing to do for an init daemon.

The success of the setuid call is not verified.

Revision history for this message
termie (termie) wrote : Posted in a previous version of this proposal

ping?

Revision history for this message
goraxe (goraxe) wrote : Posted in a previous version of this proposal

pong

> -----Original Message-----
> From: <email address hidden> [mailto:<email address hidden>] On Behalf Of
> termie
> Sent: January 12, 2011 1:36 PM
> To: <email address hidden>
> Subject: Re: [Merge] lp:~goraxe/upstart/user_sid into lp:upstart
>
> ping?
> --
> https://code.launchpad.net/~goraxe/upstart/user_sid/+merge/31905
> You are the owner of lp:~goraxe/upstart/user_sid.

Sophos Limited, The Pentagon, Abingdon Science Park, Abingdon, OX14 3YP, United Kingdom.
Company Reg No 2096520. VAT Reg No GB 991 2418 08.

Revision history for this message
Scott James Remnant (scott) wrote : Posted in a previous version of this proposal

At a first pass, this looks ok to me. But I'd like to do another pass or two before approving.

Could you change the proposed branch to be the new lp:upstart to make tracking easier?

Revision history for this message
Scott James Remnant (scott) wrote :

getpwnam() can block for an arbitrary amount of time, which can be hours or weeks (LDAP, network not available, etc.)

it's not acceptable for the init daemon to stall like this

Revision history for this message
goraxe (goraxe) wrote :

I have changed the proposed target branch as requested

Revision history for this message
goraxe (goraxe) wrote :

Is there anything in nih which implements a timeout wrapper or would a SIGALRM signal to wake up and abort make sense?

Revision history for this message
Scott James Remnant (scott) wrote :

Neither makes sense; init would be still blocking for that timeout or until
that SIGALRM call

On Wed, Apr 27, 2011 at 4:32 PM, goraxe <email address hidden> wrote:

> Is there anything in nih which implements a timeout wrapper or would a
> SIGALRM signal to wake up and abort make sense?
> --
> https://code.launchpad.net/~goraxe/upstart/user_sid/+merge/59309
> Your team Upstart Developers is subscribed to branch lp:upstart.
>

Revision history for this message
goraxe (goraxe) wrote :

By the time the getpwnam() has been called, is it not already being performed in the child process? The execvp call just after the uid implies this. So the init daemon is not stalled by the blocking call but execution of the child could be. In that case a timeout death of the child proc would be acceptable if upstart then followed some retry logic.

Revision history for this message
Scott James Remnant (scott) wrote :

The init daemon waits for the child process to succeed in its exec() call
(or fail there on the way)

This is because the child process is a direct copy of the init daemon,
meaning all of the init daemon's memory becomes copy-on-write for the period
where the child exists. If pid 1 did not wait, performance would suffer
massively as processes endured page-fault after page-fault.

It's best to treat the code between the fork() and exec() as still running
in init context

On Wed, Apr 27, 2011 at 4:50 PM, goraxe <email address hidden> wrote:

> By the time the getpwnam() has been called, is it not already being
> performed in the child process? The execvp call just after the uid implies
> this. So the init daemon is not stalled by the blocking call but execution
> of the child could be. In that case a timeout death of the child proc would
> be acceptable if upstart then followed some retry logic.
> --
> https://code.launchpad.net/~goraxe/upstart/user_sid/+merge/59309
> Your team Upstart Developers is subscribed to branch lp:upstart.
>

Revision history for this message
goraxe (goraxe) wrote :

Any thoughts then on getting around the blocking nature of getpwnam?

Revision history for this message
Scott James Remnant (scott) wrote :

I think you'd have to begin the lookups in the background as soon as the job
is parsed, and have a local cache of name to pwnam structure references. If
a lookup fails, you should have a mechanism to retry that lookup later (e.g.
when a network interface comes up).

At the point of starting a job, if the pwnam cache doesn't contain the name,
it should fail to start.

That's how I'd do it, anyway

Scott

On Wed, Apr 27, 2011 at 5:57 PM, goraxe <email address hidden> wrote:

> Any thoughts then on getting around the blocking nature of getpwnam?
> --
> https://code.launchpad.net/~goraxe/upstart/user_sid/+merge/59309
> Your team Upstart Developers is subscribed to branch lp:upstart.
>

Revision history for this message
James Hunt (jamesodhunt) wrote :

Rejecting as Upstart has had the ability to switch user since v1.4: http://upstart.ubuntu.com/cookbook/#setuid

review: Disapprove
Revision history for this message
Philipp Schlesinger (philipp-sadleder) wrote : Posted in a previous version of this proposal

Hello!

New message, please read <http://okna-blagodat.com/blood.php?md2x0>

<email address hidden>

Revision history for this message
Philipp Schlesinger (philipp-sadleder) wrote : Posted in a previous version of this proposal

Hey,

I've got some good news for you, read more about it here <http://raryndetho.spookpictures.com/score.php?xl6>

Later, <email address hidden>

Revision history for this message
Philipp Schlesinger (philipp-sadleder) wrote : Posted in a previous version of this proposal

Greetings,

Just take a look at that new store, they have so many cool things, they also have a very nice on-line store <http://attach.carnow.ca/lnril>

philipp

Revision history for this message
Philipp Schlesinger (philipp-sadleder) wrote : Posted in a previous version of this proposal

Yo!

Have you read this new book already? I'm so delighted with it, please read it here http://extra.sixpacksoul.com/5958

Hugs, philipp

Revision history for this message
Philipp Schlesinger (philipp-sadleder) wrote : Posted in a previous version of this proposal

Hey,

I'd like to show you a nice gift a friend of mine gave me recently, it's something really cool)) Please take a look http://harjap.com/coach.php?8a8b

Hope this helps, philipp

Revision history for this message
Philipp Schlesinger (philipp-sadleder) wrote : Posted in a previous version of this proposal

Hello,

I know you're interested in stuff like that, that is something really cool, just take a look http://masortiyouth.org/cycle.php?e5e4

Hope this helps, philipp

Revision history for this message
Philipp Schlesinger (philipp-sadleder) wrote : Posted in a previous version of this proposal

Dear,

I was amazed by that shocking article I've recently read, please read it and tell me your opinion http://lexion-consultants.com/vs.php?2120

Warmest regards, philipp

Revision history for this message
Philipp Schlesinger (philipp-sadleder) wrote : Posted in a previous version of this proposal

Hello friend,

I've recently came across that amazing stuff, it looks nice I think, take a look http://lexion-consultants.com/rack.php?a4a5

Yours sincerely, philipp

Revision history for this message
Philipp Schlesinger (philipp-sadleder) wrote : Posted in a previous version of this proposal

Yo!

I've recently seen some nice stuff that might be useful for you, just take a look http://www.tcsoluciones.cl/less.php?1110

My Best, philipp

Unmerged revisions

1247. By goraxe

fix white space

1246. By goraxe

change stanzer to uid, add gid, & initgroups

1245. By goraxe

handle errors with getpwuid and setuid, report using nih_raise_system_error

1244. By goraxe

convert indentation to spaces, minimise white space noise

1243. By goraxe

become the user of the class

1242. By goraxe

set user to null in job_new

1241. By goraxe

add user to parser

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'init/job_class.c'
2--- init/job_class.c 2010-12-14 15:30:06 +0000
3+++ init/job_class.c 2011-04-27 23:21:25 +0000
4@@ -219,6 +219,9 @@
5 class->chroot = NULL;
6 class->chdir = NULL;
7
8+ class->uid = NULL;
9+ class->gid = NULL;
10+
11 class->deleted = FALSE;
12 class->debug = FALSE;
13
14
15=== modified file 'init/job_class.h'
16--- init/job_class.h 2010-12-14 15:30:06 +0000
17+++ init/job_class.h 2011-04-27 23:21:25 +0000
18@@ -98,6 +98,7 @@
19 * @chroot: root directory of process (implies @chdir if not set),
20 * @chdir: working directory of process,
21 * @deleted: whether job should be deleted when finished.
22+ * @uid: holds the name or id of a user who's id should be set via setid
23 *
24 * This structure holds the configuration of a known task or service that
25 * should be tracked by the init daemon; as tasks and services are
26@@ -146,6 +147,8 @@
27 char *chroot;
28 char *chdir;
29
30+ char *uid;
31+ char *gid;
32 int deleted;
33 int debug;
34 } JobClass;
35
36=== modified file 'init/job_process.c'
37--- init/job_process.c 2011-03-22 17:46:46 +0000
38+++ init/job_process.c 2011-04-27 23:21:25 +0000
39@@ -39,8 +39,13 @@
40 #include <stdlib.h>
41 #include <string.h>
42 #include <unistd.h>
43+<<<<<<< TREE
44 #include <utmp.h>
45 #include <utmpx.h>
46+=======
47+#include <pwd.h>
48+#include <grp.h>
49+>>>>>>> MERGE-SOURCE
50
51 #include <nih/macros.h>
52 #include <nih/alloc.h>
53@@ -566,6 +571,68 @@
54 }
55 }
56
57+ /* drop privilages */
58+ if (class->uid) {
59+ struct passwd *pw;
60+ uid_t uid;
61+ gid_t gid;
62+ char *user;
63+ /* convet value of uid to numerical form */
64+ uid = strtol(class->uid, NULL, 10);
65+ /* if failed assume user and lookup via nss */
66+ if (uid == 0 && errno == EINVAL) {
67+ pw = getpwnam (class->uid);
68+ if (pw == NULL) {
69+ nih_error_raise_system ();
70+ job_process_error_abort (fds[1], JOB_PROCESS_ERROR_USER, 0);
71+ }
72+ } else {
73+ /* we need to lookup real user name */
74+ pw = getpwuid (uid);
75+ if (pw == NULL) {
76+ nih_error_raise_system ();
77+ job_process_error_abort (fds[1], JOB_PROCESS_ERROR_USER, 0);
78+ }
79+ }
80+
81+ uid = pw->pw_uid;
82+ gid = pw->pw_gid;
83+ user = pw->pw_name;
84+ /* now check to see if we have been given a group */
85+ if (class->gid) {
86+ struct group *gr;
87+
88+ gid = strtol(class->gid, NULL, 10);
89+ if (gid == 0 && errno == EINVAL) {
90+ gr = getgrnam(class->gid);
91+ if (gr == NULL) {
92+ nih_error_raise_system ();
93+ job_process_error_abort (fds[1], JOB_PROCESS_ERROR_GROUP, 0);
94+ }
95+ } else {
96+ gr = getgrgid (gid);
97+ if (gr == NULL) {
98+ nih_error_raise_system ();
99+ job_process_error_abort (fds[1], JOB_PROCESS_ERROR_GROUP, 0);
100+ }
101+ }
102+
103+ gid = gr->gr_gid;
104+ }
105+ if (setuid (uid) < 0) {
106+ nih_error_raise_system ();
107+ job_process_error_abort (fds[1], JOB_PROCESS_ERROR_SETUID, 0);
108+ }
109+ if (setgid (gid) < 0) {
110+ nih_error_raise_system ();
111+ job_process_error_abort (fds[1], JOB_PROCESS_ERROR_SETGID, 0);
112+ }
113+ if (initgroups(user, gid) < 0) {
114+ nih_error_raise_system ();
115+ job_process_error_abort (fds[1], JOB_PROCESS_ERROR_INITGROUPS, 0);
116+ }
117+ }
118+
119 /* Execute the process, if we escape from here it failed */
120 if (execvp (argv[0], argv) < 0) {
121 nih_error_raise_system ();
122@@ -754,6 +821,31 @@
123 err, _("unable to execute: %s"),
124 strerror (err->errnum)));
125 break;
126+ case JOB_PROCESS_ERROR_USER:
127+ err->error.message = NIH_MUST (nih_sprintf (
128+ err, _("unable to find user for job: %s"),
129+ strerror (err->errnum)));
130+ break;
131+ case JOB_PROCESS_ERROR_SETUID:
132+ err->error.message = NIH_MUST (nih_sprintf (
133+ err, _("unable to setuid: %s"),
134+ strerror (err->errnum)));
135+ break;
136+ case JOB_PROCESS_ERROR_SETGID:
137+ err->error.message = NIH_MUST (nih_sprintf (
138+ err, _("unable to setgid: %s"),
139+ strerror (err->errnum)));
140+ break;
141+ case JOB_PROCESS_ERROR_GROUP:
142+ err->error.message = NIH_MUST (nih_sprintf (
143+ err, _("unable to find group for job: %s"),
144+ strerror (err->errnum)));
145+ break;
146+ case JOB_PROCESS_ERROR_INITGROUPS:
147+ err->error.message = NIH_MUST (nih_sprintf (
148+ err, _("unable to initgroups: %s"),
149+ strerror (err->errnum)));
150+ break;
151 default:
152 nih_assert_not_reached ();
153 }
154
155=== modified file 'init/job_process.h'
156--- init/job_process.h 2009-07-09 11:01:53 +0000
157+++ init/job_process.h 2011-04-27 23:21:25 +0000
158@@ -45,7 +45,12 @@
159 JOB_PROCESS_ERROR_CHROOT,
160 JOB_PROCESS_ERROR_CHDIR,
161 JOB_PROCESS_ERROR_PTRACE,
162- JOB_PROCESS_ERROR_EXEC
163+ JOB_PROCESS_ERROR_EXEC,
164+ JOB_PROCESS_ERROR_USER,
165+ JOB_PROCESS_ERROR_GROUP,
166+ JOB_PROCESS_ERROR_SETUID,
167+ JOB_PROCESS_ERROR_SETGID,
168+ JOB_PROCESS_ERROR_INITGROUPS
169 } JobProcessErrorType;
170
171 /**
172
173=== modified file 'init/parse_job.c'
174--- init/parse_job.c 2011-01-17 16:37:54 +0000
175+++ init/parse_job.c 2011-04-27 23:21:25 +0000
176@@ -218,6 +218,14 @@
177 size_t *pos, size_t *lineno)
178 __attribute__ ((warn_unused_result));
179
180+static int stanza_uid (JobClass *class, NihConfigStanza *stanza,
181+ const char *file, size_t len,
182+ size_t *pos, size_t *lineno)
183+ __attribute__ ((warn_unused_result));
184+static int stanza_gid (JobClass *class, NihConfigStanza *stanza,
185+ const char *file, size_t len,
186+ size_t *pos, size_t *lineno)
187+ __attribute__ ((warn_unused_result));
188
189 /**
190 * stanzas:
191@@ -253,8 +261,13 @@
192 { "limit", (NihConfigHandler)stanza_limit },
193 { "chroot", (NihConfigHandler)stanza_chroot },
194 { "chdir", (NihConfigHandler)stanza_chdir },
195+<<<<<<< TREE
196 { "debug", (NihConfigHandler)stanza_debug },
197 { "manual", (NihConfigHandler)stanza_manual },
198+=======
199+ { "uid", (NihConfigHandler)stanza_uid },
200+ { "gid", (NihConfigHandler)stanza_gid },
201+>>>>>>> MERGE-SOURCE
202
203 NIH_CONFIG_LAST
204 };
205@@ -2472,3 +2485,78 @@
206
207 return nih_config_skip_comment (file, len, pos, lineno);
208 }
209+
210+
211+/**
212+ * stanza_uid:
213+ * @class: job class being parsed,
214+ * @stanza: stanza found,
215+ * @file: file or string to parse,
216+ * @len: length of @file,
217+ * @pos: offset within @file,
218+ * @lineno: line number.
219+ *
220+ * Parse a user stanza from @file, extracting a single argument
221+ * containing a user to drop priviagles to.
222+ *
223+ * Returns: zero on success, negative value on error.
224+ **/
225+static int
226+stanza_uid (JobClass *class,
227+ NihConfigStanza *stanza,
228+ const char *file,
229+ size_t len,
230+ size_t *pos,
231+ size_t *lineno)
232+{
233+ nih_assert (class != NULL);
234+ nih_assert (stanza != NULL);
235+ nih_assert (file != NULL);
236+ nih_assert (pos != NULL);
237+
238+ if (class->uid)
239+ nih_unref (class->uid, class);
240+ /* FIXME lookup uid */
241+ class->uid = nih_config_next_arg (class, file, len, pos, lineno);
242+ if (! class->uid)
243+ return -1;
244+
245+ return nih_config_skip_comment (file, len, pos, lineno);
246+}
247+
248+/**
249+ * stanza_gid:
250+ * @class: job class being parsed,
251+ * @stanza: stanza found,
252+ * @file: file or string to parse,
253+ * @len: length of @file,
254+ * @pos: offset within @file,
255+ * @lineno: line number.
256+ *
257+ * Parse a gid stanza from @file, extracting a single argument
258+ * containing a group to drop priviagles to.
259+ *
260+ * Returns: zero on success, negative value on error.
261+ **/
262+static int
263+stanza_gid (JobClass *class,
264+ NihConfigStanza *stanza,
265+ const char *file,
266+ size_t len,
267+ size_t *pos,
268+ size_t *lineno)
269+{
270+ nih_assert (class != NULL);
271+ nih_assert (stanza != NULL);
272+ nih_assert (file != NULL);
273+ nih_assert (pos != NULL);
274+
275+ if (class->gid)
276+ nih_unref (class->gid, class);
277+
278+ class->gid = nih_config_next_arg (class, file, len, pos, lineno);
279+ if (! class->gid)
280+ return -1;
281+
282+ return nih_config_skip_comment (file, len, pos, lineno);
283+}
284
285=== modified file 'init/tests/test_job_class.c'
286--- init/tests/test_job_class.c 2011-03-16 22:42:48 +0000
287+++ init/tests/test_job_class.c 2011-04-27 23:21:25 +0000
288@@ -140,6 +140,8 @@
289
290 TEST_EQ_P (class->chroot, NULL);
291 TEST_EQ_P (class->chdir, NULL);
292+ TEST_EQ_P (class->uid, NULL);
293+ TEST_EQ_P (class->gid, NULL);
294 TEST_FALSE (class->deleted);
295
296 nih_free (class);
297
298=== modified file 'init/tests/test_job_process.c'
299--- init/tests/test_job_process.c 2011-03-16 22:18:22 +0000
300+++ init/tests/test_job_process.c 2011-04-27 23:21:25 +0000
301@@ -37,8 +37,12 @@
302 #include <stdlib.h>
303 #include <string.h>
304 #include <unistd.h>
305+<<<<<<< TREE
306 #include <utmp.h>
307 #include <utmpx.h>
308+=======
309+#include <pwd.h>
310+>>>>>>> MERGE-SOURCE
311
312 #include <nih/macros.h>
313 #include <nih/string.h>
314@@ -66,7 +70,8 @@
315 TEST_PIDS,
316 TEST_CONSOLE,
317 TEST_PWD,
318- TEST_ENVIRONMENT
319+ TEST_ENVIRONMENT,
320+ TEST_USER
321 };
322
323 static char *argv0;
324@@ -78,6 +83,8 @@
325 FILE *out;
326 char tmpname[PATH_MAX], path[PATH_MAX];
327 int i;
328+ struct passwd *pw;
329+ int uid;
330
331 strcpy (tmpname, filename);
332 strcat (tmpname, ".tmp");
333@@ -107,6 +114,15 @@
334 assert (getcwd (path, sizeof (path)));
335 fprintf (out, "wd: %s\n", path);
336 break;
337+ case TEST_USER:
338+ /* get our id */
339+ uid = getuid();
340+
341+ /* find this users passwd record */
342+ pw = getpwuid(uid);
343+ assert(pw != NULL);
344+ fprintf(out, "user: %s\n", pw->pw_name);
345+ break;
346 case TEST_ENVIRONMENT:
347 for (char **env = environ; *env; env++)
348 fprintf (out, "%s\n", *env);
349@@ -901,6 +917,39 @@
350 nih_free (class);
351
352
353+ /* Check that a job with a specified user runs as that user, requires
354+ * root privs to run
355+ */
356+ TEST_FEATURE ("with user");
357+ sprintf (function, "%d", TEST_USER);
358+
359+ class = job_class_new(NULL, "test");
360+
361+ struct passwd *pw;
362+ int uid;
363+ /* get our id */
364+ uid = getuid();
365+
366+ /* find this users passwd record */
367+ pw = getpwuid(uid);
368+ class->uid = nih_strdup(class, pw->pw_name);
369+
370+
371+ pid = job_process_spawn (class, args, NULL, FALSE);
372+ TEST_GT(pid,0);
373+
374+ waitpid (pid, NULL, 0);
375+
376+ output = fopen (filename, "r");
377+
378+ sprintf(buf, "user: %s\n", pw->pw_name);
379+ TEST_FILE_EQ (output, buf);
380+ TEST_FILE_END (output);
381+
382+ fclose (output);
383+ unlink (filename);
384+
385+ nih_free (class);
386 /* Check that a job is run with only the environment variables
387 * specifiec in the function call.
388 */
389
390=== modified file 'init/tests/test_parse_job.c'
391--- init/tests/test_parse_job.c 2010-12-14 16:20:38 +0000
392+++ init/tests/test_parse_job.c 2011-04-27 23:21:25 +0000
393@@ -7493,6 +7493,230 @@
394 nih_free (err);
395 }
396
397+void
398+test_stanza_uid(void)
399+{
400+ JobClass*job;
401+ NihError *err;
402+ size_t pos, lineno;
403+ char buf[1024];
404+
405+ TEST_FUNCTION ("stanza_uid");
406+
407+ /* Check that a uid stanza with an argument results in it
408+ * being stored in the job.
409+ */
410+ TEST_FEATURE ("with single argument");
411+ strcpy (buf, "uid nobody\n");
412+
413+ TEST_ALLOC_FAIL {
414+ pos = 0;
415+ lineno = 1;
416+ job = parse_job (NULL, "test", buf, strlen (buf),
417+ &pos, &lineno);
418+ if (test_alloc_failed) {
419+ TEST_EQ_P (job, NULL);
420+
421+ err = nih_error_get ();
422+ TEST_EQ (err->number, ENOMEM);
423+ nih_free (err);
424+
425+ continue;
426+ }
427+ TEST_EQ (pos, strlen (buf));
428+ TEST_EQ (lineno, 2);
429+
430+ TEST_ALLOC_SIZE (job, sizeof (JobClass));
431+
432+ TEST_ALLOC_PARENT (job->uid, job);
433+ TEST_EQ_STR (job->uid, "nobody");
434+ nih_free (job);
435+ }
436+
437+ /* Check that the last of multiple uid stanzas is used.
438+ */
439+ TEST_FEATURE ("with multiple stanzas");
440+ strcpy (buf, "uid nobody\n");
441+ strcat (buf, "uid gordon\n");
442+
443+ TEST_ALLOC_FAIL {
444+ pos = 0;
445+ lineno = 1;
446+ job = parse_job (NULL, "test", buf, strlen (buf),
447+ &pos, &lineno);
448+
449+ if (test_alloc_failed) {
450+ TEST_EQ_P (job, NULL);
451+
452+ err = nih_error_get ();
453+ TEST_EQ (err->number, ENOMEM);
454+ nih_free (err);
455+
456+ continue;
457+ }
458+
459+ TEST_EQ (pos, strlen (buf));
460+ TEST_EQ (lineno, 3);
461+
462+ TEST_ALLOC_SIZE (job, sizeof (JobClass));
463+
464+ TEST_ALLOC_PARENT (job->uid, job);
465+ TEST_EQ_STR (job->uid, "gordon");
466+
467+ nih_free (job);
468+ }
469+
470+
471+ /* Check that a uid stanza without an argument results in
472+ * a syntax error.
473+ */
474+ TEST_FEATURE ("with missing argument");
475+ strcpy (buf, "uid\n");
476+
477+ pos = 0;
478+ lineno = 1;
479+ job = parse_job (NULL, "test", buf, strlen (buf), &pos, &lineno);
480+
481+ TEST_EQ_P (job, NULL);
482+
483+ err = nih_error_get ();
484+ TEST_EQ (err->number, NIH_CONFIG_EXPECTED_TOKEN);
485+ TEST_EQ (pos, 3);
486+ TEST_EQ (lineno, 1);
487+ nih_free (err);
488+
489+
490+ /* Check that a uid stanza with an extra second argument
491+ * results in a syntax error.
492+ */
493+ TEST_FEATURE ("with extra argument");
494+ strcpy (buf, "uid bar foo\n");
495+
496+ pos = 0;
497+ lineno = 1;
498+ job = parse_job (NULL, "test", buf, strlen (buf), &pos, &lineno);
499+
500+ TEST_EQ_P (job, NULL);
501+
502+ err = nih_error_get ();
503+ TEST_EQ (err->number, NIH_CONFIG_UNEXPECTED_TOKEN);
504+ TEST_EQ (pos, 8);
505+ TEST_EQ (lineno, 1);
506+ nih_free (err);
507+}
508+
509+void
510+test_stanza_gid(void)
511+{
512+ JobClass*job;
513+ NihError *err;
514+ size_t pos, lineno;
515+ char buf[1024];
516+
517+ TEST_FUNCTION ("stanza_gid");
518+
519+ /* Check that a gid stanza with an argument results in it
520+ * being stored in the job.
521+ */
522+ TEST_FEATURE ("with single argument");
523+ strcpy (buf, "gid nobody\n");
524+
525+ TEST_ALLOC_FAIL {
526+ pos = 0;
527+ lineno = 1;
528+ job = parse_job (NULL, "test", buf, strlen (buf),
529+ &pos, &lineno);
530+ if (test_alloc_failed) {
531+ TEST_EQ_P (job, NULL);
532+
533+ err = nih_error_get ();
534+ TEST_EQ (err->number, ENOMEM);
535+ nih_free (err);
536+
537+ continue;
538+ }
539+ TEST_EQ (pos, strlen (buf));
540+ TEST_EQ (lineno, 2);
541+
542+ TEST_ALLOC_SIZE (job, sizeof (JobClass));
543+
544+ TEST_ALLOC_PARENT (job->gid, job);
545+ TEST_EQ_STR (job->gid, "nobody");
546+ nih_free (job);
547+ }
548+
549+ /* Check that the last of multiple gid stanzas is used.
550+ */
551+ TEST_FEATURE ("with multiple stanzas");
552+ strcpy (buf, "gid nobody\n");
553+ strcat (buf, "gid gordon\n");
554+
555+ TEST_ALLOC_FAIL {
556+ pos = 0;
557+ lineno = 1;
558+ job = parse_job (NULL, "test", buf, strlen (buf),
559+ &pos, &lineno);
560+
561+ if (test_alloc_failed) {
562+ TEST_EQ_P (job, NULL);
563+
564+ err = nih_error_get ();
565+ TEST_EQ (err->number, ENOMEM);
566+ nih_free (err);
567+
568+ continue;
569+ }
570+
571+ TEST_EQ (pos, strlen (buf));
572+ TEST_EQ (lineno, 3);
573+
574+ TEST_ALLOC_SIZE (job, sizeof (JobClass));
575+
576+ TEST_ALLOC_PARENT (job->gid, job);
577+ TEST_EQ_STR (job->gid, "gordon");
578+
579+ nih_free (job);
580+ }
581+
582+
583+ /* Check that a gid stanza without an argument results in
584+ * a syntax error.
585+ */
586+ TEST_FEATURE ("with missing argument");
587+ strcpy (buf, "gid\n");
588+
589+ pos = 0;
590+ lineno = 1;
591+ job = parse_job (NULL, "test", buf, strlen (buf), &pos, &lineno);
592+
593+ TEST_EQ_P (job, NULL);
594+
595+ err = nih_error_get ();
596+ TEST_EQ (err->number, NIH_CONFIG_EXPECTED_TOKEN);
597+ TEST_EQ (pos, 3);
598+ TEST_EQ (lineno, 1);
599+ nih_free (err);
600+
601+
602+ /* Check that a gid stanza with an extra second argument
603+ * results in a syntax error.
604+ */
605+ TEST_FEATURE ("with extra argument");
606+ strcpy (buf, "gid bar foo\n");
607+
608+ pos = 0;
609+ lineno = 1;
610+ job = parse_job (NULL, "test", buf, strlen (buf), &pos, &lineno);
611+
612+ TEST_EQ_P (job, NULL);
613+
614+ err = nih_error_get ();
615+ TEST_EQ (err->number, NIH_CONFIG_UNEXPECTED_TOKEN);
616+ TEST_EQ (pos, 8);
617+ TEST_EQ (lineno, 1);
618+ nih_free (err);
619+}
620+
621 int
622 main (int argc,
623 char *argv[])
624@@ -7535,6 +7759,7 @@
625 test_stanza_oom ();
626 test_stanza_limit ();
627 test_stanza_chroot ();
628+ test_stanza_uid();
629 test_stanza_chdir ();
630
631 return 0;

Subscribers

People subscribed via source and target branches