aboutsummaryrefslogtreecommitdiff
path: root/modules/pam_motd/pam_motd.c
diff options
context:
space:
mode:
Diffstat (limited to 'modules/pam_motd/pam_motd.c')
-rw-r--r--modules/pam_motd/pam_motd.c146
1 files changed, 115 insertions, 31 deletions
diff --git a/modules/pam_motd/pam_motd.c b/modules/pam_motd/pam_motd.c
index 46f4fe61..5ca486e4 100644
--- a/modules/pam_motd/pam_motd.c
+++ b/modules/pam_motd/pam_motd.c
@@ -166,11 +166,6 @@ static int compare_strings(const void *a, const void *b)
}
}
-static int filter_dirents(const struct dirent *d)
-{
- return (d->d_type == DT_REG || d->d_type == DT_LNK);
-}
-
static void try_to_display_directories_with_overrides(pam_handle_t *pamh,
char **motd_dir_path_split, unsigned int num_motd_dirs, int report_missing)
{
@@ -199,8 +194,7 @@ static void try_to_display_directories_with_overrides(pam_handle_t *pamh,
for (i = 0; i < num_motd_dirs; i++) {
int rv;
- rv = scandir(motd_dir_path_split[i], &(dirscans[i]),
- filter_dirents, alphasort);
+ rv = scandir(motd_dir_path_split[i], &(dirscans[i]), NULL, NULL);
if (rv < 0) {
if (errno != ENOENT || report_missing) {
pam_syslog(pamh, LOG_ERR, "error scanning directory %s: %m",
@@ -215,6 +209,41 @@ static void try_to_display_directories_with_overrides(pam_handle_t *pamh,
if (dirscans_size_total == 0)
goto out;
+ /* filter out unwanted names, directories, and complement data with lstat() */
+ for (i = 0; i < num_motd_dirs; i++) {
+ struct dirent **d = dirscans[i];
+ for (unsigned int j = 0; j < dirscans_sizes[i]; j++) {
+ int rc;
+ char *fullpath;
+ struct stat s;
+
+ switch(d[j]->d_type) { /* the filetype determines how to proceed */
+ case DT_REG: /* regular files and */
+ case DT_LNK: /* symlinks */
+ continue; /* are good. */
+ case DT_UNKNOWN: /* for file systems that do not provide */
+ /* a filetype, we use lstat() */
+ if (join_dir_strings(&fullpath, motd_dir_path_split[i],
+ d[j]->d_name) <= 0)
+ break;
+ rc = lstat(fullpath, &s);
+ _pam_drop(fullpath); /* free the memory alloc'ed by join_dir_strings */
+ if (rc != 0) /* if the lstat() somehow failed */
+ break;
+
+ if (S_ISREG(s.st_mode) || /* regular files and */
+ S_ISLNK(s.st_mode)) continue; /* symlinks are good */
+ break;
+ case DT_DIR: /* We don't want directories */
+ default: /* nor anything else */
+ break;
+ }
+ _pam_drop(d[j]); /* free memory */
+ d[j] = NULL; /* indicate this one was dropped */
+ dirscans_size_total--;
+ }
+ }
+
/* Allocate space for all file names found in the directories, including duplicates. */
if ((dirnames_all = calloc(dirscans_size_total, sizeof(*dirnames_all))) == NULL) {
pam_syslog(pamh, LOG_CRIT, "failed to allocate dirname array");
@@ -225,8 +254,10 @@ static void try_to_display_directories_with_overrides(pam_handle_t *pamh,
unsigned int j;
for (j = 0; j < dirscans_sizes[i]; j++) {
- dirnames_all[i_dirnames] = dirscans[i][j]->d_name;
- i_dirnames++;
+ if (NULL != dirscans[i][j]) {
+ dirnames_all[i_dirnames] = dirscans[i][j]->d_name;
+ i_dirnames++;
+ }
}
}
@@ -282,6 +313,72 @@ static void try_to_display_directories_with_overrides(pam_handle_t *pamh,
_pam_drop(dirscans);
}
+static int drop_privileges(pam_handle_t *pamh, struct pam_modutil_privs *privs)
+{
+ struct passwd *pw;
+ const char *username;
+ int retval;
+
+ retval = pam_get_user(pamh, &username, NULL);
+
+ if (retval == PAM_SUCCESS) {
+ pw = pam_modutil_getpwnam (pamh, username);
+ } else {
+ return PAM_SESSION_ERR;
+ }
+
+ if (pw == NULL || pam_modutil_drop_priv(pamh, privs, pw)) {
+ return PAM_SESSION_ERR;
+ }
+
+ return PAM_SUCCESS;
+}
+
+static int try_to_display(pam_handle_t *pamh, char **motd_path_split,
+ unsigned int num_motd_paths,
+ char **motd_dir_path_split,
+ unsigned int num_motd_dir_paths, int report_missing)
+{
+ PAM_MODUTIL_DEF_PRIVS(privs);
+
+ if (drop_privileges(pamh, &privs) != PAM_SUCCESS) {
+ pam_syslog(pamh, LOG_ERR, "Unable to drop privileges");
+ return PAM_SESSION_ERR;
+ }
+
+ if (motd_path_split != NULL) {
+ unsigned int i;
+
+ for (i = 0; i < num_motd_paths; i++) {
+ int fd = open(motd_path_split[i], O_RDONLY, 0);
+
+ if (fd >= 0) {
+ try_to_display_fd(pamh, fd);
+ close(fd);
+
+ /* We found and displayed a file,
+ * move onto next filename.
+ */
+ break;
+ }
+ }
+ }
+
+ if (motd_dir_path_split != NULL) {
+ try_to_display_directories_with_overrides(pamh,
+ motd_dir_path_split,
+ num_motd_dir_paths,
+ report_missing);
+ }
+
+ if (pam_modutil_regain_priv(pamh, &privs)) {
+ pam_syslog(pamh, LOG_ERR, "Unable to regain privileges");
+ return PAM_SESSION_ERR;
+ }
+
+ return PAM_SUCCESS;
+}
+
int pam_sm_open_session(pam_handle_t *pamh, int flags,
int argc, const char **argv)
{
@@ -358,25 +455,9 @@ int pam_sm_open_session(pam_handle_t *pamh, int flags,
}
}
- if (motd_path_split != NULL) {
- unsigned int i;
-
- for (i = 0; i < num_motd_paths; i++) {
- int fd = open(motd_path_split[i], O_RDONLY, 0);
-
- if (fd >= 0) {
- try_to_display_fd(pamh, fd);
- close(fd);
-
- /* We found and displayed a file, move onto next filename. */
- break;
- }
- }
- }
-
- if (motd_dir_path_split != NULL)
- try_to_display_directories_with_overrides(pamh, motd_dir_path_split,
- num_motd_dir_paths, report_missing);
+ retval = try_to_display(pamh, motd_path_split, num_motd_paths,
+ motd_dir_path_split, num_motd_dir_paths,
+ report_missing);
out:
_pam_drop(motd_path_copy);
@@ -384,9 +465,12 @@ int pam_sm_open_session(pam_handle_t *pamh, int flags,
_pam_drop(motd_dir_path_copy);
_pam_drop(motd_dir_path_split);
- retval = pam_putenv(pamh, "MOTD_SHOWN=pam");
-
- return retval == PAM_SUCCESS ? PAM_IGNORE : retval;
+ if (retval == PAM_SUCCESS) {
+ retval = pam_putenv(pamh, "MOTD_SHOWN=pam");
+ return retval == PAM_SUCCESS ? PAM_IGNORE : retval;
+ } else {
+ return retval;
+ }
}
/* end of module definition */