-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
+/* SPDX-License-Identifier: LGPL-2.1+ */
#include <endian.h>
#include <errno.h>
#include "def.h"
#include "fd-util.h"
#include "fileio.h"
-#include "formats-util.h"
+#include "format-util.h"
#include "hostname-util.h"
#include "login-util.h"
#include "macro.h"
#include "parse-util.h"
+#include "process-util.h"
#include "socket-util.h"
#include "strv.h"
#include "terminal-util.h"
#include "util.h"
+#include "path-util.h"
+//#include "cgroup-util.h"
static int parse_argv(
pam_handle_t *handle,
if (fd < 0)
return -errno;
- if (connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0)
+ if (connect(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0)
return -errno;
r = getpeercred(fd, &ucred);
_cleanup_free_ char *s = NULL;
int r = PAM_BUF_ERR;
- if (is_kdbus_available()) {
- if (asprintf(&s, KERNEL_USER_BUS_ADDRESS_FMT ";" UNIX_USER_BUS_ADDRESS_FMT, uid, runtime) < 0)
- goto error;
- } else {
- /* FIXME: We *really* should move the access() check into the
- * daemons that spawn dbus-daemon, instead of forcing
- * DBUS_SESSION_BUS_ADDRESS= here. */
+ /* FIXME: We *really* should move the access() check into the
+ * daemons that spawn dbus-daemon, instead of forcing
+ * DBUS_SESSION_BUS_ADDRESS= here. */
- s = strjoin(runtime, "/bus", NULL);
- if (!s)
- goto error;
+ s = strjoin(runtime, "/bus");
+ if (!s)
+ goto error;
- if (access(s, F_OK) < 0)
- return PAM_SUCCESS;
+ if (access(s, F_OK) < 0)
+ return PAM_SUCCESS;
- s = mfree(s);
- if (asprintf(&s, UNIX_USER_BUS_ADDRESS_FMT, runtime) < 0)
- goto error;
- }
+ s = mfree(s);
+ if (asprintf(&s, DEFAULT_USER_BUS_ADDRESS_FMT, runtime) < 0)
+ goto error;
r = pam_misc_setenv(handle, "DBUS_SESSION_BUS_ADDRESS", s, 0);
if (r != PAM_SUCCESS)
return r;
}
+static int append_session_memory_max(pam_handle_t *handle, sd_bus_message *m, const char *limit) {
+ uint64_t val;
+ int r;
+
+ if (isempty(limit))
+ return 0;
+
+ if (streq(limit, "infinity")) {
+ r = sd_bus_message_append(m, "(sv)", "MemoryMax", "t", (uint64_t)-1);
+ if (r < 0) {
+ pam_syslog(handle, LOG_ERR, "Failed to append to bus message: %s", strerror(-r));
+ return r;
+ }
+ } else {
+ r = parse_percent(limit);
+ if (r >= 0) {
+ r = sd_bus_message_append(m, "(sv)", "MemoryMaxScale", "u", (uint32_t) (((uint64_t) UINT32_MAX * r) / 100U));
+ if (r < 0) {
+ pam_syslog(handle, LOG_ERR, "Failed to append to bus message: %s", strerror(-r));
+ return r;
+ }
+ } else {
+ r = parse_size(limit, 1024, &val);
+ if (r >= 0) {
+ r = sd_bus_message_append(m, "(sv)", "MemoryMax", "t", val);
+ if (r < 0) {
+ pam_syslog(handle, LOG_ERR, "Failed to append to bus message: %s", strerror(-r));
+ return r;
+ }
+ } else
+ pam_syslog(handle, LOG_WARNING, "Failed to parse elogind.limit: %s, ignoring.", limit);
+ }
+ }
+
+ return 0;
+}
+
+static int append_session_tasks_max(pam_handle_t *handle, sd_bus_message *m, const char *limit)
+{
+ uint64_t val;
+ int r;
+
+ /* No need to parse "infinity" here, it will be set unconditionally later in manager_start_scope() */
+ if (isempty(limit) || streq(limit, "infinity"))
+ return 0;
+
+ r = safe_atou64(limit, &val);
+ if (r >= 0) {
+ r = sd_bus_message_append(m, "(sv)", "TasksMax", "t", val);
+ if (r < 0) {
+ pam_syslog(handle, LOG_ERR, "Failed to append to bus message: %s", strerror(-r));
+ return r;
+ }
+ } else
+ pam_syslog(handle, LOG_WARNING, "Failed to parse elogind.limit: %s, ignoring.", limit);
+
+ return 0;
+}
+
+static int append_session_cg_weight(pam_handle_t *handle, sd_bus_message *m, const char *limit, const char *field) {
+ uint64_t val;
+ int r;
+
+ if (!isempty(limit)) {
+ r = cg_weight_parse(limit, &val);
+ if (r >= 0) {
+ r = sd_bus_message_append(m, "(sv)", field, "t", val);
+ if (r < 0) {
+ pam_syslog(handle, LOG_ERR, "Failed to append to bus message: %s", strerror(-r));
+ return r;
+ }
+ } else if (streq(field, "CPUWeight"))
+ pam_syslog(handle, LOG_WARNING, "Failed to parse elogind.cpu_weight: %s, ignoring.", limit);
+ else
+ pam_syslog(handle, LOG_WARNING, "Failed to parse elogind.io_weight: %s, ignoring.", limit);
+ }
+
+ return 0;
+}
+
_public_ PAM_EXTERN int pam_sm_open_session(
pam_handle_t *handle,
int flags,
int argc, const char **argv) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
const char
*username, *id, *object_path, *runtime_path,
*service = NULL,
*remote_user = NULL, *remote_host = NULL,
*seat = NULL,
*type = NULL, *class = NULL,
- *class_pam = NULL, *type_pam = NULL, *cvtnr = NULL, *desktop = NULL;
+ *class_pam = NULL, *type_pam = NULL, *cvtnr = NULL, *desktop = NULL,
+ *memory_max = NULL, *tasks_max = NULL, *cpu_weight = NULL, *io_weight = NULL;
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
int session_fd = -1, existing, r;
bool debug = false, remote;
assert(handle);
+#if 0 /// with elogind, it is always a "logind system".
/* Make this a NOP on non-logind systems */
if (!logind_running())
return PAM_SUCCESS;
+#endif // 0
if (parse_argv(handle,
argc, argv,
return PAM_SESSION_ERR;
if (debug)
- pam_syslog(handle, LOG_DEBUG, "pam-systemd initializing");
+ pam_syslog(handle, LOG_DEBUG, "pam-elogind initializing");
r = get_user_data(handle, &username, &pw);
if (r != PAM_SUCCESS) {
}
/* Make sure we don't enter a loop by talking to
- * systemd-logind when it is actually waiting for the
+ * elogind when it is actually waiting for the
* background to finish start-up. If the service is
- * "systemd-user" we simply set XDG_RUNTIME_DIR and
+ * "elogind-user" we simply set XDG_RUNTIME_DIR and
* leave. */
pam_get_item(handle, PAM_SERVICE, (const void**) &service);
- if (streq_ptr(service, "systemd-user")) {
+ if (streq_ptr(service, "elogind-user")) {
_cleanup_free_ char *rt = NULL;
if (asprintf(&rt, "/run/user/"UID_FMT, pw->pw_uid) < 0)
return PAM_BUF_ERR;
- 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 = 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 = export_legacy_dbus_address(handle, pw->pw_uid, rt);
+ if (r != PAM_SUCCESS)
+ return r;
return PAM_SUCCESS;
}
type ="tty";
class = "user";
tty = NULL;
- }
+ } else
+ /* Chop off leading /dev prefix that some clients specify, but others do not. */
+ tty = skip_dev_prefix(tty);
/* If this fails vtnr will be 0, that's intended */
if (!isempty(cvtnr))
remote = !isempty(remote_host) && !is_localhost(remote_host);
+ (void) pam_get_data(handle, "elogind.memory_max", (const void **)&memory_max);
+ (void) pam_get_data(handle, "elogind.tasks_max", (const void **)&tasks_max);
+ (void) pam_get_data(handle, "elogind.cpu_weight", (const void **)&cpu_weight);
+ (void) pam_get_data(handle, "elogind.io_weight", (const void **)&io_weight);
+
/* Talk to logind over the message bus */
r = sd_bus_open_system(&bus);
return PAM_SESSION_ERR;
}
- if (debug)
+ if (debug) {
pam_syslog(handle, LOG_DEBUG, "Asking logind to create session: "
"uid="UID_FMT" pid="PID_FMT" service=%s type=%s class=%s desktop=%s seat=%s vtnr=%"PRIu32" tty=%s display=%s remote=%s remote_user=%s remote_host=%s",
- pw->pw_uid, getpid(),
+ pw->pw_uid, getpid_cached(),
strempty(service),
type, class, strempty(desktop),
strempty(seat), vtnr, strempty(tty), strempty(display),
yes_no(remote), strempty(remote_user), strempty(remote_host));
+ pam_syslog(handle, LOG_DEBUG, "Session limits: "
+ "memory_max=%s tasks_max=%s cpu_weight=%s io_weight=%s",
+ strna(memory_max), strna(tasks_max), strna(cpu_weight), strna(io_weight));
+ }
+
+ r = sd_bus_message_new_method_call(
+ bus,
+ &m,
+ "org.freedesktop.login1",
+ "/org/freedesktop/login1",
+ "org.freedesktop.login1.Manager",
+ "CreateSession");
+ if (r < 0) {
+ pam_syslog(handle, LOG_ERR, "Failed to create CreateSession method call: %s", strerror(-r));
+ return PAM_SESSION_ERR;
+ }
+
+ r = sd_bus_message_append(m, "uusssssussbss",
+ (uint32_t) pw->pw_uid,
+ (uint32_t) getpid_cached(),
+ service,
+ type,
+ class,
+ desktop,
+ seat,
+ vtnr,
+ tty,
+ display,
+ remote,
+ remote_user,
+ remote_host);
+ if (r < 0) {
+ pam_syslog(handle, LOG_ERR, "Failed to append to bus message: %s", strerror(-r));
+ return PAM_SESSION_ERR;
+ }
+
+ r = sd_bus_message_open_container(m, 'a', "(sv)");
+ if (r < 0) {
+ pam_syslog(handle, LOG_ERR, "Failed to open message container: %s", strerror(-r));
+ return PAM_SYSTEM_ERR;
+ }
+
+ r = append_session_memory_max(handle, m, memory_max);
+ if (r < 0)
+ return PAM_SESSION_ERR;
+
+ r = append_session_tasks_max(handle, m, tasks_max);
+ if (r < 0)
+ return PAM_SESSION_ERR;
+
+ r = append_session_cg_weight(handle, m, cpu_weight, "CPUWeight");
+ if (r < 0)
+ return PAM_SESSION_ERR;
+
+ r = append_session_cg_weight(handle, m, io_weight, "IOWeight");
+ if (r < 0)
+ return PAM_SESSION_ERR;
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0) {
+ pam_syslog(handle, LOG_ERR, "Failed to close message container: %s", strerror(-r));
+ return PAM_SYSTEM_ERR;
+ }
- r = sd_bus_call_method(bus,
- "org.freedesktop.login1",
- "/org/freedesktop/login1",
- "org.freedesktop.login1.Manager",
- "CreateSession",
- &error,
- &reply,
- "uusssssussbssa(sv)",
- (uint32_t) pw->pw_uid,
- (uint32_t) getpid(),
- service,
- type,
- class,
- desktop,
- seat,
- vtnr,
- tty,
- display,
- remote,
- remote_user,
- remote_host,
- 0);
+ r = sd_bus_call(bus, m, 0, &error, &reply);
if (r < 0) {
if (sd_bus_error_has_name(&error, BUS_ERROR_SESSION_BUSY)) {
pam_syslog(handle, LOG_DEBUG, "Cannot create session: %s", bus_error_message(&error, r));