summaryrefslogtreecommitdiff
path: root/src/login
diff options
context:
space:
mode:
Diffstat (limited to 'src/login')
-rw-r--r--src/login/logind-acl.h2
-rw-r--r--src/login/logind-action.h2
-rw-r--r--src/login/logind-core.c11
-rw-r--r--src/login/logind-dbus.c132
-rw-r--r--src/login/logind-gperf.gperf1
-rw-r--r--src/login/logind-session.c27
-rw-r--r--src/login/logind-session.h2
-rw-r--r--src/login/logind-user.c255
-rw-r--r--src/login/logind-user.h12
-rw-r--r--src/login/logind-utmp.c2
-rw-r--r--src/login/logind.c1
-rw-r--r--src/login/logind.conf1
-rw-r--r--src/login/logind.h4
-rw-r--r--src/login/pam_systemd.c30
-rw-r--r--src/login/test-login-shared.c2
-rw-r--r--src/login/test-login-tables.c1
16 files changed, 292 insertions, 193 deletions
diff --git a/src/login/logind-acl.h b/src/login/logind-acl.h
index 93e9ed02eb..1f55759798 100644
--- a/src/login/logind-acl.h
+++ b/src/login/logind-acl.h
@@ -21,8 +21,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/types.h>
#include <stdbool.h>
+#include <sys/types.h>
#include "libudev.h"
diff --git a/src/login/logind-action.h b/src/login/logind-action.h
index e9b424b5f6..63c279cde7 100644
--- a/src/login/logind-action.h
+++ b/src/login/logind-action.h
@@ -35,8 +35,8 @@ typedef enum HandleAction {
_HANDLE_ACTION_INVALID = -1
} HandleAction;
-#include "logind.h"
#include "logind-inhibit.h"
+#include "logind.h"
int manager_handle_action(
Manager *m,
diff --git a/src/login/logind-core.c b/src/login/logind-core.c
index b3f30c8dc9..36cdbbe0f9 100644
--- a/src/login/logind-core.c
+++ b/src/login/logind-core.c
@@ -19,10 +19,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/types.h>
-#include <sys/ioctl.h>
#include <fcntl.h>
#include <pwd.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
#include <linux/vt.h>
#include "alloc-util.h"
@@ -98,15 +98,16 @@ int manager_add_session(Manager *m, const char *id, Session **_session) {
int manager_add_user(Manager *m, uid_t uid, gid_t gid, const char *name, User **_user) {
User *u;
+ int r;
assert(m);
assert(name);
u = hashmap_get(m->users, UID_TO_PTR(uid));
if (!u) {
- u = user_new(m, uid, gid, name);
- if (!u)
- return -ENOMEM;
+ r = user_new(&u, m, uid, gid, name);
+ if (r < 0)
+ return r;
}
if (_user)
diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c
index 7890d68aa0..e507a19aef 100644
--- a/src/login/logind-dbus.c
+++ b/src/login/logind-dbus.c
@@ -308,8 +308,10 @@ static int method_get_session_by_pid(sd_bus_message *message, void *userdata, sd
r = sd_bus_message_read(message, "u", &pid);
if (r < 0)
return r;
+ if (pid < 0)
+ return -EINVAL;
- if (pid <= 0) {
+ if (pid == 0) {
r = manager_get_session_from_creds(m, message, NULL, error, &session);
if (r < 0)
return r;
@@ -369,8 +371,10 @@ static int method_get_user_by_pid(sd_bus_message *message, void *userdata, sd_bu
r = sd_bus_message_read(message, "u", &pid);
if (r < 0)
return r;
+ if (pid < 0)
+ return -EINVAL;
- if (pid <= 0) {
+ if (pid == 0) {
r = manager_get_user_from_creds(m, message, UID_INVALID, error, &user);
if (r < 0)
return r;
@@ -573,12 +577,14 @@ static int method_list_inhibitors(sd_bus_message *message, void *userdata, sd_bu
static int method_create_session(sd_bus_message *message, void *userdata, sd_bus_error *error) {
const char *service, *type, *class, *cseat, *tty, *display, *remote_user, *remote_host, *desktop;
- uint32_t uid, leader, audit_id = 0;
+ uint32_t audit_id = 0;
_cleanup_free_ char *id = NULL;
Session *session = NULL;
Manager *m = userdata;
User *user = NULL;
Seat *seat = NULL;
+ pid_t leader;
+ uid_t uid;
int remote;
uint32_t vtnr = 0;
SessionType t;
@@ -588,11 +594,16 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus
assert(message);
assert(m);
+ assert_cc(sizeof(pid_t) == sizeof(uint32_t));
+ assert_cc(sizeof(uid_t) == sizeof(uint32_t));
+
r = sd_bus_message_read(message, "uusssssussbss", &uid, &leader, &service, &type, &class, &desktop, &cseat, &vtnr, &tty, &display, &remote, &remote_user, &remote_host);
if (r < 0)
return r;
- if (leader == 1)
+ if (!uid_is_valid(uid))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid UID");
+ if (leader < 0 || leader == 1)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid leader PID");
if (isempty(type))
@@ -684,7 +695,7 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus
c = SESSION_USER;
}
- if (leader <= 0) {
+ if (leader == 0) {
_cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
@@ -1093,7 +1104,9 @@ static int method_set_user_linger(sd_bus_message *message, void *userdata, sd_bu
r = sd_bus_creds_get_owner_uid(creds, &uid);
if (r < 0)
return r;
- }
+
+ } else if (!uid_is_valid(uid))
+ return -EINVAL;
errno = 0;
pw = getpwuid(uid);
@@ -2607,11 +2620,8 @@ int match_job_removed(sd_bus_message *message, void *userdata, sd_bus_error *err
}
session = hashmap_get(m->session_units, unit);
- if (session) {
-
- if (streq_ptr(path, session->scope_job))
- session->scope_job = mfree(session->scope_job);
-
+ if (session && streq_ptr(path, session->scope_job)) {
+ session->scope_job = mfree(session->scope_job);
session_jobs_reply(session, unit, result);
session_save(session);
@@ -2620,7 +2630,9 @@ int match_job_removed(sd_bus_message *message, void *userdata, sd_bus_error *err
}
user = hashmap_get(m->user_units, unit);
- if (user) {
+ if (user &&
+ (streq_ptr(path, user->service_job) ||
+ streq_ptr(path, user->slice_job))) {
if (streq_ptr(path, user->service_job))
user->service_job = mfree(user->service_job);
@@ -2740,13 +2752,101 @@ int manager_send_changed(Manager *manager, const char *property, ...) {
l);
}
+int manager_start_slice(
+ Manager *manager,
+ const char *slice,
+ const char *description,
+ const char *after,
+ const char *after2,
+ uint64_t tasks_max,
+ sd_bus_error *error,
+ char **job) {
+
+ _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
+ int r;
+
+ assert(manager);
+ assert(slice);
+
+ r = sd_bus_message_new_method_call(
+ manager->bus,
+ &m,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "StartTransientUnit");
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_append(m, "ss", strempty(slice), "fail");
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_open_container(m, 'a', "(sv)");
+ if (r < 0)
+ return r;
+
+ if (!isempty(description)) {
+ r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
+ if (r < 0)
+ return r;
+ }
+
+ if (!isempty(after)) {
+ r = sd_bus_message_append(m, "(sv)", "After", "as", 1, after);
+ if (r < 0)
+ return r;
+ }
+
+ if (!isempty(after2)) {
+ r = sd_bus_message_append(m, "(sv)", "After", "as", 1, after2);
+ if (r < 0)
+ return r;
+ }
+
+ r = sd_bus_message_append(m, "(sv)", "TasksMax", "t", tasks_max);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_append(m, "a(sa(sv))", 0);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_call(manager->bus, m, 0, error, &reply);
+ if (r < 0)
+ return r;
+
+ if (job) {
+ const char *j;
+ char *copy;
+
+ r = sd_bus_message_read(reply, "o", &j);
+ if (r < 0)
+ return r;
+
+ copy = strdup(j);
+ if (!copy)
+ return -ENOMEM;
+
+ *job = copy;
+ }
+
+ return 1;
+}
+
int manager_start_scope(
Manager *manager,
const char *scope,
pid_t pid,
const char *slice,
const char *description,
- const char *after, const char *after2,
+ const char *after,
+ const char *after2,
+ uint64_t tasks_max,
sd_bus_error *error,
char **job) {
@@ -2814,6 +2914,10 @@ int manager_start_scope(
if (r < 0)
return r;
+ r = sd_bus_message_append(m, "(sv)", "TasksMax", "t", tasks_max);
+ if (r < 0)
+ return r;
+
r = sd_bus_message_close_container(m);
if (r < 0)
return r;
@@ -2859,7 +2963,7 @@ int manager_start_unit(Manager *manager, const char *unit, sd_bus_error *error,
"StartUnit",
error,
&reply,
- "ss", unit, "fail");
+ "ss", unit, "replace");
if (r < 0)
return r;
diff --git a/src/login/logind-gperf.gperf b/src/login/logind-gperf.gperf
index 9218d098e0..8552c464cc 100644
--- a/src/login/logind-gperf.gperf
+++ b/src/login/logind-gperf.gperf
@@ -34,3 +34,4 @@ Login.IdleAction, config_parse_handle_action, 0, offsetof(Manag
Login.IdleActionSec, config_parse_sec, 0, offsetof(Manager, idle_action_usec)
Login.RuntimeDirectorySize, config_parse_tmpfs_size, 0, offsetof(Manager, runtime_dir_size)
Login.RemoveIPC, config_parse_bool, 0, offsetof(Manager, remove_ipc)
+Login.UserTasksMax, config_parse_uint64, 0, offsetof(Manager, user_tasks_max)
diff --git a/src/login/logind-session.c b/src/login/logind-session.c
index 1d561a6f8a..9f03a7b31e 100644
--- a/src/login/logind-session.c
+++ b/src/login/logind-session.c
@@ -36,7 +36,6 @@
#include "bus-util.h"
#include "escape.h"
#include "fd-util.h"
-#include "fd-util.h"
#include "fileio.h"
#include "formats-util.h"
#include "io-util.h"
@@ -513,25 +512,31 @@ static int session_start_scope(Session *s) {
assert(s);
assert(s->user);
- assert(s->user->slice);
if (!s->scope) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
- _cleanup_free_ char *description = NULL;
char *scope, *job = NULL;
-
- description = strjoin("Session ", s->id, " of user ", s->user->name, NULL);
- if (!description)
- return log_oom();
+ const char *description;
scope = strjoin("session-", s->id, ".scope", NULL);
if (!scope)
return log_oom();
- r = manager_start_scope(s->manager, scope, s->leader, s->user->slice, description, "systemd-logind.service", "systemd-user-sessions.service", &error, &job);
+ description = strjoina("Session ", s->id, " of user ", s->user->name, NULL);
+
+ r = manager_start_scope(
+ s->manager,
+ scope,
+ s->leader,
+ s->user->slice,
+ description,
+ "systemd-logind.service",
+ "systemd-user-sessions.service",
+ (uint64_t) -1, /* disable TasksMax= for the scope, rely on the slice setting for it */
+ &error,
+ &job);
if (r < 0) {
- log_error("Failed to start session scope %s: %s %s",
- scope, bus_error_message(&error, r), error.name);
+ log_error_errno(r, "Failed to start session scope %s: %s", scope, bus_error_message(&error, r));
free(scope);
return r;
} else {
@@ -543,7 +548,7 @@ static int session_start_scope(Session *s) {
}
if (s->scope)
- hashmap_put(s->manager->session_units, s->scope, s);
+ (void) hashmap_put(s->manager->session_units, s->scope, s);
return 0;
}
diff --git a/src/login/logind-session.h b/src/login/logind-session.h
index d054c33cec..d27407fc92 100644
--- a/src/login/logind-session.h
+++ b/src/login/logind-session.h
@@ -25,8 +25,8 @@ typedef struct Session Session;
typedef enum KillWho KillWho;
#include "list.h"
-#include "logind-user.h"
#include "login-util.h"
+#include "logind-user.h"
typedef enum SessionState {
SESSION_OPENING, /* Session scope is being created */
diff --git a/src/login/logind-user.c b/src/login/logind-user.c
index 56bc5a010c..778f19b50d 100644
--- a/src/login/logind-user.c
+++ b/src/login/logind-user.c
@@ -25,6 +25,7 @@
#include <unistd.h>
#include "alloc-util.h"
+#include "bus-common-errors.h"
#include "bus-error.h"
#include "bus-util.h"
#include "clean-ipc.h"
@@ -44,47 +45,68 @@
#include "rm-rf.h"
#include "smack-util.h"
#include "special.h"
+#include "stdio-util.h"
#include "string-table.h"
#include "unit-name.h"
#include "user-util.h"
#include "util.h"
-User* user_new(Manager *m, uid_t uid, gid_t gid, const char *name) {
- User *u;
+int user_new(User **out, Manager *m, uid_t uid, gid_t gid, const char *name) {
+ _cleanup_(user_freep) User *u = NULL;
+ char lu[DECIMAL_STR_MAX(uid_t) + 1];
+ int r;
+ assert(out);
assert(m);
assert(name);
u = new0(User, 1);
if (!u)
- return NULL;
+ return -ENOMEM;
+
+ u->manager = m;
+ u->uid = uid;
+ u->gid = gid;
+ xsprintf(lu, UID_FMT, uid);
u->name = strdup(name);
if (!u->name)
- goto fail;
+ return -ENOMEM;
if (asprintf(&u->state_file, "/run/systemd/users/"UID_FMT, uid) < 0)
- goto fail;
+ return -ENOMEM;
- if (hashmap_put(m->users, UID_TO_PTR(uid), u) < 0)
- goto fail;
+ if (asprintf(&u->runtime_path, "/run/user/"UID_FMT, uid) < 0)
+ return -ENOMEM;
- u->manager = m;
- u->uid = uid;
- u->gid = gid;
+ r = slice_build_subslice(SPECIAL_USER_SLICE, lu, &u->slice);
+ if (r < 0)
+ return r;
- return u;
+ r = unit_name_build("user", lu, ".service", &u->service);
+ if (r < 0)
+ return r;
-fail:
- free(u->state_file);
- free(u->name);
- free(u);
+ r = hashmap_put(m->users, UID_TO_PTR(uid), u);
+ if (r < 0)
+ return r;
+
+ r = hashmap_put(m->user_units, u->slice, u);
+ if (r < 0)
+ return r;
- return NULL;
+ r = hashmap_put(m->user_units, u->service, u);
+ if (r < 0)
+ return r;
+
+ *out = u;
+ u = NULL;
+ return 0;
}
-void user_free(User *u) {
- assert(u);
+User *user_free(User *u) {
+ if (!u)
+ return NULL;
if (u->in_gc_queue)
LIST_REMOVE(gc_queue, u->manager->user_gc_queue, u);
@@ -92,26 +114,24 @@ void user_free(User *u) {
while (u->sessions)
session_free(u->sessions);
- if (u->slice) {
- hashmap_remove(u->manager->user_units, u->slice);
- free(u->slice);
- }
+ if (u->service)
+ hashmap_remove_value(u->manager->user_units, u->service, u);
- if (u->service) {
- hashmap_remove(u->manager->user_units, u->service);
- free(u->service);
- }
+ if (u->slice)
+ hashmap_remove_value(u->manager->user_units, u->slice, u);
- free(u->slice_job);
- free(u->service_job);
+ hashmap_remove_value(u->manager->users, UID_TO_PTR(u->uid), u);
- free(u->runtime_path);
+ u->slice_job = mfree(u->slice_job);
+ u->service_job = mfree(u->service_job);
- hashmap_remove(u->manager->users, UID_TO_PTR(u->uid));
+ u->service = mfree(u->service);
+ u->slice = mfree(u->slice);
+ u->runtime_path = mfree(u->runtime_path);
+ u->state_file = mfree(u->state_file);
+ u->name = mfree(u->name);
- free(u->name);
- free(u->state_file);
- free(u);
+ return mfree(u);
}
static int user_save_internal(User *u) {
@@ -139,16 +159,13 @@ static int user_save_internal(User *u) {
u->name,
user_state_to_string(user_get_state(u)));
+ /* LEGACY: no-one reads RUNTIME= anymore, drop it at some point */
if (u->runtime_path)
fprintf(f, "RUNTIME=%s\n", u->runtime_path);
- if (u->service)
- fprintf(f, "SERVICE=%s\n", u->service);
if (u->service_job)
fprintf(f, "SERVICE_JOB=%s\n", u->service_job);
- if (u->slice)
- fprintf(f, "SLICE=%s\n", u->slice);
if (u->slice_job)
fprintf(f, "SLICE_JOB=%s\n", u->slice_job);
@@ -286,10 +303,7 @@ int user_load(User *u) {
assert(u);
r = parse_env_file(u->state_file, NEWLINE,
- "RUNTIME", &u->runtime_path,
- "SERVICE", &u->service,
"SERVICE_JOB", &u->service_job,
- "SLICE", &u->slice,
"SLICE_JOB", &u->slice_job,
"DISPLAY", &display,
"REALTIME", &realtime,
@@ -325,7 +339,6 @@ int user_load(User *u) {
}
static int user_mkdir_runtime_path(User *u) {
- char *p;
int r;
assert(u);
@@ -334,16 +347,10 @@ static int user_mkdir_runtime_path(User *u) {
if (r < 0)
return log_error_errno(r, "Failed to create /run/user: %m");
- if (!u->runtime_path) {
- if (asprintf(&p, "/run/user/" UID_FMT, u->uid) < 0)
- return log_oom();
- } else
- p = u->runtime_path;
-
- if (path_is_mount_point(p, 0) <= 0) {
+ if (path_is_mount_point(u->runtime_path, 0) <= 0) {
_cleanup_free_ char *t = NULL;
- (void) mkdir_label(p, 0700);
+ (void) mkdir_label(u->runtime_path, 0700);
if (mac_smack_use())
r = asprintf(&t, "mode=0700,smackfsroot=*,uid=" UID_FMT ",gid=" GID_FMT ",size=%zu", u->uid, u->gid, u->manager->runtime_dir_size);
@@ -354,10 +361,10 @@ static int user_mkdir_runtime_path(User *u) {
goto fail;
}
- r = mount("tmpfs", p, "tmpfs", MS_NODEV|MS_NOSUID, t);
+ r = mount("tmpfs", u->runtime_path, "tmpfs", MS_NODEV|MS_NOSUID, t);
if (r < 0) {
if (errno != EPERM) {
- r = log_error_errno(errno, "Failed to mount per-user tmpfs directory %s: %m", p);
+ r = log_error_errno(errno, "Failed to mount per-user tmpfs directory %s: %m", u->runtime_path);
goto fail;
}
@@ -365,62 +372,54 @@ static int user_mkdir_runtime_path(User *u) {
* CAP_SYS_ADMIN-less container? In this case,
* just use a normal directory. */
- r = chmod_and_chown(p, 0700, u->uid, u->gid);
+ r = chmod_and_chown(u->runtime_path, 0700, u->uid, u->gid);
if (r < 0) {
log_error_errno(r, "Failed to change runtime directory ownership and mode: %m");
goto fail;
}
}
- r = label_fix(p, false, false);
+ r = label_fix(u->runtime_path, false, false);
if (r < 0)
- log_warning_errno(r, "Failed to fix label of '%s', ignoring: %m", p);
+ log_warning_errno(r, "Failed to fix label of '%s', ignoring: %m", u->runtime_path);
}
- u->runtime_path = p;
return 0;
fail:
- if (p) {
- /* Try to clean up, but ignore errors */
- (void) rmdir(p);
- free(p);
- }
-
- u->runtime_path = NULL;
+ /* Try to clean up, but ignore errors */
+ (void) rmdir(u->runtime_path);
return r;
}
static int user_start_slice(User *u) {
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ const char *description;
char *job;
int r;
assert(u);
- if (!u->slice) {
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
- char lu[DECIMAL_STR_MAX(uid_t) + 1], *slice;
- sprintf(lu, UID_FMT, u->uid);
-
- r = slice_build_subslice(SPECIAL_USER_SLICE, lu, &slice);
- if (r < 0)
- return r;
-
- r = manager_start_unit(u->manager, slice, &error, &job);
- if (r < 0) {
- log_error("Failed to start user slice: %s", bus_error_message(&error, r));
- free(slice);
- } else {
- u->slice = slice;
-
- free(u->slice_job);
- u->slice_job = job;
- }
+ u->slice_job = mfree(u->slice_job);
+ description = strjoina("User Slice of ", u->name);
+
+ r = manager_start_slice(
+ u->manager,
+ u->slice,
+ description,
+ "systemd-logind.service",
+ "systemd-user-sessions.service",
+ u->manager->user_tasks_max,
+ &error,
+ &job);
+ if (r < 0) {
+ /* we don't fail due to this, let's try to continue */
+ if (!sd_bus_error_has_name(&error, BUS_ERROR_UNIT_EXISTS))
+ log_error_errno(r, "Failed to start user slice %s, ignoring: %s (%s)", u->slice, bus_error_message(&error, r), error.name);
+ } else {
+ u->slice_job = job;
}
- if (u->slice)
- hashmap_put(u->manager->user_units, u->slice, u);
-
return 0;
}
@@ -431,29 +430,20 @@ static int user_start_service(User *u) {
assert(u);
- if (!u->service) {
- char lu[DECIMAL_STR_MAX(uid_t) + 1], *service;
- sprintf(lu, UID_FMT, u->uid);
-
- r = unit_name_build("user", lu, ".service", &service);
- if (r < 0)
- return log_error_errno(r, "Failed to build service name: %m");
-
- r = manager_start_unit(u->manager, service, &error, &job);
- if (r < 0) {
- log_error("Failed to start user service: %s", bus_error_message(&error, r));
- free(service);
- } else {
- u->service = service;
+ u->service_job = mfree(u->service_job);
- free(u->service_job);
- u->service_job = job;
- }
+ r = manager_start_unit(
+ u->manager,
+ u->service,
+ &error,
+ &job);
+ if (r < 0) {
+ /* we don't fail due to this, let's try to continue */
+ log_error_errno(r, "Failed to start user service, ignoring: %s", bus_error_message(&error, r));
+ } else {
+ u->service_job = job;
}
- if (u->service)
- hashmap_put(u->manager->user_units, u->service, u);
-
return 0;
}
@@ -462,15 +452,32 @@ int user_start(User *u) {
assert(u);
- if (u->started)
+ if (u->started && !u->stopping)
return 0;
- log_debug("New user %s logged in.", u->name);
-
- /* Make XDG_RUNTIME_DIR */
- r = user_mkdir_runtime_path(u);
- if (r < 0)
- return r;
+ /*
+ * If u->stopping is set, the user is marked for removal and the slice
+ * and service stop-jobs are queued. We have to clear that flag before
+ * queing the start-jobs again. If they succeed, the user object can be
+ * re-used just fine (pid1 takes care of job-ordering and proper
+ * restart), but if they fail, we want to force another user_stop() so
+ * possibly pending units are stopped.
+ * Note that we don't clear u->started, as we have no clue what state
+ * the user is in on failure here. Hence, we pretend the user is
+ * running so it will be properly taken down by GC. However, we clearly
+ * return an error from user_start() in that case, so no further
+ * reference to the user is taken.
+ */
+ u->stopping = false;
+
+ if (!u->started) {
+ log_debug("New user %s logged in.", u->name);
+
+ /* Make XDG_RUNTIME_DIR */
+ r = user_mkdir_runtime_path(u);
+ if (r < 0)
+ return r;
+ }
/* Create cgroup */
r = user_start_slice(u);
@@ -488,16 +495,16 @@ int user_start(User *u) {
if (r < 0)
return r;
- if (!dual_timestamp_is_set(&u->timestamp))
- dual_timestamp_get(&u->timestamp);
-
- u->started = true;
+ if (!u->started) {
+ if (!dual_timestamp_is_set(&u->timestamp))
+ dual_timestamp_get(&u->timestamp);
+ user_send_signal(u, true);
+ u->started = true;
+ }
/* Save new user data */
user_save(u);
- user_send_signal(u, true);
-
return 0;
}
@@ -508,9 +515,6 @@ static int user_stop_slice(User *u) {
assert(u);
- if (!u->slice)
- return 0;
-
r = manager_stop_unit(u->manager, u->slice, &error, &job);
if (r < 0) {
log_error("Failed to stop user slice: %s", bus_error_message(&error, r));
@@ -530,9 +534,6 @@ static int user_stop_service(User *u) {
assert(u);
- if (!u->service)
- return 0;
-
r = manager_stop_unit(u->manager, u->service, &error, &job);
if (r < 0) {
log_error("Failed to stop user service: %s", bus_error_message(&error, r));
@@ -550,9 +551,6 @@ static int user_remove_runtime_path(User *u) {
assert(u);
- if (!u->runtime_path)
- return 0;
-
r = rm_rf(u->runtime_path, 0);
if (r < 0)
log_error_errno(r, "Failed to remove runtime directory %s: %m", u->runtime_path);
@@ -568,8 +566,6 @@ static int user_remove_runtime_path(User *u) {
if (r < 0)
log_error_errno(r, "Failed to remove runtime directory %s: %m", u->runtime_path);
- u->runtime_path = mfree(u->runtime_path);
-
return r;
}
@@ -761,9 +757,6 @@ UserState user_get_state(User *u) {
int user_kill(User *u, int signo) {
assert(u);
- if (!u->slice)
- return -ESRCH;
-
return manager_kill_unit(u->manager, u->slice, KILL_ALL, signo, NULL);
}
diff --git a/src/login/logind-user.h b/src/login/logind-user.h
index 722247806b..de99cf47b4 100644
--- a/src/login/logind-user.h
+++ b/src/login/logind-user.h
@@ -39,16 +39,13 @@ typedef enum UserState {
struct User {
Manager *manager;
-
uid_t uid;
gid_t gid;
char *name;
-
char *state_file;
char *runtime_path;
-
- char *service;
char *slice;
+ char *service;
char *service_job;
char *slice_job;
@@ -65,8 +62,11 @@ struct User {
LIST_FIELDS(User, gc_queue);
};
-User* user_new(Manager *m, uid_t uid, gid_t gid, const char *name);
-void user_free(User *u);
+int user_new(User **out, Manager *m, uid_t uid, gid_t gid, const char *name);
+User *user_free(User *u);
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(User *, user_free);
+
bool user_check_gc(User *u, bool drop_not_started);
void user_add_to_gc_queue(User *u);
int user_start(User *u);
diff --git a/src/login/logind-utmp.c b/src/login/logind-utmp.c
index 3e7a935a34..3bd61a81fd 100644
--- a/src/login/logind-utmp.c
+++ b/src/login/logind-utmp.c
@@ -20,9 +20,9 @@
***/
#include <errno.h>
+#include <pwd.h>
#include <string.h>
#include <unistd.h>
-#include <pwd.h>
#include "sd-messages.h"
diff --git a/src/login/logind.c b/src/login/logind.c
index be6bbe5b5c..7b41174c64 100644
--- a/src/login/logind.c
+++ b/src/login/logind.c
@@ -70,6 +70,7 @@ static Manager *manager_new(void) {
m->idle_action_not_before_usec = now(CLOCK_MONOTONIC);
m->runtime_dir_size = PAGE_ALIGN((size_t) (physical_memory() / 10)); /* 10% */
+ m->user_tasks_max = UINT64_C(4096);
m->devices = hashmap_new(&string_hash_ops);
m->seats = hashmap_new(&string_hash_ops);
diff --git a/src/login/logind.conf b/src/login/logind.conf
index 6df6f04c77..81f6695434 100644
--- a/src/login/logind.conf
+++ b/src/login/logind.conf
@@ -32,3 +32,4 @@
#IdleActionSec=30min
#RuntimeDirectorySize=10%
#RemoveIPC=yes
+#UserTasksMax=4096
diff --git a/src/login/logind.h b/src/login/logind.h
index 44e05d8b01..f34544e64c 100644
--- a/src/login/logind.h
+++ b/src/login/logind.h
@@ -134,6 +134,7 @@ struct Manager {
sd_event_source *lid_switch_ignore_event_source;
size_t runtime_dir_size;
+ uint64_t user_tasks_max;
};
int manager_add_device(Manager *m, const char *sysfs, bool master, Device **_device);
@@ -171,7 +172,8 @@ int bus_manager_shutdown_or_sleep_now_or_later(Manager *m, const char *unit_name
int manager_send_changed(Manager *manager, const char *property, ...) _sentinel_;
-int manager_start_scope(Manager *manager, const char *scope, pid_t pid, const char *slice, const char *description, const char *after, const char *after2, sd_bus_error *error, char **job);
+int manager_start_slice(Manager *manager, const char *slice, const char *description, const char *after, const char *after2, uint64_t tasks_max, sd_bus_error *error, char **job);
+int manager_start_scope(Manager *manager, const char *scope, pid_t pid, const char *slice, const char *description, const char *after, const char *after2, uint64_t tasks_max, sd_bus_error *error, char **job);
int manager_start_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job);
int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job);
int manager_abandon_scope(Manager *manager, const char *scope, sd_bus_error *error);
diff --git a/src/login/pam_systemd.c b/src/login/pam_systemd.c
index 0d61f528db..ed4f7c726f 100644
--- a/src/login/pam_systemd.c
+++ b/src/login/pam_systemd.c
@@ -267,29 +267,21 @@ _public_ PAM_EXTERN int pam_sm_open_session(
pam_get_item(handle, PAM_SERVICE, (const void**) &service);
if (streq_ptr(service, "systemd-user")) {
- _cleanup_free_ char *p = NULL, *rt = NULL;
+ _cleanup_free_ char *rt = NULL;
- if (asprintf(&p, "/run/systemd/users/"UID_FMT, pw->pw_uid) < 0)
+ if (asprintf(&rt, "/run/user/"UID_FMT, pw->pw_uid) < 0)
return PAM_BUF_ERR;
- r = parse_env_file(p, NEWLINE,
- "RUNTIME", &rt,
- NULL);
- if (r < 0 && r != -ENOENT)
- return PAM_SESSION_ERR;
-
- if (rt) {
- r = pam_misc_setenv(handle, "XDG_RUNTIME_DIR", rt, 0);
- if (r != PAM_SUCCESS) {
- pam_syslog(handle, LOG_ERR, "Failed to set runtime dir.");
- return r;
- }
-
- r = export_legacy_dbus_address(handle, pw->pw_uid, rt);
- if (r != PAM_SUCCESS)
- return r;
+ r = pam_misc_setenv(handle, "XDG_RUNTIME_DIR", rt, 0);
+ if (r != PAM_SUCCESS) {
+ pam_syslog(handle, LOG_ERR, "Failed to set runtime dir.");
+ return r;
}
+ r = export_legacy_dbus_address(handle, pw->pw_uid, rt);
+ if (r != PAM_SUCCESS)
+ return r;
+
return PAM_SUCCESS;
}
@@ -501,7 +493,7 @@ _public_ PAM_EXTERN int pam_sm_open_session(
return PAM_SESSION_ERR;
}
- r = pam_set_data(handle, "systemd.session-fd", INT_TO_PTR(session_fd+1), NULL);
+ r = pam_set_data(handle, "systemd.session-fd", FD_TO_PTR(session_fd), NULL);
if (r != PAM_SUCCESS) {
pam_syslog(handle, LOG_ERR, "Failed to install session fd.");
safe_close(session_fd);
diff --git a/src/login/test-login-shared.c b/src/login/test-login-shared.c
index 4c4275d124..ac327f71fb 100644
--- a/src/login/test-login-shared.c
+++ b/src/login/test-login-shared.c
@@ -19,8 +19,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "macro.h"
#include "login-util.h"
+#include "macro.h"
static void test_session_id_valid(void) {
assert_se(session_id_valid("c1"));
diff --git a/src/login/test-login-tables.c b/src/login/test-login-tables.c
index a4196bf14b..4fbc893a9a 100644
--- a/src/login/test-login-tables.c
+++ b/src/login/test-login-tables.c
@@ -19,7 +19,6 @@
#include "logind-action.h"
#include "logind-session.h"
-
#include "test-tables.h"
int main(int argc, char **argv) {