Package: shadow
Severity: wishlist
Version: 1:4.4-4
Tags: patch
User: reproducible-bui...@lists.alioth.debian.org
Usertags: toolchain
X-Debbugs-Cc: reproducible-b...@lists.alioth.debian.org

Hi,

Attached is the following:

  commit 2dd84b0ee31e44dc51cba7b7cdc8657bf9ff0a31
  Author: Chris Lamb <la...@debian.org>
  Date:   Wed Mar 15 11:35:35 2017 +0100
  
      Make the sp_lstchg shadow field reproducible.
      
      The third field in the /etc/shadow file (sp_lstchg) contains the date of
      the last password change expressed as the number of days since Jan 1, 
1970.
      As this is a relative time, creating a user today will result in:
      
         username:17238:0:99999:7:::
      
      whilst creating the same user tomorrow will result in:
      
         username:17239:0:99999:7:::
      
      This has an impact for the Reproducible Builds[0] project where we aim to
      be independent of as many elements the build environment as possible,
      including the current date.
      
      This patch changes the behaviour to use the SOURCE_DATE_EPOCH[1]
      environment variable (instead of Jan 1, 1970) if available.
      
       [0] https://reproducible-builds.org/
       [1] https://reproducible-builds.org/specs/source-date-epoch/
      
      Signed-off-by: Chris Lamb <la...@debian.org>
  
   lib/prototypes.h    |  3 ++
   libmisc/Makefile.am |  1 +
   libmisc/gettime.c   | 86 
+++++++++++++++++++++++++++++++++++++++++++++++++++++
   src/chpasswd.c      |  2 +-
   src/newusers.c      |  4 +--
   src/passwd.c        |  2 +-
   src/useradd.c       |  2 +-
   src/usermod.c       |  4 +--
   8 files changed, 97 insertions(+), 7 deletions(-)


Regards,

-- 
      ,''`.
     : :'  :     Chris Lamb
     `. `'`      la...@debian.org / chris-lamb.co.uk
       `-
>From 2dd84b0ee31e44dc51cba7b7cdc8657bf9ff0a31 Mon Sep 17 00:00:00 2001
From: Chris Lamb <la...@debian.org>
Date: Wed, 15 Mar 2017 11:35:35 +0100
Subject: [PATCH] Make the sp_lstchg shadow field reproducible.

The third field in the /etc/shadow file (sp_lstchg) contains the date of
the last password change expressed as the number of days since Jan 1, 1970.
As this is a relative time, creating a user today will result in:

   username:17238:0:99999:7:::

whilst creating the same user tomorrow will result in:

   username:17239:0:99999:7:::

This has an impact for the Reproducible Builds[0] project where we aim to
be independent of as many elements the build environment as possible,
including the current date.

This patch changes the behaviour to use the SOURCE_DATE_EPOCH[1]
environment variable (instead of Jan 1, 1970) if available.

 [0] https://reproducible-builds.org/
 [1] https://reproducible-builds.org/specs/source-date-epoch/

Signed-off-by: Chris Lamb <la...@debian.org>
---
 lib/prototypes.h    |  3 ++
 libmisc/Makefile.am |  1 +
 libmisc/gettime.c   | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/chpasswd.c      |  2 +-
 src/newusers.c      |  4 +--
 src/passwd.c        |  2 +-
 src/useradd.c       |  2 +-
 src/usermod.c       |  4 +--
 8 files changed, 97 insertions(+), 7 deletions(-)
 create mode 100644 libmisc/gettime.c

diff --git a/lib/prototypes.h b/lib/prototypes.h
index 7aaf1a6..4808d5d 100644
--- a/lib/prototypes.h
+++ b/lib/prototypes.h
@@ -179,6 +179,9 @@ extern int getrange (char *range,
                      unsigned long *min, bool *has_min,
                      unsigned long *max, bool *has_max);
 
+/* gettime.c */
+extern time_t gettime ();
+
 /* get_uid.c */
 extern int get_uid (const char *uidstr, uid_t *uid);
 
diff --git a/libmisc/Makefile.am b/libmisc/Makefile.am
index 76f3c05..e691dac 100644
--- a/libmisc/Makefile.am
+++ b/libmisc/Makefile.am
@@ -31,6 +31,7 @@ libmisc_a_SOURCES = \
 	getdate.y \
 	getgr_nam_gid.c \
 	getrange.c \
+	gettime.c \
 	hushed.c \
 	idmapping.h \
 	idmapping.c \
diff --git a/libmisc/gettime.c b/libmisc/gettime.c
new file mode 100644
index 0000000..b0c539b
--- /dev/null
+++ b/libmisc/gettime.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2017, Chris Lamb
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the copyright holders or contributors may not be used to
+ *    endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#ident "$Id$"
+
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include "defines.h"
+#include "prototypes.h"
+
+/*
+ * gettime() returns the time as the number of seconds since the Epoch
+ *
+ * Like time(), gettime() returns the time as the number of seconds since the
+ * Epoch, 1970-01-01 00:00:00 +0000 (UTC), except that if the SOURCE_DATE_EPOCH
+ * environment variable is exported it will use that instead.
+ */
+/*@observer@*/time_t gettime ()
+{
+	char *endptr;
+	char *source_date_epoch;
+	unsigned long long epoch;
+
+	source_date_epoch = getenv ("SOURCE_DATE_EPOCH");
+	if (!source_date_epoch)
+		return time (NULL);
+
+	errno = 0;
+	epoch = strtoull (source_date_epoch, &endptr, 10);
+	if ((errno == ERANGE && (epoch == ULLONG_MAX || epoch == 0))
+			|| (errno != 0 && epoch == 0)) {
+		fprintf (stderr,
+		         _("Environment variable $SOURCE_DATE_EPOCH: strtoull: %s\n"),
+			 strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+	if (endptr == source_date_epoch) {
+		fprintf (stderr,
+		         _("Environment variable $SOURCE_DATE_EPOCH: No digits were found: %s\n"),
+			 endptr);
+		exit(EXIT_FAILURE);
+	}
+	if (*endptr != '\0') {
+		fprintf (stderr,
+		         _("Environment variable $SOURCE_DATE_EPOCH: Trailing garbage: %s\n"),
+			 endptr);
+		exit(EXIT_FAILURE);
+	}
+	if (epoch > ULONG_MAX) {
+		fprintf (stderr,
+		         _("Environment variable $SOURCE_DATE_EPOCH: value must be smaller than or equal to %lu but was found to be: %llu \n"),
+			 ULONG_MAX, epoch);
+		exit(EXIT_FAILURE);
+	}
+
+	return (time_t)epoch;
+}
diff --git a/src/chpasswd.c b/src/chpasswd.c
index 21008f5..f985672 100644
--- a/src/chpasswd.c
+++ b/src/chpasswd.c
@@ -552,7 +552,7 @@ int main (int argc, char **argv)
 		if (NULL != sp) {
 			newsp = *sp;
 			newsp.sp_pwdp = cp;
-			newsp.sp_lstchg = (long) time ((time_t *)NULL) / SCALE;
+			newsp.sp_lstchg = (long) gettime () / SCALE;
 			if (0 == newsp.sp_lstchg) {
 				/* Better disable aging than requiring a
 				 * password change */
diff --git a/src/newusers.c b/src/newusers.c
index 724cbb4..2b0c693 100644
--- a/src/newusers.c
+++ b/src/newusers.c
@@ -496,7 +496,7 @@ static int add_passwd (struct passwd *pwd, const char *password)
 			}
 			spent.sp_pwdp = cp;
 		}
-		spent.sp_lstchg = (long) time ((time_t *) 0) / SCALE;
+		spent.sp_lstchg = (long) gettime () / SCALE;
 		if (0 == spent.sp_lstchg) {
 			/* Better disable aging than requiring a password
 			 * change */
@@ -553,7 +553,7 @@ static int add_passwd (struct passwd *pwd, const char *password)
 	 */
 	spent.sp_pwdp = "!";
 #endif
-	spent.sp_lstchg = (long) time ((time_t *) 0) / SCALE;
+	spent.sp_lstchg = (long) gettime () / SCALE;
 	if (0 == spent.sp_lstchg) {
 		/* Better disable aging than requiring a password change */
 		spent.sp_lstchg = -1;
diff --git a/src/passwd.c b/src/passwd.c
index 1191111..3af3e65 100644
--- a/src/passwd.c
+++ b/src/passwd.c
@@ -668,7 +668,7 @@ static void update_shadow (void)
 	}
 #ifndef USE_PAM
 	if (do_update_age) {
-		nsp->sp_lstchg = (long) time ((time_t *) 0) / SCALE;
+		nsp->sp_lstchg = (long) gettime () / SCALE;
 		if (0 == nsp->sp_lstchg) {
 			/* Better disable aging than requiring a password
 			 * change */
diff --git a/src/useradd.c b/src/useradd.c
index fefa234..d7bde8f 100644
--- a/src/useradd.c
+++ b/src/useradd.c
@@ -825,7 +825,7 @@ static void new_spent (struct spwd *spent)
 	memzero (spent, sizeof *spent);
 	spent->sp_namp = (char *) user_name;
 	spent->sp_pwdp = (char *) user_pass;
-	spent->sp_lstchg = (long) time ((time_t *) 0) / SCALE;
+	spent->sp_lstchg = (long) gettime () / SCALE;
 	if (0 == spent->sp_lstchg) {
 		/* Better disable aging than requiring a password change */
 		spent->sp_lstchg = -1;
diff --git a/src/usermod.c b/src/usermod.c
index 687487d..db8c0a8 100644
--- a/src/usermod.c
+++ b/src/usermod.c
@@ -641,7 +641,7 @@ static void new_spent (struct spwd *spent)
 	spent->sp_pwdp = new_pw_passwd (spent->sp_pwdp);
 
 	if (pflg) {
-		spent->sp_lstchg = (long) time ((time_t *) 0) / SCALE;
+		spent->sp_lstchg = (long) gettime () / SCALE;
 		if (0 == spent->sp_lstchg) {
 			/* Better disable aging than requiring a password
 			 * change. */
@@ -1673,7 +1673,7 @@ static void usr_update (void)
 			spent.sp_pwdp   = xstrdup (pwent.pw_passwd);
 			pwent.pw_passwd = xstrdup (SHADOW_PASSWD_STRING);
 
-			spent.sp_lstchg = (long) time ((time_t *) 0) / SCALE;
+			spent.sp_lstchg = (long) gettime () / SCALE;
 			if (0 == spent.sp_lstchg) {
 				/* Better disable aging than
 				 * requiring a password change */
-- 
2.11.0

Reply via email to