From 74b91131ed09850ed487a2f7849147ff6f80194d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 14 Jul 2011 22:50:01 +0200 Subject: [PATCH 1/1] logind: introduce libsystemd-login.so as fast path to access logind data --- .gitignore | 2 + Makefile.am | 47 +++++- TODO | 2 + libsystemd-login.pc.in | 18 +++ src/sd-login.c | 323 +++++++++++++++++++++++++++++++++++++++++ src/sd-login.h | 51 +++++++ src/test-login.c | 65 +++++++++ systemd.pc.in | 2 +- 8 files changed, 507 insertions(+), 3 deletions(-) create mode 100644 libsystemd-login.pc.in create mode 100644 src/sd-login.c create mode 100644 src/sd-login.h create mode 100644 src/test-login.c diff --git a/.gitignore b/.gitignore index b108fd987..cd2540457 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +libsystemd-login.pc +test-login systemd-loginctl systemd-localed systemd-timedated diff --git a/Makefile.am b/Makefile.am index 53167ff20..445cc1e37 100644 --- a/Makefile.am +++ b/Makefile.am @@ -19,6 +19,10 @@ ACLOCAL_AMFLAGS = -I m4 SUBDIRS = po +LIBSYSTEMD_LOGIN_CURRENT=0 +LIBSYSTEMD_LOGIN_REVISION=0 +LIBSYSTEMD_LOGIN_AGE=0 + # Dirs of external packages dbuspolicydir=@dbuspolicydir@ dbussessionservicedir=@dbussessionservicedir@ @@ -35,6 +39,7 @@ pkgsysconfdir=$(sysconfdir)/systemd userunitdir=$(prefix)/lib/systemd/user tmpfilesdir=$(prefix)/lib/tmpfiles.d usergeneratordir=$(pkglibexecdir)/user-generators +pkgincludedir=$(includedir)/systemd # And these are the special ones for / rootdir=@rootdir@ @@ -183,6 +188,12 @@ systemgenerator_PROGRAMS += \ systemd-cryptsetup-generator endif +lib_LTLIBRARIES = \ + libsystemd-login.la + +pkginclude_HEADERS = \ + src/sd-login.h + noinst_PROGRAMS = \ test-engine \ test-job-type \ @@ -192,7 +203,8 @@ noinst_PROGRAMS = \ test-daemon \ test-cgroup \ test-env-replace \ - test-strv + test-strv \ + test-login if HAVE_PAM pamlib_LTLIBRARIES = \ @@ -410,6 +422,7 @@ EXTRA_DIST = \ units/quotacheck.service.in \ units/user@.service.in \ systemd.pc.in \ + libsystemd-login.pc.in \ introspect.awk \ src/73-seat-late.rules.in @@ -472,7 +485,8 @@ dist_doc_DATA = \ src/sd-readahead.c pkgconfigdata_DATA = \ - systemd.pc + systemd.pc \ + libsystemd-login.pc # Passed through intltool only polkitpolicy_in_files = \ @@ -801,6 +815,16 @@ test_strv_CFLAGS = \ test_strv_LDADD = \ libsystemd-basic.la +test_login_SOURCES = \ + src/test-login.c + +test_login_CFLAGS = \ + $(AM_CFLAGS) + +test_login_LDADD = \ + libsystemd-basic.la \ + libsystemd-login.la + systemd_logger_SOURCES = \ src/logger.c \ src/tcpwrap.c @@ -946,6 +970,7 @@ systemd_uaccess_CFLAGS = \ systemd_uaccess_LDADD = \ libsystemd-basic.la \ + libsystemd-daemon.la \ $(UDEV_LIBS) \ $(ACL_LIBS) @@ -1339,6 +1364,21 @@ pam_systemd_la_LIBADD = \ $(PAM_LIBS) \ $(DBUS_LIBS) +libsystemd_login_la_CFLAGS = \ + $(AM_CFLAGS) \ + -fvisibility=hidden + +libsystemd_login_la_LDFLAGS = \ + -shared \ + -version-info $(LIBSYSTEMD_LOGIN_CURRENT):$(LIBSYSTEMD_LOGIN_REVISION):$(LIBSYSTEMD_LOGIN_AGE) + +libsystemd_login_la_SOURCES = \ + src/sd-login.c \ + src/cgroup-util.c + +libsystemd_login_la_LIBADD = \ + libsystemd-basic.la + SED_PROCESS = \ $(AM_V_GEN)$(MKDIR_P) $(dir $@) && \ $(SED) -e 's,@rootlibexecdir\@,$(rootlibexecdir),g' \ @@ -1355,6 +1395,9 @@ SED_PROCESS = \ -e 's,@PACKAGE_NAME\@,$(PACKAGE_NAME),g' \ -e 's,@PACKAGE_URL\@,$(PACKAGE_URL),g' \ -e 's,@prefix\@,$(prefix),g' \ + -e 's,@exec_prefix\@,$(exec_prefix),g' \ + -e 's,@libdir\@,$(libdir),g' \ + -e 's,@includedir\@,$(includedir),g' \ < $< > $@ || rm $@ units/%: units/%.in Makefile diff --git a/TODO b/TODO index 8a807b48f..1577565e0 100644 --- a/TODO +++ b/TODO @@ -20,6 +20,8 @@ F15 External: Features: +* logind: ensure ACLs are updated on login and logout + * warn if the user stops a service but not its associated socket * ensure we always set the facility when logging to kmsg diff --git a/libsystemd-login.pc.in b/libsystemd-login.pc.in new file mode 100644 index 000000000..cd36a9cb3 --- /dev/null +++ b/libsystemd-login.pc.in @@ -0,0 +1,18 @@ +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: systemd +Description: systemd Login Utility Library +URL: @PACKAGE_URL@ +Version: @PACKAGE_VERSION@ +Libs: -L${libdir} -lsystemd-login +Cflags: -I${includedir} diff --git a/src/sd-login.c b/src/sd-login.c new file mode 100644 index 000000000..3ae850d80 --- /dev/null +++ b/src/sd-login.c @@ -0,0 +1,323 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include + +#include "util.h" +#include "cgroup-util.h" +#include "macro.h" +#include "sd-login.h" + +_public_ int sd_pid_get_session(pid_t pid, char **session) { + int r; + char *cg_process, *cg_init, *p; + + if (pid == 0) + pid = getpid(); + + if (pid <= 0) + return -EINVAL; + + if (!session) + return -EINVAL; + + r = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, pid, &cg_process); + if (r < 0) + return r; + + r = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, 1, &cg_init); + if (r < 0) { + free(cg_process); + return r; + } + + if (endswith(cg_init, "/system")) + cg_init[strlen(cg_init)-7] = 0; + else if (streq(cg_init, "/")) + cg_init[0] = 0; + + if (startswith(cg_process, cg_init)) + p = cg_process + strlen(cg_init); + else + p = cg_process; + + free(cg_init); + + if (!startswith(p, "/user/")) { + free(cg_process); + return -ENOENT; + } + + p += 6; + if (startswith(p, "shared/") || streq(p, "shared")) { + free(cg_process); + return -ENOENT; + } + + p = strchr(p, '/'); + if (!p) { + free(cg_process); + return -ENOENT; + } + + p++; + p = strndup(p, strcspn(p, "/")); + free(cg_process); + + if (!p) + return -ENOMEM; + + *session = p; + return 0; +} + +_public_ int sd_uid_get_state(uid_t uid, char**state) { + char *p, *s = NULL; + int r; + + if (!state) + return -EINVAL; + + if (asprintf(&p, "/run/systemd/users/%lu", (unsigned long) uid) < 0) + return -ENOMEM; + + r = parse_env_file(p, NEWLINE, "STATE", &s, NULL); + free(p); + + if (r == -ENOENT) { + free(s); + s = strdup("offline"); + if (!s) + return -ENOMEM; + + *state = s; + return 0; + } else if (r < 0) { + free(s); + return r; + } else if (!s) + return -EIO; + + *state = s; + return 0; +} + +static int uid_is_on_seat_internal(uid_t uid, const char *seat, const char *variable) { + char *p, *w, *t, *state, *s = NULL; + size_t l; + int r; + + if (!seat) + return -EINVAL; + + p = strappend("/run/systemd/seats/", seat); + if (!p) + return -ENOMEM; + + r = parse_env_file(p, NEWLINE, "UIDS", &s, NULL); + free(p); + + if (r < 0) { + free(s); + return r; + } + + if (!s) + return -EIO; + + if (asprintf(&t, "%lu", (unsigned long) uid) < 0) { + free(s); + return -ENOMEM; + } + + FOREACH_WORD(w, l, s, state) { + if (strncmp(t, w, l) == 0) { + free(s); + free(t); + + return 1; + } + } + + free(s); + free(t); + + return 0; +} + +_public_ int sd_uid_is_on_seat(uid_t uid, const char *seat) { + return uid_is_on_seat_internal(uid, seat, "UIDS"); +} + +_public_ int sd_uid_is_active_on_seat(uid_t uid, const char *seat) { + return uid_is_on_seat_internal(uid, seat, "ACTIVE_UID"); +} + +_public_ int sd_session_is_active(const char *session) { + int r; + char *p, *s = NULL; + + if (!session) + return -EINVAL; + + p = strappend("/run/systemd/sessions/", session); + if (!p) + return -ENOMEM; + + r = parse_env_file(p, NEWLINE, "ACTIVE", &s, NULL); + free(p); + + if (r < 0) { + free(s); + return r; + } + + if (!s) + return -EIO; + + r = parse_boolean(s); + free(s); + + return r; +} + +_public_ int sd_session_get_uid(const char *session, uid_t *uid) { + int r; + char *p, *s = NULL; + unsigned long ul; + + if (!session) + return -EINVAL; + if (!uid) + return -EINVAL; + + p = strappend("/run/systemd/sessions/", session); + if (!p) + return -ENOMEM; + + r = parse_env_file(p, NEWLINE, "UID", &s, NULL); + free(p); + + if (r < 0) { + free(s); + return r; + } + + if (!s) + return -EIO; + + r = safe_atolu(s, &ul); + free(s); + + if (r < 0) + return r; + + *uid = (uid_t) ul; + return 0; +} + +_public_ int sd_session_get_seat(const char *session, char **seat) { + char *p, *s = NULL; + int r; + + if (!session) + return -EINVAL; + if (!seat) + return -EINVAL; + + p = strappend("/run/systemd/sessions/", session); + if (!p) + return -ENOMEM; + + r = parse_env_file(p, NEWLINE, "SEAT", &s, NULL); + free(p); + + if (r < 0) { + free(s); + return r; + } + + if (isempty(s)) + return -ENOENT; + + *seat = s; + return 0; +} + +_public_ int sd_seat_get_active(const char *seat, char **session, uid_t *uid) { + char *p, *s = NULL, *t = NULL; + int r; + + if (!seat) + return -EINVAL; + if (!session && !uid) + return -EINVAL; + + p = strappend("/run/systemd/seats/", seat); + if (!p) + return -ENOMEM; + + r = parse_env_file(p, NEWLINE, + "ACTIVE", &s, + "ACTIVE_UID", &t, + NULL); + free(p); + + if (r < 0) { + free(s); + free(t); + return r; + } + + if (session && !s) { + free(t); + return -EIO; + } + + if (uid && !t) { + free(s); + return -EIO; + } + + if (uid && t) { + unsigned long ul; + + r = safe_atolu(t, &ul); + if (r < 0) { + free(t); + free(s); + return r; + } + + *uid = (uid_t) ul; + } + + free(t); + + if (session && s) + *session = s; + else + free(s); + + return 0; +} diff --git a/src/sd-login.h b/src/sd-login.h new file mode 100644 index 000000000..f23ac8052 --- /dev/null +++ b/src/sd-login.h @@ -0,0 +1,51 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#ifndef foosdloginhfoo +#define foosdloginhfoo + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with systemd; If not, see . +***/ + +#include + +/* Get session from PID */ +int sd_pid_get_session(pid_t pid, char **session); + +/* Get state from uid. Possible states: offline, lingering, online, active */ +int sd_uid_get_state(uid_t uid, char**state); + +/* Return 1 if uid has session on seat */ +int sd_uid_is_on_seat(uid_t uid, const char *seat); + +/* Return 1 if uid has active session on seat */ +int sd_uid_is_active_on_seat(uid_t uid, const char *seat); + +/* Return 1 if the session is a active */ +int sd_session_is_active(const char *session); + +/* Determine user id of session */ +int sd_session_get_uid(const char *session, uid_t *uid); + +/* Determine seat of session */ +int sd_session_get_seat(const char *session, char **seat); + +/* Return active session and user of seat */ +int sd_seat_get_active(const char *seat, char **session, uid_t *uid); + +#endif diff --git a/src/test-login.c b/src/test-login.c new file mode 100644 index 000000000..97313fcbc --- /dev/null +++ b/src/test-login.c @@ -0,0 +1,65 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with systemd; If not, see . +***/ + +#include "sd-login.h" +#include "util.h" + +int main(int argc, char* argv[]) { + int r, k; + uid_t u, u2; + char *seat; + char *session; + char *state; + char *session2; + + assert_se(sd_pid_get_session(0, &session) == 0); + printf("session = %s\n", session); + + r = sd_session_is_active(session); + assert_se(r >= 0); + printf("active = %s\n", yes_no(r)); + + assert_se(sd_session_get_uid(session, &u) >= 0); + printf("uid = %lu\n", (unsigned long) u); + + assert_se(sd_session_get_seat(session, &seat) >= 0); + printf("seat = %s\n", seat); + + assert_se(sd_uid_get_state(u, &state) >= 0); + printf("state = %s\n", state); + + assert_se(sd_uid_is_on_seat(u, seat) > 0); + + k = sd_uid_is_active_on_seat(u, seat); + assert_se(k >= 0); + assert_se(!!r == !!r); + + assert_se(sd_seat_get_active(seat, &session2, &u2) >= 0); + printf("session2 = %s\n", session2); + printf("uid2 = %lu\n", (unsigned long) u2); + + free(session); + free(state); + free(session2); + free(seat); + + return 0; +} diff --git a/systemd.pc.in b/systemd.pc.in index 2e2217ec4..29376e55b 100644 --- a/systemd.pc.in +++ b/systemd.pc.in @@ -6,7 +6,7 @@ # (at your option) any later version. prefix=@prefix@ -exec_prefix=${prefix} +exec_prefix=@exec_prefix@ systemdsystemunitdir=@systemunitdir@ systemduserunitdir=@userunitdir@ systemdsystemconfdir=@pkgsysconfdir@/system -- 2.30.2