return r;
}
-static int connect_logger_as(const ExecContext *context, ExecOutput output, const char *ident, const char *unit_id, int nfd) {
- int fd, r;
+static int connect_journal_socket(int fd, uid_t uid, gid_t gid) {
union sockaddr_union sa = {
.un.sun_family = AF_UNIX,
.un.sun_path = "/run/systemd/journal/stdout",
};
+ uid_t olduid = UID_INVALID;
+ gid_t oldgid = GID_INVALID;
+ int r;
+
+ if (gid != GID_INVALID) {
+ oldgid = getgid();
+
+ r = setegid(gid);
+ if (r < 0)
+ return -errno;
+ }
+
+ if (uid != UID_INVALID) {
+ olduid = getuid();
+
+ r = seteuid(uid);
+ if (r < 0) {
+ r = -errno;
+ goto restore_gid;
+ }
+ }
+
+ r = connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path));
+ if (r < 0)
+ r = -errno;
+
+ /* If we fail to restore the uid or gid, things will likely
+ fail later on. This should only happen if an LSM interferes. */
+
+ if (uid != UID_INVALID)
+ (void) seteuid(olduid);
+
+ restore_gid:
+ if (gid != GID_INVALID)
+ (void) setegid(oldgid);
+
+ return r;
+}
+
+static int connect_logger_as(const ExecContext *context, ExecOutput output, const char *ident, const char *unit_id, int nfd, uid_t uid, gid_t gid) {
+ int fd, r;
assert(context);
assert(output < _EXEC_OUTPUT_MAX);
if (fd < 0)
return -errno;
- r = connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path));
- if (r < 0) {
- safe_close(fd);
- return -errno;
- }
+ r = connect_journal_socket(fd, uid, gid);
+ if (r < 0)
+ return r;
if (shutdown(fd, SHUT_RD) < 0) {
safe_close(fd);
}
}
-static int setup_output(const ExecContext *context, int fileno, int socket_fd, const char *ident, const char *unit_id, bool apply_tty_stdin) {
+static int setup_output(const ExecContext *context, int fileno, int socket_fd, const char *ident, const char *unit_id, bool apply_tty_stdin, uid_t uid, gid_t gid) {
ExecOutput o;
ExecInput i;
int r;
case EXEC_OUTPUT_KMSG_AND_CONSOLE:
case EXEC_OUTPUT_JOURNAL:
case EXEC_OUTPUT_JOURNAL_AND_CONSOLE:
- r = connect_logger_as(context, o, ident, unit_id, fileno);
+ r = connect_logger_as(context, o, ident, unit_id, fileno, uid, gid);
if (r < 0) {
log_unit_struct(unit_id,
- LOG_CRIT,
+ LOG_ERR,
LOG_MESSAGE("Failed to connect %s of %s to the journal socket: %s",
fileno == STDOUT_FILENO ? "stdout" : "stderr",
unit_id, strerror(-r)),
* daemon. We do things this way to ensure that the main PID
* of the daemon is the one we initially fork()ed. */
- if (log_get_max_level() < LOG_PRI(LOG_DEBUG))
+ if (log_get_max_level() < LOG_DEBUG)
flags |= PAM_SILENT;
pam_code = pam_start(name, user, &conv, &handle);
}
}
+ if (context->user) {
+ username = context->user;
+ err = get_user_creds(&username, &uid, &gid, &home, &shell);
+ if (err < 0) {
+ *error = EXIT_USER;
+ return err;
+ }
+ }
+
/* If a socket is connected to STDIN/STDOUT/STDERR, we
* must sure to drop O_NONBLOCK */
if (socket_fd >= 0)
return err;
}
- err = setup_output(context, STDOUT_FILENO, socket_fd, basename(command->path), params->unit_id, params->apply_tty_stdin);
+ err = setup_output(context, STDOUT_FILENO, socket_fd, basename(command->path), params->unit_id, params->apply_tty_stdin, uid, gid);
if (err < 0) {
*error = EXIT_STDOUT;
return err;
}
- err = setup_output(context, STDERR_FILENO, socket_fd, basename(command->path), params->unit_id, params->apply_tty_stdin);
+ err = setup_output(context, STDERR_FILENO, socket_fd, basename(command->path), params->unit_id, params->apply_tty_stdin, uid, gid);
if (err < 0) {
*error = EXIT_STDERR;
return err;
if (context->utmp_id)
utmp_put_init_process(context->utmp_id, getpid(), getsid(0), context->tty_path);
- if (context->user) {
- username = context->user;
- err = get_user_creds(&username, &uid, &gid, &home, &shell);
+ if (context->user && is_terminal_input(context->std_input)) {
+ err = chown_terminal(STDIN_FILENO, uid);
if (err < 0) {
- *error = EXIT_USER;
+ *error = EXIT_STDIN;
return err;
}
-
- if (is_terminal_input(context->std_input)) {
- err = chown_terminal(STDIN_FILENO, uid);
- if (err < 0) {
- *error = EXIT_STDIN;
- return err;
- }
- }
}
#ifdef ENABLE_KDBUS
final_env = strv_env_clean(final_env);
- if (_unlikely_(log_get_max_level() >= LOG_PRI(LOG_DEBUG))) {
+ if (_unlikely_(log_get_max_level() >= LOG_DEBUG)) {
_cleanup_free_ char *line;
line = exec_command_line(final_argv);
c[i] = exec_command_free_list(c[i]);
}
+typedef struct InvalidEnvInfo {
+ const char *unit_id;
+ const char *path;
+} InvalidEnvInfo;
+
+static void invalid_env(const char *p, void *userdata) {
+ InvalidEnvInfo *info = userdata;
+
+ log_unit_error(info->unit_id, "Ignoring invalid environment assignment '%s': %s", p, info->path);
+}
+
int exec_context_load_environment(const ExecContext *c, const char *unit_id, char ***l) {
char **i, **r = NULL;
return k;
}
/* Log invalid environment variables with filename */
- if (p)
- p = strv_env_clean_log(p, unit_id, pglob.gl_pathv[n]);
+ if (p) {
+ InvalidEnvInfo info = {
+ .unit_id = unit_id,
+ .path = pglob.gl_pathv[n]
+ };
+
+ p = strv_env_clean_with_callback(p, invalid_env, &info);
+ }
if (r == NULL)
r = p;