LCOV - code coverage report
Current view: top level - login - logind-user.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 1 424 0.2 %
Date: 2019-08-23 13:36:53 Functions: 2 26 7.7 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 4 416 1.0 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: LGPL-2.1+ */
       2                 :            : 
       3                 :            : #include <errno.h>
       4                 :            : #include <string.h>
       5                 :            : #include <unistd.h>
       6                 :            : 
       7                 :            : #include "alloc-util.h"
       8                 :            : #include "bus-common-errors.h"
       9                 :            : #include "bus-error.h"
      10                 :            : #include "bus-util.h"
      11                 :            : #include "cgroup-util.h"
      12                 :            : #include "clean-ipc.h"
      13                 :            : #include "env-file.h"
      14                 :            : #include "escape.h"
      15                 :            : #include "fd-util.h"
      16                 :            : #include "fileio.h"
      17                 :            : #include "format-util.h"
      18                 :            : #include "fs-util.h"
      19                 :            : #include "hashmap.h"
      20                 :            : #include "label.h"
      21                 :            : #include "limits-util.h"
      22                 :            : #include "logind-dbus.h"
      23                 :            : #include "logind-user.h"
      24                 :            : #include "logind-user-dbus.h"
      25                 :            : #include "mkdir.h"
      26                 :            : #include "parse-util.h"
      27                 :            : #include "path-util.h"
      28                 :            : #include "rm-rf.h"
      29                 :            : #include "serialize.h"
      30                 :            : #include "special.h"
      31                 :            : #include "stdio-util.h"
      32                 :            : #include "string-table.h"
      33                 :            : #include "strv.h"
      34                 :            : #include "tmpfile-util.h"
      35                 :            : #include "unit-name.h"
      36                 :            : #include "user-util.h"
      37                 :            : #include "util.h"
      38                 :            : 
      39                 :          0 : int user_new(User **ret,
      40                 :            :              Manager *m,
      41                 :            :              uid_t uid,
      42                 :            :              gid_t gid,
      43                 :            :              const char *name,
      44                 :            :              const char *home) {
      45                 :            : 
      46                 :          0 :         _cleanup_(user_freep) User *u = NULL;
      47                 :            :         char lu[DECIMAL_STR_MAX(uid_t) + 1];
      48                 :            :         int r;
      49                 :            : 
      50         [ #  # ]:          0 :         assert(ret);
      51         [ #  # ]:          0 :         assert(m);
      52         [ #  # ]:          0 :         assert(name);
      53                 :            : 
      54                 :          0 :         u = new(User, 1);
      55         [ #  # ]:          0 :         if (!u)
      56                 :          0 :                 return -ENOMEM;
      57                 :            : 
      58                 :          0 :         *u = (User) {
      59                 :            :                 .manager = m,
      60                 :            :                 .uid = uid,
      61                 :            :                 .gid = gid,
      62                 :            :                 .last_session_timestamp = USEC_INFINITY,
      63                 :            :         };
      64                 :            : 
      65                 :          0 :         u->name = strdup(name);
      66         [ #  # ]:          0 :         if (!u->name)
      67                 :          0 :                 return -ENOMEM;
      68                 :            : 
      69                 :          0 :         u->home = strdup(home);
      70         [ #  # ]:          0 :         if (!u->home)
      71                 :          0 :                 return -ENOMEM;
      72                 :            : 
      73                 :          0 :         path_simplify(u->home, true);
      74                 :            : 
      75         [ #  # ]:          0 :         if (asprintf(&u->state_file, "/run/systemd/users/"UID_FMT, uid) < 0)
      76                 :          0 :                 return -ENOMEM;
      77                 :            : 
      78         [ #  # ]:          0 :         if (asprintf(&u->runtime_path, "/run/user/"UID_FMT, uid) < 0)
      79                 :          0 :                 return -ENOMEM;
      80                 :            : 
      81         [ #  # ]:          0 :         xsprintf(lu, UID_FMT, uid);
      82                 :          0 :         r = slice_build_subslice(SPECIAL_USER_SLICE, lu, &u->slice);
      83         [ #  # ]:          0 :         if (r < 0)
      84                 :          0 :                 return r;
      85                 :            : 
      86                 :          0 :         r = unit_name_build("user", lu, ".service", &u->service);
      87         [ #  # ]:          0 :         if (r < 0)
      88                 :          0 :                 return r;
      89                 :            : 
      90                 :          0 :         r = unit_name_build("user-runtime-dir", lu, ".service", &u->runtime_dir_service);
      91         [ #  # ]:          0 :         if (r < 0)
      92                 :          0 :                 return r;
      93                 :            : 
      94                 :          0 :         r = hashmap_put(m->users, UID_TO_PTR(uid), u);
      95         [ #  # ]:          0 :         if (r < 0)
      96                 :          0 :                 return r;
      97                 :            : 
      98                 :          0 :         r = hashmap_put(m->user_units, u->slice, u);
      99         [ #  # ]:          0 :         if (r < 0)
     100                 :          0 :                 return r;
     101                 :            : 
     102                 :          0 :         r = hashmap_put(m->user_units, u->service, u);
     103         [ #  # ]:          0 :         if (r < 0)
     104                 :          0 :                 return r;
     105                 :            : 
     106                 :          0 :         r = hashmap_put(m->user_units, u->runtime_dir_service, u);
     107         [ #  # ]:          0 :         if (r < 0)
     108                 :          0 :                 return r;
     109                 :            : 
     110                 :          0 :         *ret = TAKE_PTR(u);
     111                 :          0 :         return 0;
     112                 :            : }
     113                 :            : 
     114                 :          0 : User *user_free(User *u) {
     115         [ #  # ]:          0 :         if (!u)
     116                 :          0 :                 return NULL;
     117                 :            : 
     118         [ #  # ]:          0 :         if (u->in_gc_queue)
     119   [ #  #  #  #  :          0 :                 LIST_REMOVE(gc_queue, u->manager->user_gc_queue, u);
             #  #  #  # ]
     120                 :            : 
     121         [ #  # ]:          0 :         while (u->sessions)
     122                 :          0 :                 session_free(u->sessions);
     123                 :            : 
     124         [ #  # ]:          0 :         if (u->service)
     125                 :          0 :                 hashmap_remove_value(u->manager->user_units, u->service, u);
     126                 :            : 
     127         [ #  # ]:          0 :         if (u->runtime_dir_service)
     128                 :          0 :                 hashmap_remove_value(u->manager->user_units, u->runtime_dir_service, u);
     129                 :            : 
     130         [ #  # ]:          0 :         if (u->slice)
     131                 :          0 :                 hashmap_remove_value(u->manager->user_units, u->slice, u);
     132                 :            : 
     133                 :          0 :         hashmap_remove_value(u->manager->users, UID_TO_PTR(u->uid), u);
     134                 :            : 
     135                 :          0 :         (void) sd_event_source_unref(u->timer_event_source);
     136                 :            : 
     137                 :          0 :         u->service_job = mfree(u->service_job);
     138                 :            : 
     139                 :          0 :         u->service = mfree(u->service);
     140                 :          0 :         u->runtime_dir_service = mfree(u->runtime_dir_service);
     141                 :          0 :         u->slice = mfree(u->slice);
     142                 :          0 :         u->runtime_path = mfree(u->runtime_path);
     143                 :          0 :         u->state_file = mfree(u->state_file);
     144                 :          0 :         u->name = mfree(u->name);
     145                 :          0 :         u->home = mfree(u->home);
     146                 :            : 
     147                 :          0 :         return mfree(u);
     148                 :            : }
     149                 :            : 
     150                 :          0 : static int user_save_internal(User *u) {
     151                 :          0 :         _cleanup_free_ char *temp_path = NULL;
     152                 :          0 :         _cleanup_fclose_ FILE *f = NULL;
     153                 :            :         int r;
     154                 :            : 
     155         [ #  # ]:          0 :         assert(u);
     156         [ #  # ]:          0 :         assert(u->state_file);
     157                 :            : 
     158                 :          0 :         r = mkdir_safe_label("/run/systemd/users", 0755, 0, 0, MKDIR_WARN_MODE);
     159         [ #  # ]:          0 :         if (r < 0)
     160                 :          0 :                 goto fail;
     161                 :            : 
     162                 :          0 :         r = fopen_temporary(u->state_file, &f, &temp_path);
     163         [ #  # ]:          0 :         if (r < 0)
     164                 :          0 :                 goto fail;
     165                 :            : 
     166                 :          0 :         (void) fchmod(fileno(f), 0644);
     167                 :            : 
     168                 :          0 :         fprintf(f,
     169                 :            :                 "# This is private data. Do not parse.\n"
     170                 :            :                 "NAME=%s\n"
     171                 :            :                 "STATE=%s\n"         /* friendly user-facing state */
     172                 :            :                 "STOPPING=%s\n",     /* low-level state */
     173                 :            :                 u->name,
     174                 :            :                 user_state_to_string(user_get_state(u)),
     175                 :          0 :                 yes_no(u->stopping));
     176                 :            : 
     177                 :            :         /* LEGACY: no-one reads RUNTIME= anymore, drop it at some point */
     178         [ #  # ]:          0 :         if (u->runtime_path)
     179                 :          0 :                 fprintf(f, "RUNTIME=%s\n", u->runtime_path);
     180                 :            : 
     181         [ #  # ]:          0 :         if (u->service_job)
     182                 :          0 :                 fprintf(f, "SERVICE_JOB=%s\n", u->service_job);
     183                 :            : 
     184         [ #  # ]:          0 :         if (u->display)
     185                 :          0 :                 fprintf(f, "DISPLAY=%s\n", u->display->id);
     186                 :            : 
     187         [ #  # ]:          0 :         if (dual_timestamp_is_set(&u->timestamp))
     188                 :          0 :                 fprintf(f,
     189                 :            :                         "REALTIME="USEC_FMT"\n"
     190                 :            :                         "MONOTONIC="USEC_FMT"\n",
     191                 :            :                         u->timestamp.realtime,
     192                 :            :                         u->timestamp.monotonic);
     193                 :            : 
     194         [ #  # ]:          0 :         if (u->last_session_timestamp != USEC_INFINITY)
     195                 :          0 :                 fprintf(f, "LAST_SESSION_TIMESTAMP=" USEC_FMT "\n",
     196                 :            :                         u->last_session_timestamp);
     197                 :            : 
     198         [ #  # ]:          0 :         if (u->sessions) {
     199                 :            :                 Session *i;
     200                 :            :                 bool first;
     201                 :            : 
     202                 :          0 :                 fputs("SESSIONS=", f);
     203                 :          0 :                 first = true;
     204         [ #  # ]:          0 :                 LIST_FOREACH(sessions_by_user, i, u->sessions) {
     205         [ #  # ]:          0 :                         if (first)
     206                 :          0 :                                 first = false;
     207                 :            :                         else
     208                 :          0 :                                 fputc(' ', f);
     209                 :            : 
     210                 :          0 :                         fputs(i->id, f);
     211                 :            :                 }
     212                 :            : 
     213                 :          0 :                 fputs("\nSEATS=", f);
     214                 :          0 :                 first = true;
     215         [ #  # ]:          0 :                 LIST_FOREACH(sessions_by_user, i, u->sessions) {
     216         [ #  # ]:          0 :                         if (!i->seat)
     217                 :          0 :                                 continue;
     218                 :            : 
     219         [ #  # ]:          0 :                         if (first)
     220                 :          0 :                                 first = false;
     221                 :            :                         else
     222                 :          0 :                                 fputc(' ', f);
     223                 :            : 
     224                 :          0 :                         fputs(i->seat->id, f);
     225                 :            :                 }
     226                 :            : 
     227                 :          0 :                 fputs("\nACTIVE_SESSIONS=", f);
     228                 :          0 :                 first = true;
     229         [ #  # ]:          0 :                 LIST_FOREACH(sessions_by_user, i, u->sessions) {
     230         [ #  # ]:          0 :                         if (!session_is_active(i))
     231                 :          0 :                                 continue;
     232                 :            : 
     233         [ #  # ]:          0 :                         if (first)
     234                 :          0 :                                 first = false;
     235                 :            :                         else
     236                 :          0 :                                 fputc(' ', f);
     237                 :            : 
     238                 :          0 :                         fputs(i->id, f);
     239                 :            :                 }
     240                 :            : 
     241                 :          0 :                 fputs("\nONLINE_SESSIONS=", f);
     242                 :          0 :                 first = true;
     243         [ #  # ]:          0 :                 LIST_FOREACH(sessions_by_user, i, u->sessions) {
     244         [ #  # ]:          0 :                         if (session_get_state(i) == SESSION_CLOSING)
     245                 :          0 :                                 continue;
     246                 :            : 
     247         [ #  # ]:          0 :                         if (first)
     248                 :          0 :                                 first = false;
     249                 :            :                         else
     250                 :          0 :                                 fputc(' ', f);
     251                 :            : 
     252                 :          0 :                         fputs(i->id, f);
     253                 :            :                 }
     254                 :            : 
     255                 :          0 :                 fputs("\nACTIVE_SEATS=", f);
     256                 :          0 :                 first = true;
     257         [ #  # ]:          0 :                 LIST_FOREACH(sessions_by_user, i, u->sessions) {
     258   [ #  #  #  # ]:          0 :                         if (!session_is_active(i) || !i->seat)
     259                 :          0 :                                 continue;
     260                 :            : 
     261         [ #  # ]:          0 :                         if (first)
     262                 :          0 :                                 first = false;
     263                 :            :                         else
     264                 :          0 :                                 fputc(' ', f);
     265                 :            : 
     266                 :          0 :                         fputs(i->seat->id, f);
     267                 :            :                 }
     268                 :            : 
     269                 :          0 :                 fputs("\nONLINE_SEATS=", f);
     270                 :          0 :                 first = true;
     271         [ #  # ]:          0 :                 LIST_FOREACH(sessions_by_user, i, u->sessions) {
     272   [ #  #  #  # ]:          0 :                         if (session_get_state(i) == SESSION_CLOSING || !i->seat)
     273                 :          0 :                                 continue;
     274                 :            : 
     275         [ #  # ]:          0 :                         if (first)
     276                 :          0 :                                 first = false;
     277                 :            :                         else
     278                 :          0 :                                 fputc(' ', f);
     279                 :            : 
     280                 :          0 :                         fputs(i->seat->id, f);
     281                 :            :                 }
     282                 :          0 :                 fputc('\n', f);
     283                 :            :         }
     284                 :            : 
     285                 :          0 :         r = fflush_and_check(f);
     286         [ #  # ]:          0 :         if (r < 0)
     287                 :          0 :                 goto fail;
     288                 :            : 
     289         [ #  # ]:          0 :         if (rename(temp_path, u->state_file) < 0) {
     290                 :          0 :                 r = -errno;
     291                 :          0 :                 goto fail;
     292                 :            :         }
     293                 :            : 
     294                 :          0 :         return 0;
     295                 :            : 
     296                 :          0 : fail:
     297                 :          0 :         (void) unlink(u->state_file);
     298                 :            : 
     299         [ #  # ]:          0 :         if (temp_path)
     300                 :          0 :                 (void) unlink(temp_path);
     301                 :            : 
     302         [ #  # ]:          0 :         return log_error_errno(r, "Failed to save user data %s: %m", u->state_file);
     303                 :            : }
     304                 :            : 
     305                 :          0 : int user_save(User *u) {
     306         [ #  # ]:          0 :         assert(u);
     307                 :            : 
     308         [ #  # ]:          0 :         if (!u->started)
     309                 :          0 :                 return 0;
     310                 :            : 
     311                 :          0 :         return user_save_internal(u);
     312                 :            : }
     313                 :            : 
     314                 :          0 : int user_load(User *u) {
     315                 :          0 :         _cleanup_free_ char *realtime = NULL, *monotonic = NULL, *stopping = NULL, *last_session_timestamp = NULL;
     316                 :            :         int r;
     317                 :            : 
     318         [ #  # ]:          0 :         assert(u);
     319                 :            : 
     320                 :          0 :         r = parse_env_file(NULL, u->state_file,
     321                 :            :                            "SERVICE_JOB",            &u->service_job,
     322                 :            :                            "STOPPING",               &stopping,
     323                 :            :                            "REALTIME",               &realtime,
     324                 :            :                            "MONOTONIC",              &monotonic,
     325                 :            :                            "LAST_SESSION_TIMESTAMP", &last_session_timestamp);
     326         [ #  # ]:          0 :         if (r == -ENOENT)
     327                 :          0 :                 return 0;
     328         [ #  # ]:          0 :         if (r < 0)
     329         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to read %s: %m", u->state_file);
     330                 :            : 
     331         [ #  # ]:          0 :         if (stopping) {
     332                 :          0 :                 r = parse_boolean(stopping);
     333         [ #  # ]:          0 :                 if (r < 0)
     334         [ #  # ]:          0 :                         log_debug_errno(r, "Failed to parse 'STOPPING' boolean: %s", stopping);
     335                 :            :                 else
     336                 :          0 :                         u->stopping = r;
     337                 :            :         }
     338                 :            : 
     339         [ #  # ]:          0 :         if (realtime)
     340                 :          0 :                 (void) deserialize_usec(realtime, &u->timestamp.realtime);
     341         [ #  # ]:          0 :         if (monotonic)
     342                 :          0 :                 (void) deserialize_usec(monotonic, &u->timestamp.monotonic);
     343         [ #  # ]:          0 :         if (last_session_timestamp)
     344                 :          0 :                 (void) deserialize_usec(last_session_timestamp, &u->last_session_timestamp);
     345                 :            : 
     346                 :          0 :         return 0;
     347                 :            : }
     348                 :            : 
     349                 :          0 : static void user_start_service(User *u) {
     350                 :          0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
     351                 :            :         int r;
     352                 :            : 
     353         [ #  # ]:          0 :         assert(u);
     354                 :            : 
     355                 :            :         /* Start the service containing the "systemd --user" instance (user@.service). Note that we don't explicitly
     356                 :            :          * start the per-user slice or the systemd-runtime-dir@.service instance, as those are pulled in both by
     357                 :            :          * user@.service and the session scopes as dependencies. */
     358                 :            : 
     359                 :          0 :         u->service_job = mfree(u->service_job);
     360                 :            : 
     361                 :          0 :         r = manager_start_unit(u->manager, u->service, &error, &u->service_job);
     362         [ #  # ]:          0 :         if (r < 0)
     363   [ #  #  #  # ]:          0 :                 log_full_errno(sd_bus_error_has_name(&error, BUS_ERROR_UNIT_MASKED) ? LOG_DEBUG : LOG_WARNING, r,
     364                 :            :                                "Failed to start user service '%s', ignoring: %s", u->service, bus_error_message(&error, r));
     365                 :          0 : }
     366                 :            : 
     367                 :          0 : int user_start(User *u) {
     368         [ #  # ]:          0 :         assert(u);
     369                 :            : 
     370   [ #  #  #  # ]:          0 :         if (u->started && !u->stopping)
     371                 :          0 :                 return 0;
     372                 :            : 
     373                 :            :         /* If u->stopping is set, the user is marked for removal and service stop-jobs are queued. We have to clear
     374                 :            :          * that flag before queueing the start-jobs again. If they succeed, the user object can be re-used just fine
     375                 :            :          * (pid1 takes care of job-ordering and proper restart), but if they fail, we want to force another user_stop()
     376                 :            :          * so possibly pending units are stopped. */
     377                 :          0 :         u->stopping = false;
     378                 :            : 
     379         [ #  # ]:          0 :         if (!u->started)
     380         [ #  # ]:          0 :                 log_debug("Starting services for new user %s.", u->name);
     381                 :            : 
     382                 :            :         /* Save the user data so far, because pam_systemd will read the XDG_RUNTIME_DIR out of it while starting up
     383                 :            :          * systemd --user.  We need to do user_save_internal() because we have not "officially" started yet. */
     384                 :          0 :         user_save_internal(u);
     385                 :            : 
     386                 :            :         /* Start user@UID.service */
     387                 :          0 :         user_start_service(u);
     388                 :            : 
     389         [ #  # ]:          0 :         if (!u->started) {
     390         [ #  # ]:          0 :                 if (!dual_timestamp_is_set(&u->timestamp))
     391                 :          0 :                         dual_timestamp_get(&u->timestamp);
     392                 :          0 :                 user_send_signal(u, true);
     393                 :          0 :                 u->started = true;
     394                 :            :         }
     395                 :            : 
     396                 :            :         /* Save new user data */
     397                 :          0 :         user_save(u);
     398                 :            : 
     399                 :          0 :         return 0;
     400                 :            : }
     401                 :            : 
     402                 :          0 : static void user_stop_service(User *u) {
     403                 :          0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
     404                 :            :         int r;
     405                 :            : 
     406         [ #  # ]:          0 :         assert(u);
     407         [ #  # ]:          0 :         assert(u->service);
     408                 :            : 
     409                 :            :         /* The reverse of user_start_service(). Note that we only stop user@UID.service here, and let StopWhenUnneeded=
     410                 :            :          * deal with the slice and the user-runtime-dir@.service instance. */
     411                 :            : 
     412                 :          0 :         u->service_job = mfree(u->service_job);
     413                 :            : 
     414                 :          0 :         r = manager_stop_unit(u->manager, u->service, &error, &u->service_job);
     415         [ #  # ]:          0 :         if (r < 0)
     416         [ #  # ]:          0 :                 log_warning_errno(r, "Failed to stop user service '%s', ignoring: %s", u->service, bus_error_message(&error, r));
     417                 :          0 : }
     418                 :            : 
     419                 :          0 : int user_stop(User *u, bool force) {
     420                 :            :         Session *s;
     421                 :          0 :         int r = 0;
     422         [ #  # ]:          0 :         assert(u);
     423                 :            : 
     424                 :            :         /* This is called whenever we begin with tearing down a user record. It's called in two cases: explicit API
     425                 :            :          * request to do so via the bus (in which case 'force' is true) and automatically due to GC, if there's no
     426                 :            :          * session left pinning it (in which case 'force' is false). Note that this just initiates tearing down of the
     427                 :            :          * user, the User object will remain in memory until user_finalize() is called, see below. */
     428                 :            : 
     429         [ #  # ]:          0 :         if (!u->started)
     430                 :          0 :                 return 0;
     431                 :            : 
     432         [ #  # ]:          0 :         if (u->stopping) { /* Stop jobs have already been queued */
     433                 :          0 :                 user_save(u);
     434                 :          0 :                 return 0;
     435                 :            :         }
     436                 :            : 
     437         [ #  # ]:          0 :         LIST_FOREACH(sessions_by_user, s, u->sessions) {
     438                 :            :                 int k;
     439                 :            : 
     440                 :          0 :                 k = session_stop(s, force);
     441         [ #  # ]:          0 :                 if (k < 0)
     442                 :          0 :                         r = k;
     443                 :            :         }
     444                 :            : 
     445                 :          0 :         user_stop_service(u);
     446                 :            : 
     447                 :          0 :         u->stopping = true;
     448                 :            : 
     449                 :          0 :         user_save(u);
     450                 :            : 
     451                 :          0 :         return r;
     452                 :            : }
     453                 :            : 
     454                 :          0 : int user_finalize(User *u) {
     455                 :            :         Session *s;
     456                 :          0 :         int r = 0, k;
     457                 :            : 
     458         [ #  # ]:          0 :         assert(u);
     459                 :            : 
     460                 :            :         /* Called when the user is really ready to be freed, i.e. when all unit stop jobs and suchlike for it are
     461                 :            :          * done. This is called as a result of an earlier user_done() when all jobs are completed. */
     462                 :            : 
     463         [ #  # ]:          0 :         if (u->started)
     464         [ #  # ]:          0 :                 log_debug("User %s logged out.", u->name);
     465                 :            : 
     466         [ #  # ]:          0 :         LIST_FOREACH(sessions_by_user, s, u->sessions) {
     467                 :          0 :                 k = session_finalize(s);
     468         [ #  # ]:          0 :                 if (k < 0)
     469                 :          0 :                         r = k;
     470                 :            :         }
     471                 :            : 
     472                 :            :         /* Clean SysV + POSIX IPC objects, but only if this is not a system user. Background: in many setups cronjobs
     473                 :            :          * are run in full PAM and thus logind sessions, even if the code run doesn't belong to actual users but to
     474                 :            :          * system components. Since enable RemoveIPC= globally for all users, we need to be a bit careful with such
     475                 :            :          * cases, as we shouldn't accidentally remove a system service's IPC objects while it is running, just because
     476                 :            :          * a cronjob running as the same user just finished. Hence: exclude system users generally from IPC clean-up,
     477                 :            :          * and do it only for normal users. */
     478   [ #  #  #  # ]:          0 :         if (u->manager->remove_ipc && !uid_is_system(u->uid)) {
     479                 :          0 :                 k = clean_ipc_by_uid(u->uid);
     480         [ #  # ]:          0 :                 if (k < 0)
     481                 :          0 :                         r = k;
     482                 :            :         }
     483                 :            : 
     484                 :          0 :         (void) unlink(u->state_file);
     485                 :          0 :         user_add_to_gc_queue(u);
     486                 :            : 
     487         [ #  # ]:          0 :         if (u->started) {
     488                 :          0 :                 user_send_signal(u, false);
     489                 :          0 :                 u->started = false;
     490                 :            :         }
     491                 :            : 
     492                 :          0 :         return r;
     493                 :            : }
     494                 :            : 
     495                 :          0 : int user_get_idle_hint(User *u, dual_timestamp *t) {
     496                 :            :         Session *s;
     497                 :          0 :         bool idle_hint = true;
     498                 :          0 :         dual_timestamp ts = DUAL_TIMESTAMP_NULL;
     499                 :            : 
     500         [ #  # ]:          0 :         assert(u);
     501                 :            : 
     502         [ #  # ]:          0 :         LIST_FOREACH(sessions_by_user, s, u->sessions) {
     503                 :            :                 dual_timestamp k;
     504                 :            :                 int ih;
     505                 :            : 
     506                 :          0 :                 ih = session_get_idle_hint(s, &k);
     507         [ #  # ]:          0 :                 if (ih < 0)
     508                 :          0 :                         return ih;
     509                 :            : 
     510         [ #  # ]:          0 :                 if (!ih) {
     511         [ #  # ]:          0 :                         if (!idle_hint) {
     512         [ #  # ]:          0 :                                 if (k.monotonic < ts.monotonic)
     513                 :          0 :                                         ts = k;
     514                 :            :                         } else {
     515                 :          0 :                                 idle_hint = false;
     516                 :          0 :                                 ts = k;
     517                 :            :                         }
     518         [ #  # ]:          0 :                 } else if (idle_hint) {
     519                 :            : 
     520         [ #  # ]:          0 :                         if (k.monotonic > ts.monotonic)
     521                 :          0 :                                 ts = k;
     522                 :            :                 }
     523                 :            :         }
     524                 :            : 
     525         [ #  # ]:          0 :         if (t)
     526                 :          0 :                 *t = ts;
     527                 :            : 
     528                 :          0 :         return idle_hint;
     529                 :            : }
     530                 :            : 
     531                 :          0 : int user_check_linger_file(User *u) {
     532                 :          0 :         _cleanup_free_ char *cc = NULL;
     533                 :          0 :         char *p = NULL;
     534                 :            : 
     535                 :          0 :         cc = cescape(u->name);
     536         [ #  # ]:          0 :         if (!cc)
     537                 :          0 :                 return -ENOMEM;
     538                 :            : 
     539   [ #  #  #  #  :          0 :         p = strjoina("/var/lib/systemd/linger/", cc);
          #  #  #  #  #  
                #  #  # ]
     540         [ #  # ]:          0 :         if (access(p, F_OK) < 0) {
     541         [ #  # ]:          0 :                 if (errno != ENOENT)
     542                 :          0 :                         return -errno;
     543                 :            : 
     544                 :          0 :                 return false;
     545                 :            :         }
     546                 :            : 
     547                 :          0 :         return true;
     548                 :            : }
     549                 :            : 
     550                 :          0 : static bool user_unit_active(User *u) {
     551                 :            :         const char *i;
     552                 :            :         int r;
     553                 :            : 
     554         [ #  # ]:          0 :         assert(u->service);
     555         [ #  # ]:          0 :         assert(u->runtime_dir_service);
     556         [ #  # ]:          0 :         assert(u->slice);
     557                 :            : 
     558         [ #  # ]:          0 :         FOREACH_STRING(i, u->service, u->runtime_dir_service, u->slice) {
     559         [ #  # ]:          0 :                 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
     560                 :            : 
     561                 :          0 :                 r = manager_unit_is_active(u->manager, i, &error);
     562         [ #  # ]:          0 :                 if (r < 0)
     563         [ #  # ]:          0 :                         log_debug_errno(r, "Failed to determine whether unit '%s' is active, ignoring: %s", u->service, bus_error_message(&error, r));
     564         [ #  # ]:          0 :                 if (r != 0)
     565                 :          0 :                         return true;
     566                 :            :         }
     567                 :            : 
     568                 :          0 :         return false;
     569                 :            : }
     570                 :            : 
     571                 :          0 : bool user_may_gc(User *u, bool drop_not_started) {
     572                 :            :         int r;
     573                 :            : 
     574         [ #  # ]:          0 :         assert(u);
     575                 :            : 
     576   [ #  #  #  # ]:          0 :         if (drop_not_started && !u->started)
     577                 :          0 :                 return true;
     578                 :            : 
     579         [ #  # ]:          0 :         if (u->sessions)
     580                 :          0 :                 return false;
     581                 :            : 
     582         [ #  # ]:          0 :         if (u->last_session_timestamp != USEC_INFINITY) {
     583                 :            :                 /* All sessions have been closed. Let's see if we shall leave the user record around for a bit */
     584                 :            : 
     585         [ #  # ]:          0 :                 if (u->manager->user_stop_delay == USEC_INFINITY)
     586                 :          0 :                         return false; /* Leave it around forever! */
     587   [ #  #  #  # ]:          0 :                 if (u->manager->user_stop_delay > 0 &&
     588                 :          0 :                     now(CLOCK_MONOTONIC) < usec_add(u->last_session_timestamp, u->manager->user_stop_delay))
     589                 :          0 :                         return false; /* Leave it around for a bit longer. */
     590                 :            :         }
     591                 :            : 
     592                 :            :         /* Is this a user that shall stay around forever ("linger")? Before we say "no" to GC'ing for lingering users, let's check
     593                 :            :          * if any of the three units that we maintain for this user is still around. If none of them is,
     594                 :            :          * there's no need to keep this user around even if lingering is enabled. */
     595   [ #  #  #  # ]:          0 :         if (user_check_linger_file(u) > 0 && user_unit_active(u))
     596                 :          0 :                 return false;
     597                 :            : 
     598                 :            :         /* Check if our job is still pending */
     599         [ #  # ]:          0 :         if (u->service_job) {
     600         [ #  # ]:          0 :                 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
     601                 :            : 
     602                 :          0 :                 r = manager_job_is_active(u->manager, u->service_job, &error);
     603         [ #  # ]:          0 :                 if (r < 0)
     604         [ #  # ]:          0 :                         log_debug_errno(r, "Failed to determine whether job '%s' is pending, ignoring: %s", u->service_job, bus_error_message(&error, r));
     605         [ #  # ]:          0 :                 if (r != 0)
     606                 :          0 :                         return false;
     607                 :            :         }
     608                 :            : 
     609                 :            :         /* Note that we don't care if the three units we manage for each user object are up or not, as we are managing
     610                 :            :          * their state rather than tracking it. */
     611                 :            : 
     612                 :          0 :         return true;
     613                 :            : }
     614                 :            : 
     615                 :          0 : void user_add_to_gc_queue(User *u) {
     616         [ #  # ]:          0 :         assert(u);
     617                 :            : 
     618         [ #  # ]:          0 :         if (u->in_gc_queue)
     619                 :          0 :                 return;
     620                 :            : 
     621   [ #  #  #  # ]:          0 :         LIST_PREPEND(gc_queue, u->manager->user_gc_queue, u);
     622                 :          0 :         u->in_gc_queue = true;
     623                 :            : }
     624                 :            : 
     625                 :          0 : UserState user_get_state(User *u) {
     626                 :            :         Session *i;
     627                 :            : 
     628         [ #  # ]:          0 :         assert(u);
     629                 :            : 
     630         [ #  # ]:          0 :         if (u->stopping)
     631                 :          0 :                 return USER_CLOSING;
     632                 :            : 
     633   [ #  #  #  # ]:          0 :         if (!u->started || u->service_job)
     634                 :          0 :                 return USER_OPENING;
     635                 :            : 
     636         [ #  # ]:          0 :         if (u->sessions) {
     637                 :          0 :                 bool all_closing = true;
     638                 :            : 
     639         [ #  # ]:          0 :                 LIST_FOREACH(sessions_by_user, i, u->sessions) {
     640                 :            :                         SessionState state;
     641                 :            : 
     642                 :          0 :                         state = session_get_state(i);
     643         [ #  # ]:          0 :                         if (state == SESSION_ACTIVE)
     644                 :          0 :                                 return USER_ACTIVE;
     645         [ #  # ]:          0 :                         if (state != SESSION_CLOSING)
     646                 :          0 :                                 all_closing = false;
     647                 :            :                 }
     648                 :            : 
     649         [ #  # ]:          0 :                 return all_closing ? USER_CLOSING : USER_ONLINE;
     650                 :            :         }
     651                 :            : 
     652   [ #  #  #  # ]:          0 :         if (user_check_linger_file(u) > 0 && user_unit_active(u))
     653                 :          0 :                 return USER_LINGERING;
     654                 :            : 
     655                 :          0 :         return USER_CLOSING;
     656                 :            : }
     657                 :            : 
     658                 :          0 : int user_kill(User *u, int signo) {
     659         [ #  # ]:          0 :         assert(u);
     660                 :            : 
     661                 :          0 :         return manager_kill_unit(u->manager, u->slice, KILL_ALL, signo, NULL);
     662                 :            : }
     663                 :            : 
     664                 :          0 : static bool elect_display_filter(Session *s) {
     665                 :            :         /* Return true if the session is a candidate for the user’s ‘primary session’ or ‘display’. */
     666         [ #  # ]:          0 :         assert(s);
     667                 :            : 
     668   [ #  #  #  #  :          0 :         return IN_SET(s->class, SESSION_USER, SESSION_GREETER) && s->started && !s->stopping;
             #  #  #  # ]
     669                 :            : }
     670                 :            : 
     671                 :          0 : static int elect_display_compare(Session *s1, Session *s2) {
     672                 :            :         /* Indexed by SessionType. Lower numbers mean more preferred. */
     673                 :            :         static const int type_ranks[_SESSION_TYPE_MAX] = {
     674                 :            :                 [SESSION_UNSPECIFIED] = 0,
     675                 :            :                 [SESSION_TTY] = -2,
     676                 :            :                 [SESSION_X11] = -3,
     677                 :            :                 [SESSION_WAYLAND] = -3,
     678                 :            :                 [SESSION_MIR] = -3,
     679                 :            :                 [SESSION_WEB] = -1,
     680                 :            :         };
     681                 :            : 
     682                 :            :         /* Calculate the partial order relationship between s1 and s2,
     683                 :            :          * returning < 0 if s1 is preferred as the user’s ‘primary session’,
     684                 :            :          * 0 if s1 and s2 are equally preferred or incomparable, or > 0 if s2
     685                 :            :          * is preferred.
     686                 :            :          *
     687                 :            :          * s1 or s2 may be NULL. */
     688   [ #  #  #  # ]:          0 :         if (!s1 && !s2)
     689                 :          0 :                 return 0;
     690                 :            : 
     691         [ #  # ]:          0 :         if ((s1 == NULL) != (s2 == NULL))
     692                 :          0 :                 return (s1 == NULL) - (s2 == NULL);
     693                 :            : 
     694         [ #  # ]:          0 :         if (s1->stopping != s2->stopping)
     695                 :          0 :                 return s1->stopping - s2->stopping;
     696                 :            : 
     697         [ #  # ]:          0 :         if ((s1->class != SESSION_USER) != (s2->class != SESSION_USER))
     698                 :          0 :                 return (s1->class != SESSION_USER) - (s2->class != SESSION_USER);
     699                 :            : 
     700         [ #  # ]:          0 :         if ((s1->type == _SESSION_TYPE_INVALID) != (s2->type == _SESSION_TYPE_INVALID))
     701                 :          0 :                 return (s1->type == _SESSION_TYPE_INVALID) - (s2->type == _SESSION_TYPE_INVALID);
     702                 :            : 
     703         [ #  # ]:          0 :         if (s1->type != s2->type)
     704                 :          0 :                 return type_ranks[s1->type] - type_ranks[s2->type];
     705                 :            : 
     706                 :          0 :         return 0;
     707                 :            : }
     708                 :            : 
     709                 :          0 : void user_elect_display(User *u) {
     710                 :            :         Session *s;
     711                 :            : 
     712         [ #  # ]:          0 :         assert(u);
     713                 :            : 
     714                 :            :         /* This elects a primary session for each user, which we call the "display". We try to keep the assignment
     715                 :            :          * stable, but we "upgrade" to better choices. */
     716         [ #  # ]:          0 :         log_debug("Electing new display for user %s", u->name);
     717                 :            : 
     718         [ #  # ]:          0 :         LIST_FOREACH(sessions_by_user, s, u->sessions) {
     719         [ #  # ]:          0 :                 if (!elect_display_filter(s)) {
     720         [ #  # ]:          0 :                         log_debug("Ignoring session %s", s->id);
     721                 :          0 :                         continue;
     722                 :            :                 }
     723                 :            : 
     724         [ #  # ]:          0 :                 if (elect_display_compare(s, u->display) < 0) {
     725   [ #  #  #  # ]:          0 :                         log_debug("Choosing session %s in preference to %s", s->id, u->display ? u->display->id : "-");
     726                 :          0 :                         u->display = s;
     727                 :            :                 }
     728                 :            :         }
     729                 :          0 : }
     730                 :            : 
     731                 :          0 : static int user_stop_timeout_callback(sd_event_source *es, uint64_t usec, void *userdata) {
     732                 :          0 :         User *u = userdata;
     733                 :            : 
     734         [ #  # ]:          0 :         assert(u);
     735                 :          0 :         user_add_to_gc_queue(u);
     736                 :            : 
     737                 :          0 :         return 0;
     738                 :            : }
     739                 :            : 
     740                 :          0 : void user_update_last_session_timer(User *u) {
     741                 :            :         int r;
     742                 :            : 
     743         [ #  # ]:          0 :         assert(u);
     744                 :            : 
     745         [ #  # ]:          0 :         if (u->sessions) {
     746                 :            :                 /* There are sessions, turn off the timer */
     747                 :          0 :                 u->last_session_timestamp = USEC_INFINITY;
     748                 :          0 :                 u->timer_event_source = sd_event_source_unref(u->timer_event_source);
     749                 :          0 :                 return;
     750                 :            :         }
     751                 :            : 
     752         [ #  # ]:          0 :         if (u->last_session_timestamp != USEC_INFINITY)
     753                 :          0 :                 return; /* Timer already started */
     754                 :            : 
     755                 :          0 :         u->last_session_timestamp = now(CLOCK_MONOTONIC);
     756                 :            : 
     757         [ #  # ]:          0 :         assert(!u->timer_event_source);
     758                 :            : 
     759   [ #  #  #  # ]:          0 :         if (IN_SET(u->manager->user_stop_delay, 0, USEC_INFINITY))
     760                 :          0 :                 return;
     761                 :            : 
     762         [ #  # ]:          0 :         if (sd_event_get_state(u->manager->event) == SD_EVENT_FINISHED) {
     763         [ #  # ]:          0 :                 log_debug("Not allocating user stop timeout, since we are already exiting.");
     764                 :          0 :                 return;
     765                 :            :         }
     766                 :            : 
     767                 :          0 :         r = sd_event_add_time(u->manager->event,
     768                 :            :                               &u->timer_event_source,
     769                 :            :                               CLOCK_MONOTONIC,
     770                 :          0 :                               usec_add(u->last_session_timestamp, u->manager->user_stop_delay), 0,
     771                 :            :                               user_stop_timeout_callback, u);
     772         [ #  # ]:          0 :         if (r < 0)
     773         [ #  # ]:          0 :                 log_warning_errno(r, "Failed to enqueue user stop event source, ignoring: %m");
     774                 :            : 
     775         [ #  # ]:          0 :         if (DEBUG_LOGGING) {
     776                 :            :                 char s[FORMAT_TIMESPAN_MAX];
     777                 :            : 
     778         [ #  # ]:          0 :                 log_debug("Last session of user '%s' logged out, terminating user context in %s.",
     779                 :            :                           u->name,
     780                 :            :                           format_timespan(s, sizeof(s), u->manager->user_stop_delay, USEC_PER_MSEC));
     781                 :            :         }
     782                 :            : }
     783                 :            : 
     784                 :            : static const char* const user_state_table[_USER_STATE_MAX] = {
     785                 :            :         [USER_OFFLINE] = "offline",
     786                 :            :         [USER_OPENING] = "opening",
     787                 :            :         [USER_LINGERING] = "lingering",
     788                 :            :         [USER_ONLINE] = "online",
     789                 :            :         [USER_ACTIVE] = "active",
     790                 :            :         [USER_CLOSING] = "closing"
     791                 :            : };
     792                 :            : 
     793   [ +  +  +  + ]:         64 : DEFINE_STRING_TABLE_LOOKUP(user_state, UserState);
     794                 :            : 
     795                 :          0 : int config_parse_tmpfs_size(
     796                 :            :                 const char* unit,
     797                 :            :                 const char *filename,
     798                 :            :                 unsigned line,
     799                 :            :                 const char *section,
     800                 :            :                 unsigned section_line,
     801                 :            :                 const char *lvalue,
     802                 :            :                 int ltype,
     803                 :            :                 const char *rvalue,
     804                 :            :                 void *data,
     805                 :            :                 void *userdata) {
     806                 :            : 
     807                 :          0 :         uint64_t *sz = data;
     808                 :            :         int r;
     809                 :            : 
     810         [ #  # ]:          0 :         assert(filename);
     811         [ #  # ]:          0 :         assert(lvalue);
     812         [ #  # ]:          0 :         assert(rvalue);
     813         [ #  # ]:          0 :         assert(data);
     814                 :            : 
     815                 :            :         /* First, try to parse as percentage */
     816                 :          0 :         r = parse_permille(rvalue);
     817   [ #  #  #  # ]:          0 :         if (r > 0 && r < 1000)
     818                 :          0 :                 *sz = physical_memory_scale(r, 1000U);
     819                 :            :         else {
     820                 :            :                 uint64_t k;
     821                 :            : 
     822                 :            :                 /* If the passed argument was not a percentage, or out of range, parse as byte size */
     823                 :            : 
     824                 :          0 :                 r = parse_size(rvalue, 1024, &k);
     825   [ #  #  #  # ]:          0 :                 if (r >= 0 && (k <= 0 || (uint64_t) (size_t) k != k))
     826                 :          0 :                         r = -ERANGE;
     827         [ #  # ]:          0 :                 if (r < 0) {
     828         [ #  # ]:          0 :                         log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value '%s', ignoring: %m", rvalue);
     829                 :          0 :                         return 0;
     830                 :            :                 }
     831                 :            : 
     832                 :          0 :                 *sz = PAGE_ALIGN((size_t) k);
     833                 :            :         }
     834                 :            : 
     835                 :          0 :         return 0;
     836                 :            : }
     837                 :            : 
     838                 :          0 : int config_parse_compat_user_tasks_max(
     839                 :            :                 const char *unit,
     840                 :            :                 const char *filename,
     841                 :            :                 unsigned line,
     842                 :            :                 const char *section,
     843                 :            :                 unsigned section_line,
     844                 :            :                 const char *lvalue,
     845                 :            :                 int ltype,
     846                 :            :                 const char *rvalue,
     847                 :            :                 void *data,
     848                 :            :                 void *userdata) {
     849                 :            : 
     850         [ #  # ]:          0 :         assert(filename);
     851         [ #  # ]:          0 :         assert(lvalue);
     852         [ #  # ]:          0 :         assert(rvalue);
     853         [ #  # ]:          0 :         assert(data);
     854                 :            : 
     855         [ #  # ]:          0 :         log_syntax(unit, LOG_NOTICE, filename, line, 0,
     856                 :            :                    "Support for option %s= has been removed.",
     857                 :            :                    lvalue);
     858         [ #  # ]:          0 :         log_info("Hint: try creating /etc/systemd/system/user-.slice.d/50-limits.conf with:\n"
     859                 :            :                  "        [Slice]\n"
     860                 :            :                  "        TasksMax=%s",
     861                 :            :                  rvalue);
     862                 :          0 :         return 0;
     863                 :            : }

Generated by: LCOV version 1.14