chiark / gitweb /
exec: hangup/reset/deallocate VTs in gettys
[elogind.git] / src / execute.c
index 1e376ff89e08beacdf46aa344e3a2128f9bde6ac..a62f9dbbc64fb149e3c8cffef3cec7968216089f 100644 (file)
@@ -140,6 +140,19 @@ static const char *tty_path(const ExecContext *context) {
         return "/dev/console";
 }
 
+void exec_context_tty_reset(const ExecContext *context) {
+        assert(context);
+
+        if (context->tty_vhangup)
+                terminal_vhangup(tty_path(context));
+
+        if (context->tty_reset)
+                reset_terminal(tty_path(context));
+
+        if (context->tty_vt_disallocate && context->tty_path)
+                vt_disallocate(context->tty_path);
+}
+
 static int open_null_as(int flags, int nfd) {
         int fd, r;
 
@@ -904,6 +917,68 @@ fail:
 }
 #endif
 
+static int do_capability_bounding_set_drop(uint64_t drop) {
+        unsigned long i;
+        cap_t old_cap = NULL, new_cap = NULL;
+        cap_flag_value_t fv;
+        int r;
+
+        /* If we are run as PID 1 we will lack CAP_SETPCAP by default
+         * in the effective set (yes, the kernel drops that when
+         * executing init!), so get it back temporarily so that we can
+         * call PR_CAPBSET_DROP. */
+
+        old_cap = cap_get_proc();
+        if (!old_cap)
+                return -errno;
+
+        if (cap_get_flag(old_cap, CAP_SETPCAP, CAP_EFFECTIVE, &fv) < 0) {
+                r = -errno;
+                goto finish;
+        }
+
+        if (fv != CAP_SET) {
+                static const cap_value_t v = CAP_SETPCAP;
+
+                new_cap = cap_dup(old_cap);
+                if (!new_cap) {
+                        r = -errno;
+                        goto finish;
+                }
+
+                if (cap_set_flag(new_cap, CAP_EFFECTIVE, 1, &v, CAP_SET) < 0) {
+                        r = -errno;
+                        goto finish;
+                }
+
+                if (cap_set_proc(new_cap) < 0) {
+                        r = -errno;
+                        goto finish;
+                }
+        }
+
+        for (i = 0; i <= CAP_LAST_CAP; i++)
+                if (drop & ((uint64_t) 1ULL << (uint64_t) i)) {
+                        if (prctl(PR_CAPBSET_DROP, i) < 0) {
+                                r = -errno;
+                                goto finish;
+                        }
+                }
+
+        r = 0;
+
+finish:
+        if (new_cap)
+                cap_free(new_cap);
+
+        if (old_cap) {
+                cap_set_proc(old_cap);
+                cap_free(old_cap);
+        }
+
+        return r;
+}
+
 int exec_spawn(ExecCommand *command,
                char **argv,
                const ExecContext *context,
@@ -1027,6 +1102,8 @@ int exec_spawn(ExecCommand *command,
                         }
                 }
 
+                exec_context_tty_reset(context);
+
                 /* We skip the confirmation step if we shall not apply the TTY */
                 if (confirm_spawn &&
                     (!is_terminal_input(context->std_input) || apply_tty_stdin)) {
@@ -1251,13 +1328,10 @@ int exec_spawn(ExecCommand *command,
                         }
 
                         if (context->capability_bounding_set_drop)
-                                for (i = 0; i <= CAP_LAST_CAP; i++)
-                                        if (context->capability_bounding_set_drop & ((uint64_t) 1ULL << (uint64_t) i)) {
-                                                if (prctl(PR_CAPBSET_DROP, i) < 0) {
-                                                        r = EXIT_CAPABILITIES;
-                                                        goto fail_child;
-                                                }
-                                        }
+                                if (do_capability_bounding_set_drop(context->capability_bounding_set_drop) < 0) {
+                                        r = EXIT_CAPABILITIES;
+                                        goto fail_child;
+                                }
 
                         if (context->user)
                                 if (enforce_user(context, uid) < 0) {
@@ -1641,8 +1715,14 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
 
         if (c->tty_path)
                 fprintf(f,
-                        "%sTTYPath: %s\n",
-                        prefix, c->tty_path);
+                        "%sTTYPath: %s\n"
+                        "%sTTYReset: %s\n"
+                        "%sTTYVHangup: %s\n"
+                        "%sTTYVTDisallocate: %s\n",
+                        prefix, c->tty_path,
+                        prefix, yes_no(c->tty_reset),
+                        prefix, yes_no(c->tty_vhangup),
+                        prefix, yes_no(c->tty_vt_disallocate));
 
         if (c->std_output == EXEC_OUTPUT_SYSLOG || c->std_output == EXEC_OUTPUT_KMSG ||
             c->std_output == EXEC_OUTPUT_SYSLOG_AND_CONSOLE || c->std_output == EXEC_OUTPUT_KMSG_AND_CONSOLE ||
@@ -1743,7 +1823,7 @@ void exec_status_start(ExecStatus *s, pid_t pid) {
         dual_timestamp_get(&s->start_timestamp);
 }
 
-void exec_status_exit(ExecStatus *s, pid_t pid, int code, int status, const char *utmp_id) {
+void exec_status_exit(ExecStatus *s, ExecContext *context, pid_t pid, int code, int status) {
         assert(s);
 
         if ((s->pid && s->pid != pid) ||
@@ -1756,8 +1836,12 @@ void exec_status_exit(ExecStatus *s, pid_t pid, int code, int status, const char
         s->code = code;
         s->status = status;
 
-        if (utmp_id)
-                utmp_put_dead_process(utmp_id, pid, code, status);
+        if (context) {
+                if (context->utmp_id)
+                        utmp_put_dead_process(context->utmp_id, pid, code, status);
+
+                exec_context_tty_reset(context);
+        }
 }
 
 void exec_status_dump(ExecStatus *s, FILE *f, const char *prefix) {