[v2,6/7] login: Use 64-bit time on struct lastlog

Message ID 20200805185915.2025314-6-adhemerval.zanella@linaro.org
State Superseded
Headers
Series [v2,1/7] login: Move gnu utmpx to default implementation |

Commit Message

Adhemerval Zanella Netto Aug. 5, 2020, 6:59 p.m. UTC
  The new struct has the same size on both 32-bit and 64-bit
architectures.  As for utmp{x} 64-bit time_t support, a new file name
is defined for _PATH_LASTLOG.

Also two new symbols are added that read/write 'struct lastlog'
entries, 'lastlog_read' and 'lastlog_write'.  Both are GNU extensions
and handle the 32-bit entry operation if the argument is the old
_PATH_LASTLOG path.

Different than utmp{x}, no concurrent access is done (such as
advisory locking).  I modeled these function on how program that
access lastlog file uses (such as shadow-utils and util-linux).

The s390 is the only architecture that already defined the
'struct lastlog' with 64-bit time_t and to handle s390 has a specific
lastlog-compat.h header where 'is_path_lastlog_compat' already
return false (thus making both lastlog_read and lastlog_write
always read/write registers with 64-bit ll_time).

It also fixes BZ#25844 by adding the __attribute_nonstring__ on
ll_line and ll_host.

Checked on x86_64-linux-gnu and i686-linux-gnu.
---
 bits/types/struct_lastlog.h                   |  8 +-
 login/Makefile                                |  5 +-
 login/Versions                                |  3 +
 .../lastlog-compat.h                          | 27 ++++---
 login/lastlog_read.c                          | 71 +++++++++++++++++
 login/lastlog_write.c                         | 59 ++++++++++++++
 login/tst-lastlog.c                           | 79 +++++++++++++++++++
 login/tst-lastlog.root/tst-lastlog.script     |  6 ++
 login/utmp.h                                  | 11 +++
 sysdeps/generic/paths.h                       |  3 +-
 sysdeps/mach/hurd/i386/libc.abilist           |  2 +
 sysdeps/unix/sysv/linux/aarch64/libc.abilist  |  2 +
 sysdeps/unix/sysv/linux/alpha/libc.abilist    |  2 +
 sysdeps/unix/sysv/linux/arc/libc.abilist      |  2 +
 sysdeps/unix/sysv/linux/arm/le/libc.abilist   |  2 +
 sysdeps/unix/sysv/linux/csky/libc.abilist     |  2 +
 sysdeps/unix/sysv/linux/hppa/libc.abilist     |  2 +
 sysdeps/unix/sysv/linux/i386/libc.abilist     |  2 +
 sysdeps/unix/sysv/linux/ia64/libc.abilist     |  2 +
 .../unix/sysv/linux/m68k/m680x0/libc.abilist  |  2 +
 .../sysv/linux/microblaze/be/libc.abilist     |  2 +
 .../sysv/linux/mips/mips32/fpu/libc.abilist   |  2 +
 .../sysv/linux/mips/mips64/n32/libc.abilist   |  2 +
 .../sysv/linux/mips/mips64/n64/libc.abilist   |  2 +
 sysdeps/unix/sysv/linux/nios2/libc.abilist    |  2 +
 sysdeps/unix/sysv/linux/paths.h               |  3 +-
 .../linux/powerpc/powerpc32/fpu/libc.abilist  |  2 +
 .../linux/powerpc/powerpc64/be/libc.abilist   |  2 +
 .../linux/powerpc/powerpc64/le/libc.abilist   |  2 +
 .../unix/sysv/linux/riscv/rv64/libc.abilist   |  2 +
 sysdeps/unix/sysv/linux/s390/lastlog-compat.h | 38 +++++++++
 .../unix/sysv/linux/s390/s390-32/libc.abilist |  2 +
 .../unix/sysv/linux/s390/s390-64/libc.abilist |  2 +
 sysdeps/unix/sysv/linux/sh/le/libc.abilist    |  2 +
 .../sysv/linux/sparc/sparc32/libc.abilist     |  2 +
 .../sysv/linux/sparc/sparc64/libc.abilist     |  2 +
 .../unix/sysv/linux/x86_64/64/libc.abilist    |  2 +
 .../unix/sysv/linux/x86_64/x32/libc.abilist   |  2 +
 38 files changed, 345 insertions(+), 20 deletions(-)
 rename sysdeps/unix/sysv/linux/s390/bits/struct_lastlog.h => login/lastlog-compat.h (74%)
 create mode 100644 login/lastlog_read.c
 create mode 100644 login/lastlog_write.c
 create mode 100644 login/tst-lastlog.c
 create mode 100644 login/tst-lastlog.root/tst-lastlog.script
 create mode 100644 sysdeps/unix/sysv/linux/s390/lastlog-compat.h
  

Comments

Florian Weimer Aug. 5, 2020, 7:56 p.m. UTC | #1
* Adhemerval Zanella via Libc-alpha:

> diff --git a/bits/types/struct_lastlog.h b/bits/types/struct_lastlog.h
> index 67ffec1b08..9e8983b57d 100644
> --- a/bits/types/struct_lastlog.h
> +++ b/bits/types/struct_lastlog.h
> @@ -24,11 +24,11 @@
>     previous logins.  */
>  struct lastlog
>  {
> -#if __WORDSIZE_TIME64_COMPAT32
> -  int32_t ll_time;
> +#if __WORDSIZE == 32
> +  int64_t ll_time;
>  #else
>    __time_t ll_time;
>  #endif

Should this check for __TIMESIZE instead of __WORDSIZE?  It shouldn't
make a difference; I just think it would be clearer.

Or maybe use int64_t unconditionally?  That would be simpler.
  
Adhemerval Zanella Netto Aug. 5, 2020, 8:36 p.m. UTC | #2
On 05/08/2020 16:56, Florian Weimer wrote:
> * Adhemerval Zanella via Libc-alpha:
> 
>> diff --git a/bits/types/struct_lastlog.h b/bits/types/struct_lastlog.h
>> index 67ffec1b08..9e8983b57d 100644
>> --- a/bits/types/struct_lastlog.h
>> +++ b/bits/types/struct_lastlog.h
>> @@ -24,11 +24,11 @@
>>     previous logins.  */
>>  struct lastlog
>>  {
>> -#if __WORDSIZE_TIME64_COMPAT32
>> -  int32_t ll_time;
>> +#if __WORDSIZE == 32
>> +  int64_t ll_time;
>>  #else
>>    __time_t ll_time;
>>  #endif
> 
> Should this check for __TIMESIZE instead of __WORDSIZE?  It shouldn't
> make a difference; I just think it would be clearer.
> 
> Or maybe use int64_t unconditionally?  That would be simpler.
> 

The lastlog is not really defined in any standard, so I guess we have
this liberty here.  I agree that int64_t unconditionally is simpler.
  

Patch

diff --git a/bits/types/struct_lastlog.h b/bits/types/struct_lastlog.h
index 67ffec1b08..9e8983b57d 100644
--- a/bits/types/struct_lastlog.h
+++ b/bits/types/struct_lastlog.h
@@ -24,11 +24,11 @@ 
    previous logins.  */
 struct lastlog
 {
-#if __WORDSIZE_TIME64_COMPAT32
-  int32_t ll_time;
+#if __WORDSIZE == 32
+  int64_t ll_time;
 #else
   __time_t ll_time;
 #endif
-  char ll_line[UT_LINESIZE];
-  char ll_host[UT_HOSTSIZE];
+  char ll_line[UT_LINESIZE] __attribute_nonstring__;
+  char ll_host[UT_HOSTSIZE] __attribute_nonstring__;
 };
diff --git a/login/Makefile b/login/Makefile
index 848caa0c44..c072dfdf46 100644
--- a/login/Makefile
+++ b/login/Makefile
@@ -31,7 +31,8 @@  headers	:= utmp.h bits/utmp.h lastlog.h pty.h \
 routines := getlogin getlogin_r setlogin getlogin_r_chk \
 	    getutent getutent_r getutid getutline getutid_r getutline_r \
 	    utmp_file utmpname updwtmp getpt grantpt unlockpt ptsname \
-	    ptsname_r_chk utmp32 utmpx32 utmp-convert
+	    ptsname_r_chk utmp32 utmpx32 utmp-convert \
+	    lastlog_read lastlog_write
 
 CFLAGS-grantpt.c += -DLIBEXECDIR='"$(libexecdir)"'
 
@@ -50,7 +51,7 @@  tests := tst-utmp tst-utmpx tst-grantpt tst-ptsname tst-getlogin tst-updwtmpx \
   tst-pututxline-lockfail tst-pututxline-cache
 
 tests-internal := tst-utmp32
-tests-container := tst-utmp32 tst-utmp-default
+tests-container := tst-utmp32 tst-utmp-default tst-lastlog
 
 # Build the -lutil library with these extra functions.
 extra-libs      := libutil
diff --git a/login/Versions b/login/Versions
index 6c53d6639e..13da0d15fd 100644
--- a/login/Versions
+++ b/login/Versions
@@ -45,6 +45,9 @@  libc {
     __getlogin_r_chk;
     __ptsname_r_chk;
   }
+  GLIBC_2.33 {
+    lastlog_read; lastlog_write;
+  }
   GLIBC_PRIVATE {
     # Used on compat login from libutil.
     __utmp_convert32to64;
diff --git a/sysdeps/unix/sysv/linux/s390/bits/struct_lastlog.h b/login/lastlog-compat.h
similarity index 74%
rename from sysdeps/unix/sysv/linux/s390/bits/struct_lastlog.h
rename to login/lastlog-compat.h
index 1faa472ec8..687774a21e 100644
--- a/sysdeps/unix/sysv/linux/s390/bits/struct_lastlog.h
+++ b/login/lastlog-compat.h
@@ -1,4 +1,4 @@ 
-/* The 'struct lastlog' type.
+/* Compat lastlog definitions.
    Copyright (C) 2020 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
@@ -16,19 +16,22 @@ 
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
-#ifndef _UTMP_H
-# error "Never include <bits/struct_lastlog.h> directly; use <utmp.h> instead."
-#endif
+#ifndef _LASTLOG_COMPAT_H
+#define _LASTLOG_COMPAT_H 1
+
+#include <string.h>
 
-/* The structure describing an entry in the database of
-   previous logins.  */
-struct lastlog
+struct lastlog_compat
 {
-#if __WORDSIZE == 32
-  int64_t ll_time;
-#else
-  __time_t ll_time;
-#endif
+  int32_t ll_time;
   char ll_line[UT_LINESIZE];
   char ll_host[UT_HOSTSIZE];
 };
+
+static inline bool
+is_path_lastlog_compat (const char *file)
+{
+  return strcmp (file, "/var/log/lastlog") == 0;
+}
+
+#endif
diff --git a/login/lastlog_read.c b/login/lastlog_read.c
new file mode 100644
index 0000000000..e2c6e82a15
--- /dev/null
+++ b/login/lastlog_read.c
@@ -0,0 +1,71 @@ 
+/* Read a lastlog entry.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <utmp.h>
+#include <stdbool.h>
+#include <not-cancel.h>
+#include <lastlog-compat.h>
+
+ssize_t
+lastlog_read (const char *file, uid_t uid, struct lastlog *ll)
+{
+  int fd = __open_nocancel (file, O_RDONLY | O_LARGEFILE | O_CLOEXEC);
+  if (fd == -1)
+    return -1;
+
+  size_t llsize;
+  struct lastlog_compat llcompat;
+  void *data;
+
+  if (is_path_lastlog_compat (file))
+    {
+      llsize = sizeof (struct lastlog_compat);
+      data = &llcompat;
+    }
+  else
+    {
+      llsize = sizeof (struct lastlog);
+      data = ll;
+    }
+
+  off64_t off = llsize * uid;
+  ssize_t r = __pread64_nocancel (fd, data, llsize, off);
+  __close_nocancel_nostatus (fd);
+
+  if (r == llsize && data == &llcompat)
+    {
+      ll->ll_time = llcompat.ll_time;
+      memcpy (ll->ll_line, llcompat.ll_line, UT_LINESIZE);
+      memcpy (ll->ll_host, llcompat.ll_host, UT_HOSTSIZE);
+    }
+
+  if (r == llsize)
+    {
+      if (data == &llcompat)
+	{
+	  ll->ll_time = llcompat.ll_time;
+	  memcpy (ll->ll_line, llcompat.ll_line, UT_LINESIZE);
+	  memcpy (ll->ll_host, llcompat.ll_host, UT_HOSTSIZE);
+	}
+      /* We need to return the expected 'struct lastlog' size in case of
+	 success.  */
+      r = sizeof (struct lastlog);
+    }
+
+  return r;
+}
diff --git a/login/lastlog_write.c b/login/lastlog_write.c
new file mode 100644
index 0000000000..f3aedcbdb7
--- /dev/null
+++ b/login/lastlog_write.c
@@ -0,0 +1,59 @@ 
+/* Write a lastlog entry.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <utmp.h>
+#include <stdbool.h>
+#include <not-cancel.h>
+#include <lastlog-compat.h>
+
+ssize_t
+lastlog_write (const char *file, uid_t uid, const struct lastlog *ll)
+{
+  int fd = __open_nocancel (file, O_WRONLY | O_LARGEFILE | O_CLOEXEC);
+  if (fd == -1)
+    return -1;
+
+  size_t llsize;
+  struct lastlog_compat llcompat;
+  const void *data;
+
+  if (is_path_lastlog_compat (file))
+    {
+      llcompat.ll_time = ll->ll_time;
+      memcpy (llcompat.ll_line, ll->ll_line, UT_LINESIZE);
+      memcpy (llcompat.ll_host, ll->ll_host, UT_HOSTSIZE);
+      llsize = sizeof (struct lastlog_compat);
+      data = &llcompat;
+    }
+  else
+    {
+      llsize = sizeof (struct lastlog);
+      data = ll;
+    }
+
+  off64_t off = llsize * uid;
+  ssize_t r = __pwrite64_nocancel (fd, data, llsize, off);
+  __close_nocancel_nostatus (fd);
+
+  /* We need to return the expected 'struct lastlog' size in case of
+     success.  */
+  if (r == llsize && data == &llcompat)
+    r = sizeof (struct lastlog);
+
+  return r;
+}
diff --git a/login/tst-lastlog.c b/login/tst-lastlog.c
new file mode 100644
index 0000000000..9376a6ddf4
--- /dev/null
+++ b/login/tst-lastlog.c
@@ -0,0 +1,79 @@ 
+/* Tests for lastlog read/write functions.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <stdlib.h>
+#include <string.h>
+#include <utmp.h>
+
+#include <support/check.h>
+#include <support/temp_file.h>
+
+#include <stdio.h>
+
+static struct
+{
+  uid_t uid;
+  struct lastlog ll;
+} entry[] =
+{
+  { 0,    { .ll_time = 1000, .ll_line = "tty1" } },
+  { 1000, { .ll_time = 2000, .ll_line = "pts/0", .ll_host = "127.0.0.1" } },
+  { 20,   { .ll_time = 3000, .ll_line = "pts/1", .ll_host = "192.168.0.1" } },
+  { 30,   { .ll_time = 4000, .ll_line = "tty2" } },
+};
+const size_t entry_size = sizeof (entry) / sizeof (entry[0]);
+
+static void
+run_test (const char *filename)
+{
+  for (int n = 0; n < entry_size; n++)
+    TEST_COMPARE (lastlog_write (filename, entry[n].uid, &entry[n].ll),
+		  sizeof (struct lastlog));
+
+  for (int n = 0; n < entry_size; n++)
+    {
+      struct lastlog ll;
+      TEST_COMPARE (lastlog_read (filename, entry[n].uid, &ll),
+		    sizeof (struct lastlog));
+      TEST_COMPARE (ll.ll_time, entry[n].ll.ll_time);
+      TEST_COMPARE_BLOB (ll.ll_line, UT_LINESIZE,
+			 entry[n].ll.ll_line, UT_LINESIZE);
+      TEST_COMPARE_BLOB (ll.ll_host, UT_HOSTSIZE,
+			 entry[n].ll.ll_host, UT_HOSTSIZE);
+    }
+
+  /* Check with an non present uid.  */
+  {
+    struct lastlog ll;
+    TEST_COMPARE (lastlog_read (filename, 4000, &ll), 0);
+  }
+}
+
+static int
+do_test (void)
+{
+  /* The path triggers the read/write of compat (32-bit ll_time) entries.  */
+  run_test ("/var/run/lastlog");
+
+  /* Any other file handles new (64-bit ll_time) entries.  */
+  run_test ("/var/run/lastlog.v2");
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/login/tst-lastlog.root/tst-lastlog.script b/login/tst-lastlog.root/tst-lastlog.script
new file mode 100644
index 0000000000..ca34ce7021
--- /dev/null
+++ b/login/tst-lastlog.root/tst-lastlog.script
@@ -0,0 +1,6 @@ 
+mkdirp 0755 /var/run
+touch  0664 /var/run/lastlog
+touch  0664 /var/run/lastlog.v2
+
+# Must run localedef as root to write into default paths.
+su
diff --git a/login/utmp.h b/login/utmp.h
index 3de2b8596b..23304016d1 100644
--- a/login/utmp.h
+++ b/login/utmp.h
@@ -91,6 +91,17 @@  extern int getutline_r (const struct utmp *__line,
 
 #endif	/* Use misc.  */
 
+#ifdef __USE_GNU
+/* Read the struct lastlog LL with UID from file FILE.  */
+extern ssize_t lastlog_read (const char *__file, uid_t __uid,
+			     struct lastlog *__ll)
+     __THROW __nonnull ((1, 3));
+/* Write the struct lastlog LL with UID from file FILE.  */
+extern ssize_t lastlog_write (const char *__file, uid_t __uid,
+			      const struct lastlog *__ll)
+     __THROW __nonnull ((1, 3));
+#endif
+
 __END_DECLS
 
 #endif /* utmp.h  */
diff --git a/sysdeps/generic/paths.h b/sysdeps/generic/paths.h
index ab2980e14a..9321ad7294 100644
--- a/sysdeps/generic/paths.h
+++ b/sysdeps/generic/paths.h
@@ -46,7 +46,8 @@ 
 #define	_PATH_DRUM	"/dev/drum"
 #define	_PATH_GSHADOW	"/etc/gshadow"
 #define	_PATH_KMEM	"/dev/kmem"
-#define	_PATH_LASTLOG	"/var/log/lastlog"
+#define _PATH_LASTLOG_VER ".v2"
+#define	_PATH_LASTLOG	"/var/log/lastlog" _PATH_LASTLOG_VER
 #define	_PATH_MAILDIR	"/var/mail"
 #define	_PATH_MAN	"/usr/share/man"
 #define	_PATH_MEM	"/dev/mem"
diff --git a/sysdeps/mach/hurd/i386/libc.abilist b/sysdeps/mach/hurd/i386/libc.abilist
index a9bbb5028d..e58dbc1176 100644
--- a/sysdeps/mach/hurd/i386/libc.abilist
+++ b/sysdeps/mach/hurd/i386/libc.abilist
@@ -2207,6 +2207,8 @@  GLIBC_2.33 getutmpx F
 GLIBC_2.33 getutxent F
 GLIBC_2.33 getutxid F
 GLIBC_2.33 getutxline F
+GLIBC_2.33 lastlog_read F
+GLIBC_2.33 lastlog_write F
 GLIBC_2.33 lstat F
 GLIBC_2.33 lstat64 F
 GLIBC_2.33 mknod F
diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
index 9172a3347e..307e519508 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2175,6 +2175,8 @@  GLIBC_2.33 getutmpx F
 GLIBC_2.33 getutxent F
 GLIBC_2.33 getutxid F
 GLIBC_2.33 getutxline F
+GLIBC_2.33 lastlog_read F
+GLIBC_2.33 lastlog_write F
 GLIBC_2.33 lstat F
 GLIBC_2.33 lstat64 F
 GLIBC_2.33 mknod F
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index bd217cb2c2..3b160667cb 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -2257,6 +2257,8 @@  GLIBC_2.33 getutmpx F
 GLIBC_2.33 getutxent F
 GLIBC_2.33 getutxid F
 GLIBC_2.33 getutxline F
+GLIBC_2.33 lastlog_read F
+GLIBC_2.33 lastlog_write F
 GLIBC_2.33 lstat F
 GLIBC_2.33 lstat64 F
 GLIBC_2.33 mknod F
diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist
index 898fd755ea..e460316be2 100644
--- a/sysdeps/unix/sysv/linux/arc/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arc/libc.abilist
@@ -1935,6 +1935,8 @@  GLIBC_2.33 getutmpx F
 GLIBC_2.33 getutxent F
 GLIBC_2.33 getutxid F
 GLIBC_2.33 getutxline F
+GLIBC_2.33 lastlog_read F
+GLIBC_2.33 lastlog_write F
 GLIBC_2.33 lstat F
 GLIBC_2.33 lstat64 F
 GLIBC_2.33 mknod F
diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
index dd52296951..b4ecc0ebe2 100644
--- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
@@ -156,6 +156,8 @@  GLIBC_2.33 getutmpx F
 GLIBC_2.33 getutxent F
 GLIBC_2.33 getutxid F
 GLIBC_2.33 getutxline F
+GLIBC_2.33 lastlog_read F
+GLIBC_2.33 lastlog_write F
 GLIBC_2.33 lstat F
 GLIBC_2.33 lstat64 F
 GLIBC_2.33 mknod F
diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist
index 02636a8fa2..e663f473b5 100644
--- a/sysdeps/unix/sysv/linux/csky/libc.abilist
+++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
@@ -2119,6 +2119,8 @@  GLIBC_2.33 getutmpx F
 GLIBC_2.33 getutxent F
 GLIBC_2.33 getutxid F
 GLIBC_2.33 getutxline F
+GLIBC_2.33 lastlog_read F
+GLIBC_2.33 lastlog_write F
 GLIBC_2.33 lstat F
 GLIBC_2.33 lstat64 F
 GLIBC_2.33 mknod F
diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
index 21912899a1..0c7e306946 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -2078,6 +2078,8 @@  GLIBC_2.33 getutmpx F
 GLIBC_2.33 getutxent F
 GLIBC_2.33 getutxid F
 GLIBC_2.33 getutxline F
+GLIBC_2.33 lastlog_read F
+GLIBC_2.33 lastlog_write F
 GLIBC_2.33 lstat F
 GLIBC_2.33 lstat64 F
 GLIBC_2.33 mknod F
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index 77b0d47f2a..7550213cda 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2244,6 +2244,8 @@  GLIBC_2.33 getutmpx F
 GLIBC_2.33 getutxent F
 GLIBC_2.33 getutxid F
 GLIBC_2.33 getutxline F
+GLIBC_2.33 lastlog_read F
+GLIBC_2.33 lastlog_write F
 GLIBC_2.33 lstat F
 GLIBC_2.33 lstat64 F
 GLIBC_2.33 mknod F
diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
index 7c84d98fcb..4ed0dc12cc 100644
--- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
@@ -2110,6 +2110,8 @@  GLIBC_2.33 getutmpx F
 GLIBC_2.33 getutxent F
 GLIBC_2.33 getutxid F
 GLIBC_2.33 getutxline F
+GLIBC_2.33 lastlog_read F
+GLIBC_2.33 lastlog_write F
 GLIBC_2.33 lstat F
 GLIBC_2.33 lstat64 F
 GLIBC_2.33 mknod F
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
index 421a82107f..e1940b2af8 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -2190,6 +2190,8 @@  GLIBC_2.33 getutmpx F
 GLIBC_2.33 getutxent F
 GLIBC_2.33 getutxid F
 GLIBC_2.33 getutxline F
+GLIBC_2.33 lastlog_read F
+GLIBC_2.33 lastlog_write F
 GLIBC_2.33 lstat F
 GLIBC_2.33 lstat64 F
 GLIBC_2.33 mknod F
diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
index 6ae7a8f5ba..1bbd2eaa00 100644
--- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
@@ -2170,6 +2170,8 @@  GLIBC_2.33 getutmpx F
 GLIBC_2.33 getutxent F
 GLIBC_2.33 getutxid F
 GLIBC_2.33 getutxline F
+GLIBC_2.33 lastlog_read F
+GLIBC_2.33 lastlog_write F
 GLIBC_2.33 lstat F
 GLIBC_2.33 lstat64 F
 GLIBC_2.33 mknod F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
index 817b22b428..0dd1fb731e 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -2161,6 +2161,8 @@  GLIBC_2.33 getutmpx F
 GLIBC_2.33 getutxent F
 GLIBC_2.33 getutxid F
 GLIBC_2.33 getutxline F
+GLIBC_2.33 lastlog_read F
+GLIBC_2.33 lastlog_write F
 GLIBC_2.33 lstat F
 GLIBC_2.33 lstat64 F
 GLIBC_2.33 mknod F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
index 22772a572a..740e322ee0 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -2167,6 +2167,8 @@  GLIBC_2.33 getutmpx F
 GLIBC_2.33 getutxent F
 GLIBC_2.33 getutxid F
 GLIBC_2.33 getutxline F
+GLIBC_2.33 lastlog_read F
+GLIBC_2.33 lastlog_write F
 GLIBC_2.33 lstat F
 GLIBC_2.33 lstat64 F
 GLIBC_2.33 mknod F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
index 310db16538..b3d6cd7dbc 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -2161,6 +2161,8 @@  GLIBC_2.33 getutmpx F
 GLIBC_2.33 getutxent F
 GLIBC_2.33 getutxid F
 GLIBC_2.33 getutxline F
+GLIBC_2.33 lastlog_read F
+GLIBC_2.33 lastlog_write F
 GLIBC_2.33 lstat F
 GLIBC_2.33 lstat64 F
 GLIBC_2.33 mknod F
diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
index ba11176736..17dded8e1f 100644
--- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
@@ -2208,6 +2208,8 @@  GLIBC_2.33 getutmpx F
 GLIBC_2.33 getutxent F
 GLIBC_2.33 getutxid F
 GLIBC_2.33 getutxline F
+GLIBC_2.33 lastlog_read F
+GLIBC_2.33 lastlog_write F
 GLIBC_2.33 lstat F
 GLIBC_2.33 lstat64 F
 GLIBC_2.33 mknod F
diff --git a/sysdeps/unix/sysv/linux/paths.h b/sysdeps/unix/sysv/linux/paths.h
index 89686bcf88..b78dff7ae3 100644
--- a/sysdeps/unix/sysv/linux/paths.h
+++ b/sysdeps/unix/sysv/linux/paths.h
@@ -47,7 +47,8 @@ 
 #define	_PATH_GSHADOW	"/etc/gshadow"
 #define	_PATH_KLOG	"/proc/kmsg"
 #define	_PATH_KMEM	"/dev/kmem"
-#define	_PATH_LASTLOG	"/var/log/lastlog"
+#define _PATH_LASTLOG_VER ".v2"
+#define	_PATH_LASTLOG	"/var/log/lastlog" _PATH_LASTLOG_VER
 #define	_PATH_MAILDIR	"/var/mail"
 #define	_PATH_MAN	"/usr/share/man"
 #define	_PATH_MEM	"/dev/mem"
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index c599b985d1..960a6364b9 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -2217,6 +2217,8 @@  GLIBC_2.33 getutmpx F
 GLIBC_2.33 getutxent F
 GLIBC_2.33 getutxid F
 GLIBC_2.33 getutxline F
+GLIBC_2.33 lastlog_read F
+GLIBC_2.33 lastlog_write F
 GLIBC_2.33 lstat F
 GLIBC_2.33 lstat64 F
 GLIBC_2.33 mknod F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
index 3362f3f6bb..248569d295 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
@@ -2080,6 +2080,8 @@  GLIBC_2.33 getutmpx F
 GLIBC_2.33 getutxent F
 GLIBC_2.33 getutxid F
 GLIBC_2.33 getutxline F
+GLIBC_2.33 lastlog_read F
+GLIBC_2.33 lastlog_write F
 GLIBC_2.33 lstat F
 GLIBC_2.33 lstat64 F
 GLIBC_2.33 mknod F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
index aca57d0f38..d1c84dba37 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
@@ -2370,6 +2370,8 @@  GLIBC_2.33 getutmpx F
 GLIBC_2.33 getutxent F
 GLIBC_2.33 getutxid F
 GLIBC_2.33 getutxline F
+GLIBC_2.33 lastlog_read F
+GLIBC_2.33 lastlog_write F
 GLIBC_2.33 lstat F
 GLIBC_2.33 lstat64 F
 GLIBC_2.33 mknod F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
index d4e6f75078..ca89f2d719 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
@@ -2137,6 +2137,8 @@  GLIBC_2.33 getutmpx F
 GLIBC_2.33 getutxent F
 GLIBC_2.33 getutxid F
 GLIBC_2.33 getutxline F
+GLIBC_2.33 lastlog_read F
+GLIBC_2.33 lastlog_write F
 GLIBC_2.33 lstat F
 GLIBC_2.33 lstat64 F
 GLIBC_2.33 mknod F
diff --git a/sysdeps/unix/sysv/linux/s390/lastlog-compat.h b/sysdeps/unix/sysv/linux/s390/lastlog-compat.h
new file mode 100644
index 0000000000..56fadc3b3b
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/s390/lastlog-compat.h
@@ -0,0 +1,38 @@ 
+/* Compat lastlog definitions.  s390 definition.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _LASTLOG_COMPAT_H
+#define _LASTLOG_COMPAT_H 1
+
+/* The s390 changes its lastlog to 64-bit on glibc 2.9 without any handling
+   of old format.  The is_path_lastlog_compat assumes 64-bit as default.  */
+
+struct lastlog_compat
+{
+  int64_t ll_time;
+  char ll_line[UT_LINESIZE];
+  char ll_host[UT_HOSTSIZE];
+};
+
+static inline bool
+is_path_lastlog_compat (const char *file)
+{
+  return false;
+}
+
+#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
index 47591dc5b5..30c8837c0f 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
@@ -2204,6 +2204,8 @@  GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
 GLIBC_2.33 fstatat64 F
+GLIBC_2.33 lastlog_read F
+GLIBC_2.33 lastlog_write F
 GLIBC_2.33 lstat F
 GLIBC_2.33 lstat64 F
 GLIBC_2.33 mknod F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
index bd96aeaff7..09112747dd 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
@@ -2105,6 +2105,8 @@  GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
 GLIBC_2.33 fstatat64 F
+GLIBC_2.33 lastlog_read F
+GLIBC_2.33 lastlog_write F
 GLIBC_2.33 lstat F
 GLIBC_2.33 lstat64 F
 GLIBC_2.33 mknod F
diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
index ea78226332..6f19690273 100644
--- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
@@ -2082,6 +2082,8 @@  GLIBC_2.33 getutmpx F
 GLIBC_2.33 getutxent F
 GLIBC_2.33 getutxid F
 GLIBC_2.33 getutxline F
+GLIBC_2.33 lastlog_read F
+GLIBC_2.33 lastlog_write F
 GLIBC_2.33 lstat F
 GLIBC_2.33 lstat64 F
 GLIBC_2.33 mknod F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index 6f3a2df230..c00a11f68c 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -2206,6 +2206,8 @@  GLIBC_2.33 getutmpx F
 GLIBC_2.33 getutxent F
 GLIBC_2.33 getutxid F
 GLIBC_2.33 getutxline F
+GLIBC_2.33 lastlog_read F
+GLIBC_2.33 lastlog_write F
 GLIBC_2.33 lstat F
 GLIBC_2.33 lstat64 F
 GLIBC_2.33 mknod F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
index b4e75bb47e..af5b71b548 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -2133,6 +2133,8 @@  GLIBC_2.33 getutmpx F
 GLIBC_2.33 getutxent F
 GLIBC_2.33 getutxid F
 GLIBC_2.33 getutxline F
+GLIBC_2.33 lastlog_read F
+GLIBC_2.33 lastlog_write F
 GLIBC_2.33 lstat F
 GLIBC_2.33 lstat64 F
 GLIBC_2.33 mknod F
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
index 74c0c26ba5..34c53c17fe 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -2091,6 +2091,8 @@  GLIBC_2.33 getutmpx F
 GLIBC_2.33 getutxent F
 GLIBC_2.33 getutxid F
 GLIBC_2.33 getutxline F
+GLIBC_2.33 lastlog_read F
+GLIBC_2.33 lastlog_write F
 GLIBC_2.33 lstat F
 GLIBC_2.33 lstat64 F
 GLIBC_2.33 mknod F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
index 3597a3ff88..bfd31c5944 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2188,6 +2188,8 @@  GLIBC_2.33 getutmpx F
 GLIBC_2.33 getutxent F
 GLIBC_2.33 getutxid F
 GLIBC_2.33 getutxline F
+GLIBC_2.33 lastlog_read F
+GLIBC_2.33 lastlog_write F
 GLIBC_2.33 lstat F
 GLIBC_2.33 lstat64 F
 GLIBC_2.33 mknod F