1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2011 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
23 #include <sys/mount.h>
25 #include <stdio_ext.h>
27 #include "alloc-util.h"
28 #include "bus-common-errors.h"
29 #include "bus-error.h"
31 #include "cgroup-util.h"
32 #include "clean-ipc.h"
33 #include "conf-parser.h"
37 #include "format-util.h"
41 #include "logind-user.h"
43 #include "mount-util.h"
44 #include "parse-util.h"
45 #include "path-util.h"
47 #include "smack-util.h"
49 #include "stdio-util.h"
50 #include "string-table.h"
51 #include "unit-name.h"
52 #include "user-util.h"
55 int user_new(User
**out
, Manager
*m
, uid_t uid
, gid_t gid
, const char *name
) {
56 _cleanup_(user_freep
) User
*u
= NULL
;
57 char lu
[DECIMAL_STR_MAX(uid_t
) + 1];
71 xsprintf(lu
, UID_FMT
, uid
);
73 u
->name
= strdup(name
);
77 if (asprintf(&u
->state_file
, "/run/systemd/users/"UID_FMT
, uid
) < 0)
80 if (asprintf(&u
->runtime_path
, "/run/user/"UID_FMT
, uid
) < 0)
83 r
= slice_build_subslice(SPECIAL_USER_SLICE
, lu
, &u
->slice
);
87 r
= unit_name_build("user", lu
, ".service", &u
->service
);
91 r
= hashmap_put(m
->users
, UID_TO_PTR(uid
), u
);
95 r
= hashmap_put(m
->user_units
, u
->slice
, u
);
99 r
= hashmap_put(m
->user_units
, u
->service
, u
);
108 User
*user_free(User
*u
) {
113 LIST_REMOVE(gc_queue
, u
->manager
->user_gc_queue
, u
);
116 session_free(u
->sessions
);
119 hashmap_remove_value(u
->manager
->user_units
, u
->service
, u
);
122 hashmap_remove_value(u
->manager
->user_units
, u
->slice
, u
);
124 hashmap_remove_value(u
->manager
->users
, UID_TO_PTR(u
->uid
), u
);
126 u
->slice_job
= mfree(u
->slice_job
);
127 u
->service_job
= mfree(u
->service_job
);
129 u
->service
= mfree(u
->service
);
130 u
->slice
= mfree(u
->slice
);
131 u
->runtime_path
= mfree(u
->runtime_path
);
132 u
->state_file
= mfree(u
->state_file
);
133 u
->name
= mfree(u
->name
);
138 static int user_save_internal(User
*u
) {
139 _cleanup_free_
char *temp_path
= NULL
;
140 _cleanup_fclose_
FILE *f
= NULL
;
144 assert(u
->state_file
);
146 r
= mkdir_safe_label("/run/systemd/users", 0755, 0, 0, false);
150 r
= fopen_temporary(u
->state_file
, &f
, &temp_path
);
154 (void) __fsetlocking(f
, FSETLOCKING_BYCALLER
);
155 (void) fchmod(fileno(f
), 0644);
158 "# This is private data. Do not parse.\n"
162 user_state_to_string(user_get_state(u
)));
164 /* LEGACY: no-one reads RUNTIME= anymore, drop it at some point */
166 fprintf(f
, "RUNTIME=%s\n", u
->runtime_path
);
169 fprintf(f
, "SERVICE_JOB=%s\n", u
->service_job
);
172 fprintf(f
, "SLICE_JOB=%s\n", u
->slice_job
);
175 fprintf(f
, "DISPLAY=%s\n", u
->display
->id
);
177 if (dual_timestamp_is_set(&u
->timestamp
))
179 "REALTIME="USEC_FMT
"\n"
180 "MONOTONIC="USEC_FMT
"\n",
181 u
->timestamp
.realtime
,
182 u
->timestamp
.monotonic
);
188 fputs("SESSIONS=", f
);
190 LIST_FOREACH(sessions_by_user
, i
, u
->sessions
) {
199 fputs("\nSEATS=", f
);
201 LIST_FOREACH(sessions_by_user
, i
, u
->sessions
) {
210 fputs(i
->seat
->id
, f
);
213 fputs("\nACTIVE_SESSIONS=", f
);
215 LIST_FOREACH(sessions_by_user
, i
, u
->sessions
) {
216 if (!session_is_active(i
))
227 fputs("\nONLINE_SESSIONS=", f
);
229 LIST_FOREACH(sessions_by_user
, i
, u
->sessions
) {
230 if (session_get_state(i
) == SESSION_CLOSING
)
241 fputs("\nACTIVE_SEATS=", f
);
243 LIST_FOREACH(sessions_by_user
, i
, u
->sessions
) {
244 if (!session_is_active(i
) || !i
->seat
)
252 fputs(i
->seat
->id
, f
);
255 fputs("\nONLINE_SEATS=", f
);
257 LIST_FOREACH(sessions_by_user
, i
, u
->sessions
) {
258 if (session_get_state(i
) == SESSION_CLOSING
|| !i
->seat
)
266 fputs(i
->seat
->id
, f
);
271 r
= fflush_and_check(f
);
275 if (rename(temp_path
, u
->state_file
) < 0) {
283 (void) unlink(u
->state_file
);
286 (void) unlink(temp_path
);
288 return log_error_errno(r
, "Failed to save user data %s: %m", u
->state_file
);
291 int user_save(User
*u
) {
297 return user_save_internal (u
);
300 int user_load(User
*u
) {
301 _cleanup_free_
char *display
= NULL
, *realtime
= NULL
, *monotonic
= NULL
;
307 r
= parse_env_file(u
->state_file
, NEWLINE
,
308 "SERVICE_JOB", &u
->service_job
,
309 "SLICE_JOB", &u
->slice_job
,
311 "REALTIME", &realtime
,
312 "MONOTONIC", &monotonic
,
318 return log_error_errno(r
, "Failed to read %s: %m", u
->state_file
);
322 s
= hashmap_get(u
->manager
->sessions
, display
);
324 if (s
&& s
->display
&& display_is_local(s
->display
))
328 timestamp_deserialize(realtime
, &u
->timestamp
.realtime
);
330 timestamp_deserialize(monotonic
, &u
->timestamp
.monotonic
);
335 static int user_mkdir_runtime_path(User
*u
) {
340 r
= mkdir_safe_label("/run/user", 0755, 0, 0, false);
342 return log_error_errno(r
, "Failed to create /run/user: %m");
344 if (path_is_mount_point(u
->runtime_path
, NULL
, 0) <= 0) {
345 _cleanup_free_
char *t
= NULL
;
347 r
= asprintf(&t
, "mode=0700,uid=" UID_FMT
",gid=" GID_FMT
",size=%zu%s",
348 u
->uid
, u
->gid
, u
->manager
->runtime_dir_size
,
349 mac_smack_use() ? ",smackfsroot=*" : "");
353 (void) mkdir_label(u
->runtime_path
, 0700);
355 r
= mount("tmpfs", u
->runtime_path
, "tmpfs", MS_NODEV
|MS_NOSUID
, t
);
357 if (!IN_SET(errno
, EPERM
, EACCES
)) {
358 r
= log_error_errno(errno
, "Failed to mount per-user tmpfs directory %s: %m", u
->runtime_path
);
362 log_debug_errno(errno
, "Failed to mount per-user tmpfs directory %s, assuming containerized execution, ignoring: %m", u
->runtime_path
);
364 r
= chmod_and_chown(u
->runtime_path
, 0700, u
->uid
, u
->gid
);
366 log_error_errno(r
, "Failed to change runtime directory ownership and mode: %m");
371 r
= label_fix(u
->runtime_path
, false, false);
373 log_warning_errno(r
, "Failed to fix label of '%s', ignoring: %m", u
->runtime_path
);
379 /* Try to clean up, but ignore errors */
380 (void) rmdir(u
->runtime_path
);
384 static int user_start_slice(User
*u
) {
385 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
386 const char *description
;
392 u
->slice_job
= mfree(u
->slice_job
);
393 description
= strjoina("User Slice of ", u
->name
);
395 r
= manager_start_slice(
399 "systemd-logind.service",
400 "systemd-user-sessions.service",
401 u
->manager
->user_tasks_max
,
406 else if (!sd_bus_error_has_name(&error
, BUS_ERROR_UNIT_EXISTS
))
407 /* we don't fail due to this, let's try to continue */
408 log_error_errno(r
, "Failed to start user slice %s, ignoring: %s (%s)",
409 u
->slice
, bus_error_message(&error
, r
), error
.name
);
414 static int user_start_service(User
*u
) {
415 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
421 u
->service_job
= mfree(u
->service_job
);
423 r
= manager_start_unit(
429 /* we don't fail due to this, let's try to continue */
430 log_error_errno(r
, "Failed to start user service, ignoring: %s", bus_error_message(&error
, r
));
432 u
->service_job
= job
;
437 int user_start(User
*u
) {
442 if (u
->started
&& !u
->stopping
)
446 * If u->stopping is set, the user is marked for removal and the slice
447 * and service stop-jobs are queued. We have to clear that flag before
448 * queing the start-jobs again. If they succeed, the user object can be
449 * re-used just fine (pid1 takes care of job-ordering and proper
450 * restart), but if they fail, we want to force another user_stop() so
451 * possibly pending units are stopped.
452 * Note that we don't clear u->started, as we have no clue what state
453 * the user is in on failure here. Hence, we pretend the user is
454 * running so it will be properly taken down by GC. However, we clearly
455 * return an error from user_start() in that case, so no further
456 * reference to the user is taken.
461 log_debug("New user %s logged in.", u
->name
);
463 /* Make XDG_RUNTIME_DIR */
464 r
= user_mkdir_runtime_path(u
);
470 r
= user_start_slice(u
);
474 /* Save the user data so far, because pam_systemd will read the
475 * XDG_RUNTIME_DIR out of it while starting up systemd --user.
476 * We need to do user_save_internal() because we have not
477 * "officially" started yet. */
478 user_save_internal(u
);
480 /* Spawn user systemd */
481 r
= user_start_service(u
);
486 if (!dual_timestamp_is_set(&u
->timestamp
))
487 dual_timestamp_get(&u
->timestamp
);
488 user_send_signal(u
, true);
492 /* Save new user data */
498 static int user_stop_slice(User
*u
) {
499 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
505 r
= manager_stop_unit(u
->manager
, u
->slice
, &error
, &job
);
507 log_error("Failed to stop user slice: %s", bus_error_message(&error
, r
));
517 static int user_stop_service(User
*u
) {
518 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
524 r
= manager_stop_unit(u
->manager
, u
->service
, &error
, &job
);
526 log_error("Failed to stop user service: %s", bus_error_message(&error
, r
));
530 free(u
->service_job
);
531 u
->service_job
= job
;
536 static int user_remove_runtime_path(User
*u
) {
541 r
= rm_rf(u
->runtime_path
, 0);
543 log_error_errno(r
, "Failed to remove runtime directory %s (before unmounting): %m", u
->runtime_path
);
545 /* Ignore cases where the directory isn't mounted, as that's
546 * quite possible, if we lacked the permissions to mount
548 r
= umount2(u
->runtime_path
, MNT_DETACH
);
549 if (r
< 0 && !IN_SET(errno
, EINVAL
, ENOENT
))
550 log_error_errno(errno
, "Failed to unmount user runtime directory %s: %m", u
->runtime_path
);
552 r
= rm_rf(u
->runtime_path
, REMOVE_ROOT
);
554 log_error_errno(r
, "Failed to remove runtime directory %s (after unmounting): %m", u
->runtime_path
);
559 int user_stop(User
*u
, bool force
) {
564 /* Stop jobs have already been queued */
570 LIST_FOREACH(sessions_by_user
, s
, u
->sessions
) {
571 k
= session_stop(s
, force
);
577 k
= user_stop_service(u
);
582 k
= user_stop_slice(u
);
593 int user_finalize(User
*u
) {
600 log_debug("User %s logged out.", u
->name
);
602 LIST_FOREACH(sessions_by_user
, s
, u
->sessions
) {
603 k
= session_finalize(s
);
608 /* Kill XDG_RUNTIME_DIR */
609 k
= user_remove_runtime_path(u
);
613 /* Clean SysV + POSIX IPC objects, but only if this is not a system user. Background: in many setups cronjobs
614 * are run in full PAM and thus logind sessions, even if the code run doesn't belong to actual users but to
615 * system components. Since enable RemoveIPC= globally for all users, we need to be a bit careful with such
616 * cases, as we shouldn't accidentally remove a system service's IPC objects while it is running, just because
617 * a cronjob running as the same user just finished. Hence: exclude system users generally from IPC clean-up,
618 * and do it only for normal users. */
619 if (u
->manager
->remove_ipc
&& !uid_is_system(u
->uid
)) {
620 k
= clean_ipc_by_uid(u
->uid
);
625 unlink(u
->state_file
);
626 user_add_to_gc_queue(u
);
629 user_send_signal(u
, false);
636 int user_get_idle_hint(User
*u
, dual_timestamp
*t
) {
638 bool idle_hint
= true;
639 dual_timestamp ts
= DUAL_TIMESTAMP_NULL
;
643 LIST_FOREACH(sessions_by_user
, s
, u
->sessions
) {
647 ih
= session_get_idle_hint(s
, &k
);
653 if (k
.monotonic
< ts
.monotonic
)
659 } else if (idle_hint
) {
661 if (k
.monotonic
> ts
.monotonic
)
672 int user_check_linger_file(User
*u
) {
673 _cleanup_free_
char *cc
= NULL
;
676 cc
= cescape(u
->name
);
680 p
= strjoina("/var/lib/systemd/linger/", cc
);
682 return access(p
, F_OK
) >= 0;
685 bool user_check_gc(User
*u
, bool drop_not_started
) {
688 if (drop_not_started
&& !u
->started
)
694 if (user_check_linger_file(u
) > 0)
697 if (u
->slice_job
&& manager_job_is_active(u
->manager
, u
->slice_job
))
700 if (u
->service_job
&& manager_job_is_active(u
->manager
, u
->service_job
))
706 void user_add_to_gc_queue(User
*u
) {
712 LIST_PREPEND(gc_queue
, u
->manager
->user_gc_queue
, u
);
713 u
->in_gc_queue
= true;
716 UserState
user_get_state(User
*u
) {
724 if (!u
->started
|| u
->slice_job
|| u
->service_job
)
728 bool all_closing
= true;
730 LIST_FOREACH(sessions_by_user
, i
, u
->sessions
) {
733 state
= session_get_state(i
);
734 if (state
== SESSION_ACTIVE
)
736 if (state
!= SESSION_CLOSING
)
740 return all_closing
? USER_CLOSING
: USER_ONLINE
;
743 if (user_check_linger_file(u
) > 0)
744 return USER_LINGERING
;
749 int user_kill(User
*u
, int signo
) {
752 return manager_kill_unit(u
->manager
, u
->slice
, KILL_ALL
, signo
, NULL
);
755 static bool elect_display_filter(Session
*s
) {
756 /* Return true if the session is a candidate for the user’s ‘primary
757 * session’ or ‘display’. */
760 return (s
->class == SESSION_USER
&& !s
->stopping
);
763 static int elect_display_compare(Session
*s1
, Session
*s2
) {
764 /* Indexed by SessionType. Lower numbers mean more preferred. */
765 const int type_ranks
[_SESSION_TYPE_MAX
] = {
766 [SESSION_UNSPECIFIED
] = 0,
769 [SESSION_WAYLAND
] = -3,
774 /* Calculate the partial order relationship between s1 and s2,
775 * returning < 0 if s1 is preferred as the user’s ‘primary session’,
776 * 0 if s1 and s2 are equally preferred or incomparable, or > 0 if s2
779 * s1 or s2 may be NULL. */
783 if ((s1
== NULL
) != (s2
== NULL
))
784 return (s1
== NULL
) - (s2
== NULL
);
786 if (s1
->stopping
!= s2
->stopping
)
787 return s1
->stopping
- s2
->stopping
;
789 if ((s1
->class != SESSION_USER
) != (s2
->class != SESSION_USER
))
790 return (s1
->class != SESSION_USER
) - (s2
->class != SESSION_USER
);
792 if ((s1
->type
== _SESSION_TYPE_INVALID
) != (s2
->type
== _SESSION_TYPE_INVALID
))
793 return (s1
->type
== _SESSION_TYPE_INVALID
) - (s2
->type
== _SESSION_TYPE_INVALID
);
795 if (s1
->type
!= s2
->type
)
796 return type_ranks
[s1
->type
] - type_ranks
[s2
->type
];
801 void user_elect_display(User
*u
) {
806 /* This elects a primary session for each user, which we call
807 * the "display". We try to keep the assignment stable, but we
808 * "upgrade" to better choices. */
809 log_debug("Electing new display for user %s", u
->name
);
811 LIST_FOREACH(sessions_by_user
, s
, u
->sessions
) {
812 if (!elect_display_filter(s
)) {
813 log_debug("Ignoring session %s", s
->id
);
817 if (elect_display_compare(s
, u
->display
) < 0) {
818 log_debug("Choosing session %s in preference to %s", s
->id
, u
->display
? u
->display
->id
: "-");
824 static const char* const user_state_table
[_USER_STATE_MAX
] = {
825 [USER_OFFLINE
] = "offline",
826 [USER_OPENING
] = "opening",
827 [USER_LINGERING
] = "lingering",
828 [USER_ONLINE
] = "online",
829 [USER_ACTIVE
] = "active",
830 [USER_CLOSING
] = "closing"
833 DEFINE_STRING_TABLE_LOOKUP(user_state
, UserState
);
835 int config_parse_tmpfs_size(
837 const char *filename
,
840 unsigned section_line
,
855 /* First, try to parse as percentage */
856 r
= parse_percent(rvalue
);
857 if (r
> 0 && r
< 100)
858 *sz
= physical_memory_scale(r
, 100U);
862 /* If the passed argument was not a percentage, or out of range, parse as byte size */
864 r
= parse_size(rvalue
, 1024, &k
);
865 if (r
< 0 || k
<= 0 || (uint64_t) (size_t) k
!= k
) {
866 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse size value, ignoring: %s", rvalue
);
870 *sz
= PAGE_ALIGN((size_t) k
);
876 int config_parse_user_tasks_max(
878 const char *filename
,
881 unsigned section_line
,
897 if (isempty(rvalue
)) {
898 *m
= system_tasks_max_scale(DEFAULT_USER_TASKS_MAX_PERCENTAGE
, 100U);
902 if (streq(rvalue
, "infinity")) {
903 *m
= CGROUP_LIMIT_MAX
;
907 /* Try to parse as percentage */
908 r
= parse_percent(rvalue
);
910 k
= system_tasks_max_scale(r
, 100U);
913 /* If the passed argument was not a percentage, or out of range, parse as byte size */
915 r
= safe_atou64(rvalue
, &k
);
917 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse tasks maximum, ignoring: %s", rvalue
);
922 if (k
<= 0 || k
>= UINT64_MAX
) {
923 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Tasks maximum out of range, ignoring: %s", rvalue
);