Skip to content

Commit

Permalink
pam_motd: add support for a motd.d directory
Browse files Browse the repository at this point in the history
Add a new feature to pam_motd to allow packages to install their own
message files in a "motd.d" directory, to be displayed after the primary
motd.

Add an option motd_d= to specify the location of this directory.

Modify the defaults, in the case where no options are given, to display
both /etc/motd and /etc/motd.d.

Fixes linux-pam#47

 * modules/pam_motd/pam_motd.c: add support for motd.d
 * modules/pam_motd/pam_motd.8.xml: update the manpage
  • Loading branch information
allisonkarlitskaya committed May 4, 2018
1 parent 042a387 commit acd50bf
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 28 deletions.
36 changes: 35 additions & 1 deletion modules/pam_motd/pam_motd.8.xml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,24 @@
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<option>motd_d=<replaceable>/path/dirname.d</replaceable></option>
</term>
<listitem>
<para>
The <filename>/path/dirname.d</filename> directory is scanned
and each file contained inside of it is displayed.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
When no options are given, the default is to display both
<filename>/etc/motd</filename> and the contents of
<filename>/etc/motd.d</filename>. Specifying either option (or both)
will disable this default behavior.
</para>
</refsect1>

<refsect1 id="pam_motd-types">
Expand Down Expand Up @@ -81,7 +98,20 @@
<para>
The suggested usage for <filename>/etc/pam.d/login</filename> is:
<programlisting>
session optional pam_motd.so motd=/etc/motd
session optional pam_motd.so
</programlisting>
</para>
<para>
To use a <filename>motd</filename> file from a different location:
<programlisting>
session optional pam_motd.so motd=/elsewhere/motd
</programlisting>
</para>
<para>
To use a <filename>motd</filename> file from elsewhere, along with a
corresponding <filename>.d</filename> directory:
<programlisting>
session optional pam_motd.so motd=/elsewhere/motd motd_d=/elsewhere/motd.d
</programlisting>
</para>
</refsect1>
Expand Down Expand Up @@ -109,6 +139,10 @@ session optional pam_motd.so motd=/etc/motd
<para>
pam_motd was written by Ben Collins &lt;bcollins@debian.org&gt;.
</para>
<para>
The <option>motd_d=</option> option was added by
Allison Karlitskaya &lt;allison.karlitskaya@redhat.com&gt;.
</para>
</refsect1>

</refentry>
100 changes: 73 additions & 27 deletions modules/pam_motd/pam_motd.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <pwd.h>
Expand All @@ -33,6 +34,7 @@

#define PAM_SM_SESSION
#define DEFAULT_MOTD "/etc/motd"
#define DEFAULT_MOTD_D "/etc/motd.d"

#include <security/pam_modules.h>
#include <security/pam_modutil.h>
Expand All @@ -47,14 +49,60 @@ pam_sm_close_session (pam_handle_t *pamh UNUSED, int flags UNUSED,
}

static char default_motd[] = DEFAULT_MOTD;
static char default_motd_d[] = 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);
}

static void try_to_display_directory(pam_handle_t *pamh, const char *dirname)
{
DIR *dirp;

dirp = opendir(dirname);

if (dirp != NULL) {
struct dirent *entry;

while ((entry = readdir(dirp))) {
int fd = openat(dirfd(dirp), entry->d_name, O_RDONLY);

if (fd >= 0) {
try_to_display_fd(pamh, fd);
close(fd);
}
}

closedir(dirp);
}
}

int pam_sm_open_session(pam_handle_t *pamh, int flags,
int argc, const char **argv)
{
int retval = PAM_IGNORE;
int fd;
const char *motd_path = NULL;
char *mtmp = NULL;
const char *motd_d_path = NULL;

if (flags & PAM_SILENT) {
return retval;
Expand All @@ -72,41 +120,39 @@ int pam_sm_open_session(pam_handle_t *pamh, int flags,
"motd= specification missing argument - ignored");
}
}
else if (!strncmp(*argv,"motd_d=",5)) {

motd_d_path = 7 + *argv;
if (*motd_d_path != '\0') {
D(("set motd.d path: %s", motd_d_path));
} else {
motd_d_path = NULL;
pam_syslog(pamh, LOG_ERR,
"motd_d= specification missing argument - ignored");
}
}
else
pam_syslog(pamh, LOG_ERR, "unknown option: %s", *argv);
}

if (motd_path == NULL)
if (motd_path == NULL && motd_d_path == NULL) {
motd_path = default_motd;
motd_d_path = default_motd_d;
}

while ((fd = open(motd_path, O_RDONLY, 0)) >= 0) {
struct stat st;

/* fill in message buffer with contents of motd */
if ((fstat(fd, &st) < 0) || !st.st_size || st.st_size > 0x10000)
break;

if (!(mtmp = malloc(st.st_size+1)))
break;

if (pam_modutil_read(fd, mtmp, st.st_size) != st.st_size)
break;
if (motd_path != NULL) {
int fd = open(motd_path, O_RDONLY, 0);

if (mtmp[st.st_size-1] == '\n')
mtmp[st.st_size-1] = '\0';
else
mtmp[st.st_size] = '\0';

pam_info (pamh, "%s", mtmp);
break;
if (fd >= 0) {
try_to_display_fd(pamh, fd);
close(fd);
}
}

_pam_drop (mtmp);

if (fd >= 0)
close(fd);
if (motd_d_path != NULL)
try_to_display_directory(pamh, motd_d_path);

return retval;
return retval;
}

/* end of module definition */

0 comments on commit acd50bf

Please sign in to comment.