From: Ray Strode <halfline@gmail.com>
To: util-linux@vger.kernel.org
Cc: Karel Zak <kzak@redhat.com>,
Lennart Poettering <lennart@poettering.net>,
Ray Strode <rstrode@redhat.com>
Subject: [PATCH] login-utils: import environment from user manager on systemd systems
Date: Tue, 25 Oct 2016 16:34:21 -0400 [thread overview]
Message-ID: <1477427661-19788-1-git-send-email-halfline@gmail.com> (raw)
From: Ray Strode <rstrode@redhat.com>
If the user is using a systemd system, then its useful to grab the
environment from the systemd user manager process.
This allows administrators to initialize the environment of the sessions
via systemd configuration.
Reference: https://github.com/systemd/systemd/pull/3904
Signed-off-by: Ray Strode <rstrode@redhat.com>
---
login-utils/Makemodule.am | 5 +++
login-utils/login.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 89 insertions(+)
diff --git a/login-utils/Makemodule.am b/login-utils/Makemodule.am
index be07ace..d65bfc1 100644
--- a/login-utils/Makemodule.am
+++ b/login-utils/Makemodule.am
@@ -16,70 +16,75 @@ endif
if BUILD_SULOGIN
sbin_PROGRAMS += sulogin
dist_man_MANS += login-utils/sulogin.8
sulogin_SOURCES = \
login-utils/sulogin.c \
login-utils/sulogin-consoles.c \
login-utils/sulogin-consoles.h
sulogin_LDADD = $(LDADD) libcommon.la
if HAVE_LIBCRYPT
sulogin_LDADD += -lcrypt
endif
if HAVE_SELINUX
sulogin_LDADD += -lselinux
endif
check_PROGRAMS += test_consoles
test_consoles_SOURCES = login-utils/sulogin-consoles.c
test_consoles_CFLAGS = $(AM_CFLAGS) -DTEST_PROGRAM
test_consoles_LDADD = $(LDADD) libcommon.la
endif # BUILD_SULOGIN
if BUILD_LOGIN
bin_PROGRAMS += login
dist_man_MANS += login-utils/login.1
login_SOURCES = \
login-utils/login.c \
login-utils/logindefs.c \
login-utils/logindefs.h
+login_CFLAGS =
login_LDADD = $(LDADD) libcommon.la -lpam
if HAVE_LINUXPAM
login_LDADD += -lpam_misc
endif
if HAVE_AUDIT
login_LDADD += -laudit
endif
if HAVE_SELINUX
login_LDADD += -lselinux
endif
+if HAVE_SYSTEMD
+login_LDADD += $(SYSTEMD_LIBS)
+login_CFLAGS += $(SYSTEMD_CFLAGS)
+endif
endif # BUILD_LOGIN
if BUILD_NOLOGIN
sbin_PROGRAMS += nologin
dist_man_MANS += login-utils/nologin.8
nologin_SOURCES = login-utils/nologin.c
endif
if BUILD_UTMPDUMP
usrbin_exec_PROGRAMS += utmpdump
dist_man_MANS += login-utils/utmpdump.1
utmpdump_SOURCES = login-utils/utmpdump.c
utmpdump_LDADD = $(LDADD) libcommon.la
endif
if BUILD_CHFN_CHSH
usrbin_exec_PROGRAMS += chfn chsh
dist_man_MANS += \
login-utils/chfn.1 \
login-utils/chsh.1
chfn_chsh_sources = \
login-utils/ch-common.h \
login-utils/ch-common.c
chfn_chsh_cflags = $(SUID_CFLAGS) $(AM_CFLAGS)
chfn_chsh_ldflags = $(SUID_LDFLAGS) $(AM_LDFLAGS)
chfn_chsh_ldadd = libcommon.la
diff --git a/login-utils/login.c b/login-utils/login.c
index 2350fc3..9a9a86e 100644
--- a/login-utils/login.c
+++ b/login-utils/login.c
@@ -37,69 +37,74 @@
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/file.h>
#include <termios.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/wait.h>
#include <signal.h>
#include <errno.h>
#include <grp.h>
#include <pwd.h>
#include <utmp.h>
#include <stdlib.h>
#include <sys/syslog.h>
#ifdef HAVE_LINUX_MAJOR_H
# include <linux/major.h>
#endif
#include <netdb.h>
#include <security/pam_appl.h>
#ifdef HAVE_SECURITY_PAM_MISC_H
# include <security/pam_misc.h>
#elif defined(HAVE_SECURITY_OPENPAM_H)
# include <security/openpam.h>
#endif
#include <sys/sendfile.h>
#ifdef HAVE_LIBAUDIT
# include <libaudit.h>
#endif
+#ifdef HAVE_LIBSYSTEMD
+# include <systemd/sd-bus.h>
+#endif
+
#include "c.h"
#include "setproctitle.h"
#include "pathnames.h"
#include "strutils.h"
#include "nls.h"
#include "env.h"
#include "xalloc.h"
#include "all-io.h"
#include "fileutils.h"
+#include "strv.h"
#include "ttyutils.h"
#include "logindefs.h"
#define is_pam_failure(_rc) ((_rc) != PAM_SUCCESS)
#define LOGIN_MAX_TRIES 3
#define LOGIN_EXIT_TIMEOUT 5
#define LOGIN_TIMEOUT 60
#ifdef USE_TTY_GROUP
# define TTY_MODE 0620
#else
# define TTY_MODE 0600
#endif
#define TTYGRPNAME "tty" /* name of group to own ttys */
#define VCS_PATH_MAX 64
/*
* Login control struct
*/
struct login_context {
const char *tty_path; /* ttyname() return value */
const char *tty_name; /* tty_path without /dev prefix */
const char *tty_number; /* end of the tty_path */
mode_t tty_mode; /* chmod() mode */
char *username; /* from command line or PAM */
@@ -994,108 +999,187 @@ static void fork_session(struct login_context *cxt)
/*
* child
*/
sigaction(SIGHUP, &oldsa_hup, NULL); /* restore old state */
sigaction(SIGTERM, &oldsa_term, NULL);
if (got_sig)
exit(EXIT_FAILURE);
/*
* Problem: if the user's shell is a shell like ash that doesn't do
* setsid() or setpgrp(), then a ctrl-\, sending SIGQUIT to every
* process in the pgrp, will kill us.
*/
/* start new session */
setsid();
/* make sure we have a controlling tty */
open_tty(cxt->tty_path);
openlog("login", LOG_ODELAY, LOG_AUTHPRIV); /* reopen */
/*
* TIOCSCTTY: steal tty from other process group.
*/
if (ioctl(0, TIOCSCTTY, 1))
syslog(LOG_ERR, _("TIOCSCTTY failed: %m"));
signal(SIGINT, SIG_DFL);
}
+#ifdef HAVE_LIBSYSTEMD
+/*
+ * Import environment from systemd user manager
+ */
+static void import_systemd_user_environ(struct login_context *cxt)
+{
+ struct passwd *pwd = cxt->pwd;
+ int rc;
+ sd_bus *bus = NULL;
+ sd_bus_error error = SD_BUS_ERROR_NULL;
+ sd_bus_message *reply = NULL;
+ char *env_entry = NULL;
+ uid_t old_euid = geteuid();
+ int euid_changed = 0;
+
+ if (pwd->pw_uid != 0) {
+ assert(old_euid == getuid());
+
+ if (seteuid(pwd->pw_uid) < 0) {
+ syslog(LOG_ERR, _("seteuid failed: %m"));
+ return;
+ }
+ euid_changed = 1;
+ }
+
+ rc = sd_bus_default_user(&bus);
+
+ if (rc < 0) {
+ syslog(LOG_NOTICE, _("user bus unavailable: %m"));
+ return;
+ }
+
+ rc = sd_bus_get_property(bus,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "Environment",
+ &error,
+ &reply,
+ "as");
+
+ if (rc < 0) {
+ syslog(LOG_NOTICE, _("user bus unable to return environment: %m"));
+ goto out;
+ }
+
+ rc = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "s");
+
+ if (rc < 0)
+ goto out;
+
+ while ((rc = sd_bus_message_read_basic(reply, SD_BUS_TYPE_STRING, &env_entry)) > 0) {
+ char **env_tuple;
+
+ env_tuple = strv_split(env_entry, "=");
+
+ if (env_tuple && env_tuple[0] && env_tuple[1])
+ xsetenv(env_tuple[0], env_tuple[1], 0);
+
+ strv_free (env_tuple);
+ }
+ sd_bus_message_exit_container(reply);
+
+out:
+ sd_bus_error_free(&error);
+ reply = sd_bus_message_unref(reply);
+ bus = sd_bus_unref(bus);
+
+ if (euid_changed && seteuid(old_euid) < 0) {
+ syslog(LOG_ALERT, _("seteuid() failed"));
+ exit(EXIT_FAILURE);
+ }
+}
+#endif
+
/*
* Initialize $TERM, $HOME, ...
*/
static void init_environ(struct login_context *cxt)
{
struct passwd *pwd = cxt->pwd;
char *termenv, **env;
char tmp[PATH_MAX];
int len, i;
termenv = getenv("TERM");
if (termenv)
termenv = xstrdup(termenv);
/* destroy environment unless user has requested preservation (-p) */
if (!cxt->keep_env) {
environ = xmalloc(sizeof(char *));
memset(environ, 0, sizeof(char *));
}
xsetenv("HOME", pwd->pw_dir, 0); /* legal to override */
xsetenv("USER", pwd->pw_name, 1);
xsetenv("SHELL", pwd->pw_shell, 1);
xsetenv("TERM", termenv ? termenv : "dumb", 1);
free(termenv);
if (pwd->pw_uid) {
if (logindefs_setenv("PATH", "ENV_PATH", _PATH_DEFPATH) != 0)
err(EXIT_FAILURE, _("failed to set the %s environment variable"), "PATH");
} else if (logindefs_setenv("PATH", "ENV_ROOTPATH", NULL) != 0 &&
logindefs_setenv("PATH", "ENV_SUPATH", _PATH_DEFPATH_ROOT) != 0) {
err(EXIT_FAILURE, _("failed to set the %s environment variable"), "PATH");
}
/* mailx will give a funny error msg if you forget this one */
len = snprintf(tmp, sizeof(tmp), "%s/%s", _PATH_MAILDIR, pwd->pw_name);
if (len > 0 && (size_t) len < sizeof(tmp))
xsetenv("MAIL", tmp, 0);
/* LOGNAME is not documented in login(1) but HP-UX 6.5 does it. We'll
* not allow modifying it.
*/
xsetenv("LOGNAME", pwd->pw_name, 1);
env = pam_getenvlist(cxt->pamh);
for (i = 0; env && env[i]; i++)
putenv(env[i]);
+
+#ifdef HAVE_LIBSYSTEMD
+ import_systemd_user_environ(cxt);
+#endif
}
/*
* This is called for the -h option, initializes cxt->{hostname,hostaddress}.
*/
static void init_remote_info(struct login_context *cxt, char *remotehost)
{
const char *domain;
char *p;
struct addrinfo hints, *info = NULL;
cxt->remote = 1;
get_thishost(cxt, &domain);
if (domain && (p = strchr(remotehost, '.')) &&
strcasecmp(p + 1, domain) == 0)
*p = '\0';
cxt->hostname = xstrdup(remotehost);
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_ADDRCONFIG;
cxt->hostaddress[0] = 0;
if (getaddrinfo(cxt->hostname, NULL, &hints, &info) == 0 && info) {
if (info->ai_family == AF_INET) {
struct sockaddr_in *sa =
(struct sockaddr_in *) info->ai_addr;
--
2.7.4
next reply other threads:[~2016-10-25 20:34 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-10-25 20:34 Ray Strode [this message]
2016-10-25 21:06 ` [PATCH] login-utils: import environment from user manager on systemd systems Linda Walsh
2016-10-26 19:38 ` Ray Strode
2016-10-27 21:53 ` L. Walsh
2016-10-28 15:06 ` Ray Strode
2016-10-28 3:02 ` L. Walsh
2016-10-28 15:14 ` Ray Strode
2016-12-07 19:45 ` Ray Strode
2016-12-07 20:04 ` Ruediger Meier
2016-12-08 11:24 ` Karel Zak
2016-12-08 15:00 ` Ray Strode
2016-12-08 18:39 ` Fwd: " Ray Strode
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1477427661-19788-1-git-send-email-halfline@gmail.com \
--to=halfline@gmail.com \
--cc=kzak@redhat.com \
--cc=lennart@poettering.net \
--cc=rstrode@redhat.com \
--cc=util-linux@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox