123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445 |
- /*
- * pam_motd module
- *
- * Modified for pam_motd by Ben Collins <bcollins@debian.org>
- * Written by Michael K. Johnson <johnsonm@redhat.com> 1996/10/24
- */
- #include "config.h"
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <dirent.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <pwd.h>
- #include <syslog.h>
- #include <errno.h>
- #include <security/_pam_macros.h>
- #include <security/pam_ext.h>
- #include <security/pam_modules.h>
- #include <security/pam_modutil.h>
- #include "pam_inline.h"
- #define DEFAULT_MOTD "/etc/motd:/run/motd:/usr/lib/motd"
- #define DEFAULT_MOTD_D "/etc/motd.d:/run/motd.d:/usr/lib/motd.d"
- /* --- session management functions (only) --- */
- int
- pam_sm_close_session (pam_handle_t *pamh UNUSED, int flags UNUSED,
- int argc UNUSED, const char **argv UNUSED)
- {
- return PAM_IGNORE;
- }
- static const char default_motd[] = DEFAULT_MOTD;
- static const char default_motd_dir[] = DEFAULT_MOTD_D;
- static void try_to_display_fd(pam_handle_t *pamh, int fd)
- {
- struct stat st;
- char *mtmp = NULL;
- /* fill in message buffer with contents of motd */
- if ((fstat(fd, &st) < 0) || !st.st_size || st.st_size > 0x10000)
- return;
- if (!(mtmp = malloc(st.st_size+1)))
- return;
- if (pam_modutil_read(fd, mtmp, st.st_size) == st.st_size) {
- if (mtmp[st.st_size-1] == '\n')
- mtmp[st.st_size-1] = '\0';
- else
- mtmp[st.st_size] = '\0';
- pam_info (pamh, "%s", mtmp);
- }
- _pam_drop(mtmp);
- }
- /*
- * Split a DELIM-separated string ARG into an array.
- * Outputs a newly allocated array of strings OUT_ARG_SPLIT
- * and the number of strings OUT_NUM_STRS.
- * Returns 0 in case of error, 1 in case of success.
- */
- static int pam_split_string(const pam_handle_t *pamh, char *arg, char delim,
- char ***out_arg_split, unsigned int *out_num_strs)
- {
- char *arg_extracted = NULL;
- const char *arg_ptr = arg;
- char **arg_split = NULL;
- char delim_str[2];
- unsigned int i = 0;
- unsigned int num_strs = 0;
- int retval = 0;
- delim_str[0] = delim;
- delim_str[1] = '\0';
- if (arg == NULL) {
- goto out;
- }
- while (arg_ptr != NULL) {
- num_strs++;
- arg_ptr = strchr(arg_ptr + sizeof(const char), delim);
- }
- arg_split = calloc(num_strs, sizeof(*arg_split));
- if (arg_split == NULL) {
- pam_syslog(pamh, LOG_CRIT, "failed to allocate string array");
- goto out;
- }
- arg_extracted = strtok_r(arg, delim_str, &arg);
- while (arg_extracted != NULL && i < num_strs) {
- arg_split[i++] = arg_extracted;
- arg_extracted = strtok_r(NULL, delim_str, &arg);
- }
- retval = 1;
- out:
- *out_num_strs = num_strs;
- *out_arg_split = arg_split;
- return retval;
- }
- /* Join A_STR and B_STR, inserting a "/" between them if one is not already trailing
- * in A_STR or beginning B_STR. A pointer to a newly allocated string holding the
- * joined string is returned in STRP_OUT.
- * Returns -1 in case of error, or the number of bytes in the joined string in
- * case of success. */
- static int join_dir_strings(char **strp_out, const char *a_str, const char *b_str)
- {
- int has_sep = 0;
- int retval = -1;
- char *join_strp = NULL;
- if (strp_out == NULL || a_str == NULL || b_str == NULL) {
- goto out;
- }
- if (strlen(a_str) == 0) {
- goto out;
- }
- has_sep = (a_str[strlen(a_str) - 1] == '/') || (b_str[0] == '/');
- retval = asprintf(&join_strp, "%s%s%s", a_str,
- (has_sep == 1) ? "" : "/", b_str);
- if (retval < 0) {
- goto out;
- }
- *strp_out = join_strp;
- out:
- return retval;
- }
- static int compare_strings(const void *a, const void *b)
- {
- const char *a_str = *(const char * const *)a;
- const char *b_str = *(const char * const *)b;
- if (a_str == NULL && b_str == NULL) {
- return 0;
- }
- else if (a_str == NULL) {
- return -1;
- }
- else if (b_str == NULL) {
- return 1;
- }
- else {
- return strcmp(a_str, b_str);
- }
- }
- 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)
- {
- struct dirent ***dirscans = NULL;
- unsigned int *dirscans_sizes = NULL;
- unsigned int dirscans_size_total = 0;
- char **dirnames_all = NULL;
- unsigned int i;
- int i_dirnames = 0;
- if (pamh == NULL || motd_dir_path_split == NULL) {
- goto out;
- }
- if (num_motd_dirs < 1) {
- goto out;
- }
- if ((dirscans = calloc(num_motd_dirs, sizeof(*dirscans))) == NULL) {
- pam_syslog(pamh, LOG_CRIT, "failed to allocate dirent arrays");
- goto out;
- }
- if ((dirscans_sizes = calloc(num_motd_dirs, sizeof(*dirscans_sizes))) == NULL) {
- pam_syslog(pamh, LOG_CRIT, "failed to allocate dirent array sizes");
- goto out;
- }
- for (i = 0; i < num_motd_dirs; i++) {
- int rv;
- rv = scandir(motd_dir_path_split[i], &(dirscans[i]),
- filter_dirents, alphasort);
- if (rv < 0) {
- if (errno != ENOENT || report_missing) {
- pam_syslog(pamh, LOG_ERR, "error scanning directory %s: %m",
- motd_dir_path_split[i]);
- }
- } else {
- dirscans_sizes[i] = rv;
- }
- dirscans_size_total += dirscans_sizes[i];
- }
- if (dirscans_size_total == 0)
- goto out;
- /* 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");
- goto out;
- }
- for (i = 0; i < num_motd_dirs; i++) {
- unsigned int j;
- for (j = 0; j < dirscans_sizes[i]; j++) {
- dirnames_all[i_dirnames] = dirscans[i][j]->d_name;
- i_dirnames++;
- }
- }
- qsort(dirnames_all, dirscans_size_total,
- sizeof(const char *), compare_strings);
- for (i = 0; i < dirscans_size_total; i++) {
- unsigned int j;
- if (dirnames_all[i] == NULL) {
- continue;
- }
- /* Skip duplicate file names. */
- if (i > 0 && strcmp(dirnames_all[i], dirnames_all[i - 1]) == 0) {
- continue;
- }
- for (j = 0; j < num_motd_dirs; j++) {
- char *abs_path = NULL;
- int fd;
- if (join_dir_strings(&abs_path, motd_dir_path_split[j],
- dirnames_all[i]) < 0 || abs_path == NULL) {
- continue;
- }
- fd = open(abs_path, O_RDONLY, 0);
- _pam_drop(abs_path);
- if (fd >= 0) {
- try_to_display_fd(pamh, fd);
- close(fd);
- /* We displayed a file, skip to the next file name. */
- break;
- }
- }
- }
- out:
- _pam_drop(dirnames_all);
- if (dirscans_sizes != NULL) {
- for (i = 0; i < num_motd_dirs; i++) {
- unsigned int j;
- for (j = 0; j < dirscans_sizes[i]; j++)
- _pam_drop(dirscans[i][j]);
- _pam_drop(dirscans[i]);
- }
- _pam_drop(dirscans_sizes);
- }
- _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)
- {
- int retval = PAM_IGNORE;
- const char *motd_path = NULL;
- char *motd_path_copy = NULL;
- unsigned int num_motd_paths = 0;
- char **motd_path_split = NULL;
- const char *motd_dir_path = NULL;
- char *motd_dir_path_copy = NULL;
- unsigned int num_motd_dir_paths = 0;
- char **motd_dir_path_split = NULL;
- int report_missing;
- if (flags & PAM_SILENT) {
- return retval;
- }
- for (; argc-- > 0; ++argv) {
- const char *str;
- if ((str = pam_str_skip_prefix(*argv, "motd=")) != NULL) {
- motd_path = str;
- if (*motd_path != '\0') {
- D(("set motd path: %s", motd_path));
- } else {
- motd_path = NULL;
- pam_syslog(pamh, LOG_ERR,
- "motd= specification missing argument - ignored");
- }
- }
- else if ((str = pam_str_skip_prefix(*argv, "motd_dir=")) != NULL) {
- motd_dir_path = str;
- if (*motd_dir_path != '\0') {
- D(("set motd.d path: %s", motd_dir_path));
- } else {
- motd_dir_path = NULL;
- pam_syslog(pamh, LOG_ERR,
- "motd_dir= specification missing argument - ignored");
- }
- }
- else
- pam_syslog(pamh, LOG_ERR, "unknown option: %s", *argv);
- }
- if (motd_path == NULL && motd_dir_path == NULL) {
- motd_path = default_motd;
- motd_dir_path = default_motd_dir;
- report_missing = 0;
- } else {
- report_missing = 1;
- }
- if (motd_path != NULL) {
- motd_path_copy = strdup(motd_path);
- }
- if (motd_path_copy != NULL) {
- if (pam_split_string(pamh, motd_path_copy, ':',
- &motd_path_split, &num_motd_paths) == 0) {
- goto out;
- }
- }
- if (motd_dir_path != NULL) {
- motd_dir_path_copy = strdup(motd_dir_path);
- }
- if (motd_dir_path_copy != NULL) {
- if (pam_split_string(pamh, motd_dir_path_copy, ':',
- &motd_dir_path_split, &num_motd_dir_paths) == 0) {
- goto out;
- }
- }
- 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);
- _pam_drop(motd_path_split);
- _pam_drop(motd_dir_path_copy);
- _pam_drop(motd_dir_path_split);
- 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 */
|