chiark / gitweb /
login: fix memory-leak on DropController()
[elogind.git] / src / login / logind-session.c
index 9a541013017f7cf75faa46edee7519932b89c219..0c6e425603830f2bf74bef83523bc7fe1146de48 100644 (file)
 
 static void session_remove_fifo(Session *s);
 
-static unsigned long devt_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) {
-        uint64_t u = *(const dev_t*)p;
-
-        return uint64_hash_func(&u, hash_key);
-}
-
-static int devt_compare_func(const void *_a, const void *_b) {
-        dev_t a, b;
-
-        a = *(const dev_t*) _a;
-        b = *(const dev_t*) _b;
-
-        return a < b ? -1 : (a > b ? 1 : 0);
-}
-
 Session* session_new(Manager *m, const char *id) {
         Session *s;
 
@@ -153,8 +138,6 @@ void session_free(Session *s) {
 
         hashmap_remove(s->manager->sessions, s->id);
 
-        s->vt_source = sd_event_source_unref(s->vt_source);
-
         free(s->state_file);
         free(s);
 }
@@ -213,7 +196,6 @@ int session_save(Session *s) {
 
         if (s->scope)
                 fprintf(f, "SCOPE=%s\n", s->scope);
-
         if (s->scope_job)
                 fprintf(f, "SCOPE_JOB=%s\n", s->scope_job);
 
@@ -229,17 +211,54 @@ int session_save(Session *s) {
         if (s->display)
                 fprintf(f, "DISPLAY=%s\n", s->display);
 
-        if (s->remote_host)
-                fprintf(f, "REMOTE_HOST=%s\n", s->remote_host);
+        if (s->remote_host) {
+                _cleanup_free_ char *escaped;
 
-        if (s->remote_user)
-                fprintf(f, "REMOTE_USER=%s\n", s->remote_user);
+                escaped = cescape(s->remote_host);
+                if (!escaped) {
+                        r = -ENOMEM;
+                        goto finish;
+                }
+
+                fprintf(f, "REMOTE_HOST=%s\n", escaped);
+        }
+
+        if (s->remote_user) {
+                _cleanup_free_ char *escaped;
 
-        if (s->service)
-                fprintf(f, "SERVICE=%s\n", s->service);
+                escaped = cescape(s->remote_user);
+                if (!escaped) {
+                        r = -ENOMEM;
+                        goto finish;
+                }
+
+                fprintf(f, "REMOTE_USER=%s\n", escaped);
+        }
 
-        if (s->desktop)
-                fprintf(f, "DESKTOP=%s\n", s->desktop);
+        if (s->service) {
+                _cleanup_free_ char *escaped;
+
+                escaped = cescape(s->service);
+                if (!escaped) {
+                        r = -ENOMEM;
+                        goto finish;
+                }
+
+                fprintf(f, "SERVICE=%s\n", escaped);
+        }
+
+        if (s->desktop) {
+                _cleanup_free_ char *escaped;
+
+
+                escaped = cescape(s->desktop);
+                if (!escaped) {
+                        r = -ENOMEM;
+                        goto finish;
+                }
+
+                fprintf(f, "DESKTOP=%s\n", escaped);
+        }
 
         if (s->seat && seat_has_vts(s->seat))
                 fprintf(f, "VTNR=%u\n", s->vtnr);
@@ -942,8 +961,8 @@ int session_kill(Session *s, KillWho who, int signo) {
 static int session_open_vt(Session *s) {
         char path[sizeof("/dev/tty") + DECIMAL_STR_MAX(s->vtnr)];
 
-        if (!s->vtnr)
-                return -1;
+        if (s->vtnr < 1)
+                return -ENODEV;
 
         if (s->vtfd >= 0)
                 return s->vtfd;
@@ -958,59 +977,56 @@ static int session_open_vt(Session *s) {
         return s->vtfd;
 }
 
-static int session_vt_fn(sd_event_source *source, const struct signalfd_siginfo *si, void *data) {
-        Session *s = data;
-
-        if (s->vtfd >= 0)
-                ioctl(s->vtfd, VT_RELDISP, 1);
-
-        return 0;
-}
-
-void session_prepare_vt(Session *s) {
+int session_prepare_vt(Session *s) {
         int vt, r;
         struct vt_mode mode = { 0 };
-        sigset_t mask;
+
+        if (s->vtnr < 1)
+                return 0;
 
         vt = session_open_vt(s);
         if (vt < 0)
-                return;
+                return vt;
 
         r = fchown(vt, s->user->uid, -1);
-        if (r < 0)
+        if (r < 0) {
+                r = -errno;
+                log_error("Cannot change owner of /dev/tty%u: %m", s->vtnr);
                 goto error;
+        }
 
         r = ioctl(vt, KDSKBMODE, K_OFF);
-        if (r < 0)
+        if (r < 0) {
+                r = -errno;
+                log_error("Cannot set K_OFF on /dev/tty%u: %m", s->vtnr);
                 goto error;
+        }
 
         r = ioctl(vt, KDSETMODE, KD_GRAPHICS);
-        if (r < 0)
-                goto error;
-
-        sigemptyset(&mask);
-        sigaddset(&mask, SIGUSR1);
-        sigprocmask(SIG_BLOCK, &mask, NULL);
-
-        r = sd_event_add_signal(s->manager->event, &s->vt_source, SIGUSR1, session_vt_fn, s);
-        if (r < 0)
+        if (r < 0) {
+                r = -errno;
+                log_error("Cannot set KD_GRAPHICS on /dev/tty%u: %m", s->vtnr);
                 goto error;
+        }
 
         /* Oh, thanks to the VT layer, VT_AUTO does not work with KD_GRAPHICS.
          * So we need a dummy handler here which just acknowledges *all* VT
          * switch requests. */
         mode.mode = VT_PROCESS;
-        mode.relsig = SIGUSR1;
-        mode.acqsig = SIGUSR1;
+        mode.relsig = SIGRTMIN;
+        mode.acqsig = SIGRTMIN + 1;
         r = ioctl(vt, VT_SETMODE, &mode);
-        if (r < 0)
+        if (r < 0) {
+                r = -errno;
+                log_error("Cannot set VT_PROCESS on /dev/tty%u: %m", s->vtnr);
                 goto error;
+        }
 
-        return;
+        return 0;
 
 error:
-        log_error("cannot mute VT %u for session %s (%d/%d)", s->vtnr, s->id, r, errno);
         session_restore_vt(s);
+        return r;
 }
 
 void session_restore_vt(Session *s) {
@@ -1022,8 +1038,6 @@ void session_restore_vt(Session *s) {
         if (vt < 0)
                 return;
 
-        s->vt_source = sd_event_source_unref(s->vt_source);
-
         ioctl(vt, KDSETMODE, KD_TEXT);
 
         if (read_one_line_file("/sys/module/vt/parameters/default_utf8", &utf8) >= 0 && *utf8 == '1')
@@ -1047,11 +1061,13 @@ bool session_is_controller(Session *s, const char *sender) {
 
 static void session_swap_controller(Session *s, char *name) {
         SessionDevice *sd;
+        char *c;
 
         if (s->controller) {
-                manager_drop_busname(s->manager, s->controller);
-                free(s->controller);
+                c = s->controller;
                 s->controller = NULL;
+                manager_drop_busname(s->manager, c);
+                free(c);
 
                 /* Drop all devices as they're now unused. Do that after the
                  * controller is released to avoid sending out useles
@@ -1089,8 +1105,6 @@ int session_set_controller(Session *s, const char *sender, bool force) {
                 return r;
         }
 
-        session_swap_controller(s, t);
-
         /* When setting a session controller, we forcibly mute the VT and set
          * it into graphics-mode. Applications can override that by changing
          * VT state after calling TakeControl(). However, this serves as a good
@@ -1099,7 +1113,11 @@ int session_set_controller(Session *s, const char *sender, bool force) {
          * exits.
          * If logind crashes/restarts, we restore the controller during restart
          * or reset the VT in case it crashed/exited, too. */
-        session_prepare_vt(s);
+        r = session_prepare_vt(s);
+        if (r < 0)
+                return r;
+
+        session_swap_controller(s, t);
 
         return 0;
 }
@@ -1128,6 +1146,7 @@ static const char* const session_type_table[_SESSION_TYPE_MAX] = {
         [SESSION_X11] = "x11",
         [SESSION_WAYLAND] = "wayland",
         [SESSION_MIR] = "mir",
+        [SESSION_WEB] = "web",
 };
 
 DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);