]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
write: query logind for list of users with tty (#2088)
authorThorsten Kukuk <kukuk@suse.com>
Wed, 31 May 2023 07:00:09 +0000 (09:00 +0200)
committerThorsten Kukuk <kukuk@suse.com>
Wed, 31 May 2023 11:58:26 +0000 (13:58 +0200)
term-utils/Makemodule.am
term-utils/write.c

index b7037fb116d60f5a3e6f018e6851a299f4e060cd..1efe1c57e3710005fc275065752f6ead0e87cee6 100644 (file)
@@ -126,6 +126,10 @@ write_SOURCES = term-utils/write.c
 write_CFLAGS = $(SUID_CFLAGS) $(AM_CFLAGS)
 write_LDFLAGS = $(SUID_LDFLAGS) $(AM_LDFLAGS)
 write_LDADD = $(LDADD) libcommon.la
+if HAVE_SYSTEMD
+write_LDADD += $(SYSTEMD_LIBS)
+write_CFLAGS += $(SYSTEMD_CFLAGS)
+endif
 
 if USE_TTY_GROUP
 if MAKEINSTALL_DO_CHOWN
index 8b86e9a9d5ac8f735a6f2ebee3be95f3841953e0..8aa450d563fd5ef5f40abc32f205a7951c4f6655 100644 (file)
 #include <unistd.h>
 #include <utmpx.h>
 
+#if defined(USE_SYSTEMD) && HAVE_DECL_SD_SESSION_GET_USERNAME == 1
+# include <systemd/sd-login.h>
+# include <systemd/sd-daemon.h>
+#endif
+
 #include "c.h"
 #include "carefulputc.h"
 #include "closestream.h"
@@ -131,19 +136,56 @@ static int check_utmp(const struct write_control *ctl)
 {
        struct utmpx *u;
        int res = 1;
-
-       utmpxname(_PATH_UTMP);
-       setutxent();
-
-       while ((u = getutxent())) {
-               if (strncmp(ctl->dst_login, u->ut_user, sizeof(u->ut_user)) == 0 &&
-                   strncmp(ctl->dst_tty_name, u->ut_line, sizeof(u->ut_line)) == 0) {
-                       res = 0;
-                       break;
+#if defined(USE_SYSTEMD) && HAVE_DECL_SD_SESSION_GET_USERNAME == 1
+       if (sd_booted() > 0) {
+               char **sessions_list;
+               int sessions = sd_get_sessions(&sessions_list);
+               if (sessions < 0)
+                       errx(EXIT_FAILURE, _("error getting sessions: %s"),
+                               strerror(-sessions));
+
+               for (int i = 0; i < sessions; i++) {
+
+                       char *name, *tty;
+                       int r;
+
+                       if ((r = sd_session_get_username(sessions_list[i], &name)) < 0)
+                               errx(EXIT_FAILURE, _("get user name failed: %s"), strerror (-r));
+                       if (sd_session_get_tty(sessions_list[i], &tty) < 0) {
+                               free(name);
+                               continue;
+                       }
+
+                       if  (strcmp(ctl->dst_login, name) == 0 &&
+                                       strcmp(ctl->dst_tty_name, tty) == 0) {
+                               free(name);
+                               free(tty);
+                               res = 0;
+                               break;
+                       }
+                       free(name);
+                       free(tty);
+               }
+               for (int i = 0; i < sessions; i++)
+                       free(sessions_list[i]);
+               free(sessions_list);
+       } else {
+#endif
+               utmpxname(_PATH_UTMP);
+               setutxent();
+
+               while ((u = getutxent())) {
+                       if (strncmp(ctl->dst_login, u->ut_user, sizeof(u->ut_user)) == 0 &&
+                               strncmp(ctl->dst_tty_name, u->ut_line, sizeof(u->ut_line)) == 0) {
+                               res = 0;
+                               break;
+                       }
                }
-       }
 
-       endutxent();
+               endutxent();
+#if defined(USE_SYSTEMD) && HAVE_DECL_SD_SESSION_GET_USERNAME == 1
+       }
+#endif
        return res;
 }
 
@@ -163,6 +205,69 @@ static void search_utmp(struct write_control *ctl)
        struct utmpx *u;
        time_t best_atime = 0, tty_atime;
        int num_ttys = 0, valid_ttys = 0, tty_writeable = 0, user_is_me = 0;
+
+#if defined(USE_SYSTEMD) && HAVE_DECL_SD_SESSION_GET_USERNAME == 1
+       if (sd_booted() > 0) {
+               char path[256];
+               char **sessions_list;
+               int sessions = sd_get_sessions(&sessions_list);
+               if (sessions < 0)
+                       errx(EXIT_FAILURE, _("error getting sessions: %s"),
+                            strerror(-sessions));
+
+               for (int i = 0; i < sessions; i++) {
+                       char *name, *tty;
+                       int r;
+
+                       if ((r = sd_session_get_username(sessions_list[i], &name)) < 0)
+                               errx(EXIT_FAILURE, _("get user name failed: %s"), strerror (-r));
+
+                       if  (strcmp(ctl->dst_login, name) != 0) {
+                               free(name);
+                               continue;
+                       }
+
+                       if (sd_session_get_tty(sessions_list[i], &tty) < 0) {
+                               free(name);
+                               continue;
+                       }
+
+                       num_ttys++;
+                       snprintf(path, sizeof(path), "/dev/%s", tty);
+                       if (check_tty(path, &tty_writeable, &tty_atime, 0)) {
+                               /* bad term? skip */
+                               free(name);
+                               free(tty);
+                               continue;
+                       }
+                       if (ctl->src_uid && !tty_writeable) {
+                               /* skip ttys with msgs off */
+                               free(name);
+                               free(tty);
+                               continue;
+                       }
+                       if (strcmp(tty, ctl->src_tty_name) == 0) {
+                               user_is_me = 1;
+                               free(name);
+                               free(tty);
+                               /* don't write to yourself */
+                               continue;
+                       }
+                       valid_ttys++;
+                       if (best_atime < tty_atime) {
+                               best_atime = tty_atime;
+                               free(ctl->dst_tty_path);
+                               ctl->dst_tty_path = xstrdup(path);
+                               ctl->dst_tty_name = ctl->dst_tty_path + 5;
+                       }
+                       free(name);
+                       free(tty);
+               }
+               for (int i = 0; i < sessions; i++)
+                       free(sessions_list[i]);
+               free(sessions_list);
+       } else {
+#endif
        char path[sizeof(u->ut_line) + 6];
 
        utmpxname(_PATH_UTMP);
@@ -197,6 +302,9 @@ static void search_utmp(struct write_control *ctl)
        }
 
        endutxent();
+#if defined(USE_SYSTEMD) && HAVE_DECL_SD_SESSION_GET_USERNAME == 1
+       }
+#endif
        if (num_ttys == 0)
                errx(EXIT_FAILURE, _("%s is not logged in"), ctl->dst_login);
        if (valid_ttys == 0) {