a46dbe
From 3a3e70739834cd5cbd17469907ef718c81ae40c0 Mon Sep 17 00:00:00 2001
a46dbe
From: Carlos Santos <casantos@redhat.com>
a46dbe
Date: Wed, 11 Sep 2019 11:50:28 -0300
a46dbe
Subject: [PATCH] pam_lastlog: document the 'unlimited' option
a46dbe
a46dbe
Signed-off-by: Carlos Santos <casantos@redhat.com>
a46dbe
---
a46dbe
 modules/pam_lastlog/pam_lastlog.8.xml | 18 ++++++++++++++++++
a46dbe
 1 file changed, 18 insertions(+)
a46dbe
a46dbe
diff --git a/modules/pam_lastlog/pam_lastlog.8.xml b/modules/pam_lastlog/pam_lastlog.8.xml
a46dbe
index bc2e1be..f10e94a 100644
a46dbe
--- a/modules/pam_lastlog/pam_lastlog.8.xml
a46dbe
+++ b/modules/pam_lastlog/pam_lastlog.8.xml
a46dbe
@@ -48,6 +48,9 @@
a46dbe
       <arg choice="opt">
a46dbe
         inactive=<days>
a46dbe
       </arg>
a46dbe
+      <arg choice="opt">
a46dbe
+        unlimited
a46dbe
+      </arg>
a46dbe
     </cmdsynopsis>
a46dbe
   </refsynopsisdiv>
a46dbe
 
a46dbe
@@ -196,6 +199,18 @@
a46dbe
           </para>
a46dbe
         </listitem>
a46dbe
       </varlistentry>
a46dbe
+      <varlistentry>
a46dbe
+        <term>
a46dbe
+          <option>unlimited</option>
a46dbe
+        </term>
a46dbe
+        <listitem>
a46dbe
+          <para>
a46dbe
+	    If the <emphasis>fsize</emphasis> limit is set, this option can be
a46dbe
+	    used to override it, preventing failures on systems with large UID
a46dbe
+	    values that lead lastlog to become a huge sparse file.
a46dbe
+          </para>
a46dbe
+        </listitem>
a46dbe
+      </varlistentry>
a46dbe
     </variablelist>
a46dbe
   </refsect1>
a46dbe
 
a46dbe
@@ -300,6 +315,9 @@
a46dbe
   <refsect1 id='pam_lastlog-see_also'>
a46dbe
     <title>SEE ALSO</title>
a46dbe
     <para>
a46dbe
+      <citerefentry>
a46dbe
+	<refentrytitle>limits.conf</refentrytitle><manvolnum>5</manvolnum>
a46dbe
+      </citerefentry>,
a46dbe
       <citerefentry>
a46dbe
 	<refentrytitle>pam.conf</refentrytitle><manvolnum>5</manvolnum>
a46dbe
       </citerefentry>,
a46dbe
-- 
a46dbe
2.20.1
a46dbe
a46dbe
From 9349333a9ae958205294cd25e97fd6b4805bd82b Mon Sep 17 00:00:00 2001
a46dbe
From: Carlos Santos <casantos@redhat.com>
a46dbe
Date: Tue, 10 Sep 2019 23:08:30 -0300
a46dbe
Subject: [PATCH] pam_lastlog: prevent crash due to reduced 'fsize' limit
a46dbe
a46dbe
It a reduced fsize limit is set in /etc/security/limits.conf and
a46dbe
pam_limits is in use pam_lastlog may cause a crash, e.g.
a46dbe
a46dbe
    ----- begin /etc/pam.d/su ----
a46dbe
    auth        sufficient   pam_rootok.so
a46dbe
    auth        required     pam_wheel.so use_uid
a46dbe
    auth        required     pam_env.so
a46dbe
    auth        required     pam_unix.so nullok
a46dbe
    account     required     pam_unix.so
a46dbe
    password    required     pam_unix.so nullok
a46dbe
    session     required     pam_limits.so
a46dbe
    session     required     pam_env.so
a46dbe
    session     required     pam_unix.so
a46dbe
    session     optional     pam_lastlog.so
a46dbe
    ----- end /etc/pam.d/su -----
a46dbe
a46dbe
    ----- begin /etc/security/limits.d/fsize.conf -----
a46dbe
    * soft fsize 1710
a46dbe
    * hard fsize 1710
a46dbe
    ----- end /etc/security/limits.d/fsize.conf -----
a46dbe
a46dbe
    # id user1
a46dbe
    uid=1000(user1) gid=1000(user1) groups=1000(user1)
a46dbe
    # su - user1
a46dbe
    Last login: Wed Sep 11 01:52:44 UTC 2019 on console
a46dbe
    $ exit
a46dbe
    # id user2
a46dbe
    uid=60000(user2) gid=60000(user2) groups=60000(user2)
a46dbe
    # su - user2
a46dbe
    File size limit exceeded
a46dbe
a46dbe
This happens because pam_limits sets RLIMIT_FSIZE before pam_lastlog
a46dbe
attempts to write /var/log/lastlog, leading to a SIGXFSZ signal.
a46dbe
a46dbe
In order to fix this, and an 'unlimited' option, which leads to saving
a46dbe
the 'fsize' limit and set it to unlimited before writing lastlog. After
a46dbe
that, restore the saved value. If 'fsize' is already unlimited nothing
a46dbe
is done.
a46dbe
a46dbe
Failing to set the 'fsize' limit is not a fatal error.  With luck the
a46dbe
configured limit will suffice, so we try to write lastlog anyway, even
a46dbe
under the risk of dying due to a SIGXFSZ.
a46dbe
a46dbe
Failing to restore the 'fsize' limit is a fatal error, since we don't
a46dbe
want to keep it unlimited.
a46dbe
a46dbe
Signed-off-by: Carlos Santos <casantos@redhat.com>
a46dbe
---
a46dbe
 modules/pam_lastlog/pam_lastlog.c | 66 ++++++++++++++++++++++++++-----
a46dbe
 1 file changed, 57 insertions(+), 9 deletions(-)
a46dbe
a46dbe
diff --git a/modules/pam_lastlog/pam_lastlog.c b/modules/pam_lastlog/pam_lastlog.c
a46dbe
index e980c04..a135c9f 100644
a46dbe
--- a/modules/pam_lastlog/pam_lastlog.c
a46dbe
+++ b/modules/pam_lastlog/pam_lastlog.c
a46dbe
@@ -25,6 +25,8 @@
a46dbe
 #include <stdio.h>
a46dbe
 #include <string.h>
a46dbe
 #include <sys/types.h>
a46dbe
+#include <sys/time.h>
a46dbe
+#include <sys/resource.h>
a46dbe
 #include <syslog.h>
a46dbe
 #include <unistd.h>
a46dbe
 
a46dbe
@@ -82,15 +84,16 @@ struct lastlog {
a46dbe
 
a46dbe
 /* argument parsing */
a46dbe
 
a46dbe
-#define LASTLOG_DATE        01  /* display the date of the last login */
a46dbe
-#define LASTLOG_HOST        02  /* display the last host used (if set) */
a46dbe
-#define LASTLOG_LINE        04  /* display the last terminal used */
a46dbe
-#define LASTLOG_NEVER      010  /* display a welcome message for first login */
a46dbe
-#define LASTLOG_DEBUG      020  /* send info to syslog(3) */
a46dbe
-#define LASTLOG_QUIET      040  /* keep quiet about things */
a46dbe
-#define LASTLOG_WTMP      0100  /* log to wtmp as well as lastlog */
a46dbe
-#define LASTLOG_BTMP      0200  /* display failed login info from btmp */
a46dbe
-#define LASTLOG_UPDATE    0400  /* update the lastlog and wtmp files (default) */
a46dbe
+#define LASTLOG_DATE          01  /* display the date of the last login */
a46dbe
+#define LASTLOG_HOST          02  /* display the last host used (if set) */
a46dbe
+#define LASTLOG_LINE          04  /* display the last terminal used */
a46dbe
+#define LASTLOG_NEVER        010  /* display a welcome message for first login */
a46dbe
+#define LASTLOG_DEBUG        020  /* send info to syslog(3) */
a46dbe
+#define LASTLOG_QUIET        040  /* keep quiet about things */
a46dbe
+#define LASTLOG_WTMP        0100  /* log to wtmp as well as lastlog */
a46dbe
+#define LASTLOG_BTMP        0200  /* display failed login info from btmp */
a46dbe
+#define LASTLOG_UPDATE      0400  /* update the lastlog and wtmp files (default) */
a46dbe
+#define LASTLOG_UNLIMITED  01000  /* unlimited file size (ignore 'fsize' limit) */
a46dbe
 
a46dbe
 static int
a46dbe
 _pam_auth_parse(pam_handle_t *pamh, int flags, int argc, const char **argv,
a46dbe
@@ -158,6 +161,8 @@ _pam_session_parse(pam_handle_t *pamh, int flags, int argc, const char **argv)
a46dbe
 	    ctrl &= ~(LASTLOG_WTMP|LASTLOG_UPDATE);
a46dbe
 	} else if (!strcmp(*argv,"showfailed")) {
a46dbe
 	    ctrl |= LASTLOG_BTMP;
a46dbe
+	} else if (!strcmp(*argv,"unlimited")) {
a46dbe
+	    ctrl |= LASTLOG_UNLIMITED;
a46dbe
 	} else {
a46dbe
 	    pam_syslog(pamh, LOG_ERR, "unknown option: %s", *argv);
a46dbe
 	}
a46dbe
@@ -373,6 +378,12 @@ static int
a46dbe
 last_login_write(pam_handle_t *pamh, int announce, int last_fd,
a46dbe
 		 uid_t uid, const char *user)
a46dbe
 {
a46dbe
+    static struct rlimit no_limit = {
a46dbe
+	RLIM_INFINITY,
a46dbe
+	RLIM_INFINITY
a46dbe
+    };
a46dbe
+    struct rlimit old_limit;
a46dbe
+    int setrlimit_res;
a46dbe
     struct flock last_lock;
a46dbe
     struct lastlog last_login;
a46dbe
     time_t ll_time;
a46dbe
@@ -427,6 +438,31 @@ last_login_write(pam_handle_t *pamh, int announce, int last_fd,
a46dbe
         sleep(LASTLOG_IGNORE_LOCK_TIME);
a46dbe
     }
a46dbe
 
a46dbe
+    /*
a46dbe
+     * Failing to set the 'fsize' limit is not a fatal error. We try to write
a46dbe
+     * lastlog anyway, under the risk of dying due to a SIGXFSZ.
a46dbe
+     */
a46dbe
+    D(("setting limit for 'fsize'"));
a46dbe
+
a46dbe
+    if ((announce & LASTLOG_UNLIMITED) == 0) {    /* don't set to unlimted */
a46dbe
+	setrlimit_res = -1;
a46dbe
+    } else if (getrlimit(RLIMIT_FSIZE, &old_limit) == 0) {
a46dbe
+	if (old_limit.rlim_cur == RLIM_INFINITY) {    /* already unlimited */
a46dbe
+	    setrlimit_res = -1;
a46dbe
+	} else {
a46dbe
+	    setrlimit_res = setrlimit(RLIMIT_FSIZE, &no_limit);
a46dbe
+	    if (setrlimit_res != 0)
a46dbe
+		pam_syslog(pamh, LOG_WARNING, "Could not set limit for 'fsize': %m");
a46dbe
+	}
a46dbe
+    } else {
a46dbe
+	setrlimit_res = -1;
a46dbe
+	if (errno == EINVAL) {
a46dbe
+	    pam_syslog(pamh, LOG_INFO, "Limit for 'fsize' not supported: %m");
a46dbe
+	} else {
a46dbe
+	    pam_syslog(pamh, LOG_WARNING, "Could not get limit for 'fsize': %m");
a46dbe
+	}
a46dbe
+    }
a46dbe
+
a46dbe
     D(("writing to the lastlog file"));
a46dbe
     if (pam_modutil_write (last_fd, (char *) &last_login,
a46dbe
 			   sizeof (last_login)) != sizeof(last_login)) {
a46dbe
@@ -434,6 +470,18 @@ last_login_write(pam_handle_t *pamh, int announce, int last_fd,
a46dbe
 	retval = PAM_SERVICE_ERR;
a46dbe
     }
a46dbe
 
a46dbe
+    /*
a46dbe
+     * Failing to restore the 'fsize' limit is a fatal error.
a46dbe
+     */
a46dbe
+    D(("restoring limit for 'fsize'"));
a46dbe
+    if (setrlimit_res == 0) {
a46dbe
+	setrlimit_res = setrlimit(RLIMIT_FSIZE, &old_limit);
a46dbe
+	if (setrlimit_res != 0) {
a46dbe
+	    pam_syslog(pamh, LOG_ERR, "Could not restore limit for 'fsize': %m");
a46dbe
+	    retval = PAM_SERVICE_ERR;
a46dbe
+	}
a46dbe
+    }
a46dbe
+
a46dbe
     last_lock.l_type = F_UNLCK;
a46dbe
     (void) fcntl(last_fd, F_SETLK, &last_lock);        /* unlock */
a46dbe
     D(("unlocked"));
a46dbe
-- 
a46dbe
2.20.1
a46dbe