]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
login: add support for directories in MOTD_FILE=
authorKarel Zak <kzak@redhat.com>
Tue, 12 May 2020 12:20:54 +0000 (14:20 +0200)
committerKarel Zak <kzak@redhat.com>
Tue, 12 May 2020 12:20:54 +0000 (14:20 +0200)
The current standard is to use directories to make it easy for
distributions to share resources. This patch also add /etc/motd.d
and /run/motd.d to the default MOTD_FILE=.

Addresses: https://github.com/karelzak/util-linux/issues/10341
Signed-off-by: Karel Zak <kzak@redhat.com>
include/pathnames.h
login-utils/login.1
login-utils/login.c

index 3845d4c3319da23954a5660564e5a6d64ac67516..fac3a07831fdc58bf6418b6a20916b574f8ba713 100644 (file)
@@ -41,7 +41,7 @@
 #ifndef _PATH_MAILDIR
 # define _PATH_MAILDIR         "/var/spool/mail"
 #endif
-#define        _PATH_MOTDFILE          "/usr/share/misc/motd:/run/motd:/etc/motd"
+#define        _PATH_MOTDFILE          "/usr/share/misc/motd:/run/motd:/run/motd.d:/etc/motd:/etc/motd.d"
 #ifndef _PATH_NOLOGIN
 # define _PATH_NOLOGIN         "/etc/nologin"
 #endif
index 29fe1b7a6763aedf5a71b5378675fb5a30319ed8..1e2d3cb28990c60b080449e31eb111d9deb1feb1 100644 (file)
@@ -151,9 +151,12 @@ configuration items are relevant for
 .B MOTD_FILE
 (string)
 .RS 4
-If defined, a ":" delimited list of "message of the day" files to be
-displayed upon login.  The default value is
-.IR /etc\:/motd .
+Sepecifies a ":" delimited list of "message of the day" files and directories
+to be displayed upon login.  If the specified path is a directory then displays
+all files with .motd file extension in version-sort order from the directory.
+.PP
+The default value is
+.IR "/usr/share/misc/motd:/run/motd:/run/motd.d:/etc/motd:/etc/motd.d" .
 If the
 .B MOTD_FILE
 item is empty or a quiet login is enabled, then the message of the day
@@ -161,6 +164,10 @@ is not displayed.  Note that the same functionality is also provided
 by
 .BR pam_motd (8)
 PAM module.
+.PP
+The directories in the
+.B MOTD_FILE
+are supported since version 2.36.
 .RE
 .PP
 .B LOGIN_PLAIN_PROMPT
index 30940a6f8f679245260cd683f3b58c534f3ae53d..0ea2fbb3fa030556322cf5c8cc27543b08d94510 100644 (file)
 #define        TTYGRPNAME      "tty"   /* name of group to own ttys */
 #define VCS_PATH_MAX   64
 
+#if defined(HAVE_SCANDIRAT) && defined(HAVE_OPENAT)
+# include <dirent.h>
+# include "fileutils.h"
+# define MOTDDIR_SUPPORT
+# define MOTDDIR_EXT   ".motd"
+# define MOTDDIR_EXTSIZ        (sizeof(MOTDDIR_EXT) - 1)
+#endif
+
 /*
  * Login control struct
  */
@@ -238,40 +246,98 @@ static const char *get_thishost(struct login_context *cxt, const char **domain)
        return cxt->thishost;
 }
 
+#ifdef MOTDDIR_SUPPORT
+static int motddir_filter(const struct dirent *d)
+{
+       size_t namesz;
+
+#ifdef _DIRENT_HAVE_D_TYPE
+       if (d->d_type != DT_UNKNOWN && d->d_type != DT_REG &&
+           d->d_type != DT_LNK)
+               return 0;
+#endif
+       if (*d->d_name == '.')
+               return 0;
+
+       namesz = strlen(d->d_name);
+       if (!namesz || namesz < MOTDDIR_EXTSIZ + 1 ||
+           strcmp(d->d_name + (namesz - MOTDDIR_EXTSIZ), MOTDDIR_EXT) != 0)
+               return 0;
+
+       return 1; /* accept */
+}
+
+static void motddir(const char *dirname)
+{
+        int dd, nfiles, i;
+        struct dirent **namelist = NULL;
+
+       dd = open(dirname, O_RDONLY|O_CLOEXEC|O_DIRECTORY);
+       if (dd < 0)
+               return;
+
+       nfiles = scandirat(dd, ".", &namelist, motddir_filter, versionsort);
+       if (nfiles <= 0)
+               goto done;
+
+       for (i = 0; i < nfiles; i++) {
+               struct dirent *d = namelist[i];
+               int fd;
+
+               fd = openat(dd, d->d_name, O_RDONLY|O_CLOEXEC);
+               if (fd >= 0) {
+                       struct stat st;
+                       if (fstat(fd, &st) == 0 && st.st_size > 0)
+                               sendfile(fileno(stdout), fd, NULL, st.st_size);
+                       close(fd);
+               }
+       }
+
+       for (i = 0; i < nfiles; i++)
+               free(namelist[i]);
+       free(namelist);
+done:
+       close(dd);
+}
+#endif /* MOTDDIR_SUPPORT */
+
 /*
  * Output the /etc/motd file.
  *
- * It determines the name of a login announcement file and outputs it to the
+ * It determines the name of a login announcement file/dir and outputs it to the
  * user's terminal at login time.  The MOTD_FILE configuration option is a
- * colon-delimited list of filenames.  An empty MOTD_FILE option disables
+ * colon-delimited list of filenames or directories.  An empty option disables
  * message-of-the-day printing completely.
  */
 static void motd(void)
 {
-       char *motdlist, *motdfile;
        const char *mb;
+       char *file, *list;
 
        mb = getlogindefs_str("MOTD_FILE", _PATH_MOTDFILE);
        if (!mb || !*mb)
                return;
 
-       motdlist = xstrdup(mb);
-
-       for (motdfile = strtok(motdlist, ":"); motdfile;
-            motdfile = strtok(NULL, ":")) {
+       list = xstrdup(mb);
 
+       for (file = strtok(list, ":"); file; file = strtok(NULL, ":")) {
                struct stat st;
-               int fd;
 
-               fd = open(motdfile, O_RDONLY, 0);
-               if (fd < 0)
+               if (stat(file, &st) < 0)
                        continue;
-               if (!fstat(fd, &st) && st.st_size)
-                       sendfile(fileno(stdout), fd, NULL, st.st_size);
-               close(fd);
+#ifdef MOTDDIR_SUPPORT
+               if (S_ISDIR(st.st_mode))
+                       motddir(file);
+               else
+#endif
+               if (S_ISREG(st.st_mode) && st.st_size > 0) {
+                       int fd = open(file, O_RDONLY, 0);
+                       if (fd >= 0)
+                               sendfile(fileno(stdout), fd, NULL, st.st_size);
+                       close(fd);
+               }
        }
-
-       free(motdlist);
+       free(list);
 }
 
 /*