From: lantz moore <lmoore@debian.org>
Date: Thu, 3 Oct 2002 01:02:10 -0400
Subject: chklastlog
MIME-Version: 1.0
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: 8bit

  1. Make chklastlog support -q
	    Author:    lantz moore <lmoore@debian.org>
      Date:      Thu Oct 3 01:02:10 2002 -0400

      This makes chklastlog support -q, to suppress output.

      (A later patch to chkrootkit will pass -q through so that even more
      output is hidden if -q is passed to chkrootki).
Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=142422
Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=190978
Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=229869
Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=306263

  2. Fix compilation warnings
a) chklastlog: remove unused variable (pwdent never used)
    while ((pwdent = getpwent())) {
               ^        ~~~~~~~~~~

b) chklastlog: remove unused and shadowing variable
    chklastlog.c: In function ‘main’:
    chklastlog.c:109:10: error: declaration of ‘uid’ shadows a global declaration [-Werror=shadow]
      109 |  uid_t  *uid;
          |          ^~~
    chklastlog.c:79:8: note: shadowed declaration is here
       79 | uid_t *uid;
          |        ^~~

    chklastlog.c: In function ‘getslot’:
    chklastlog.c:295:48: error: declaration of ‘uid’ shadows a global declaration [-Werror=shadow]
      295 | int getslot(struct s_localpwd *localpwd, uid_t uid)
          |                                          ~~~~~~^~~
    chklastlog.c:79:8: note: shadowed declaration is here
       79 | uid_t *uid;
          |        ^~~

 c) chklastlog: resolve signed comparison
    This replaces an earlier patch by: Giuseppe Iuculano <giuseppe@iuculano.it>
    Date:   Sun Jul 9 18:42:55 2017 +0200

    chklastlog.c: In function ‘main’:
    chklastlog.c:169:33: error: comparison of integer expressions of different signedness: ‘long int’ and ‘long unsigned int’ [-Werror=sign-compare]
      169 |             if (wtmp_bytes_read < sizeof(struct utmp))
          |                                 ^
    chklastlog.c:189:45: error: comparison of integer expressions of different signedness: ‘long int’ and ‘long unsigned int’ [-Werror=sign-compare]
      189 |                         if (wtmp_bytes_read < sizeof(struct lastlog))
          |                                             ^

  d) chklastlog.c | 4 ++--
    chklastlog: silence array-bounds warning

    In file included from /usr/include/string.h:495,
                     from chklastlog.c:45:
    In function ‘memcpy’,
        inlined from ‘main’ at chklastlog.c:114:9:
    /usr/include/x86_64-linux-gnu/bits/string_fortified.h:34:10: error: ‘__builtin_memcpy’ forming offset [14, 126] is out of the bounds [0, 14] [-Werror=array-bounds]
       34 |   return __builtin___memcpy_chk (__dest, __src, __len, __bos0 (__dest));
          |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    In function ‘memcpy’,
        inlined from ‘main’ at chklastlog.c:115:9:
    /usr/include/x86_64-linux-gnu/bits/string_fortified.h:34:10: error: ‘__builtin_memcpy’ forming offset [17, 126] is out of the bounds [0, 17] [-Werror=array-bounds]
       34 |   return __builtin___memcpy_chk (__dest, __src, __len, __bos0 (__dest));
          |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

   e) chklastlog: fix out of bounds access - Found by Cppcheck

     We dereference userid at *uid, so *uid must be strictly smaller than userid' size.

        chklastlog.c:184:14: warning: Either the condition '*uid>99999' is redundant or the array 'userid[99999]' is accessed at index 99999, which is out of bounds. [arrayIndexOutOfBoundsCond]
          if (!userid[*uid])
                     ^
        chklastlog.c:178:26: note: Assuming that condition '*uid>99999' is not redundant
                        if (*uid > MAX_ID)
                             ^
        chklastlog.c:184:14: note: Array index out of bounds
          if (!userid[*uid])
                     ^

    2. (Author: richard.lewis.debiam@googleamail.com) Fix compilation on Android:
        Android does not use lastlog, but compilation was
        failing as there is no getpwent: make chklastlog do
        nothing on android, and add an error message so we do not silently do nothing)
        Also fix indentation.

    3. (Author: richard.lewis.debiam@googleamail.com) Fix compilation with gcc 15.
	    signal handlers must have one argument (which is unused here)

Forwarded: no
 (1-2 forwarded by email: 21 Dec 2024; 3 will be forwarded later)
---
 chklastlog.c | 357 ++++++++++++++++++++++++++++++-----------------------------
 1 file changed, 180 insertions(+), 177 deletions(-)

diff --git a/chklastlog.c b/chklastlog.c
index c895ff3..d30fa0d 100644
--- a/chklastlog.c
+++ b/chklastlog.c
@@ -25,7 +25,7 @@
    09/19/01 - Another Segfault in some systems fixed, Thanks to Andreas Tirok
    06/26/02 - Fix problem with maximum uid number - Thanks to Gerard van Wageningen
    07/02/02 - Minor fixes - Nelson Murilo, nmurilo@gmail.com
-   05/05/14 - Minor fixes - Klaus Steding-jessen 
+   05/05/14 - Minor fixes - Klaus Steding-jessen
 */
 
 #if defined(SOLARIS2) || defined(__linux__)
@@ -33,13 +33,12 @@
 #else
 #undef HAVE_LASTLOG_H
 #endif
-#if __FreeBSD__ > 9
-int main () { return 0; }
-#else
 #include <stdio.h>
-#ifdef __linux__
+#if __FreeBSD__ > 9 || defined(__ANDROID_API__)
+int main (void){ fprintf(stderr,"Unsupported operating system\n"); return 1; }
+#else
+
 #include <stdlib.h>
-#endif
 #include <sys/stat.h>
 #include <unistd.h>
 #include <string.h>
@@ -55,18 +54,10 @@ int main () { return 0; }
 #include <fcntl.h>
 #endif
 
-#ifdef __FreeBSD__ 
-#define WTMP_FILENAME "/var/log/wtmp"
-#define LASTLOG_FILENAME "/var/log/lastlog"
-#endif
-#ifdef __OpenBSD__
-#include <stdlib.h> 
-#define WTMP_FILENAME "/var/log/wtmp"
-#define LASTLOG_FILENAME "/var/log/lastlog"
-#endif
 #ifndef WTMP_FILENAME
 #define WTMP_FILENAME "/var/log/wtmp"
 #endif
+
 #ifndef LASTLOG_FILENAME
 #define LASTLOG_FILENAME "/var/log/lastlog"
 #endif
@@ -76,13 +67,12 @@ int main () { return 0; }
 
 long total_wtmp_bytes_read=0;
 size_t wtmp_file_size;
-uid_t *uid;
-void read_status();
+void read_status(int signum);
 
 struct s_localpwd {
-     int numentries;
-     uid_t *uid;
-     char  **uname;
+  int numentries;
+  uid_t *uid;
+  char **uname;
 };
 
 #ifndef SOLARIS2
@@ -95,202 +85,215 @@ int getslot(struct s_localpwd *, uid_t);
 
 #define MAX_ID 99999
 
-int main(int argc, char*argv[]) {
-	int		fh_wtmp;
-	int		fh_lastlog;
-	struct lastlog	lastlog_ent;
-	struct utmp	utmp_ent;
-	long		userid[MAX_ID];
-	long		i, slot;
-	int		status = 0;
-	long		wtmp_bytes_read;
-	struct stat	wtmp_stat;
-	struct s_localpwd	*localpwd;
-	uid_t		*uid;
-        char wtmpfile[128], lastlogfile[128];
+int main(int argc, char* argv[]) {
+  int fh_wtmp;
+  int fh_lastlog;
+  struct lastlog lastlog_ent;
+  struct utmp utmp_ent;
+  long userid[MAX_ID];
+  long i, slot;
+  int status = 0;
+  long wtmp_bytes_read;
+  struct stat wtmp_stat;
+  struct s_localpwd *localpwd;
+  uid_t* uid;
+  int quiet = 0;
 
-        memcpy(wtmpfile, WTMP_FILENAME, 127);
-        memcpy(lastlogfile, LASTLOG_FILENAME, 127);
+  char wtmpfile[128], lastlogfile[128];
 
-        while (--argc && ++argv) /* poor man getopt */
+  strncpy(wtmpfile, WTMP_FILENAME, 127);
+  strncpy(lastlogfile, LASTLOG_FILENAME, 127);
+
+  while (--argc && ++argv)
+    {
+      if (!memcmp("-f", *argv, 2))
+        {
+          if (!--argc)
+            break;
+          ++argv;
+          memcpy(wtmpfile, *argv, 127);
+        }
+      else if (!memcmp("-l", *argv, 2))
         {
-           if (!memcmp("-f", *argv, 2))
-           {
-              if (!--argc)
-                 break;
-              ++argv;
-              memcpy(wtmpfile, *argv, 127);
-           }
-           else if (!memcmp("-l", *argv, 2))
-           {
-              if (!--argc)
-                 break;
-              ++argv;
-              memcpy(lastlogfile, *argv, 127);
-           }
+          if (!--argc)
+            break;
+          ++argv;
+          memcpy(lastlogfile, *argv, 127);
         }
+      else if (!memcmp("-q", *argv, 2))
+        {
+          quiet = 1;
+        }
+    }
+
+  if (!quiet)
+    {
+      signal(SIGALRM, read_status);
+      alarm(5);
+    }
 
-	signal(SIGALRM, read_status);
-	alarm(5);
-	for (i=0; i<MAX_ID; i++)
-		userid[i]=FALSE;
+  for (i=0; i<MAX_ID; i++)
+    userid[i] = FALSE;
 
-	if ((fh_lastlog=open(lastlogfile,O_RDONLY)) < 0) {
-		fprintf(stderr, "unable to open lastlog-file %s\n", lastlogfile);
-		return(1);
-	}
+  if ((fh_lastlog=open(lastlogfile, O_RDONLY)) < 0)
+    {
+      fprintf(stderr, "unable to open lastlog file %s\n", lastlogfile);
+      return(1);
+    }
 
-	if ((fh_wtmp=open(wtmpfile,O_RDONLY)) < 0) {
-		fprintf(stderr, "unable to open wtmp-file %s\n", wtmpfile);
-		close(fh_lastlog);
-		return(2);
-	}
-	if (fstat(fh_wtmp,&wtmp_stat)) {
-		perror("chklastlog::main: ");
-		close(fh_lastlog);
-		close(fh_wtmp);
-		return(3);
-	}
-	wtmp_file_size = wtmp_stat.st_size;
+  if ((fh_wtmp=open(wtmpfile, O_RDONLY)) < 0)
+    {
+      fprintf(stderr, "unable to open wtmp file %s\n", wtmpfile);
+      close(fh_lastlog);
+      return(2);
+    }
+  if (fstat(fh_wtmp, &wtmp_stat))
+    {
+      perror("chklastlog::main: ");
+      close(fh_lastlog);
+      close(fh_wtmp);
+      return(3);
+    }
+  wtmp_file_size = wtmp_stat.st_size;
 
-	localpwd = read_pwd();
+  localpwd = read_pwd();
 
-	while ((wtmp_bytes_read = read (fh_wtmp, &utmp_ent, sizeof (struct utmp))) >0) {
-            if (wtmp_bytes_read < sizeof(struct utmp))
-            {
-               fprintf(stderr, "wtmp entry may be corrupted");
-               break;
-            }
-	    total_wtmp_bytes_read+=wtmp_bytes_read;
-	    if ( !nonuser(utmp_ent) && strncmp(utmp_ent.ut_line, "ftp", 3) &&
-		 (uid=localgetpwnam(localpwd,utmp_ent.ut_name)) != NULL )
-            {
-                if (*uid > MAX_ID)
-                {
-                   fprintf(stderr, "MAX_ID is %u and current uid is %u, please check\n\r", MAX_ID, *uid );
-                   exit (1);
+  while ((wtmp_bytes_read = read (fh_wtmp, &utmp_ent, sizeof (struct utmp))) >0) {
+    if ((size_t)wtmp_bytes_read < sizeof(struct utmp))
+      {
+        fprintf(stderr, "wtmp entry may be corrupted");
+        break;
+      }
+    total_wtmp_bytes_read+=wtmp_bytes_read;
+    if ( !nonuser(utmp_ent) && strncmp(utmp_ent.ut_line, "ftp", 3) &&
+         (uid=localgetpwnam(localpwd,utmp_ent.ut_name)) != NULL )
+      {
+        if (*uid >= MAX_ID)
+          {
+            fprintf(stderr, "MAX_ID is %lu and current uid is %lu, please check\n\r", (long int)MAX_ID, (long int)*uid );
+            exit (1);
 
-                }
-		if (!userid[*uid])
-                {
-		    lseek(fh_lastlog, (long)*uid * sizeof (struct lastlog), 0);
-		    if ((wtmp_bytes_read = read(fh_lastlog, &lastlog_ent, sizeof (struct lastlog))) > 0)
-                    {
-                        if (wtmp_bytes_read < sizeof(struct lastlog))
-                        {
-                           fprintf(stderr, "lastlog entry may be corrupted");
-                           break;
-                        }
-                        if (lastlog_ent.ll_time == 0)
-                        {
-                           if (-1 != (slot = getslot(localpwd, *uid)))
-                               printf("user %s deleted or never logged from lastlog!\n",
-                                NULL != localpwd->uname[slot] ?
-                                (char*)localpwd->uname[slot] : "(null)");
-                           else
-                              printf("deleted user uid(%d) not in passwd\n", *uid);
-                           ++status;
-                        }
-                        userid[*uid]=TRUE;
-                    }
-		}
-           }
-	}
+          }
+        if (!userid[*uid])
+          {
+            lseek(fh_lastlog, (long)*uid * sizeof (struct lastlog), 0);
+            if ((wtmp_bytes_read = read(fh_lastlog, &lastlog_ent, sizeof (struct lastlog))) > 0)
+              {
+                if ((size_t)wtmp_bytes_read < sizeof(struct lastlog))
+                  {
+                    fprintf(stderr, "lastlog entry may be corrupted");
+                    break;
+                  }
+                if (lastlog_ent.ll_time == 0)
+                  {
+                    if (-1 != (slot = getslot(localpwd, *uid)))
+                      printf("user %s deleted or never logged from lastlog!\n",
+                             NULL != localpwd->uname[slot] ?
+                             (char*)localpwd->uname[slot] : "(null)");
+                    else
+                      printf("deleted user uid(%d) not in passwd\n", *uid);
+                    ++status;
+                  }
+                userid[*uid]=TRUE;
+              }
+          }
+      }
+  }
 #if 0
-	printf("\n");
+  printf("\n");
 #endif
-	free_results(localpwd);
-	close(fh_wtmp);
-	close(fh_lastlog);
-	return(status);
+  free_results(localpwd);
+  close(fh_wtmp);
+  close(fh_lastlog);
+  return(status);
 }
 
 #ifndef SOLARIS2
 /* minimal funcionality of nonuser() */
 int nonuser(struct utmp utmp_ent)
 {
-   return (!memcmp(utmp_ent.ut_name, "shutdown", sizeof ("shutdown")));
+  return (!memcmp(utmp_ent.ut_name, "shutdown", sizeof ("shutdown")));
 }
 #endif
 
-void read_status() {
-   double remaining_time;
-   static long last_total_bytes_read=0;
-   int diff;
+void read_status(int __attribute__((unused)) signum) {
+  double remaining_time;
+  static long last_total_bytes_read=0;
+  int diff;
 
-   diff = total_wtmp_bytes_read-last_total_bytes_read;
-   if (diff == 0) diff = 1;
-   remaining_time=(wtmp_file_size-total_wtmp_bytes_read)*5/(diff);
-   last_total_bytes_read=total_wtmp_bytes_read;
+  diff = total_wtmp_bytes_read-last_total_bytes_read;
+  if (diff == 0) diff = 1;
+  remaining_time=(wtmp_file_size-total_wtmp_bytes_read)*5/(diff);
+  last_total_bytes_read=total_wtmp_bytes_read;
 
-   printf("Remaining time: %6.2f seconds\n", remaining_time);
-/*
-   signal(SIGALRM,read_status);
+  printf("Remaining time: %6.2f seconds\n", remaining_time);
+  /*
+    signal(SIGALRM,read_status);
 
-   alarm(5);
-*/
+    alarm(5);
+  */
 }
 
 struct s_localpwd *read_pwd() {
-   struct passwd *pwdent;
-   int numentries=0,i=0;
-   struct s_localpwd *localpwd;
+  struct passwd *pwdent;
+  int numentries=0,i=0;
+  struct s_localpwd *localpwd;
 
-   setpwent();
-   while ((pwdent = getpwent())) {
-	numentries++;
-   }
-   endpwent();
-   localpwd = (struct s_localpwd *)malloc((size_t)sizeof(struct s_localpwd));
-   localpwd->numentries=numentries;
-   localpwd->uid = (uid_t *)malloc((size_t)numentries*sizeof(uid_t));
-   localpwd->uname = (char **)malloc((size_t)numentries*sizeof(char *));
-   for (i=0;i<numentries;i++) {
-      localpwd->uname[i] = (char *)malloc((size_t)30*sizeof(char));
-   }
-   i=0;
-   setpwent();
-   while ((pwdent = getpwent()) && (i<numentries)) {
-	localpwd->uid[i]=pwdent->pw_uid;
-        memcpy(localpwd->uname[i],pwdent->pw_name,(strlen(pwdent->pw_name)>29)?29:strlen(pwdent->pw_name)+1);
-	i++;
-   }
-   endpwent();
-   return(localpwd);
+  setpwent();
+  while (getpwent()) {
+    numentries++;
+  }
+  endpwent();
+  localpwd = (struct s_localpwd *)malloc((size_t)sizeof(struct s_localpwd));
+  localpwd->numentries=numentries;
+  localpwd->uid = (uid_t *)malloc((size_t)numentries*sizeof(uid_t));
+  localpwd->uname = (char **)malloc((size_t)numentries*sizeof(char *));
+  for (i=0;i<numentries;i++) {
+    localpwd->uname[i] = (char *)malloc((size_t)30*sizeof(char));
+  }
+  i=0;
+  setpwent();
+  while ((pwdent = getpwent()) && (i<numentries)) {
+    localpwd->uid[i]=pwdent->pw_uid;
+    memcpy(localpwd->uname[i],pwdent->pw_name,(strlen(pwdent->pw_name)>29)?29:strlen(pwdent->pw_name)+1);
+    i++;
+  }
+  endpwent();
+  return(localpwd);
 }
 
 void free_results(struct s_localpwd *localpwd) {
-   int i;
-   free(localpwd->uid);
-   for (i=0;i<(localpwd->numentries);i++) {
-      free(localpwd->uname[i]);
-   }
-   free(localpwd->uname);
-   free(localpwd);
+  int i;
+  free(localpwd->uid);
+  for (i=0;i<(localpwd->numentries);i++) {
+    free(localpwd->uname[i]);
+  }
+  free(localpwd->uname);
+  free(localpwd);
 }
 
 uid_t *localgetpwnam(struct s_localpwd *localpwd, char *username) {
-   int i;
-   size_t len;
+  int i;
+  size_t len;
 
-   for (i=0; i<(localpwd->numentries);i++) {
-      len = (strlen(username)>29)?30:strlen(username)+1;
-      if (!memcmp(username,localpwd->uname[i],len)) {
-	return &(localpwd->uid[i]);
-      }
-   }
-   return NULL;
+  for (i=0; i<(localpwd->numentries);i++) {
+    len = (strlen(username)>29)?30:strlen(username)+1;
+    if (!memcmp(username,localpwd->uname[i],len)) {
+      return &(localpwd->uid[i]);
+    }
+  }
+  return NULL;
 }
 
 int getslot(struct s_localpwd *localpwd, uid_t uid)
 {
-        int i;
+  int i;
 
-        for (i=0; i<(localpwd->numentries);i++)
-        {
-                if (localpwd->uid[i] == uid)
-                        return i;
-        }
-        return -1;
+  for (i=0; i<(localpwd->numentries);i++)
+    {
+      if (localpwd->uid[i] == uid)
+        return i;
+    }
+  return -1;
 }
 #endif
