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("Starting services for new user %s.", 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_and_replace(u
->service_job
, job
);
534 static int user_remove_runtime_path(User
*u
) {
539 r
= rm_rf(u
->runtime_path
, 0);
541 log_error_errno(r
, "Failed to remove runtime directory %s (before unmounting): %m", u
->runtime_path
);
543 /* Ignore cases where the directory isn't mounted, as that's
544 * quite possible, if we lacked the permissions to mount
546 r
= umount2(u
->runtime_path
, MNT_DETACH
);
547 if (r
< 0 && !IN_SET(errno
, EINVAL
, ENOENT
))
548 log_error_errno(errno
, "Failed to unmount user runtime directory %s: %m", u
->runtime_path
);
550 r
= rm_rf(u
->runtime_path
, REMOVE_ROOT
);
552 log_error_errno(r
, "Failed to remove runtime directory %s (after unmounting): %m", u
->runtime_path
);
557 int user_stop(User
*u
, bool force
) {
562 /* Stop jobs have already been queued */
568 LIST_FOREACH(sessions_by_user
, s
, u
->sessions
) {
569 k
= session_stop(s
, force
);
575 k
= user_stop_service(u
);
580 k
= user_stop_slice(u
);
591 int user_finalize(User
*u
) {
598 log_debug("User %s logged out.", u
->name
);
600 LIST_FOREACH(sessions_by_user
, s
, u
->sessions
) {
601 k
= session_finalize(s
);
606 /* Kill XDG_RUNTIME_DIR */
607 k
= user_remove_runtime_path(u
);
611 /* Clean SysV + POSIX IPC objects, but only if this is not a system user. Background: in many setups cronjobs
612 * are run in full PAM and thus logind sessions, even if the code run doesn't belong to actual users but to
613 * system components. Since enable RemoveIPC= globally for all users, we need to be a bit careful with such
614 * cases, as we shouldn't accidentally remove a system service's IPC objects while it is running, just because
615 * a cronjob running as the same user just finished. Hence: exclude system users generally from IPC clean-up,
616 * and do it only for normal users. */
617 if (u
->manager
->remove_ipc
&& !uid_is_system(u
->uid
)) {
618 k
= clean_ipc_by_uid(u
->uid
);
623 unlink(u
->state_file
);
624 user_add_to_gc_queue(u
);
627 user_send_signal(u
, false);
634 int user_get_idle_hint(User
*u
, dual_timestamp
*t
) {
636 bool idle_hint
= true;
637 dual_timestamp ts
= DUAL_TIMESTAMP_NULL
;
641 LIST_FOREACH(sessions_by_user
, s
, u
->sessions
) {
645 ih
= session_get_idle_hint(s
, &k
);
651 if (k
.monotonic
< ts
.monotonic
)
657 } else if (idle_hint
) {
659 if (k
.monotonic
> ts
.monotonic
)
670 int user_check_linger_file(User
*u
) {
671 _cleanup_free_
char *cc
= NULL
;
674 cc
= cescape(u
->name
);
678 p
= strjoina("/var/lib/systemd/linger/", cc
);
680 return access(p
, F_OK
) >= 0;
683 bool user_check_gc(User
*u
, bool drop_not_started
) {
686 if (drop_not_started
&& !u
->started
)
692 if (user_check_linger_file(u
) > 0)
695 if (u
->slice_job
&& manager_job_is_active(u
->manager
, u
->slice_job
))
698 if (u
->service_job
&& manager_job_is_active(u
->manager
, u
->service_job
))
704 void user_add_to_gc_queue(User
*u
) {
710 LIST_PREPEND(gc_queue
, u
->manager
->user_gc_queue
, u
);
711 u
->in_gc_queue
= true;
714 UserState
user_get_state(User
*u
) {
722 if (!u
->started
|| u
->slice_job
|| u
->service_job
)
726 bool all_closing
= true;
728 LIST_FOREACH(sessions_by_user
, i
, u
->sessions
) {
731 state
= session_get_state(i
);
732 if (state
== SESSION_ACTIVE
)
734 if (state
!= SESSION_CLOSING
)
738 return all_closing
? USER_CLOSING
: USER_ONLINE
;
741 if (user_check_linger_file(u
) > 0)
742 return USER_LINGERING
;
747 int user_kill(User
*u
, int signo
) {
750 return manager_kill_unit(u
->manager
, u
->slice
, KILL_ALL
, signo
, NULL
);
753 static bool elect_display_filter(Session
*s
) {
754 /* Return true if the session is a candidate for the user’s ‘primary
755 * session’ or ‘display’. */
758 return (s
->class == SESSION_USER
&& !s
->stopping
);
761 static int elect_display_compare(Session
*s1
, Session
*s2
) {
762 /* Indexed by SessionType. Lower numbers mean more preferred. */
763 const int type_ranks
[_SESSION_TYPE_MAX
] = {
764 [SESSION_UNSPECIFIED
] = 0,
767 [SESSION_WAYLAND
] = -3,
772 /* Calculate the partial order relationship between s1 and s2,
773 * returning < 0 if s1 is preferred as the user’s ‘primary session’,
774 * 0 if s1 and s2 are equally preferred or incomparable, or > 0 if s2
777 * s1 or s2 may be NULL. */
781 if ((s1
== NULL
) != (s2
== NULL
))
782 return (s1
== NULL
) - (s2
== NULL
);
784 if (s1
->stopping
!= s2
->stopping
)
785 return s1
->stopping
- s2
->stopping
;
787 if ((s1
->class != SESSION_USER
) != (s2
->class != SESSION_USER
))
788 return (s1
->class != SESSION_USER
) - (s2
->class != SESSION_USER
);
790 if ((s1
->type
== _SESSION_TYPE_INVALID
) != (s2
->type
== _SESSION_TYPE_INVALID
))
791 return (s1
->type
== _SESSION_TYPE_INVALID
) - (s2
->type
== _SESSION_TYPE_INVALID
);
793 if (s1
->type
!= s2
->type
)
794 return type_ranks
[s1
->type
] - type_ranks
[s2
->type
];
799 void user_elect_display(User
*u
) {
804 /* This elects a primary session for each user, which we call
805 * the "display". We try to keep the assignment stable, but we
806 * "upgrade" to better choices. */
807 log_debug("Electing new display for user %s", u
->name
);
809 LIST_FOREACH(sessions_by_user
, s
, u
->sessions
) {
810 if (!elect_display_filter(s
)) {
811 log_debug("Ignoring session %s", s
->id
);
815 if (elect_display_compare(s
, u
->display
) < 0) {
816 log_debug("Choosing session %s in preference to %s", s
->id
, u
->display
? u
->display
->id
: "-");
822 static const char* const user_state_table
[_USER_STATE_MAX
] = {
823 [USER_OFFLINE
] = "offline",
824 [USER_OPENING
] = "opening",
825 [USER_LINGERING
] = "lingering",
826 [USER_ONLINE
] = "online",
827 [USER_ACTIVE
] = "active",
828 [USER_CLOSING
] = "closing"
831 DEFINE_STRING_TABLE_LOOKUP(user_state
, UserState
);
833 int config_parse_tmpfs_size(
835 const char *filename
,
838 unsigned section_line
,
853 /* First, try to parse as percentage */
854 r
= parse_percent(rvalue
);
855 if (r
> 0 && r
< 100)
856 *sz
= physical_memory_scale(r
, 100U);
860 /* If the passed argument was not a percentage, or out of range, parse as byte size */
862 r
= parse_size(rvalue
, 1024, &k
);
863 if (r
< 0 || k
<= 0 || (uint64_t) (size_t) k
!= k
) {
864 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse size value, ignoring: %s", rvalue
);
868 *sz
= PAGE_ALIGN((size_t) k
);
874 int config_parse_user_tasks_max(
876 const char *filename
,
879 unsigned section_line
,
895 if (isempty(rvalue
)) {
896 *m
= system_tasks_max_scale(DEFAULT_USER_TASKS_MAX_PERCENTAGE
, 100U);
900 if (streq(rvalue
, "infinity")) {
901 *m
= CGROUP_LIMIT_MAX
;
905 /* Try to parse as percentage */
906 r
= parse_percent(rvalue
);
908 k
= system_tasks_max_scale(r
, 100U);
911 /* If the passed argument was not a percentage, or out of range, parse as byte size */
913 r
= safe_atou64(rvalue
, &k
);
915 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse tasks maximum, ignoring: %s", rvalue
);
920 if (k
<= 0 || k
>= UINT64_MAX
) {
921 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Tasks maximum out of range, ignoring: %s", rvalue
);