LCOV - code coverage report
Current view: top level - login - logind-session.c (source / functions) Hit Total Coverage
Test: systemd test coverage Lines: 4 622 0.6 %
Date: 2015-07-29 18:47:03 Functions: 8 41 19.5 %

          Line data    Source code
       1             : /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
       2             : 
       3             : /***
       4             :   This file is part of systemd.
       5             : 
       6             :   Copyright 2011 Lennart Poettering
       7             : 
       8             :   systemd is free software; you can redistribute it and/or modify it
       9             :   under the terms of the GNU Lesser General Public License as published by
      10             :   the Free Software Foundation; either version 2.1 of the License, or
      11             :   (at your option) any later version.
      12             : 
      13             :   systemd is distributed in the hope that it will be useful, but
      14             :   WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
      16             :   Lesser General Public License for more details.
      17             : 
      18             :   You should have received a copy of the GNU Lesser General Public License
      19             :   along with systemd; If not, see <http://www.gnu.org/licenses/>.
      20             : ***/
      21             : 
      22             : #include <errno.h>
      23             : #include <fcntl.h>
      24             : #include <linux/vt.h>
      25             : #include <linux/kd.h>
      26             : #include <signal.h>
      27             : #include <string.h>
      28             : #include <sys/ioctl.h>
      29             : #include <unistd.h>
      30             : 
      31             : #include "sd-messages.h"
      32             : #include "util.h"
      33             : #include "mkdir.h"
      34             : #include "path-util.h"
      35             : #include "fileio.h"
      36             : #include "audit.h"
      37             : #include "bus-util.h"
      38             : #include "bus-error.h"
      39             : #include "logind-session.h"
      40             : #include "formats-util.h"
      41             : #include "terminal-util.h"
      42             : 
      43             : #define RELEASE_USEC (20*USEC_PER_SEC)
      44             : 
      45             : static void session_remove_fifo(Session *s);
      46             : 
      47           0 : Session* session_new(Manager *m, const char *id) {
      48             :         Session *s;
      49             : 
      50           0 :         assert(m);
      51           0 :         assert(id);
      52           0 :         assert(session_id_valid(id));
      53             : 
      54           0 :         s = new0(Session, 1);
      55           0 :         if (!s)
      56           0 :                 return NULL;
      57             : 
      58           0 :         s->state_file = strappend("/run/systemd/sessions/", id);
      59           0 :         if (!s->state_file) {
      60           0 :                 free(s);
      61           0 :                 return NULL;
      62             :         }
      63             : 
      64           0 :         s->devices = hashmap_new(&devt_hash_ops);
      65           0 :         if (!s->devices) {
      66           0 :                 free(s->state_file);
      67           0 :                 free(s);
      68           0 :                 return NULL;
      69             :         }
      70             : 
      71           0 :         s->id = basename(s->state_file);
      72             : 
      73           0 :         if (hashmap_put(m->sessions, s->id, s) < 0) {
      74           0 :                 hashmap_free(s->devices);
      75           0 :                 free(s->state_file);
      76           0 :                 free(s);
      77           0 :                 return NULL;
      78             :         }
      79             : 
      80           0 :         s->manager = m;
      81           0 :         s->fifo_fd = -1;
      82           0 :         s->vtfd = -1;
      83             : 
      84           0 :         return s;
      85             : }
      86             : 
      87           0 : void session_free(Session *s) {
      88             :         SessionDevice *sd;
      89             : 
      90           0 :         assert(s);
      91             : 
      92           0 :         if (s->in_gc_queue)
      93           0 :                 LIST_REMOVE(gc_queue, s->manager->session_gc_queue, s);
      94             : 
      95           0 :         s->timer_event_source = sd_event_source_unref(s->timer_event_source);
      96             : 
      97           0 :         session_remove_fifo(s);
      98             : 
      99           0 :         session_drop_controller(s);
     100             : 
     101           0 :         while ((sd = hashmap_first(s->devices)))
     102           0 :                 session_device_free(sd);
     103             : 
     104           0 :         hashmap_free(s->devices);
     105             : 
     106           0 :         if (s->user) {
     107           0 :                 LIST_REMOVE(sessions_by_user, s->user->sessions, s);
     108             : 
     109           0 :                 if (s->user->display == s)
     110           0 :                         s->user->display = NULL;
     111             :         }
     112             : 
     113           0 :         if (s->seat) {
     114           0 :                 if (s->seat->active == s)
     115           0 :                         s->seat->active = NULL;
     116           0 :                 if (s->seat->pending_switch == s)
     117           0 :                         s->seat->pending_switch = NULL;
     118             : 
     119           0 :                 seat_evict_position(s->seat, s);
     120           0 :                 LIST_REMOVE(sessions_by_seat, s->seat->sessions, s);
     121             :         }
     122             : 
     123           0 :         if (s->scope) {
     124           0 :                 hashmap_remove(s->manager->session_units, s->scope);
     125           0 :                 free(s->scope);
     126             :         }
     127             : 
     128           0 :         free(s->scope_job);
     129             : 
     130           0 :         sd_bus_message_unref(s->create_message);
     131             : 
     132           0 :         free(s->tty);
     133           0 :         free(s->display);
     134           0 :         free(s->remote_host);
     135           0 :         free(s->remote_user);
     136           0 :         free(s->service);
     137           0 :         free(s->desktop);
     138             : 
     139           0 :         hashmap_remove(s->manager->sessions, s->id);
     140             : 
     141           0 :         free(s->state_file);
     142           0 :         free(s);
     143           0 : }
     144             : 
     145           0 : void session_set_user(Session *s, User *u) {
     146           0 :         assert(s);
     147           0 :         assert(!s->user);
     148             : 
     149           0 :         s->user = u;
     150           0 :         LIST_PREPEND(sessions_by_user, u->sessions, s);
     151           0 : }
     152             : 
     153           0 : int session_save(Session *s) {
     154           0 :         _cleanup_free_ char *temp_path = NULL;
     155           0 :         _cleanup_fclose_ FILE *f = NULL;
     156           0 :         int r = 0;
     157             : 
     158           0 :         assert(s);
     159             : 
     160           0 :         if (!s->user)
     161           0 :                 return -ESTALE;
     162             : 
     163           0 :         if (!s->started)
     164           0 :                 return 0;
     165             : 
     166           0 :         r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
     167           0 :         if (r < 0)
     168           0 :                 goto finish;
     169             : 
     170           0 :         r = fopen_temporary(s->state_file, &f, &temp_path);
     171           0 :         if (r < 0)
     172           0 :                 goto finish;
     173             : 
     174           0 :         assert(s->user);
     175             : 
     176           0 :         fchmod(fileno(f), 0644);
     177             : 
     178           0 :         fprintf(f,
     179             :                 "# This is private data. Do not parse.\n"
     180             :                 "UID="UID_FMT"\n"
     181             :                 "USER=%s\n"
     182             :                 "ACTIVE=%i\n"
     183             :                 "STATE=%s\n"
     184             :                 "REMOTE=%i\n",
     185           0 :                 s->user->uid,
     186           0 :                 s->user->name,
     187           0 :                 session_is_active(s),
     188             :                 session_state_to_string(session_get_state(s)),
     189           0 :                 s->remote);
     190             : 
     191           0 :         if (s->type >= 0)
     192           0 :                 fprintf(f, "TYPE=%s\n", session_type_to_string(s->type));
     193             : 
     194           0 :         if (s->class >= 0)
     195           0 :                 fprintf(f, "CLASS=%s\n", session_class_to_string(s->class));
     196             : 
     197           0 :         if (s->scope)
     198           0 :                 fprintf(f, "SCOPE=%s\n", s->scope);
     199           0 :         if (s->scope_job)
     200           0 :                 fprintf(f, "SCOPE_JOB=%s\n", s->scope_job);
     201             : 
     202           0 :         if (s->fifo_path)
     203           0 :                 fprintf(f, "FIFO=%s\n", s->fifo_path);
     204             : 
     205           0 :         if (s->seat)
     206           0 :                 fprintf(f, "SEAT=%s\n", s->seat->id);
     207             : 
     208           0 :         if (s->tty)
     209           0 :                 fprintf(f, "TTY=%s\n", s->tty);
     210             : 
     211           0 :         if (s->display)
     212           0 :                 fprintf(f, "DISPLAY=%s\n", s->display);
     213             : 
     214           0 :         if (s->remote_host) {
     215           0 :                 _cleanup_free_ char *escaped;
     216             : 
     217           0 :                 escaped = cescape(s->remote_host);
     218           0 :                 if (!escaped) {
     219           0 :                         r = -ENOMEM;
     220           0 :                         goto finish;
     221             :                 }
     222             : 
     223           0 :                 fprintf(f, "REMOTE_HOST=%s\n", escaped);
     224             :         }
     225             : 
     226           0 :         if (s->remote_user) {
     227           0 :                 _cleanup_free_ char *escaped;
     228             : 
     229           0 :                 escaped = cescape(s->remote_user);
     230           0 :                 if (!escaped) {
     231           0 :                         r = -ENOMEM;
     232           0 :                         goto finish;
     233             :                 }
     234             : 
     235           0 :                 fprintf(f, "REMOTE_USER=%s\n", escaped);
     236             :         }
     237             : 
     238           0 :         if (s->service) {
     239           0 :                 _cleanup_free_ char *escaped;
     240             : 
     241           0 :                 escaped = cescape(s->service);
     242           0 :                 if (!escaped) {
     243           0 :                         r = -ENOMEM;
     244           0 :                         goto finish;
     245             :                 }
     246             : 
     247           0 :                 fprintf(f, "SERVICE=%s\n", escaped);
     248             :         }
     249             : 
     250           0 :         if (s->desktop) {
     251           0 :                 _cleanup_free_ char *escaped;
     252             : 
     253             : 
     254           0 :                 escaped = cescape(s->desktop);
     255           0 :                 if (!escaped) {
     256           0 :                         r = -ENOMEM;
     257           0 :                         goto finish;
     258             :                 }
     259             : 
     260           0 :                 fprintf(f, "DESKTOP=%s\n", escaped);
     261             :         }
     262             : 
     263           0 :         if (s->seat && seat_has_vts(s->seat))
     264           0 :                 fprintf(f, "VTNR=%u\n", s->vtnr);
     265             : 
     266           0 :         if (!s->vtnr)
     267           0 :                 fprintf(f, "POSITION=%u\n", s->position);
     268             : 
     269           0 :         if (s->leader > 0)
     270           0 :                 fprintf(f, "LEADER="PID_FMT"\n", s->leader);
     271             : 
     272           0 :         if (s->audit_id > 0)
     273           0 :                 fprintf(f, "AUDIT=%"PRIu32"\n", s->audit_id);
     274             : 
     275           0 :         if (dual_timestamp_is_set(&s->timestamp))
     276           0 :                 fprintf(f,
     277             :                         "REALTIME="USEC_FMT"\n"
     278             :                         "MONOTONIC="USEC_FMT"\n",
     279             :                         s->timestamp.realtime,
     280             :                         s->timestamp.monotonic);
     281             : 
     282           0 :         if (s->controller)
     283           0 :                 fprintf(f, "CONTROLLER=%s\n", s->controller);
     284             : 
     285           0 :         fflush(f);
     286             : 
     287           0 :         if (ferror(f) || rename(temp_path, s->state_file) < 0) {
     288           0 :                 r = -errno;
     289           0 :                 unlink(s->state_file);
     290           0 :                 unlink(temp_path);
     291             :         }
     292             : 
     293             : finish:
     294           0 :         if (r < 0)
     295           0 :                 log_error_errno(r, "Failed to save session data %s: %m", s->state_file);
     296             : 
     297           0 :         return r;
     298             : }
     299             : 
     300           0 : int session_load(Session *s) {
     301           0 :         _cleanup_free_ char *remote = NULL,
     302           0 :                 *seat = NULL,
     303           0 :                 *vtnr = NULL,
     304           0 :                 *state = NULL,
     305           0 :                 *position = NULL,
     306           0 :                 *leader = NULL,
     307           0 :                 *type = NULL,
     308           0 :                 *class = NULL,
     309           0 :                 *uid = NULL,
     310           0 :                 *realtime = NULL,
     311           0 :                 *monotonic = NULL,
     312           0 :                 *controller = NULL;
     313             : 
     314             :         int k, r;
     315             : 
     316           0 :         assert(s);
     317             : 
     318           0 :         r = parse_env_file(s->state_file, NEWLINE,
     319             :                            "REMOTE",         &remote,
     320             :                            "SCOPE",          &s->scope,
     321             :                            "SCOPE_JOB",      &s->scope_job,
     322             :                            "FIFO",           &s->fifo_path,
     323             :                            "SEAT",           &seat,
     324             :                            "TTY",            &s->tty,
     325             :                            "DISPLAY",        &s->display,
     326             :                            "REMOTE_HOST",    &s->remote_host,
     327             :                            "REMOTE_USER",    &s->remote_user,
     328             :                            "SERVICE",        &s->service,
     329             :                            "DESKTOP",        &s->desktop,
     330             :                            "VTNR",           &vtnr,
     331             :                            "STATE",          &state,
     332             :                            "POSITION",       &position,
     333             :                            "LEADER",         &leader,
     334             :                            "TYPE",           &type,
     335             :                            "CLASS",          &class,
     336             :                            "UID",            &uid,
     337             :                            "REALTIME",       &realtime,
     338             :                            "MONOTONIC",      &monotonic,
     339             :                            "CONTROLLER",     &controller,
     340             :                            NULL);
     341             : 
     342           0 :         if (r < 0)
     343           0 :                 return log_error_errno(r, "Failed to read %s: %m", s->state_file);
     344             : 
     345           0 :         if (!s->user) {
     346             :                 uid_t u;
     347             :                 User *user;
     348             : 
     349           0 :                 if (!uid) {
     350           0 :                         log_error("UID not specified for session %s", s->id);
     351           0 :                         return -ENOENT;
     352             :                 }
     353             : 
     354           0 :                 r = parse_uid(uid, &u);
     355           0 :                 if (r < 0)  {
     356           0 :                         log_error("Failed to parse UID value %s for session %s.", uid, s->id);
     357           0 :                         return r;
     358             :                 }
     359             : 
     360           0 :                 user = hashmap_get(s->manager->users, UID_TO_PTR(u));
     361           0 :                 if (!user) {
     362           0 :                         log_error("User of session %s not known.", s->id);
     363           0 :                         return -ENOENT;
     364             :                 }
     365             : 
     366           0 :                 session_set_user(s, user);
     367             :         }
     368             : 
     369           0 :         if (remote) {
     370           0 :                 k = parse_boolean(remote);
     371           0 :                 if (k >= 0)
     372           0 :                         s->remote = k;
     373             :         }
     374             : 
     375           0 :         if (vtnr)
     376           0 :                 safe_atou(vtnr, &s->vtnr);
     377             : 
     378           0 :         if (seat && !s->seat) {
     379             :                 Seat *o;
     380             : 
     381           0 :                 o = hashmap_get(s->manager->seats, seat);
     382           0 :                 if (o)
     383           0 :                         r = seat_attach_session(o, s);
     384           0 :                 if (!o || r < 0)
     385           0 :                         log_error("Cannot attach session %s to seat %s", s->id, seat);
     386             :         }
     387             : 
     388           0 :         if (!s->seat || !seat_has_vts(s->seat))
     389           0 :                 s->vtnr = 0;
     390             : 
     391           0 :         if (position && s->seat) {
     392             :                 unsigned int npos;
     393             : 
     394           0 :                 safe_atou(position, &npos);
     395           0 :                 seat_claim_position(s->seat, s, npos);
     396             :         }
     397             : 
     398           0 :         if (leader) {
     399           0 :                 k = parse_pid(leader, &s->leader);
     400           0 :                 if (k >= 0)
     401           0 :                         audit_session_from_pid(s->leader, &s->audit_id);
     402             :         }
     403             : 
     404           0 :         if (type) {
     405             :                 SessionType t;
     406             : 
     407           0 :                 t = session_type_from_string(type);
     408           0 :                 if (t >= 0)
     409           0 :                         s->type = t;
     410             :         }
     411             : 
     412           0 :         if (class) {
     413             :                 SessionClass c;
     414             : 
     415           0 :                 c = session_class_from_string(class);
     416           0 :                 if (c >= 0)
     417           0 :                         s->class = c;
     418             :         }
     419             : 
     420           0 :         if (state && streq(state, "closing"))
     421           0 :                 s->stopping = true;
     422             : 
     423           0 :         if (s->fifo_path) {
     424             :                 int fd;
     425             : 
     426             :                 /* If we open an unopened pipe for reading we will not
     427             :                    get an EOF. to trigger an EOF we hence open it for
     428             :                    writing, but close it right away which then will
     429             :                    trigger the EOF. This will happen immediately if no
     430             :                    other process has the FIFO open for writing, i. e.
     431             :                    when the session died before logind (re)started. */
     432             : 
     433           0 :                 fd = session_create_fifo(s);
     434           0 :                 safe_close(fd);
     435             :         }
     436             : 
     437           0 :         if (realtime) {
     438             :                 unsigned long long l;
     439           0 :                 if (sscanf(realtime, "%llu", &l) > 0)
     440           0 :                         s->timestamp.realtime = l;
     441             :         }
     442             : 
     443           0 :         if (monotonic) {
     444             :                 unsigned long long l;
     445           0 :                 if (sscanf(monotonic, "%llu", &l) > 0)
     446           0 :                         s->timestamp.monotonic = l;
     447             :         }
     448             : 
     449           0 :         if (controller) {
     450           0 :                 if (bus_name_has_owner(s->manager->bus, controller, NULL) > 0)
     451           0 :                         session_set_controller(s, controller, false);
     452             :                 else
     453           0 :                         session_restore_vt(s);
     454             :         }
     455             : 
     456           0 :         return r;
     457             : }
     458             : 
     459           0 : int session_activate(Session *s) {
     460             :         unsigned int num_pending;
     461             : 
     462           0 :         assert(s);
     463           0 :         assert(s->user);
     464             : 
     465           0 :         if (!s->seat)
     466           0 :                 return -EOPNOTSUPP;
     467             : 
     468           0 :         if (s->seat->active == s)
     469           0 :                 return 0;
     470             : 
     471             :         /* on seats with VTs, we let VTs manage session-switching */
     472           0 :         if (seat_has_vts(s->seat)) {
     473           0 :                 if (!s->vtnr)
     474           0 :                         return -EOPNOTSUPP;
     475             : 
     476           0 :                 return chvt(s->vtnr);
     477             :         }
     478             : 
     479             :         /* On seats without VTs, we implement session-switching in logind. We
     480             :          * try to pause all session-devices and wait until the session
     481             :          * controller acknowledged them. Once all devices are asleep, we simply
     482             :          * switch the active session and be done.
     483             :          * We save the session we want to switch to in seat->pending_switch and
     484             :          * seat_complete_switch() will perform the final switch. */
     485             : 
     486           0 :         s->seat->pending_switch = s;
     487             : 
     488             :         /* if no devices are running, immediately perform the session switch */
     489           0 :         num_pending = session_device_try_pause_all(s);
     490           0 :         if (!num_pending)
     491           0 :                 seat_complete_switch(s->seat);
     492             : 
     493           0 :         return 0;
     494             : }
     495             : 
     496           0 : static int session_start_scope(Session *s) {
     497             :         int r;
     498             : 
     499           0 :         assert(s);
     500           0 :         assert(s->user);
     501           0 :         assert(s->user->slice);
     502             : 
     503           0 :         if (!s->scope) {
     504           0 :                 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
     505           0 :                 _cleanup_free_ char *description = NULL;
     506           0 :                 char *scope, *job = NULL;
     507             : 
     508           0 :                 description = strjoin("Session ", s->id, " of user ", s->user->name, NULL);
     509           0 :                 if (!description)
     510           0 :                         return log_oom();
     511             : 
     512           0 :                 scope = strjoin("session-", s->id, ".scope", NULL);
     513           0 :                 if (!scope)
     514           0 :                         return log_oom();
     515             : 
     516           0 :                 r = manager_start_scope(s->manager, scope, s->leader, s->user->slice, description, "systemd-logind.service", "systemd-user-sessions.service", &error, &job);
     517           0 :                 if (r < 0) {
     518           0 :                         log_error("Failed to start session scope %s: %s %s",
     519             :                                   scope, bus_error_message(&error, r), error.name);
     520           0 :                         free(scope);
     521           0 :                         return r;
     522             :                 } else {
     523           0 :                         s->scope = scope;
     524             : 
     525           0 :                         free(s->scope_job);
     526           0 :                         s->scope_job = job;
     527             :                 }
     528             :         }
     529             : 
     530           0 :         if (s->scope)
     531           0 :                 hashmap_put(s->manager->session_units, s->scope, s);
     532             : 
     533           0 :         return 0;
     534             : }
     535             : 
     536           0 : int session_start(Session *s) {
     537             :         int r;
     538             : 
     539           0 :         assert(s);
     540             : 
     541           0 :         if (!s->user)
     542           0 :                 return -ESTALE;
     543             : 
     544           0 :         if (s->started)
     545           0 :                 return 0;
     546             : 
     547           0 :         r = user_start(s->user);
     548           0 :         if (r < 0)
     549           0 :                 return r;
     550             : 
     551             :         /* Create cgroup */
     552           0 :         r = session_start_scope(s);
     553           0 :         if (r < 0)
     554           0 :                 return r;
     555             : 
     556           0 :         log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO,
     557             :                    LOG_MESSAGE_ID(SD_MESSAGE_SESSION_START),
     558             :                    "SESSION_ID=%s", s->id,
     559             :                    "USER_ID=%s", s->user->name,
     560             :                    "LEADER="PID_FMT, s->leader,
     561             :                    LOG_MESSAGE("New session %s of user %s.", s->id, s->user->name),
     562             :                    NULL);
     563             : 
     564           0 :         if (!dual_timestamp_is_set(&s->timestamp))
     565           0 :                 dual_timestamp_get(&s->timestamp);
     566             : 
     567           0 :         if (s->seat)
     568           0 :                 seat_read_active_vt(s->seat);
     569             : 
     570           0 :         s->started = true;
     571             : 
     572           0 :         user_elect_display(s->user);
     573             : 
     574             :         /* Save data */
     575           0 :         session_save(s);
     576           0 :         user_save(s->user);
     577           0 :         if (s->seat)
     578           0 :                 seat_save(s->seat);
     579             : 
     580             :         /* Send signals */
     581           0 :         session_send_signal(s, true);
     582           0 :         user_send_changed(s->user, "Sessions", "Display", NULL);
     583           0 :         if (s->seat) {
     584           0 :                 if (s->seat->active == s)
     585           0 :                         seat_send_changed(s->seat, "Sessions", "ActiveSession", NULL);
     586             :                 else
     587           0 :                         seat_send_changed(s->seat, "Sessions", NULL);
     588             :         }
     589             : 
     590           0 :         return 0;
     591             : }
     592             : 
     593           0 : static int session_stop_scope(Session *s, bool force) {
     594           0 :         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
     595           0 :         char *job = NULL;
     596             :         int r;
     597             : 
     598           0 :         assert(s);
     599             : 
     600           0 :         if (!s->scope)
     601           0 :                 return 0;
     602             : 
     603           0 :         if (force || manager_shall_kill(s->manager, s->user->name)) {
     604           0 :                 r = manager_stop_unit(s->manager, s->scope, &error, &job);
     605           0 :                 if (r < 0) {
     606           0 :                         log_error("Failed to stop session scope: %s", bus_error_message(&error, r));
     607           0 :                         return r;
     608             :                 }
     609             : 
     610           0 :                 free(s->scope_job);
     611           0 :                 s->scope_job = job;
     612             :         } else {
     613           0 :                 r = manager_abandon_scope(s->manager, s->scope, &error);
     614           0 :                 if (r < 0) {
     615           0 :                         log_error("Failed to abandon session scope: %s", bus_error_message(&error, r));
     616           0 :                         return r;
     617             :                 }
     618             :         }
     619             : 
     620           0 :         return 0;
     621             : }
     622             : 
     623           0 : int session_stop(Session *s, bool force) {
     624             :         int r;
     625             : 
     626           0 :         assert(s);
     627             : 
     628           0 :         if (!s->user)
     629           0 :                 return -ESTALE;
     630             : 
     631           0 :         s->timer_event_source = sd_event_source_unref(s->timer_event_source);
     632             : 
     633             :         /* We are going down, don't care about FIFOs anymore */
     634           0 :         session_remove_fifo(s);
     635             : 
     636             :         /* Kill cgroup */
     637           0 :         r = session_stop_scope(s, force);
     638             : 
     639           0 :         s->stopping = true;
     640             : 
     641           0 :         user_elect_display(s->user);
     642             : 
     643           0 :         session_save(s);
     644           0 :         user_save(s->user);
     645             : 
     646           0 :         return r;
     647             : }
     648             : 
     649           0 : int session_finalize(Session *s) {
     650           0 :         int r = 0;
     651             :         SessionDevice *sd;
     652             : 
     653           0 :         assert(s);
     654             : 
     655           0 :         if (!s->user)
     656           0 :                 return -ESTALE;
     657             : 
     658           0 :         if (s->started)
     659           0 :                 log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO,
     660             :                            LOG_MESSAGE_ID(SD_MESSAGE_SESSION_STOP),
     661             :                            "SESSION_ID=%s", s->id,
     662             :                            "USER_ID=%s", s->user->name,
     663             :                            "LEADER="PID_FMT, s->leader,
     664             :                            LOG_MESSAGE("Removed session %s.", s->id),
     665             :                            NULL);
     666             : 
     667           0 :         s->timer_event_source = sd_event_source_unref(s->timer_event_source);
     668             : 
     669             :         /* Kill session devices */
     670           0 :         while ((sd = hashmap_first(s->devices)))
     671           0 :                 session_device_free(sd);
     672             : 
     673           0 :         unlink(s->state_file);
     674           0 :         session_add_to_gc_queue(s);
     675           0 :         user_add_to_gc_queue(s->user);
     676             : 
     677           0 :         if (s->started) {
     678           0 :                 session_send_signal(s, false);
     679           0 :                 s->started = false;
     680             :         }
     681             : 
     682           0 :         if (s->seat) {
     683           0 :                 if (s->seat->active == s)
     684           0 :                         seat_set_active(s->seat, NULL);
     685             : 
     686           0 :                 seat_save(s->seat);
     687           0 :                 seat_send_changed(s->seat, "Sessions", NULL);
     688             :         }
     689             : 
     690           0 :         user_save(s->user);
     691           0 :         user_send_changed(s->user, "Sessions", "Display", NULL);
     692             : 
     693           0 :         return r;
     694             : }
     695             : 
     696           0 : static int release_timeout_callback(sd_event_source *es, uint64_t usec, void *userdata) {
     697           0 :         Session *s = userdata;
     698             : 
     699           0 :         assert(es);
     700           0 :         assert(s);
     701             : 
     702           0 :         session_stop(s, false);
     703           0 :         return 0;
     704             : }
     705             : 
     706           0 : int session_release(Session *s) {
     707           0 :         assert(s);
     708             : 
     709           0 :         if (!s->started || s->stopping)
     710           0 :                 return 0;
     711             : 
     712           0 :         if (s->timer_event_source)
     713           0 :                 return 0;
     714             : 
     715           0 :         return sd_event_add_time(s->manager->event,
     716             :                                  &s->timer_event_source,
     717             :                                  CLOCK_MONOTONIC,
     718           0 :                                  now(CLOCK_MONOTONIC) + RELEASE_USEC, 0,
     719             :                                  release_timeout_callback, s);
     720             : }
     721             : 
     722           0 : bool session_is_active(Session *s) {
     723           0 :         assert(s);
     724             : 
     725           0 :         if (!s->seat)
     726           0 :                 return true;
     727             : 
     728           0 :         return s->seat->active == s;
     729             : }
     730             : 
     731           0 : static int get_tty_atime(const char *tty, usec_t *atime) {
     732           0 :         _cleanup_free_ char *p = NULL;
     733             :         struct stat st;
     734             : 
     735           0 :         assert(tty);
     736           0 :         assert(atime);
     737             : 
     738           0 :         if (!path_is_absolute(tty)) {
     739           0 :                 p = strappend("/dev/", tty);
     740           0 :                 if (!p)
     741           0 :                         return -ENOMEM;
     742             : 
     743           0 :                 tty = p;
     744           0 :         } else if (!path_startswith(tty, "/dev/"))
     745           0 :                 return -ENOENT;
     746             : 
     747           0 :         if (lstat(tty, &st) < 0)
     748           0 :                 return -errno;
     749             : 
     750           0 :         *atime = timespec_load(&st.st_atim);
     751           0 :         return 0;
     752             : }
     753             : 
     754           0 : static int get_process_ctty_atime(pid_t pid, usec_t *atime) {
     755           0 :         _cleanup_free_ char *p = NULL;
     756             :         int r;
     757             : 
     758           0 :         assert(pid > 0);
     759           0 :         assert(atime);
     760             : 
     761           0 :         r = get_ctty(pid, NULL, &p);
     762           0 :         if (r < 0)
     763           0 :                 return r;
     764             : 
     765           0 :         return get_tty_atime(p, atime);
     766             : }
     767             : 
     768           0 : int session_get_idle_hint(Session *s, dual_timestamp *t) {
     769           0 :         usec_t atime = 0, n;
     770             :         int r;
     771             : 
     772           0 :         assert(s);
     773             : 
     774             :         /* Explicit idle hint is set */
     775           0 :         if (s->idle_hint) {
     776           0 :                 if (t)
     777           0 :                         *t = s->idle_hint_timestamp;
     778             : 
     779           0 :                 return s->idle_hint;
     780             :         }
     781             : 
     782             :         /* Graphical sessions should really implement a real
     783             :          * idle hint logic */
     784           0 :         if (s->display)
     785           0 :                 goto dont_know;
     786             : 
     787             :         /* For sessions with an explicitly configured tty, let's check
     788             :          * its atime */
     789           0 :         if (s->tty) {
     790           0 :                 r = get_tty_atime(s->tty, &atime);
     791           0 :                 if (r >= 0)
     792           0 :                         goto found_atime;
     793             :         }
     794             : 
     795             :         /* For sessions with a leader but no explicitly configured
     796             :          * tty, let's check the controlling tty of the leader */
     797           0 :         if (s->leader > 0) {
     798           0 :                 r = get_process_ctty_atime(s->leader, &atime);
     799           0 :                 if (r >= 0)
     800           0 :                         goto found_atime;
     801             :         }
     802             : 
     803             : dont_know:
     804           0 :         if (t)
     805           0 :                 *t = s->idle_hint_timestamp;
     806             : 
     807           0 :         return 0;
     808             : 
     809             : found_atime:
     810           0 :         if (t)
     811           0 :                 dual_timestamp_from_realtime(t, atime);
     812             : 
     813           0 :         n = now(CLOCK_REALTIME);
     814             : 
     815           0 :         if (s->manager->idle_action_usec <= 0)
     816           0 :                 return 0;
     817             : 
     818           0 :         return atime + s->manager->idle_action_usec <= n;
     819             : }
     820             : 
     821           0 : void session_set_idle_hint(Session *s, bool b) {
     822           0 :         assert(s);
     823             : 
     824           0 :         if (s->idle_hint == b)
     825           0 :                 return;
     826             : 
     827           0 :         s->idle_hint = b;
     828           0 :         dual_timestamp_get(&s->idle_hint_timestamp);
     829             : 
     830           0 :         session_send_changed(s, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
     831             : 
     832           0 :         if (s->seat)
     833           0 :                 seat_send_changed(s->seat, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
     834             : 
     835           0 :         user_send_changed(s->user, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
     836           0 :         manager_send_changed(s->manager, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
     837             : }
     838             : 
     839           0 : static int session_dispatch_fifo(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
     840           0 :         Session *s = userdata;
     841             : 
     842           0 :         assert(s);
     843           0 :         assert(s->fifo_fd == fd);
     844             : 
     845             :         /* EOF on the FIFO means the session died abnormally. */
     846             : 
     847           0 :         session_remove_fifo(s);
     848           0 :         session_stop(s, false);
     849             : 
     850           0 :         return 1;
     851             : }
     852             : 
     853           0 : int session_create_fifo(Session *s) {
     854             :         int r;
     855             : 
     856           0 :         assert(s);
     857             : 
     858             :         /* Create FIFO */
     859           0 :         if (!s->fifo_path) {
     860           0 :                 r = mkdir_safe_label("/run/systemd/sessions", 0755, 0, 0);
     861           0 :                 if (r < 0)
     862           0 :                         return r;
     863             : 
     864           0 :                 if (asprintf(&s->fifo_path, "/run/systemd/sessions/%s.ref", s->id) < 0)
     865           0 :                         return -ENOMEM;
     866             : 
     867           0 :                 if (mkfifo(s->fifo_path, 0600) < 0 && errno != EEXIST)
     868           0 :                         return -errno;
     869             :         }
     870             : 
     871             :         /* Open reading side */
     872           0 :         if (s->fifo_fd < 0) {
     873           0 :                 s->fifo_fd = open(s->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
     874           0 :                 if (s->fifo_fd < 0)
     875           0 :                         return -errno;
     876             : 
     877             :         }
     878             : 
     879           0 :         if (!s->fifo_event_source) {
     880           0 :                 r = sd_event_add_io(s->manager->event, &s->fifo_event_source, s->fifo_fd, 0, session_dispatch_fifo, s);
     881           0 :                 if (r < 0)
     882           0 :                         return r;
     883             : 
     884           0 :                 r = sd_event_source_set_priority(s->fifo_event_source, SD_EVENT_PRIORITY_IDLE);
     885           0 :                 if (r < 0)
     886           0 :                         return r;
     887             :         }
     888             : 
     889             :         /* Open writing side */
     890           0 :         r = open(s->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
     891           0 :         if (r < 0)
     892           0 :                 return -errno;
     893             : 
     894           0 :         return r;
     895             : }
     896             : 
     897           0 : static void session_remove_fifo(Session *s) {
     898           0 :         assert(s);
     899             : 
     900           0 :         s->fifo_event_source = sd_event_source_unref(s->fifo_event_source);
     901           0 :         s->fifo_fd = safe_close(s->fifo_fd);
     902             : 
     903           0 :         if (s->fifo_path) {
     904           0 :                 unlink(s->fifo_path);
     905           0 :                 free(s->fifo_path);
     906           0 :                 s->fifo_path = NULL;
     907             :         }
     908           0 : }
     909             : 
     910           0 : bool session_check_gc(Session *s, bool drop_not_started) {
     911           0 :         assert(s);
     912             : 
     913           0 :         if (drop_not_started && !s->started)
     914           0 :                 return false;
     915             : 
     916           0 :         if (!s->user)
     917           0 :                 return false;
     918             : 
     919           0 :         if (s->fifo_fd >= 0) {
     920           0 :                 if (pipe_eof(s->fifo_fd) <= 0)
     921           0 :                         return true;
     922             :         }
     923             : 
     924           0 :         if (s->scope_job && manager_job_is_active(s->manager, s->scope_job))
     925           0 :                 return true;
     926             : 
     927           0 :         if (s->scope && manager_unit_is_active(s->manager, s->scope))
     928           0 :                 return true;
     929             : 
     930           0 :         return false;
     931             : }
     932             : 
     933           0 : void session_add_to_gc_queue(Session *s) {
     934           0 :         assert(s);
     935             : 
     936           0 :         if (s->in_gc_queue)
     937           0 :                 return;
     938             : 
     939           0 :         LIST_PREPEND(gc_queue, s->manager->session_gc_queue, s);
     940           0 :         s->in_gc_queue = true;
     941             : }
     942             : 
     943           0 : SessionState session_get_state(Session *s) {
     944           0 :         assert(s);
     945             : 
     946             :         /* always check closing first */
     947           0 :         if (s->stopping || s->timer_event_source)
     948           0 :                 return SESSION_CLOSING;
     949             : 
     950           0 :         if (s->scope_job || s->fifo_fd < 0)
     951           0 :                 return SESSION_OPENING;
     952             : 
     953           0 :         if (session_is_active(s))
     954           0 :                 return SESSION_ACTIVE;
     955             : 
     956           0 :         return SESSION_ONLINE;
     957             : }
     958             : 
     959           0 : int session_kill(Session *s, KillWho who, int signo) {
     960           0 :         assert(s);
     961             : 
     962           0 :         if (!s->scope)
     963           0 :                 return -ESRCH;
     964             : 
     965           0 :         return manager_kill_unit(s->manager, s->scope, who, signo, NULL);
     966             : }
     967             : 
     968           0 : static int session_open_vt(Session *s) {
     969             :         char path[sizeof("/dev/tty") + DECIMAL_STR_MAX(s->vtnr)];
     970             : 
     971           0 :         if (s->vtnr < 1)
     972           0 :                 return -ENODEV;
     973             : 
     974           0 :         if (s->vtfd >= 0)
     975           0 :                 return s->vtfd;
     976             : 
     977           0 :         sprintf(path, "/dev/tty%u", s->vtnr);
     978           0 :         s->vtfd = open(path, O_RDWR | O_CLOEXEC | O_NONBLOCK | O_NOCTTY);
     979           0 :         if (s->vtfd < 0)
     980           0 :                 return log_error_errno(errno, "cannot open VT %s of session %s: %m", path, s->id);
     981             : 
     982           0 :         return s->vtfd;
     983             : }
     984             : 
     985           0 : int session_prepare_vt(Session *s) {
     986             :         int vt, r;
     987           0 :         struct vt_mode mode = { 0 };
     988             : 
     989           0 :         if (s->vtnr < 1)
     990           0 :                 return 0;
     991             : 
     992           0 :         vt = session_open_vt(s);
     993           0 :         if (vt < 0)
     994           0 :                 return vt;
     995             : 
     996           0 :         r = fchown(vt, s->user->uid, -1);
     997           0 :         if (r < 0) {
     998           0 :                 r = -errno;
     999           0 :                 log_error_errno(errno, "Cannot change owner of /dev/tty%u: %m", s->vtnr);
    1000           0 :                 goto error;
    1001             :         }
    1002             : 
    1003           0 :         r = ioctl(vt, KDSKBMODE, K_OFF);
    1004           0 :         if (r < 0) {
    1005           0 :                 r = -errno;
    1006           0 :                 log_error_errno(errno, "Cannot set K_OFF on /dev/tty%u: %m", s->vtnr);
    1007           0 :                 goto error;
    1008             :         }
    1009             : 
    1010           0 :         r = ioctl(vt, KDSETMODE, KD_GRAPHICS);
    1011           0 :         if (r < 0) {
    1012           0 :                 r = -errno;
    1013           0 :                 log_error_errno(errno, "Cannot set KD_GRAPHICS on /dev/tty%u: %m", s->vtnr);
    1014           0 :                 goto error;
    1015             :         }
    1016             : 
    1017             :         /* Oh, thanks to the VT layer, VT_AUTO does not work with KD_GRAPHICS.
    1018             :          * So we need a dummy handler here which just acknowledges *all* VT
    1019             :          * switch requests. */
    1020           0 :         mode.mode = VT_PROCESS;
    1021           0 :         mode.relsig = SIGRTMIN;
    1022           0 :         mode.acqsig = SIGRTMIN + 1;
    1023           0 :         r = ioctl(vt, VT_SETMODE, &mode);
    1024           0 :         if (r < 0) {
    1025           0 :                 r = -errno;
    1026           0 :                 log_error_errno(errno, "Cannot set VT_PROCESS on /dev/tty%u: %m", s->vtnr);
    1027           0 :                 goto error;
    1028             :         }
    1029             : 
    1030           0 :         return 0;
    1031             : 
    1032             : error:
    1033           0 :         session_restore_vt(s);
    1034           0 :         return r;
    1035             : }
    1036             : 
    1037           0 : void session_restore_vt(Session *s) {
    1038           0 :         _cleanup_free_ char *utf8 = NULL;
    1039           0 :         int vt, kb = K_XLATE;
    1040           0 :         struct vt_mode mode = { 0 };
    1041             : 
    1042           0 :         vt = session_open_vt(s);
    1043           0 :         if (vt < 0)
    1044           0 :                 return;
    1045             : 
    1046           0 :         (void) ioctl(vt, KDSETMODE, KD_TEXT);
    1047             : 
    1048           0 :         if (read_one_line_file("/sys/module/vt/parameters/default_utf8", &utf8) >= 0 && *utf8 == '1')
    1049           0 :                 kb = K_UNICODE;
    1050             : 
    1051           0 :         (void) ioctl(vt, KDSKBMODE, kb);
    1052             : 
    1053           0 :         mode.mode = VT_AUTO;
    1054           0 :         (void) ioctl(vt, VT_SETMODE, &mode);
    1055             : 
    1056           0 :         fchown(vt, 0, -1);
    1057             : 
    1058           0 :         s->vtfd = safe_close(s->vtfd);
    1059             : }
    1060             : 
    1061           0 : void session_leave_vt(Session *s) {
    1062             :         int r;
    1063             : 
    1064           0 :         assert(s);
    1065             : 
    1066             :         /* This is called whenever we get a VT-switch signal from the kernel.
    1067             :          * We acknowledge all of them unconditionally. Note that session are
    1068             :          * free to overwrite those handlers and we only register them for
    1069             :          * sessions with controllers. Legacy sessions are not affected.
    1070             :          * However, if we switch from a non-legacy to a legacy session, we must
    1071             :          * make sure to pause all device before acknowledging the switch. We
    1072             :          * process the real switch only after we are notified via sysfs, so the
    1073             :          * legacy session might have already started using the devices. If we
    1074             :          * don't pause the devices before the switch, we might confuse the
    1075             :          * session we switch to. */
    1076             : 
    1077           0 :         if (s->vtfd < 0)
    1078           0 :                 return;
    1079             : 
    1080           0 :         session_device_pause_all(s);
    1081           0 :         r = ioctl(s->vtfd, VT_RELDISP, 1);
    1082           0 :         if (r < 0)
    1083           0 :                 log_debug_errno(errno, "Cannot release VT of session %s: %m", s->id);
    1084             : }
    1085             : 
    1086           0 : bool session_is_controller(Session *s, const char *sender) {
    1087           0 :         assert(s);
    1088             : 
    1089           0 :         return streq_ptr(s->controller, sender);
    1090             : }
    1091             : 
    1092           0 : static void session_release_controller(Session *s, bool notify) {
    1093           0 :         _cleanup_free_ char *name = NULL;
    1094             :         SessionDevice *sd;
    1095             : 
    1096           0 :         if (!s->controller)
    1097           0 :                 return;
    1098             : 
    1099           0 :         name = s->controller;
    1100             : 
    1101             :         /* By resetting the controller before releasing the devices, we won't
    1102             :          * send notification signals. This avoids sending useless notifications
    1103             :          * if the controller is released on disconnects. */
    1104           0 :         if (!notify)
    1105           0 :                 s->controller = NULL;
    1106             : 
    1107           0 :         while ((sd = hashmap_first(s->devices)))
    1108           0 :                 session_device_free(sd);
    1109             : 
    1110           0 :         s->controller = NULL;
    1111           0 :         manager_drop_busname(s->manager, name);
    1112             : }
    1113             : 
    1114           0 : int session_set_controller(Session *s, const char *sender, bool force) {
    1115           0 :         _cleanup_free_ char *name = NULL;
    1116             :         int r;
    1117             : 
    1118           0 :         assert(s);
    1119           0 :         assert(sender);
    1120             : 
    1121           0 :         if (session_is_controller(s, sender))
    1122           0 :                 return 0;
    1123           0 :         if (s->controller && !force)
    1124           0 :                 return -EBUSY;
    1125             : 
    1126           0 :         name = strdup(sender);
    1127           0 :         if (!name)
    1128           0 :                 return -ENOMEM;
    1129             : 
    1130           0 :         r = manager_watch_busname(s->manager, name);
    1131           0 :         if (r)
    1132           0 :                 return r;
    1133             : 
    1134             :         /* When setting a session controller, we forcibly mute the VT and set
    1135             :          * it into graphics-mode. Applications can override that by changing
    1136             :          * VT state after calling TakeControl(). However, this serves as a good
    1137             :          * default and well-behaving controllers can now ignore VTs entirely.
    1138             :          * Note that we reset the VT on ReleaseControl() and if the controller
    1139             :          * exits.
    1140             :          * If logind crashes/restarts, we restore the controller during restart
    1141             :          * or reset the VT in case it crashed/exited, too. */
    1142           0 :         r = session_prepare_vt(s);
    1143           0 :         if (r < 0) {
    1144           0 :                 manager_drop_busname(s->manager, name);
    1145           0 :                 return r;
    1146             :         }
    1147             : 
    1148           0 :         session_release_controller(s, true);
    1149           0 :         s->controller = name;
    1150           0 :         name = NULL;
    1151           0 :         session_save(s);
    1152             : 
    1153           0 :         return 0;
    1154             : }
    1155             : 
    1156           0 : void session_drop_controller(Session *s) {
    1157           0 :         assert(s);
    1158             : 
    1159           0 :         if (!s->controller)
    1160           0 :                 return;
    1161             : 
    1162           0 :         session_release_controller(s, false);
    1163           0 :         session_save(s);
    1164           0 :         session_restore_vt(s);
    1165             : }
    1166             : 
    1167             : static const char* const session_state_table[_SESSION_STATE_MAX] = {
    1168             :         [SESSION_OPENING] = "opening",
    1169             :         [SESSION_ONLINE] = "online",
    1170             :         [SESSION_ACTIVE] = "active",
    1171             :         [SESSION_CLOSING] = "closing"
    1172             : };
    1173             : 
    1174          12 : DEFINE_STRING_TABLE_LOOKUP(session_state, SessionState);
    1175             : 
    1176             : static const char* const session_type_table[_SESSION_TYPE_MAX] = {
    1177             :         [SESSION_UNSPECIFIED] = "unspecified",
    1178             :         [SESSION_TTY] = "tty",
    1179             :         [SESSION_X11] = "x11",
    1180             :         [SESSION_WAYLAND] = "wayland",
    1181             :         [SESSION_MIR] = "mir",
    1182             :         [SESSION_WEB] = "web",
    1183             : };
    1184             : 
    1185          16 : DEFINE_STRING_TABLE_LOOKUP(session_type, SessionType);
    1186             : 
    1187             : static const char* const session_class_table[_SESSION_CLASS_MAX] = {
    1188             :         [SESSION_USER] = "user",
    1189             :         [SESSION_GREETER] = "greeter",
    1190             :         [SESSION_LOCK_SCREEN] = "lock-screen",
    1191             :         [SESSION_BACKGROUND] = "background"
    1192             : };
    1193             : 
    1194          12 : DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
    1195             : 
    1196             : static const char* const kill_who_table[_KILL_WHO_MAX] = {
    1197             :         [KILL_LEADER] = "leader",
    1198             :         [KILL_ALL] = "all"
    1199             : };
    1200             : 
    1201           8 : DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);

Generated by: LCOV version 1.11