Blame SOURCES/pam-1.3.1-pam-motd-support-multiple-motd-paths.patch

b1cf0d
diff -up Linux-PAM-1.3.1/modules/pam_motd/pam_motd.8.xml.pam_motd-support-multiple-motd-paths1 Linux-PAM-1.3.1/modules/pam_motd/pam_motd.8.xml
b1cf0d
--- Linux-PAM-1.3.1/modules/pam_motd/pam_motd.8.xml.pam_motd-support-multiple-motd-paths1	2022-04-25 12:32:36.939663167 +0200
b1cf0d
+++ Linux-PAM-1.3.1/modules/pam_motd/pam_motd.8.xml	2022-04-25 12:34:43.506582206 +0200
b1cf0d
@@ -21,6 +21,9 @@
b1cf0d
       <arg choice="opt">
b1cf0d
         motd=<replaceable>/path/filename</replaceable>
b1cf0d
       </arg>
b1cf0d
+      <arg choice="opt">
b1cf0d
+        motd_dir=<replaceable>/path/dirname.d</replaceable>
b1cf0d
+      </arg>
b1cf0d
     </cmdsynopsis>
b1cf0d
   </refsynopsisdiv>
b1cf0d
 
b1cf0d
@@ -31,18 +34,49 @@
b1cf0d
     <para>
b1cf0d
       pam_motd is a PAM module that can be used to display
b1cf0d
       arbitrary motd (message of the day) files after a successful
b1cf0d
-      login. By default the <filename>/etc/motd</filename> file and
b1cf0d
-      all files from <filename>/etc/motd.d</filename> are
b1cf0d
-      shown. The message size is limited to 64KB.
b1cf0d
+      login. By default, pam_motd shows files in the
b1cf0d
+      following locations:
b1cf0d
+    </para>
b1cf0d
+    <para>
b1cf0d
+      <simplelist type='vert'>
b1cf0d
+        <member><filename>/etc/motd</filename></member>
b1cf0d
+        <member><filename>/run/motd</filename></member>
b1cf0d
+        <member><filename>/usr/lib/motd</filename></member>
b1cf0d
+        <member><filename>/etc/motd.d/</filename></member>
b1cf0d
+        <member><filename>/run/motd.d/</filename></member>
b1cf0d
+        <member><filename>/usr/lib/motd.d/</filename></member>
b1cf0d
+      </simplelist>
b1cf0d
+    </para>
b1cf0d
+    <para>
b1cf0d
+      Each message size is limited to 64KB.
b1cf0d
+    </para>
b1cf0d
+    <para>
b1cf0d
+      If <filename>/etc/motd</filename> does not exist,
b1cf0d
+      then <filename>/run/motd</filename> is shown. If
b1cf0d
+      <filename>/run/motd</filename> does not exist, then
b1cf0d
+      <filename>/usr/lib/motd</filename> is shown.
b1cf0d
+    </para>
b1cf0d
+    <para>
b1cf0d
+      Similar overriding behavior applies to the directories.
b1cf0d
+      Files in <filename>/etc/motd.d/</filename> override files
b1cf0d
+      with the same name in <filename>/run/motd.d/</filename> and
b1cf0d
+      <filename>/usr/lib/motd.d/</filename>. Files in <filename>/run/motd.d/</filename>
b1cf0d
+      override files with the same name in <filename>/usr/lib/motd.d/</filename>.
b1cf0d
+    </para>
b1cf0d
+    <para>
b1cf0d
+      Files in the directories listed above are displayed in lexicographic
b1cf0d
+      order by name. Moreover, the files are filtered by reading them with the
b1cf0d
+      credentials of the target user authenticating on the system.
b1cf0d
     </para>
b1cf0d
     <para>
b1cf0d
       To silence a message,
b1cf0d
       a symbolic link with target <filename>/dev/null</filename>
b1cf0d
       may be placed in <filename>/etc/motd.d</filename> with
b1cf0d
       the same filename as the message to be silenced. Example:
b1cf0d
+      Creating a symbolic link as follows silences <filename>/usr/lib/motd.d/my_motd</filename>.
b1cf0d
     </para>
b1cf0d
     <para>
b1cf0d
-      <command>ln -sfn /dev/null /etc/motd.d/my_motd</command>
b1cf0d
+      <command>ln -s /dev/null /etc/motd.d/my_motd</command>
b1cf0d
     </para>
b1cf0d
   </refsect1>
b1cf0d
 
b1cf0d
@@ -56,8 +90,10 @@
b1cf0d
         </term>
b1cf0d
         <listitem>
b1cf0d
           <para>
b1cf0d
-	    The <filename>/path/filename</filename> file is displayed
b1cf0d
-            as message of the day.
b1cf0d
+            The <filename>/path/filename</filename> file is displayed
b1cf0d
+            as message of the day. Multiple paths to try can be
b1cf0d
+            specified as a colon-separated list. By default this option
b1cf0d
+            is set to <filename>/etc/motd:/run/motd:/usr/lib/motd</filename>.
b1cf0d
           </para>
b1cf0d
         </listitem>
b1cf0d
       </varlistentry>
b1cf0d
@@ -68,16 +104,17 @@
b1cf0d
         <listitem>
b1cf0d
           <para>
b1cf0d
             The <filename>/path/dirname.d</filename> directory is scanned
b1cf0d
-            and each file contained inside of it is displayed.
b1cf0d
+            and each file contained inside of it is displayed. Multiple
b1cf0d
+            directories to scan can be specified as a colon-separated list.
b1cf0d
+            By default this option is set to <filename>/etc/motd.d:/run/motd.d:/usr/lib/motd.d</filename>.
b1cf0d
           </para>
b1cf0d
         </listitem>
b1cf0d
       </varlistentry>
b1cf0d
     </variablelist>
b1cf0d
     <para>
b1cf0d
-      When no options are given, the default is to display both
b1cf0d
-      <filename>/etc/motd</filename> and the contents of
b1cf0d
-      <filename>/etc/motd.d</filename>.  Specifying either option (or both)
b1cf0d
-      will disable this default behavior.
b1cf0d
+      When no options are given, the default behavior applies for both
b1cf0d
+      options. Specifying either option (or both) will disable the
b1cf0d
+      default behavior for both options.
b1cf0d
     </para>
b1cf0d
   </refsect1>
b1cf0d
 
b1cf0d
diff -up Linux-PAM-1.3.1/modules/pam_motd/pam_motd.c.pam_motd-support-multiple-motd-paths1 Linux-PAM-1.3.1/modules/pam_motd/pam_motd.c
b1cf0d
--- Linux-PAM-1.3.1/modules/pam_motd/pam_motd.c.pam_motd-support-multiple-motd-paths1	2018-05-18 11:50:46.000000000 +0200
b1cf0d
+++ Linux-PAM-1.3.1/modules/pam_motd/pam_motd.c	2022-04-25 12:32:36.947663225 +0200
b1cf0d
@@ -33,8 +33,8 @@
b1cf0d
  */
b1cf0d
 
b1cf0d
 #define PAM_SM_SESSION
b1cf0d
-#define DEFAULT_MOTD	"/etc/motd"
b1cf0d
-#define DEFAULT_MOTD_D	"/etc/motd.d"
b1cf0d
+#define DEFAULT_MOTD	"/etc/motd:/run/motd:/usr/lib/motd"
b1cf0d
+#define DEFAULT_MOTD_D	"/etc/motd.d:/run/motd.d:/usr/lib/motd.d"
b1cf0d
 
b1cf0d
 #include <security/pam_modules.h>
b1cf0d
 #include <security/pam_modutil.h>
b1cf0d
@@ -97,12 +97,235 @@ static void try_to_display_directory(pam
b1cf0d
     }
b1cf0d
 }
b1cf0d
 
b1cf0d
+/*
b1cf0d
+ * Split a DELIM-separated string ARG into an array.
b1cf0d
+ * Outputs a newly allocated array of strings OUT_ARG_SPLIT
b1cf0d
+ * and the number of strings OUT_NUM_STRS.
b1cf0d
+ * Returns 0 in case of error, 1 in case of success.
b1cf0d
+ */
b1cf0d
+static int pam_split_string(const pam_handle_t *pamh, char *arg, char delim,
b1cf0d
+			    char ***out_arg_split, uint *out_num_strs)
b1cf0d
+{
b1cf0d
+    char *arg_extracted = NULL;
b1cf0d
+    const char *arg_ptr = arg;
b1cf0d
+    char **arg_split = NULL;
b1cf0d
+    char delim_str[2];
b1cf0d
+    int i = 0;
b1cf0d
+    uint num_strs = 0;
b1cf0d
+    int retval = 0;
b1cf0d
+
b1cf0d
+    delim_str[0] = delim;
b1cf0d
+    delim_str[1] = '\0';
b1cf0d
+
b1cf0d
+    if (arg == NULL) {
b1cf0d
+	goto out;
b1cf0d
+    }
b1cf0d
+
b1cf0d
+    while (arg_ptr != NULL) {
b1cf0d
+	num_strs++;
b1cf0d
+	arg_ptr = strchr(arg_ptr + sizeof(const char), delim);
b1cf0d
+    }
b1cf0d
+
b1cf0d
+    arg_split = (char **)calloc(num_strs, sizeof(char *));
b1cf0d
+    if (arg_split == NULL) {
b1cf0d
+	pam_syslog(pamh, LOG_CRIT, "pam_motd: failed to allocate string array");
b1cf0d
+	goto out;
b1cf0d
+    }
b1cf0d
+
b1cf0d
+
b1cf0d
+    arg_extracted = strtok_r(arg, delim_str, &arg;;
b1cf0d
+    while (arg_extracted != NULL && i < num_strs) {
b1cf0d
+	arg_split[i++] = arg_extracted;
b1cf0d
+	arg_extracted = strtok_r(NULL, delim_str, &arg;;
b1cf0d
+    }
b1cf0d
+
b1cf0d
+    retval = 1;
b1cf0d
+
b1cf0d
+  out:
b1cf0d
+    *out_num_strs = num_strs;
b1cf0d
+    *out_arg_split = arg_split;
b1cf0d
+
b1cf0d
+    return retval;
b1cf0d
+}
b1cf0d
+
b1cf0d
+/* Join A_STR and B_STR, inserting a "/" between them if one is not already trailing
b1cf0d
+ * in A_STR or beginning B_STR. A pointer to a newly allocated string holding the
b1cf0d
+ * joined string is returned in STRP_OUT.
b1cf0d
+ * Returns -1 in case of error, or the number of bytes in the joined string in
b1cf0d
+ * case of success. */
b1cf0d
+static int join_dir_strings(char **strp_out, const char *a_str, const char *b_str)
b1cf0d
+{
b1cf0d
+    int has_sep = 0;
b1cf0d
+    int retval = -1;
b1cf0d
+    char *join_strp = NULL;
b1cf0d
+    
b1cf0d
+    if (strp_out == NULL || a_str == NULL || b_str == NULL) {
b1cf0d
+	goto out;
b1cf0d
+    }
b1cf0d
+    if (strlen(a_str) == 0) {
b1cf0d
+	goto out;
b1cf0d
+    }
b1cf0d
+
b1cf0d
+    has_sep = (a_str[strlen(a_str) - 1] == '/') || (b_str[0] == '/');
b1cf0d
+
b1cf0d
+    retval = asprintf(&join_strp, "%s%s%s", a_str,
b1cf0d
+	(has_sep == 1) ? "" : "/", b_str);
b1cf0d
+
b1cf0d
+    if (retval < 0) {
b1cf0d
+	goto out;
b1cf0d
+    }
b1cf0d
+
b1cf0d
+    *strp_out = join_strp;
b1cf0d
+
b1cf0d
+  out:
b1cf0d
+    return retval;
b1cf0d
+}
b1cf0d
+
b1cf0d
+static int compare_strings(const void * a, const void * b)
b1cf0d
+{
b1cf0d
+    const char *a_str = *(char **)a;
b1cf0d
+    const char *b_str = *(char **)b;
b1cf0d
+
b1cf0d
+    if (a_str == NULL && b_str == NULL) {
b1cf0d
+        return 0;
b1cf0d
+    }
b1cf0d
+    else if (a_str == NULL) {
b1cf0d
+	return -1;
b1cf0d
+    }
b1cf0d
+    else if (b_str == NULL) {
b1cf0d
+	return 1;
b1cf0d
+    }
b1cf0d
+    else {
b1cf0d
+	return strcmp(a_str, b_str);
b1cf0d
+    }
b1cf0d
+}
b1cf0d
+
b1cf0d
+static int filter_dirents(const struct dirent *d)
b1cf0d
+{
b1cf0d
+    return (d->d_type == DT_REG || d->d_type == DT_LNK);
b1cf0d
+}
b1cf0d
+
b1cf0d
+static void try_to_display_directories_with_overrides(pam_handle_t *pamh,
b1cf0d
+	char **motd_dir_path_split, int num_motd_dirs)
b1cf0d
+{
b1cf0d
+    struct dirent ***dirscans = NULL;
b1cf0d
+    int *dirscans_sizes = NULL;
b1cf0d
+    int dirscans_size_total = 0;
b1cf0d
+    char **dirnames_all = NULL;
b1cf0d
+    int i;
b1cf0d
+    int i_dirnames = 0;
b1cf0d
+
b1cf0d
+    if (pamh == NULL || motd_dir_path_split == NULL) {
b1cf0d
+	goto out;
b1cf0d
+    }
b1cf0d
+    if (num_motd_dirs < 1) {
b1cf0d
+	goto out;
b1cf0d
+    }
b1cf0d
+
b1cf0d
+    if ((dirscans = (struct dirent ***)calloc(num_motd_dirs,
b1cf0d
+	    sizeof(struct dirent **))) == NULL) {
b1cf0d
+	pam_syslog(pamh, LOG_CRIT, "pam_motd: failed to allocate dirent arrays");
b1cf0d
+	goto out;
b1cf0d
+    }
b1cf0d
+    if ((dirscans_sizes = (int *)calloc(num_motd_dirs, sizeof(int))) == NULL) {
b1cf0d
+	pam_syslog(pamh, LOG_CRIT, "pam_motd: failed to allocate dirent array sizes");
b1cf0d
+	goto out;
b1cf0d
+    }
b1cf0d
+
b1cf0d
+    for (i = 0; i < num_motd_dirs; i++) {
b1cf0d
+	dirscans_sizes[i] = scandir(motd_dir_path_split[i], &(dirscans[i]),
b1cf0d
+		filter_dirents, alphasort);
b1cf0d
+	if (dirscans_sizes[i] < 0) {
b1cf0d
+	    pam_syslog(pamh, LOG_ERR, "pam_motd: error scanning directory %s", motd_dir_path_split[i]);
b1cf0d
+	    dirscans_sizes[i] = 0;
b1cf0d
+	}
b1cf0d
+	dirscans_size_total += dirscans_sizes[i];
b1cf0d
+    }
b1cf0d
+
b1cf0d
+    /* Allocate space for all file names found in the directories, including duplicates. */
b1cf0d
+    if ((dirnames_all = (char **)calloc(dirscans_size_total,
b1cf0d
+	    sizeof(char *))) == NULL) {
b1cf0d
+	pam_syslog(pamh, LOG_CRIT, "pam_motd: failed to allocate dirname array");
b1cf0d
+	goto out;
b1cf0d
+    }
b1cf0d
+
b1cf0d
+    for (i = 0; i < dirscans_size_total; i++) {
b1cf0d
+	dirnames_all[i] = NULL;
b1cf0d
+    }
b1cf0d
+
b1cf0d
+    for (i = 0; i < num_motd_dirs; i++) {
b1cf0d
+	int j;
b1cf0d
+
b1cf0d
+	for (j = 0; j < dirscans_sizes[i]; j++) {
b1cf0d
+	    dirnames_all[i_dirnames] = dirscans[i][j]->d_name;
b1cf0d
+	    i_dirnames++;
b1cf0d
+	}
b1cf0d
+    }
b1cf0d
+
b1cf0d
+    qsort(dirnames_all, dirscans_size_total,
b1cf0d
+	    sizeof(const char *), compare_strings);
b1cf0d
+
b1cf0d
+    for (i = 0; i < dirscans_size_total; i++) {
b1cf0d
+	int j;
b1cf0d
+
b1cf0d
+	if (dirnames_all[i] == NULL) {
b1cf0d
+	    continue;
b1cf0d
+	}
b1cf0d
+
b1cf0d
+	/* Skip duplicate file names. */
b1cf0d
+	if (i > 0 && strcmp(dirnames_all[i], dirnames_all[i - 1]) == 0) {
b1cf0d
+	    continue;
b1cf0d
+	}
b1cf0d
+
b1cf0d
+	for (j = 0; j < num_motd_dirs; j++) {
b1cf0d
+	    char *abs_path = NULL;
b1cf0d
+
b1cf0d
+	    if (join_dir_strings(&abs_path, motd_dir_path_split[j],
b1cf0d
+		    dirnames_all[i]) < 0) {
b1cf0d
+		continue;
b1cf0d
+	    }
b1cf0d
+
b1cf0d
+	    if (abs_path != NULL) {
b1cf0d
+		int fd = open(abs_path, O_RDONLY, 0);
b1cf0d
+		if (fd >= 0) {
b1cf0d
+		    try_to_display_fd(pamh, fd);
b1cf0d
+		    close(fd);
b1cf0d
+
b1cf0d
+		    /* We displayed a file, skip to the next file name. */
b1cf0d
+		    break;
b1cf0d
+		}
b1cf0d
+	    }
b1cf0d
+	    _pam_drop(abs_path);
b1cf0d
+	}
b1cf0d
+    }
b1cf0d
+
b1cf0d
+  out:
b1cf0d
+    _pam_drop(dirnames_all);
b1cf0d
+    for (i = 0; i < num_motd_dirs; i++) {
b1cf0d
+	int j;
b1cf0d
+	for (j = 0; j < dirscans_sizes[i]; j++) {
b1cf0d
+	    _pam_drop(dirscans[i][j]);
b1cf0d
+	}
b1cf0d
+	_pam_drop(dirscans[i]);
b1cf0d
+    }
b1cf0d
+    _pam_drop(dirscans_sizes);
b1cf0d
+    _pam_drop(dirscans);
b1cf0d
+
b1cf0d
+    return;
b1cf0d
+}
b1cf0d
+
b1cf0d
 int pam_sm_open_session(pam_handle_t *pamh, int flags,
b1cf0d
 			int argc, const char **argv)
b1cf0d
 {
b1cf0d
     int retval = PAM_IGNORE;
b1cf0d
     const char *motd_path = NULL;
b1cf0d
+    char *motd_path_copy = NULL;
b1cf0d
+    int num_motd_paths = 0;
b1cf0d
+    char **motd_path_split = NULL;
b1cf0d
     const char *motd_dir_path = NULL;
b1cf0d
+    char *motd_dir_path_copy = NULL;
b1cf0d
+    int num_motd_dir_paths = 0;
b1cf0d
+    char **motd_dir_path_split = NULL;
b1cf0d
 
b1cf0d
     if (flags & PAM_SILENT) {
b1cf0d
 	return retval;
b1cf0d
@@ -140,17 +363,47 @@ int pam_sm_open_session(pam_handle_t *pa
b1cf0d
 	motd_dir_path = default_motd_dir;
b1cf0d
     }
b1cf0d
 
b1cf0d
-    if (motd_path != NULL) {
b1cf0d
-	int fd = open(motd_path, O_RDONLY, 0);
b1cf0d
+    motd_path_copy = strdup(motd_path);
b1cf0d
+    if (motd_path_copy != NULL) {
b1cf0d
+	if (pam_split_string(pamh, motd_path_copy, ':', &motd_path_split,
b1cf0d
+		&num_motd_paths) == 0) {
b1cf0d
+	    goto out;
b1cf0d
+	}
b1cf0d
+    }
b1cf0d
+
b1cf0d
+    motd_dir_path_copy = strdup(motd_dir_path);
b1cf0d
+    if (motd_dir_path_copy != NULL) {
b1cf0d
+	if (pam_split_string(pamh, motd_dir_path_copy, ':',
b1cf0d
+		&motd_dir_path_split, &num_motd_dir_paths) == 0) {
b1cf0d
+	    goto out;
b1cf0d
+	}
b1cf0d
+    }
b1cf0d
+
b1cf0d
+    if (motd_path_split != NULL) {
b1cf0d
+	int i;
b1cf0d
+
b1cf0d
+	for (i = 0; i < num_motd_paths; i++) {
b1cf0d
+	    int fd = open(motd_path_split[i], O_RDONLY, 0);
b1cf0d
 
b1cf0d
-	if (fd >= 0) {
b1cf0d
-	    try_to_display_fd(pamh, fd);
b1cf0d
-	    close(fd);
b1cf0d
+	    if (fd >= 0) {
b1cf0d
+		try_to_display_fd(pamh, fd);
b1cf0d
+		close(fd);
b1cf0d
+
b1cf0d
+		/* We found and displayed a file, move onto next filename. */
b1cf0d
+		break;
b1cf0d
+	    }
b1cf0d
 	}
b1cf0d
     }
b1cf0d
 
b1cf0d
-    if (motd_dir_path != NULL)
b1cf0d
-	try_to_display_directory(pamh, motd_dir_path);
b1cf0d
+    if (motd_dir_path_split != NULL)
b1cf0d
+	try_to_display_directories_with_overrides(pamh, motd_dir_path_split,
b1cf0d
+		num_motd_dir_paths);
b1cf0d
+
b1cf0d
+  out:
b1cf0d
+    _pam_drop(motd_path_copy);
b1cf0d
+    _pam_drop(motd_path_split);
b1cf0d
+    _pam_drop(motd_dir_path_copy);
b1cf0d
+    _pam_drop(motd_dir_path_split);
b1cf0d
 
b1cf0d
     return retval;
b1cf0d
 }
b1cf0d
diff -up Linux-PAM-1.3.1/xtests/Makefile.am.pam_motd-support-multiple-motd-paths1 Linux-PAM-1.3.1/xtests/Makefile.am
b1cf0d
--- Linux-PAM-1.3.1/xtests/Makefile.am.pam_motd-support-multiple-motd-paths1	2017-02-10 11:10:15.000000000 +0100
b1cf0d
+++ Linux-PAM-1.3.1/xtests/Makefile.am	2022-04-25 12:32:36.947663225 +0200
b1cf0d
@@ -32,7 +32,10 @@ EXTRA_DIST = run-xtests.sh tst-pam_dispa
b1cf0d
 	tst-pam_substack5.pamd tst-pam_substack5a.pamd tst-pam_substack5.sh \
b1cf0d
 	tst-pam_assemble_line1.pamd tst-pam_assemble_line1.sh \
b1cf0d
 	tst-pam_pwhistory1.pamd tst-pam_pwhistory1.sh \
b1cf0d
-	tst-pam_time1.pamd time.conf
b1cf0d
+	tst-pam_time1.pamd time.conf \
b1cf0d
+	tst-pam_motd.sh tst-pam_motd1.sh tst-pam_motd2.sh \
b1cf0d
+	tst-pam_motd3.sh tst-pam_motd1.pamd \
b1cf0d
+	tst-pam_motd2.pamd tst-pam_motd3.pamd
b1cf0d
 
b1cf0d
 XTESTS = tst-pam_dispatch1 tst-pam_dispatch2 tst-pam_dispatch3 \
b1cf0d
 	tst-pam_dispatch4 tst-pam_dispatch5 \
b1cf0d
@@ -41,7 +44,7 @@ XTESTS = tst-pam_dispatch1 tst-pam_dispa
b1cf0d
 	tst-pam_access1 tst-pam_access2 tst-pam_access3 \
b1cf0d
 	tst-pam_access4 tst-pam_limits1 tst-pam_succeed_if1 \
b1cf0d
 	tst-pam_group1 tst-pam_authfail tst-pam_authsucceed \
b1cf0d
-	tst-pam_pwhistory1 tst-pam_time1
b1cf0d
+	tst-pam_pwhistory1 tst-pam_time1 tst-pam_motd
b1cf0d
 
b1cf0d
 NOSRCTESTS = tst-pam_substack1 tst-pam_substack2 tst-pam_substack3 \
b1cf0d
 	tst-pam_substack4 tst-pam_substack5 tst-pam_assemble_line1
b1cf0d
diff -up Linux-PAM-1.3.1/xtests/tst-pam_motd1.pamd.pam_motd-support-multiple-motd-paths1 Linux-PAM-1.3.1/xtests/tst-pam_motd1.pamd
b1cf0d
--- Linux-PAM-1.3.1/xtests/tst-pam_motd1.pamd.pam_motd-support-multiple-motd-paths1	2022-04-25 12:32:36.947663225 +0200
b1cf0d
+++ Linux-PAM-1.3.1/xtests/tst-pam_motd1.pamd	2022-04-25 12:32:36.947663225 +0200
b1cf0d
@@ -0,0 +1,3 @@
b1cf0d
+#%PAM-1.0
b1cf0d
+session    required    pam_permit.so
b1cf0d
+session    optional    pam_motd.so motd=tst-pam_motd1.d/etc/motd motd_dir=tst-pam_motd1.d/etc/motd.d
b1cf0d
diff -up Linux-PAM-1.3.1/xtests/tst-pam_motd1.sh.pam_motd-support-multiple-motd-paths1 Linux-PAM-1.3.1/xtests/tst-pam_motd1.sh
b1cf0d
--- Linux-PAM-1.3.1/xtests/tst-pam_motd1.sh.pam_motd-support-multiple-motd-paths1	2022-04-25 12:32:36.947663225 +0200
b1cf0d
+++ Linux-PAM-1.3.1/xtests/tst-pam_motd1.sh	2022-04-25 12:32:36.947663225 +0200
b1cf0d
@@ -0,0 +1,36 @@
b1cf0d
+#!/bin/bash
b1cf0d
+
b1cf0d
+TST_DIR="tst-pam_motd1.d"
b1cf0d
+
b1cf0d
+function tst_cleanup() {
b1cf0d
+    rm -rf "${TST_DIR}"
b1cf0d
+    rm -f tst-pam_motd1.out
b1cf0d
+}
b1cf0d
+
b1cf0d
+mkdir -p ${TST_DIR}
b1cf0d
+mkdir -p ${TST_DIR}/etc/motd.d
b1cf0d
+
b1cf0d
+# Verify the case of single motd and motd.d directory works
b1cf0d
+echo "motd: /etc/motd" > ${TST_DIR}/etc/motd
b1cf0d
+echo "motd: /etc/motd.d/test" > ${TST_DIR}/etc/motd.d/test
b1cf0d
+
b1cf0d
+./tst-pam_motd tst-pam_motd1 > tst-pam_motd1.out
b1cf0d
+
b1cf0d
+RET=$?
b1cf0d
+
b1cf0d
+motd_to_show_output=$(cat tst-pam_motd1.out | grep "motd: /etc/motd")
b1cf0d
+if [ -z "${motd_to_show_output}" ];
b1cf0d
+then
b1cf0d
+    tst_cleanup
b1cf0d
+    exit 1
b1cf0d
+fi
b1cf0d
+
b1cf0d
+motd_dir_to_show_output=$(cat tst-pam_motd1.out | grep "motd: /etc/motd.d/test")
b1cf0d
+if [ -z "${motd_dir_to_show_output}" ];
b1cf0d
+then
b1cf0d
+    tst_cleanup
b1cf0d
+    exit 1
b1cf0d
+fi
b1cf0d
+
b1cf0d
+tst_cleanup
b1cf0d
+exit $RET
b1cf0d
diff -up Linux-PAM-1.3.1/xtests/tst-pam_motd2.pamd.pam_motd-support-multiple-motd-paths1 Linux-PAM-1.3.1/xtests/tst-pam_motd2.pamd
b1cf0d
--- Linux-PAM-1.3.1/xtests/tst-pam_motd2.pamd.pam_motd-support-multiple-motd-paths1	2022-04-25 12:32:36.947663225 +0200
b1cf0d
+++ Linux-PAM-1.3.1/xtests/tst-pam_motd2.pamd	2022-04-25 12:32:36.947663225 +0200
b1cf0d
@@ -0,0 +1,3 @@
b1cf0d
+#%PAM-1.0
b1cf0d
+session    required    pam_permit.so
b1cf0d
+session optional    pam_motd.so    motd=tst-pam_motd2.d/etc/motd:tst-pam_motd2.d/run/motd:tst-pam_motd2.d/usr/lib/motd motd_dir=tst-pam_motd2.d/etc/motd.d:tst-pam_motd2.d/run/motd.d:tst-pam_motd2.d/usr/lib/motd.d
b1cf0d
diff -up Linux-PAM-1.3.1/xtests/tst-pam_motd2.sh.pam_motd-support-multiple-motd-paths1 Linux-PAM-1.3.1/xtests/tst-pam_motd2.sh
b1cf0d
--- Linux-PAM-1.3.1/xtests/tst-pam_motd2.sh.pam_motd-support-multiple-motd-paths1	2022-04-25 12:32:36.947663225 +0200
b1cf0d
+++ Linux-PAM-1.3.1/xtests/tst-pam_motd2.sh	2022-04-25 12:32:36.947663225 +0200
b1cf0d
@@ -0,0 +1,53 @@
b1cf0d
+#!/bin/bash
b1cf0d
+
b1cf0d
+TST_DIR="tst-pam_motd2.d"
b1cf0d
+
b1cf0d
+function tst_cleanup() {
b1cf0d
+    rm -rf "${TST_DIR}"
b1cf0d
+    rm -f tst-pam_motd2.out
b1cf0d
+}
b1cf0d
+
b1cf0d
+mkdir -p ${TST_DIR}
b1cf0d
+mkdir -p ${TST_DIR}/etc/motd.d
b1cf0d
+mkdir -p ${TST_DIR}/run/motd.d
b1cf0d
+mkdir -p ${TST_DIR}/usr/lib/motd.d
b1cf0d
+
b1cf0d
+echo "motd: /etc/motd" > ${TST_DIR}/etc/motd
b1cf0d
+echo "motd: /run/motd" > ${TST_DIR}/run/motd
b1cf0d
+echo "motd: /usr/lib/motd" > ${TST_DIR}/usr/lib/motd
b1cf0d
+
b1cf0d
+# Drop a motd file in test directories such that every overriding
b1cf0d
+# condition (for 3 directories in this case) will be seen.
b1cf0d
+echo "motd: e0r0u1 in usr/lib - will show" > ${TST_DIR}/usr/lib/motd.d/e0r0u1.motd
b1cf0d
+echo "motd: e0r1u0 in run - will show" > ${TST_DIR}/run/motd.d/e0r1u0.motd
b1cf0d
+echo "motd: e0r1u1 in usr/lib - not show" > ${TST_DIR}/usr/lib/motd.d/e0r1u1.motd
b1cf0d
+echo "motd: e0r1u1 in run - will show" > ${TST_DIR}/run/motd.d/e0r1u1.motd
b1cf0d
+echo "motd: e1r0u0 in etc - will show" > ${TST_DIR}/etc/motd.d/e1r0u0.motd
b1cf0d
+echo "motd: e1r0u1 in usr/lib - not show" > ${TST_DIR}/usr/lib/motd.d/e1r0u1.motd
b1cf0d
+echo "motd: e1r0u1 in etc - will show" > ${TST_DIR}/etc/motd.d/e1r0u1.motd
b1cf0d
+echo "motd: e1r1u0 in run - not show" > ${TST_DIR}/run/motd.d/e1r1u0.motd
b1cf0d
+echo "motd: e1r1u0 in etc - will show" > ${TST_DIR}/etc/motd.d/e1r1u0.motd
b1cf0d
+echo "motd: e1r1u1 in usr/lib - not show" > ${TST_DIR}/usr/lib/motd.d/e1r1u1.motd
b1cf0d
+echo "motd: e1r1u1 in run - not show" > ${TST_DIR}/run/motd.d/e1r1u1.motd
b1cf0d
+echo "motd: e1r1u1 in etc - will show" > ${TST_DIR}/etc/motd.d/e1r1u1.motd
b1cf0d
+
b1cf0d
+./tst-pam_motd tst-pam_motd2 > tst-pam_motd2.out
b1cf0d
+
b1cf0d
+RET=$?
b1cf0d
+
b1cf0d
+motd_to_show_output=$(cat tst-pam_motd2.out | grep "motd: /etc/motd")
b1cf0d
+if [ -z "${motd_to_show_output}" ];
b1cf0d
+then
b1cf0d
+    tst_cleanup
b1cf0d
+    exit 1
b1cf0d
+fi
b1cf0d
+
b1cf0d
+motd_dir_not_show_output=$(cat tst-pam_motd2.out | grep "not show")
b1cf0d
+if [ -n "${motd_dir_not_show_output}" ];
b1cf0d
+then
b1cf0d
+    tst_cleanup
b1cf0d
+    exit 1
b1cf0d
+fi
b1cf0d
+
b1cf0d
+tst_cleanup
b1cf0d
+exit $RET
b1cf0d
diff -up Linux-PAM-1.3.1/xtests/tst-pam_motd3.pamd.pam_motd-support-multiple-motd-paths1 Linux-PAM-1.3.1/xtests/tst-pam_motd3.pamd
b1cf0d
--- Linux-PAM-1.3.1/xtests/tst-pam_motd3.pamd.pam_motd-support-multiple-motd-paths1	2022-04-25 12:32:36.947663225 +0200
b1cf0d
+++ Linux-PAM-1.3.1/xtests/tst-pam_motd3.pamd	2022-04-25 12:32:36.947663225 +0200
b1cf0d
@@ -0,0 +1,3 @@
b1cf0d
+#%PAM-1.0
b1cf0d
+session    required    pam_permit.so
b1cf0d
+session optional    pam_motd.so    motd=tst-pam_motd3.d/etc/motd:tst-pam_motd3.d/run/motd:tst-pam_motd3.d/usr/lib/motd motd_dir=tst-pam_motd3.d/etc/motd.d:tst-pam_motd3.d/run/motd.d:tst-pam_motd3.d/usr/lib/motd.d
b1cf0d
diff -up Linux-PAM-1.3.1/xtests/tst-pam_motd3.sh.pam_motd-support-multiple-motd-paths1 Linux-PAM-1.3.1/xtests/tst-pam_motd3.sh
b1cf0d
--- Linux-PAM-1.3.1/xtests/tst-pam_motd3.sh.pam_motd-support-multiple-motd-paths1	2022-04-25 12:32:36.947663225 +0200
b1cf0d
+++ Linux-PAM-1.3.1/xtests/tst-pam_motd3.sh	2022-04-25 12:32:36.947663225 +0200
b1cf0d
@@ -0,0 +1,53 @@
b1cf0d
+#!/bin/bash
b1cf0d
+
b1cf0d
+TST_DIR="tst-pam_motd3.d"
b1cf0d
+
b1cf0d
+function tst_cleanup() {
b1cf0d
+    rm -rf "${TST_DIR}"
b1cf0d
+    rm -f tst-pam_motd3.out
b1cf0d
+}
b1cf0d
+
b1cf0d
+mkdir -p ${TST_DIR}
b1cf0d
+mkdir -p ${TST_DIR}/etc/motd.d
b1cf0d
+mkdir -p ${TST_DIR}/run/motd.d
b1cf0d
+mkdir -p ${TST_DIR}/usr/lib/motd.d
b1cf0d
+
b1cf0d
+# Verify motd is still displayed when not overridden
b1cf0d
+echo "motd: test-show in run - show" > ${TST_DIR}/run/motd.d/test-show.motd
b1cf0d
+
b1cf0d
+# Test overridden by a symlink to a file that isn't /dev/null; symlink target should show
b1cf0d
+echo "motd: hidden-by-symlink in usr/lib - not show" > ${TST_DIR}/usr/lib/motd.d/hidden-by-symlink.motd
b1cf0d
+echo "motd: test-from-symlink - show" > ${TST_DIR}/test-from-symlink.motd
b1cf0d
+ln -sr ${TST_DIR}/test-from-symlink.motd ${TST_DIR}/run/motd.d/hidden-by-symlink.motd
b1cf0d
+
b1cf0d
+# Test hidden by a null symlink
b1cf0d
+echo "motd: hidden-by-null-symlink in run - not show" > ${TST_DIR}/run/motd.d/hidden-by-null-symlink.motd
b1cf0d
+ln -s /dev/null ${TST_DIR}/etc/motd.d/hidden-by-null-symlink.motd
b1cf0d
+
b1cf0d
+./tst-pam_motd tst-pam_motd3 > tst-pam_motd3.out
b1cf0d
+
b1cf0d
+RET=$?
b1cf0d
+
b1cf0d
+motd_dir_not_show_output=$(cat tst-pam_motd3.out | grep "not show")
b1cf0d
+if [ -n "${motd_dir_not_show_output}" ];
b1cf0d
+then
b1cf0d
+    tst_cleanup
b1cf0d
+    exit 1
b1cf0d
+fi
b1cf0d
+
b1cf0d
+motd_test_show_output=$(cat tst-pam_motd3.out | grep "test-show.*- show")
b1cf0d
+if [ -z "${motd_test_show_output}" ];
b1cf0d
+then
b1cf0d
+    tst_cleanup
b1cf0d
+    exit 1
b1cf0d
+fi
b1cf0d
+
b1cf0d
+motd_general_symlink_show_output=$(cat tst-pam_motd3.out | grep "test-from-symlink.*- show")
b1cf0d
+if [ -z "${motd_general_symlink_show_output}" ];
b1cf0d
+then
b1cf0d
+    tst_cleanup
b1cf0d
+    exit 1
b1cf0d
+fi
b1cf0d
+
b1cf0d
+tst_cleanup
b1cf0d
+exit $RET
b1cf0d
diff -up Linux-PAM-1.3.1/xtests/tst-pam_motd.c.pam_motd-support-multiple-motd-paths1 Linux-PAM-1.3.1/xtests/tst-pam_motd.c
b1cf0d
--- Linux-PAM-1.3.1/xtests/tst-pam_motd.c.pam_motd-support-multiple-motd-paths1	2022-04-25 12:32:36.947663225 +0200
b1cf0d
+++ Linux-PAM-1.3.1/xtests/tst-pam_motd.c	2022-04-25 12:32:36.947663225 +0200
b1cf0d
@@ -0,0 +1,69 @@
b1cf0d
+/*
b1cf0d
+ * Redistribution and use in source and binary forms, with or without
b1cf0d
+ * modification, are permitted provided that the following conditions
b1cf0d
+ * are met:
b1cf0d
+ * 1. Redistributions of source code must retain the above copyright
b1cf0d
+ *    notice, and the entire permission notice in its entirety,
b1cf0d
+ *    including the disclaimer of warranties.
b1cf0d
+ * 2. Redistributions in binary form must reproduce the above copyright
b1cf0d
+ *    notice, this list of conditions and the following disclaimer in the
b1cf0d
+ *    documentation and/or other materials provided with the distribution.
b1cf0d
+ * 3. The name of the author may not be used to endorse or promote
b1cf0d
+ *    products derived from this software without specific prior
b1cf0d
+ *    written permission.
b1cf0d
+ *
b1cf0d
+ * ALTERNATIVELY, this product may be distributed under the terms of
b1cf0d
+ * the GNU Public License, in which case the provisions of the GPL are
b1cf0d
+ * required INSTEAD OF the above restrictions.  (This clause is
b1cf0d
+ * necessary due to a potential bad interaction between the GPL and
b1cf0d
+ * the restrictions contained in a BSD-style copyright.)
b1cf0d
+ *
b1cf0d
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
b1cf0d
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
b1cf0d
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
b1cf0d
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
b1cf0d
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
b1cf0d
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
b1cf0d
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
b1cf0d
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
b1cf0d
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
b1cf0d
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
b1cf0d
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
b1cf0d
+ */
b1cf0d
+
b1cf0d
+#ifdef HAVE_CONFIG_H
b1cf0d
+#include <config.h>
b1cf0d
+#endif
b1cf0d
+
b1cf0d
+#include <stdio.h>
b1cf0d
+#include <stdlib.h>
b1cf0d
+#include <security/pam_appl.h>
b1cf0d
+#include <security/pam_misc.h>
b1cf0d
+
b1cf0d
+static struct pam_conv conv = {
b1cf0d
+    misc_conv,
b1cf0d
+    NULL
b1cf0d
+};
b1cf0d
+
b1cf0d
+int main(int argc, char *argv[])
b1cf0d
+{
b1cf0d
+    pam_handle_t *pamh=NULL;
b1cf0d
+    char *tst_arg = NULL;
b1cf0d
+    int retval;
b1cf0d
+
b1cf0d
+    if (argc > 1)
b1cf0d
+	tst_arg = argv[1];
b1cf0d
+
b1cf0d
+    retval = pam_start(tst_arg, NULL, &conv, &pamh);
b1cf0d
+
b1cf0d
+    retval = pam_open_session(pamh, 0);
b1cf0d
+
b1cf0d
+    retval = pam_close_session(pamh, 0);
b1cf0d
+
b1cf0d
+    if (pam_end(pamh,retval) != PAM_SUCCESS) {     /* close Linux-PAM */
b1cf0d
+	pamh = NULL;
b1cf0d
+	exit(1);
b1cf0d
+    }
b1cf0d
+
b1cf0d
+    return ( retval == PAM_SUCCESS ? 0:1 );       /* indicate success */
b1cf0d
+}
b1cf0d
diff -up Linux-PAM-1.3.1/xtests/tst-pam_motd.sh.pam_motd-support-multiple-motd-paths1 Linux-PAM-1.3.1/xtests/tst-pam_motd.sh
b1cf0d
--- Linux-PAM-1.3.1/xtests/tst-pam_motd.sh.pam_motd-support-multiple-motd-paths1	2022-04-25 12:32:36.947663225 +0200
b1cf0d
+++ Linux-PAM-1.3.1/xtests/tst-pam_motd.sh	2022-04-25 12:32:36.947663225 +0200
b1cf0d
@@ -0,0 +1,7 @@
b1cf0d
+#!/bin/bash
b1cf0d
+
b1cf0d
+set -e
b1cf0d
+
b1cf0d
+./tst-pam_motd1.sh
b1cf0d
+./tst-pam_motd2.sh
b1cf0d
+./tst-pam_motd3.sh