diff --git a/Makefile.in b/Makefile.in index f0ea07e7b..35dcf45f1 100644 --- a/Makefile.in +++ b/Makefile.in @@ -56,6 +56,7 @@ SSHDLIBS=@SSHDLIBS@ LIBEDIT=@LIBEDIT@ LIBFIDO2=@LIBFIDO2@ LIBWTMPDB=@LIBWTMPDB@ +LIBSYSTEMD=@LIBSYSTEMD@ AR=@AR@ AWK=@AWK@ RANLIB=@RANLIB@ @@ -208,7 +209,7 @@ ssh$(EXEEXT): $(LIBCOMPAT) libssh.a $(SSHOBJS) $(LD) -o $@ $(SSHOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) $(GSSLIBS) $(CHANNELLIBS) sshd$(EXEEXT): libssh.a $(LIBCOMPAT) $(SSHDOBJS) - $(LD) -o $@ $(SSHDOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(SSHDLIBS) $(LIBS) $(GSSLIBS) $(K5LIBS) $(CHANNELLIBS) $(LIBWTMPDB) + $(LD) -o $@ $(SSHDOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(SSHDLIBS) $(LIBS) $(GSSLIBS) $(K5LIBS) $(CHANNELLIBS) $(LIBWTMPDB) $(LIBSYSTEMD) scp$(EXEEXT): $(LIBCOMPAT) libssh.a $(SCP_OBJS) $(LD) -o $@ $(SCP_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) diff --git a/configure.ac b/configure.ac index a12c6f7ad..860df3379 100644 --- a/configure.ac +++ b/configure.ac @@ -1789,6 +1789,47 @@ AC_ARG_WITH([wtmpdb], ) +# Check whether user wants logind/set tty support +AC_ARG_WITH([logind], + [ --with-logind[[=PATH]] Enable logind support for sshd], + [ if test "x$withval" != "xno" ; then + if test "x$withval" = "xyes" ; then + AC_PATH_TOOL([PKGCONFIG], [pkg-config], [no]) + if test "x$PKGCONFIG" != "xno"; then + AC_MSG_CHECKING([if $PKGCONFIG knows about libsystemd]) + if "$PKGCONFIG" libsystemd; then + AC_MSG_RESULT([yes]) + use_pkgconfig_for_libsystemd=yes + else + AC_MSG_RESULT([no]) + fi + fi + else + CPPFLAGS="$CPPFLAGS -I${withval}/include" + if test -n "${rpath_opt}"; then + LDFLAGS="-L${withval}/lib ${rpath_opt}${withval}/lib ${LDFLAGS}" + else + LDFLAGS="-L${withval}/lib ${LDFLAGS}" + fi + fi + if test "x$use_pkgconfig_for_libsystemd" = "xyes"; then + LIBSYSTEMD=`$PKGCONFIG --libs libsystemd` + CPPFLAGS="$CPPFLAGS `$PKGCONFIG --cflags libsystemd`" + else + LIBSYSTEMD="-lsystemd" + fi + OTHERLIBS=`echo $LIBSYSTEMD | sed 's/-lsystemd//'` + AC_CHECK_LIB([systemd], [sd_bus_open_system], + [ AC_DEFINE([USE_LOGIND], [1], [Use systemd-logind]) + AC_SUBST([LIBSYSTEMD]) + ], + [ AC_MSG_ERROR([libsystemd not found]) ], + [ $OTHERLIBS ] + ) + fi ] +) + + AUDIT_MODULE=none AC_ARG_WITH([audit], [ --with-audit=module Enable audit support (modules=debug,bsm,linux)], diff --git a/loginrec.c b/loginrec.c index 86caf83b2..8b413190b 100644 --- a/loginrec.c +++ b/loginrec.c @@ -191,6 +191,10 @@ # include #endif +#ifdef USE_LOGIND +# include +#endif + /** ** prototypes for helper functions in this file **/ @@ -214,6 +218,9 @@ int syslogin_write_entry(struct logininfo *li); #ifdef USE_WTMPDB int wtmpdb_write_entry(struct logininfo *li); #endif +#ifdef USE_LOGIND +int logind_set_tty(struct logininfo *li); +#endif int getlast_entry(struct logininfo *li); int lastlog_get_entry(struct logininfo *li); @@ -477,6 +484,9 @@ login_write(struct logininfo *li) #ifdef USE_WTMPDB wtmpdb_write_entry(li); #endif +#ifdef USE_LOGIND + logind_set_tty(li); +#endif #ifdef CUSTOM_SYS_AUTH_RECORD_LOGIN if (li->type == LTYPE_LOGIN && !sys_auth_record_login(li->username,li->hostname,li->line, @@ -1476,6 +1486,88 @@ wtmpdb_write_entry(struct logininfo *li) } #endif +#ifdef USE_LOGIND +#define DBUS_DESTINATION "org.freedesktop.login1" +#define DBUS_PATH_ID "/org/freedesktop/login1/session/auto" +#define DBUS_INTERFACE "org.freedesktop.login1.Session" +#define DBUS_PATH "/org/freedesktop/login1/session/%s" + +static int +logind_perform_login(struct logininfo *li) +{ + sd_bus *bus = NULL; + sd_bus_error error = SD_BUS_ERROR_NULL; + char *session_id = NULL; + char *dbus_path; + const char *tty; + char buf[PATH_MAX]; + int r; + int fd; + + if (sd_bus_open_system(&bus) < 0) + { + logit("logind: canot open dbus"); + return (0); + } + + if (sd_bus_get_property_string(bus, DBUS_DESTINATION, + DBUS_PATH_ID, DBUS_INTERFACE, + "Id", &error, &session_id) < 0) + { + logit("logind: cannot get session ID"); + return (0); + } + + if (strncmp(li->line, "/dev/", 5) != 0) + snprintf (buf, sizeof(buf), "/dev/%s", li->line); + else + tty = li->line; + + fd = open(tty, O_RDWR|O_CLOEXEC|O_NOCTTY); + + if (asprintf (&dbus_path, DBUS_PATH, session_id) < 0) + return (0); + + if (sd_bus_call_method(bus, DBUS_DESTINATION, dbus_path, + DBUS_INTERFACE, "TakeControl", &error, NULL, + "b", 1) < 0) { + logit("logind: cannot take control"); + free(dbus_path); + return (0); + } + + if ((r = sd_bus_call_method(bus, DBUS_DESTINATION, dbus_path, + DBUS_INTERFACE, "SetTTY", &error, NULL, + "h", fd)) < 0) { + if (r != -EBADR) /* logind does not support "SetTTY" */ + logit("logind: cannot set TTY(%s, %s): %s", session_id, tty, strerror(-r)); + free(dbus_path); + return (0); + } + + free(dbus_path); + + if (sd_bus_flush(bus) < 0) + return (0); + + return (1); +} + +int +logind_set_tty(struct logininfo *li) +{ + switch(li->type) { + case LTYPE_LOGIN: + return (logind_perform_login(li)); + case LTYPE_LOGOUT: + return (1); + default: + logit("%s: invalid type field", __func__); + return (0); + } +} +#endif + /** ** Low-level libutil login() functions