Blame SOURCES/0091-last-sync-utmp-strings-use-with-upstream-code.patch

edfd2c
From 25f7136d326753cb0bb7612a98db6542c9fdc3bd Mon Sep 17 00:00:00 2001
edfd2c
From: Karel Zak <kzak@redhat.com>
edfd2c
Date: Thu, 2 Feb 2023 15:22:52 +0100
edfd2c
Subject: last: sync utmp strings use with upstream code
edfd2c
edfd2c
Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=2160321
edfd2c
Signed-off-by: Karel Zak <kzak@redhat.com>
edfd2c
---
edfd2c
 include/strutils.h  | 30 +++++++++++++++++++
edfd2c
 include/timeutils.h |  1 +
edfd2c
 login-utils/last.c  | 73 +++++++++++++++++++++++----------------------
edfd2c
 3 files changed, 69 insertions(+), 35 deletions(-)
edfd2c
edfd2c
diff --git a/include/strutils.h b/include/strutils.h
edfd2c
index 5d07fcc7c..193f1acbc 100644
edfd2c
--- a/include/strutils.h
edfd2c
+++ b/include/strutils.h
edfd2c
@@ -65,6 +65,36 @@ static inline void xstrncpy(char *dest, const char *src, size_t n)
edfd2c
 	dest[n-1] = 0;
edfd2c
 }
edfd2c
 
edfd2c
+/* This is like strncpy(), but based on memcpy(), so compilers and static
edfd2c
+ * analyzers do not complain when sizeof(destination) is the same as 'n' and
edfd2c
+ * result is not terminated by zero.
edfd2c
+ *
edfd2c
+ * Use this function to copy string to logs with fixed sizes (wtmp/utmp. ...)
edfd2c
+ * where string terminator is optional.
edfd2c
+ */
edfd2c
+static inline void * __attribute__((nonnull (1)))
edfd2c
+str2memcpy(void *dest, const char *src, size_t n)
edfd2c
+{
edfd2c
+	size_t bytes = strlen(src) + 1;
edfd2c
+
edfd2c
+	if (bytes > n)
edfd2c
+		bytes = n;
edfd2c
+
edfd2c
+	memcpy(dest, src, bytes);
edfd2c
+	return dest;
edfd2c
+}
edfd2c
+
edfd2c
+static inline char * __attribute__((nonnull (1)))
edfd2c
+mem2strcpy(char *dest, const void *src, size_t n, size_t nmax)
edfd2c
+{
edfd2c
+	if (n + 1 > nmax)
edfd2c
+		n = nmax - 1;
edfd2c
+
edfd2c
+	memset(dest, '\0', nmax);
edfd2c
+	memcpy(dest, src, n);
edfd2c
+	return dest;
edfd2c
+}
edfd2c
+
edfd2c
 static inline int strdup_to_offset(void *stru, size_t offset, const char *str)
edfd2c
 {
edfd2c
 	char *n = NULL;
edfd2c
diff --git a/include/timeutils.h b/include/timeutils.h
edfd2c
index 230e6db5f..f1540a183 100644
edfd2c
--- a/include/timeutils.h
edfd2c
+++ b/include/timeutils.h
edfd2c
@@ -74,6 +74,7 @@ enum {
edfd2c
 	ISO_TIMESTAMP_COMMA_GT  = ISO_TIMESTAMP_COMMA_G | ISO_T
edfd2c
 };
edfd2c
 
edfd2c
+#define CTIME_BUFSIZ    26
edfd2c
 #define ISO_BUFSIZ	42
edfd2c
 
edfd2c
 int strtimeval_iso(struct timeval *tv, int flags, char *buf, size_t bufsz);
edfd2c
diff --git a/login-utils/last.c b/login-utils/last.c
edfd2c
index 80d77d20b..8f7c36984 100644
edfd2c
--- a/login-utils/last.c
edfd2c
+++ b/login-utils/last.c
edfd2c
@@ -339,15 +339,22 @@ static int time_formatter(int fmt, char *dst, size_t dlen, time_t *when)
edfd2c
 		break;
edfd2c
 	case LAST_TIMEFTM_HHMM:
edfd2c
 	{
edfd2c
-		struct tm *tm = localtime(when);
edfd2c
-		if (!snprintf(dst, dlen, "%02d:%02d", tm->tm_hour, tm->tm_min))
edfd2c
+		struct tm tm;
edfd2c
+
edfd2c
+		localtime_r(when, &tm;;
edfd2c
+		if (!snprintf(dst, dlen, "%02d:%02d", tm.tm_hour, tm.tm_min))
edfd2c
 			ret = -1;
edfd2c
 		break;
edfd2c
 	}
edfd2c
 	case LAST_TIMEFTM_CTIME:
edfd2c
-		snprintf(dst, dlen, "%s", ctime(when));
edfd2c
+	{
edfd2c
+		char buf[CTIME_BUFSIZ];
edfd2c
+
edfd2c
+		ctime_r(when, buf);
edfd2c
+		snprintf(dst, dlen, "%s", buf);
edfd2c
 		ret = rtrim_whitespace((unsigned char *) dst);
edfd2c
 		break;
edfd2c
+	}
edfd2c
 	case LAST_TIMEFTM_ISO8601:
edfd2c
 		ret = strtime_iso(when, ISO_TIMESTAMP_T, dst, dlen);
edfd2c
 		break;
edfd2c
@@ -394,8 +401,7 @@ static int list(const struct last_control *ctl, struct utmpx *p, time_t logout_t
edfd2c
 	/*
edfd2c
 	 *	uucp and ftp have special-type entries
edfd2c
 	 */
edfd2c
-	utline[0] = 0;
edfd2c
-	strncat(utline, p->ut_line, sizeof(p->ut_line));
edfd2c
+	mem2strcpy(utline, p->ut_line, sizeof(p->ut_line), sizeof(utline));
edfd2c
 	if (strncmp(utline, "ftp", 3) == 0 && isdigit(utline[3]))
edfd2c
 		utline[3] = 0;
edfd2c
 	if (strncmp(utline, "uucp", 4) == 0 && isdigit(utline[4]))
edfd2c
@@ -447,48 +453,48 @@ static int list(const struct last_control *ctl, struct utmpx *p, time_t logout_t
edfd2c
 
edfd2c
 	if (logout_time == currentdate) {
edfd2c
 		if (ctl->time_fmt > LAST_TIMEFTM_SHORT) {
edfd2c
-			sprintf(logouttime, "  still running");
edfd2c
+			snprintf(logouttime, sizeof(logouttime), "  still running");
edfd2c
 			length[0] = 0;
edfd2c
 		} else {
edfd2c
-			sprintf(logouttime, "  still");
edfd2c
-			sprintf(length, "running");
edfd2c
+			snprintf(logouttime, sizeof(logouttime), "  still");
edfd2c
+			snprintf(length, sizeof(length), "running");
edfd2c
 		}
edfd2c
 	} else if (days) {
edfd2c
-		sprintf(length, "(%d+%02d:%02d)", days, abs(hours), abs(mins)); /* hours and mins always shown as positive (w/o minus sign!) even if secs < 0 */
edfd2c
+		snprintf(length, sizeof(length), "(%d+%02d:%02d)", days, abs(hours), abs(mins)); /* hours and mins always shown as positive (w/o minus sign!) even if secs < 0 */
edfd2c
 	} else if (hours) {
edfd2c
-		sprintf(length, " (%02d:%02d)", hours, abs(mins));  /* mins always shown as positive (w/o minus sign!) even if secs < 0 */
edfd2c
+		snprintf(length, sizeof(length), " (%02d:%02d)", hours, abs(mins));  /* mins always shown as positive (w/o minus sign!) even if secs < 0 */
edfd2c
 	} else if (secs >= 0) {
edfd2c
-		sprintf(length, " (%02d:%02d)", hours, mins); 
edfd2c
+		snprintf(length, sizeof(length), " (%02d:%02d)", hours, mins);
edfd2c
 	} else {
edfd2c
-		sprintf(length, " (-00:%02d)", abs(mins));  /* mins always shown as positive (w/o minus sign!) even if secs < 0 */
edfd2c
+		snprintf(length, sizeof(length), " (-00:%02d)", abs(mins));  /* mins always shown as positive (w/o minus sign!) even if secs < 0 */
edfd2c
 	}
edfd2c
 
edfd2c
 	switch(what) {
edfd2c
 		case R_CRASH:
edfd2c
-			sprintf(logouttime, "- crash");
edfd2c
+			snprintf(logouttime, sizeof(logouttime), "- crash");
edfd2c
 			break;
edfd2c
 		case R_DOWN:
edfd2c
-			sprintf(logouttime, "- down ");
edfd2c
+			snprintf(logouttime, sizeof(logouttime), "- down ");
edfd2c
 			break;
edfd2c
 		case R_NOW:
edfd2c
 			if (ctl->time_fmt > LAST_TIMEFTM_SHORT) {
edfd2c
-				sprintf(logouttime, "  still logged in");
edfd2c
+				snprintf(logouttime, sizeof(logouttime), "  still logged in");
edfd2c
 				length[0] = 0;
edfd2c
 			} else {
edfd2c
-				sprintf(logouttime, "  still");
edfd2c
-				sprintf(length, "logged in");
edfd2c
+				snprintf(logouttime, sizeof(logouttime), "  still");
edfd2c
+				snprintf(length, sizeof(length), "logged in");
edfd2c
 			}
edfd2c
 			break;
edfd2c
 		case R_PHANTOM:
edfd2c
 			if (ctl->time_fmt > LAST_TIMEFTM_SHORT) {
edfd2c
-				sprintf(logouttime, "  gone - no logout");
edfd2c
+				snprintf(logouttime, sizeof(logouttime), "  gone - no logout");
edfd2c
 				length[0] = 0;
edfd2c
 			} else if (ctl->time_fmt == LAST_TIMEFTM_SHORT) {
edfd2c
-				sprintf(logouttime, "   gone");
edfd2c
-				sprintf(length, "- no logout");
edfd2c
+				snprintf(logouttime, sizeof(logouttime), "   gone");
edfd2c
+				snprintf(length, sizeof(length), "- no logout");
edfd2c
 			} else {
edfd2c
 				logouttime[0] = 0;
edfd2c
-				sprintf(length, "no logout");
edfd2c
+				snprintf(length, sizeof(length), "no logout");
edfd2c
 			}
edfd2c
 			break;
edfd2c
 		case R_TIMECHANGE:
edfd2c
@@ -508,15 +514,8 @@ static int list(const struct last_control *ctl, struct utmpx *p, time_t logout_t
edfd2c
 	r = -1;
edfd2c
 	if (ctl->usedns || ctl->useip)
edfd2c
 		r = dns_lookup(domain, sizeof(domain), ctl->useip, (int32_t*)p->ut_addr_v6);
edfd2c
-	if (r < 0) {
edfd2c
-		size_t sz = sizeof(p->ut_host);
edfd2c
-
edfd2c
-		if (sz > sizeof(domain))
edfd2c
-			sz = sizeof(domain);
edfd2c
-
edfd2c
-		xstrncpy(domain, p->ut_host, sz);
edfd2c
-	}
edfd2c
-
edfd2c
+	if (r < 0)
edfd2c
+		mem2strcpy(domain, p->ut_host, sizeof(p->ut_host), sizeof(domain));
edfd2c
 
edfd2c
 	if (ctl->showhost) {
edfd2c
 		if (!ctl->altlist) {
edfd2c
@@ -607,10 +606,11 @@ static int is_phantom(const struct last_control *ctl, struct utmpx *ut)
edfd2c
 
edfd2c
 	if (ut->ut_tv.tv_sec < ctl->boot_time.tv_sec)
edfd2c
 		return 1;
edfd2c
+	ut->ut_user[sizeof(ut->ut_user) - 1] = '\0';
edfd2c
 	pw = getpwnam(ut->ut_user);
edfd2c
 	if (!pw)
edfd2c
 		return 1;
edfd2c
-	sprintf(path, "/proc/%u/loginuid", ut->ut_pid);
edfd2c
+	snprintf(path, sizeof(path), "/proc/%u/loginuid", ut->ut_pid);
edfd2c
 	if (access(path, R_OK) == 0) {
edfd2c
 		unsigned int loginuid;
edfd2c
 		FILE *f = NULL;
edfd2c
@@ -624,8 +624,11 @@ static int is_phantom(const struct last_control *ctl, struct utmpx *ut)
edfd2c
 			return 1;
edfd2c
 	} else {
edfd2c
 		struct stat st;
edfd2c
+		char utline[sizeof(ut->ut_line) + 1];
edfd2c
+
edfd2c
+		mem2strcpy(utline, ut->ut_line, sizeof(ut->ut_line), sizeof(utline));
edfd2c
 
edfd2c
-		sprintf(path, "/dev/%s", ut->ut_line);
edfd2c
+		snprintf(path, sizeof(path), "/dev/%s", utline);
edfd2c
 		if (stat(path, &st))
edfd2c
 			return 1;
edfd2c
 		if (pw->pw_uid != st.st_uid)
edfd2c
@@ -736,7 +739,7 @@ static void process_wtmp_file(const struct last_control *ctl,
edfd2c
 		else {
edfd2c
 			if (ut.ut_type != DEAD_PROCESS &&
edfd2c
 			    ut.ut_user[0] && ut.ut_line[0] &&
edfd2c
-			    strcmp(ut.ut_user, "LOGIN") != 0)
edfd2c
+			    strncmp(ut.ut_user, "LOGIN", 5) != 0)
edfd2c
 				ut.ut_type = USER_PROCESS;
edfd2c
 			/*
edfd2c
 			 * Even worse, applications that write ghost
edfd2c
@@ -749,7 +752,7 @@ static void process_wtmp_file(const struct last_control *ctl,
edfd2c
 			/*
edfd2c
 			 * Clock changes.
edfd2c
 			 */
edfd2c
-			if (strcmp(ut.ut_user, "date") == 0) {
edfd2c
+			if (strncmp(ut.ut_user, "date", 4) == 0) {
edfd2c
 				if (ut.ut_line[0] == '|')
edfd2c
 					ut.ut_type = OLD_TIME;
edfd2c
 				if (ut.ut_line[0] == '{')
edfd2c
@@ -784,7 +787,7 @@ static void process_wtmp_file(const struct last_control *ctl,
edfd2c
 		case RUN_LVL:
edfd2c
 			x = ut.ut_pid & 255;
edfd2c
 			if (ctl->extended) {
edfd2c
-				sprintf(ut.ut_line, "(to lvl %c)", x);
edfd2c
+				snprintf(ut.ut_line, sizeof(ut.ut_line), "(to lvl %c)", x);
edfd2c
 				quit = list(ctl, &ut, lastrch, R_NORMAL);
edfd2c
 			}
edfd2c
 			if (x == '0' || x == '6') {
edfd2c
-- 
edfd2c
2.39.1
edfd2c