Patrick Williams | 8e7b46e | 2023-05-01 14:19:06 -0500 | [diff] [blame^] | 1 | From 42404548721c653317c911c83d885e2fc7fbca70 Mon Sep 17 00:00:00 2001 |
| 2 | From: Per Jessen <per@jessen.ch> |
| 3 | Date: Fri, 22 Apr 2022 18:15:36 +0200 |
| 4 | Subject: [PATCH] pam_motd: do not rely on all filesystems providing a filetype |
| 5 | |
| 6 | When using scandir() to look for MOTD files to display, we wrongly |
| 7 | relied on all filesystems providing a filetype. This is a fix to divert |
| 8 | to lstat() when we have no filetype. To maintain MT safety, it isn't |
| 9 | possible to use lstat() in the scandir() filter function, so all of the |
| 10 | filtering has been moved to an additional loop after scanning all the |
| 11 | motd dirs. |
| 12 | Also, remove superfluous alphasort from scandir(), we are doing |
| 13 | a qsort() later. |
| 14 | |
| 15 | Resolves: https://github.com/linux-pam/linux-pam/issues/455 |
| 16 | |
| 17 | Upstream-Status: Backport [https://github.com/linux-pam/linux-pam/commit/42404548721c653317c911c83d885e2fc7fbca70] |
| 18 | |
| 19 | Signed-off-by: Per Jessen <per@jessen.ch> |
| 20 | Signed-off-by: Zhixiong Chi <zhixiong.chi@windriver.com> |
| 21 | --- |
| 22 | modules/pam_motd/pam_motd.c | 49 ++++++++++++++++++++++++++++++------- |
| 23 | 1 file changed, 40 insertions(+), 9 deletions(-) |
| 24 | |
| 25 | diff --git a/modules/pam_motd/pam_motd.c b/modules/pam_motd/pam_motd.c |
| 26 | index 6ac8cba2..5ca486e4 100644 |
| 27 | --- a/modules/pam_motd/pam_motd.c |
| 28 | +++ b/modules/pam_motd/pam_motd.c |
| 29 | @@ -166,11 +166,6 @@ static int compare_strings(const void *a, const void *b) |
| 30 | } |
| 31 | } |
| 32 | |
| 33 | -static int filter_dirents(const struct dirent *d) |
| 34 | -{ |
| 35 | - return (d->d_type == DT_REG || d->d_type == DT_LNK); |
| 36 | -} |
| 37 | - |
| 38 | static void try_to_display_directories_with_overrides(pam_handle_t *pamh, |
| 39 | char **motd_dir_path_split, unsigned int num_motd_dirs, int report_missing) |
| 40 | { |
| 41 | @@ -199,8 +194,7 @@ static void try_to_display_directories_with_overrides(pam_handle_t *pamh, |
| 42 | |
| 43 | for (i = 0; i < num_motd_dirs; i++) { |
| 44 | int rv; |
| 45 | - rv = scandir(motd_dir_path_split[i], &(dirscans[i]), |
| 46 | - filter_dirents, alphasort); |
| 47 | + rv = scandir(motd_dir_path_split[i], &(dirscans[i]), NULL, NULL); |
| 48 | if (rv < 0) { |
| 49 | if (errno != ENOENT || report_missing) { |
| 50 | pam_syslog(pamh, LOG_ERR, "error scanning directory %s: %m", |
| 51 | @@ -215,6 +209,41 @@ static void try_to_display_directories_with_overrides(pam_handle_t *pamh, |
| 52 | if (dirscans_size_total == 0) |
| 53 | goto out; |
| 54 | |
| 55 | + /* filter out unwanted names, directories, and complement data with lstat() */ |
| 56 | + for (i = 0; i < num_motd_dirs; i++) { |
| 57 | + struct dirent **d = dirscans[i]; |
| 58 | + for (unsigned int j = 0; j < dirscans_sizes[i]; j++) { |
| 59 | + int rc; |
| 60 | + char *fullpath; |
| 61 | + struct stat s; |
| 62 | + |
| 63 | + switch(d[j]->d_type) { /* the filetype determines how to proceed */ |
| 64 | + case DT_REG: /* regular files and */ |
| 65 | + case DT_LNK: /* symlinks */ |
| 66 | + continue; /* are good. */ |
| 67 | + case DT_UNKNOWN: /* for file systems that do not provide */ |
| 68 | + /* a filetype, we use lstat() */ |
| 69 | + if (join_dir_strings(&fullpath, motd_dir_path_split[i], |
| 70 | + d[j]->d_name) <= 0) |
| 71 | + break; |
| 72 | + rc = lstat(fullpath, &s); |
| 73 | + _pam_drop(fullpath); /* free the memory alloc'ed by join_dir_strings */ |
| 74 | + if (rc != 0) /* if the lstat() somehow failed */ |
| 75 | + break; |
| 76 | + |
| 77 | + if (S_ISREG(s.st_mode) || /* regular files and */ |
| 78 | + S_ISLNK(s.st_mode)) continue; /* symlinks are good */ |
| 79 | + break; |
| 80 | + case DT_DIR: /* We don't want directories */ |
| 81 | + default: /* nor anything else */ |
| 82 | + break; |
| 83 | + } |
| 84 | + _pam_drop(d[j]); /* free memory */ |
| 85 | + d[j] = NULL; /* indicate this one was dropped */ |
| 86 | + dirscans_size_total--; |
| 87 | + } |
| 88 | + } |
| 89 | + |
| 90 | /* Allocate space for all file names found in the directories, including duplicates. */ |
| 91 | if ((dirnames_all = calloc(dirscans_size_total, sizeof(*dirnames_all))) == NULL) { |
| 92 | pam_syslog(pamh, LOG_CRIT, "failed to allocate dirname array"); |
| 93 | @@ -225,8 +254,10 @@ static void try_to_display_directories_with_overrides(pam_handle_t *pamh, |
| 94 | unsigned int j; |
| 95 | |
| 96 | for (j = 0; j < dirscans_sizes[i]; j++) { |
| 97 | - dirnames_all[i_dirnames] = dirscans[i][j]->d_name; |
| 98 | - i_dirnames++; |
| 99 | + if (NULL != dirscans[i][j]) { |
| 100 | + dirnames_all[i_dirnames] = dirscans[i][j]->d_name; |
| 101 | + i_dirnames++; |
| 102 | + } |
| 103 | } |
| 104 | } |
| 105 | |
| 106 | -- |
| 107 | 2.39.0 |
| 108 | |