diff options
Diffstat (limited to 'modules/pam_motd/pam_motd.c')
-rw-r--r-- | modules/pam_motd/pam_motd.c | 146 |
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 */ |