On Tue, Dec 1, 2009 at 10:38 PM, Scott James Remnant <[email protected]> wrote:

> I've deliberately omitted this functionality for now, because it's far,
> far more complex than just adding a setuid() call to the child process.
>
> Things like PAM sessions, users being able to start/stop their own jobs,
> etc. all come into play.

Hmm, some sort of basic draft attached. Any pointers where
this goes wrong?


-- 
// Janne
Index: upstart/init/job_class.h
===================================================================
--- upstart.orig/init/job_class.h
+++ upstart/init/job_class.h
@@ -91,6 +91,8 @@ typedef enum console_type {
  * @normalexit: array of exit codes that prevent a respawn,
  * @normalexit_len: length of @normalexit array,
  * @console: how to arrange processes' stdin/out/err file descriptors,
+ * @uid: user ID,
+ * @gid: group ID,
  * @umask: file mode creation mask,
  * @nice: process priority,
  * @oom_adj: OOM killer adjustment,
@@ -139,6 +141,8 @@ typedef struct job_class {
 
 	ConsoleType     console;
 
+	uid_t           uid;
+	gid_t           gid;
 	mode_t          umask;
 	int             nice;
 	int             oom_adj;
Index: upstart/init/job_class.c
===================================================================
--- upstart.orig/init/job_class.c
+++ upstart/init/job_class.c
@@ -208,6 +208,8 @@ job_class_new (const void *parent,
 
 	class->console = CONSOLE_NONE;
 
+	class->uid = 0;
+	class->gid = 0;
 	class->umask = JOB_DEFAULT_UMASK;
 	class->nice = 0;
 	class->oom_adj = 0;
Index: upstart/init/job_process.c
===================================================================
--- upstart.orig/init/job_process.c
+++ upstart/init/job_process.c
@@ -548,6 +548,22 @@ job_process_spawn (JobClass     *class,
 		}
 	}
 
+	/* set uid & gid */
+	if (class->gid) {
+		if (setgid (class->gid)) {
+			nih_error_raise_system ();
+			job_process_error_abort (fds[1],
+						 JOB_PROCESS_ERROR_SETGID, 0);
+		}
+	}
+	if (class->uid) {
+		if (setuid (class->uid)) {
+			nih_error_raise_system ();
+			job_process_error_abort (fds[1],
+						 JOB_PROCESS_ERROR_SETUID, 0);
+		}
+	}
+
 	/* Execute the process, if we escape from here it failed */
 	if (execvp (argv[0], argv) < 0) {
 		nih_error_raise_system ();
Index: upstart/init/job_process.h
===================================================================
--- upstart.orig/init/job_process.h
+++ upstart/init/job_process.h
@@ -45,6 +45,8 @@ typedef enum job_process_error_type {
 	JOB_PROCESS_ERROR_CHROOT,
 	JOB_PROCESS_ERROR_CHDIR,
 	JOB_PROCESS_ERROR_PTRACE,
+	JOB_PROCESS_ERROR_SETGID,
+	JOB_PROCESS_ERROR_SETUID,
 	JOB_PROCESS_ERROR_EXEC
 } JobProcessErrorType;
 
Index: upstart/init/parse_job.c
===================================================================
--- upstart.orig/init/parse_job.c
+++ upstart/init/parse_job.c
@@ -31,6 +31,8 @@
 #include <limits.h>
 #include <stdlib.h>
 #include <string.h>
+#include <pwd.h>
+#include <grp.h>
 
 #include <nih/macros.h>
 #include <nih/alloc.h>
@@ -185,6 +187,22 @@ static int stanza_console     (JobClass 
 			       size_t *pos, size_t *lineno)
 	__attribute__ ((warn_unused_result));
 
+static int stanza_user        (JobClass *class, NihConfigStanza *stanza,
+			       const char *file, size_t len,
+			       size_t *pos, size_t *lineno)
+	__attribute__ ((warn_unused_result));
+static int stanza_group       (JobClass *class, NihConfigStanza *stanza,
+			       const char *file, size_t len,
+			       size_t *pos, size_t *lineno)
+	__attribute__ ((warn_unused_result));
+static int stanza_uid         (JobClass *class, NihConfigStanza *stanza,
+			       const char *file, size_t len,
+			       size_t *pos, size_t *lineno)
+	__attribute__ ((warn_unused_result));
+static int stanza_gid         (JobClass *class, NihConfigStanza *stanza,
+			       const char *file, size_t len,
+			       size_t *pos, size_t *lineno)
+	__attribute__ ((warn_unused_result));
 static int stanza_umask       (JobClass *class, NihConfigStanza *stanza,
 			       const char *file, size_t len,
 			       size_t *pos, size_t *lineno)
@@ -243,6 +261,10 @@ static NihConfigStanza stanzas[] = {
 	{ "respawn",     (NihConfigHandler)stanza_respawn     },
 	{ "normal",      (NihConfigHandler)stanza_normal      },
 	{ "console",     (NihConfigHandler)stanza_console     },
+	{ "user",        (NihConfigHandler)stanza_user        },
+	{ "group",       (NihConfigHandler)stanza_group       },
+	{ "uid",         (NihConfigHandler)stanza_uid         },
+	{ "gid",         (NihConfigHandler)stanza_gid         },
 	{ "umask",       (NihConfigHandler)stanza_umask       },
 	{ "nice",        (NihConfigHandler)stanza_nice        },
 	{ "oom",         (NihConfigHandler)stanza_oom         },
@@ -2023,6 +2045,228 @@ finish:
 
 
 /**
+ * stanza_user:
+ * @class: job class being parsed,
+ * @stanza: stanza found,
+ * @file: file or string to parse,
+ * @len: length of @file,
+ * @pos: offset within @file,
+ * @lineno: line number.
+ *
+ * Parse a user stanza from @file, extracting a single argument containing
+ * a username.
+ *
+ * Returns: zero on success, negative value on error.
+ **/
+static int
+stanza_user (JobClass        *class,
+	     NihConfigStanza *stanza,
+	     const char      *file,
+	     size_t           len,
+	     size_t          *pos,
+	     size_t          *lineno)
+{
+	nih_local char *arg = NULL;
+	size_t          a_pos, a_lineno;
+	int             ret = -1;
+	struct passwd  *pw_entry;
+
+	nih_assert (class != NULL);
+	nih_assert (stanza != NULL);
+	nih_assert (file != NULL);
+	nih_assert (pos != NULL);
+
+	a_pos = *pos;
+	a_lineno = (lineno ? *lineno : 1);
+
+	arg = nih_config_next_arg (NULL, file, len, &a_pos, &a_lineno);
+	if (! arg)
+		goto finish;
+
+	pw_entry = getpwnam(arg);
+	if (!pw_entry)
+		nih_return_error (-1, PARSE_ILLEGAL_USER,
+				  _(PARSE_ILLEGAL_USER_STR));
+
+	class->uid = pw_entry->pw_uid;
+
+	ret = nih_config_skip_comment (file, len, &a_pos, &a_lineno);
+
+finish:
+	*pos = a_pos;
+	if (lineno)
+		*lineno = a_lineno;
+
+	return ret;
+}
+
+/**
+ * stanza_group:
+ * @class: job class being parsed,
+ * @stanza: stanza found,
+ * @file: file or string to parse,
+ * @len: length of @file,
+ * @pos: offset within @file,
+ * @lineno: line number.
+ *
+ * Parse a group stanza from @file, extracting a single argument containing
+ * a groupname.
+ *
+ * Returns: zero on success, negative value on error.
+ **/
+static int
+stanza_group (JobClass        *class,
+	      NihConfigStanza *stanza,
+	      const char      *file,
+	      size_t           len,
+	      size_t          *pos,
+	      size_t          *lineno)
+{
+	nih_local char *arg = NULL;
+	size_t          a_pos, a_lineno;
+	int             ret = -1;
+	struct group   *gr_entry;
+
+	nih_assert (class != NULL);
+	nih_assert (stanza != NULL);
+	nih_assert (file != NULL);
+	nih_assert (pos != NULL);
+
+	a_pos = *pos;
+	a_lineno = (lineno ? *lineno : 1);
+
+	arg = nih_config_next_arg (NULL, file, len, &a_pos, &a_lineno);
+	if (! arg)
+		goto finish;
+
+	gr_entry = getgrnam(arg);
+	if (!gr_entry)
+		nih_return_error (-1, PARSE_ILLEGAL_GROUP,
+				  _(PARSE_ILLEGAL_GROUP_STR));
+
+	class->gid = gr_entry->gr_gid;
+
+	ret = nih_config_skip_comment (file, len, &a_pos, &a_lineno);
+
+finish:
+	*pos = a_pos;
+	if (lineno)
+		*lineno = a_lineno;
+
+	return ret;
+}
+
+/**
+ * stanza_uid:
+ * @class: job class being parsed,
+ * @stanza: stanza found,
+ * @file: file or string to parse,
+ * @len: length of @file,
+ * @pos: offset within @file,
+ * @lineno: line number.
+ *
+ * Parse a gid stanza from @file, extracting a single argument containing
+ * a user ID.
+ *
+ * Returns: zero on success, negative value on error.
+ **/
+static int
+stanza_uid (JobClass        *class,
+	    NihConfigStanza *stanza,
+	    const char      *file,
+	    size_t           len,
+	    size_t          *pos,
+	    size_t          *lineno)
+{
+	nih_local char *arg = NULL;
+	char           *endptr;
+	size_t          a_pos, a_lineno;
+	int             ret = -1;
+
+	nih_assert (class != NULL);
+	nih_assert (stanza != NULL);
+	nih_assert (file != NULL);
+	nih_assert (pos != NULL);
+
+	a_pos = *pos;
+	a_lineno = (lineno ? *lineno : 1);
+
+	arg = nih_config_next_arg (NULL, file, len, &a_pos, &a_lineno);
+	if (! arg)
+		goto finish;
+
+	errno = 0;
+	class->uid = (uid_t)strtoul (arg, &endptr, 10);
+	if (errno || *endptr)
+		nih_return_error (-1, PARSE_ILLEGAL_UID,
+				  _(PARSE_ILLEGAL_UID_STR));
+
+	ret = nih_config_skip_comment (file, len, &a_pos, &a_lineno);
+
+finish:
+	*pos = a_pos;
+	if (lineno)
+		*lineno = a_lineno;
+
+	return ret;
+}
+
+/**
+ * stanza_gid:
+ * @class: job class being parsed,
+ * @stanza: stanza found,
+ * @file: file or string to parse,
+ * @len: length of @file,
+ * @pos: offset within @file,
+ * @lineno: line number.
+ *
+ * Parse a gid stanza from @file, extracting a single argument containing
+ * a group ID.
+ *
+ * Returns: zero on success, negative value on error.
+ **/
+static int
+stanza_gid (JobClass        *class,
+	    NihConfigStanza *stanza,
+	    const char      *file,
+	    size_t           len,
+	    size_t          *pos,
+	    size_t          *lineno)
+{
+	nih_local char *arg = NULL;
+	char           *endptr;
+	size_t          a_pos, a_lineno;
+	int             ret = -1;
+
+	nih_assert (class != NULL);
+	nih_assert (stanza != NULL);
+	nih_assert (file != NULL);
+	nih_assert (pos != NULL);
+
+	a_pos = *pos;
+	a_lineno = (lineno ? *lineno : 1);
+
+	arg = nih_config_next_arg (NULL, file, len, &a_pos, &a_lineno);
+	if (! arg)
+		goto finish;
+
+	errno = 0;
+	class->gid = (gid_t)strtoul (arg, &endptr, 10);
+	if (errno || *endptr)
+		nih_return_error (-1, PARSE_ILLEGAL_GID,
+				  _(PARSE_ILLEGAL_GID_STR));
+
+	ret = nih_config_skip_comment (file, len, &a_pos, &a_lineno);
+
+finish:
+	*pos = a_pos;
+	if (lineno)
+		*lineno = a_lineno;
+
+	return ret;
+}
+
+/**
  * stanza_umask:
  * @class: job class being parsed,
  * @stanza: stanza found,
Index: upstart/init/errors.h
===================================================================
--- upstart.orig/init/errors.h
+++ upstart/init/errors.h
@@ -40,6 +40,10 @@ enum {
 	/* Errors while parsing configuration files */
 	PARSE_ILLEGAL_INTERVAL,
 	PARSE_ILLEGAL_EXIT,
+	PARSE_ILLEGAL_USER,
+	PARSE_ILLEGAL_GROUP,
+	PARSE_ILLEGAL_UID,
+	PARSE_ILLEGAL_GID,
 	PARSE_ILLEGAL_UMASK,
 	PARSE_ILLEGAL_NICE,
 	PARSE_ILLEGAL_OOM,
@@ -60,9 +64,13 @@ enum {
 #define ENVIRON_MISMATCHED_BRACES_STR	N_("Mismatched braces")
 #define PARSE_ILLEGAL_INTERVAL_STR	N_("Illegal interval, expected number of seconds")
 #define PARSE_ILLEGAL_EXIT_STR		N_("Illegal exit status, expected integer")
+#define PARSE_ILLEGAL_USER_STR		N_("Illegal username")
+#define PARSE_ILLEGAL_GROUP_STR		N_("Illegal groupname")
+#define PARSE_ILLEGAL_UID_STR		N_("Illegal user ID, expected integer")
+#define PARSE_ILLEGAL_GID_STR		N_("Illegal group ID, expected integer")
 #define PARSE_ILLEGAL_UMASK_STR		N_("Illegal file creation mask, expected octal integer")
 #define PARSE_ILLEGAL_NICE_STR		N_("Illegal nice value, expected -20 to 19")
-#define PARSE_ILLEGAL_OOM_STR		N_("Illegal oom adjustment, expected -16 to 15 or never")
+#define PARSE_ILLEGAL_OOM_STR		N_("Illegal oom adjustment, expected -16 to 15 or 'never'")
 #define PARSE_ILLEGAL_LIMIT_STR		N_("Illegal limit, expected 'unlimited' or integer")
 #define PARSE_EXPECTED_EVENT_STR	N_("Expected event")
 #define PARSE_EXPECTED_OPERATOR_STR	N_("Expected operator")
-- 
upstart-devel mailing list
[email protected]
Modify settings or unsubscribe at: 
https://lists.ubuntu.com/mailman/listinfo/upstart-devel

Reply via email to