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