diff --git a/Makefile.in b/Makefile.in index e1b77ebc649..bcdec0c46e5 100644 --- a/Makefile.in +++ b/Makefile.in @@ -57,6 +57,7 @@ GSSLIBS=@GSSLIBS@ SSHDLIBS=@SSHDLIBS@ LIBEDIT=@LIBEDIT@ LIBFIDO2=@LIBFIDO2@ +LIBSYSTEMD=@LIBSYSTEMD@ AR=@AR@ AWK=@AWK@ RANLIB=@RANLIB@ @@ -218,7 +219,7 @@ sshd$(EXEEXT): libssh.a $(LIBCOMPAT) $(SSHDOBJS) $(LD) -o $@ $(SSHDOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(SSHDLIBS) $(LIBS) $(CHANNELLIBS) sshd-session$(EXEEXT): libssh.a $(LIBCOMPAT) $(SSHD_SESSION_OBJS) - $(LD) -o $@ $(SSHD_SESSION_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(SSHDLIBS) $(LIBS) $(GSSLIBS) $(K5LIBS) $(CHANNELLIBS) + $(LD) -o $@ $(SSHD_SESSION_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(SSHDLIBS) $(LIBS) $(GSSLIBS) $(K5LIBS) $(CHANNELLIBS) $(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 717fef83279..63fe1efb332 100644 --- a/configure.ac +++ b/configure.ac @@ -1765,6 +1765,47 @@ AC_ARG_WITH([libedit], fi ] ) +# 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 4f21499586a..0481ad75a93 100644 --- a/loginrec.c +++ b/loginrec.c @@ -187,6 +187,10 @@ # include #endif +#ifdef USE_LOGIND +# include +#endif + /** ** prototypes for helper functions in this file **/ @@ -200,6 +204,9 @@ void construct_utmp(struct logininfo *li, struct utmp *ut); void set_utmpx_time(struct logininfo *li, struct utmpx *ut); void construct_utmpx(struct logininfo *li, struct utmpx *ut); #endif +#ifdef USE_LOGIND +int logind_set_tty(struct logininfo *li); +#endif int utmp_write_entry(struct logininfo *li); int utmpx_write_entry(struct logininfo *li); @@ -467,6 +474,9 @@ login_write(struct logininfo *li) #ifdef USE_WTMPX wtmpx_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, @@ -1409,6 +1419,88 @@ wtmpx_get_entry(struct logininfo *li) } #endif /* USE_WTMPX */ +#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 **/