1 /*
2  * @(#)check_wtmpx.c 0.02 beta 2001/06/27 NsFocus Copyleft 2001-2010
3  *------------------------------------------------------------------------
4  * File     : check_wtmpx.c
5  * Version  : 0.02 beta
6  * Platform : SPARC/Solaris 2.6/7
7  * Author   : NsFocus Security Team
8  *          : http://www.nsfocus.com
9  * Fix      : scz < mailto: scz@nsfocus.com >
10  * Compile  : gcc -Wall -O3 -o check_wtmpx check_wtmpx.c
11  *          : /usr/ccs/bin/strip check_wtmpx
12  *          : /usr/ccs/bin/mcs -d check_wtmpx
13  * Date     : 2001-06-27 11:36
14  */
15 #if !defined(__SunOS__) && !defined(SOLARIS2)
main()16 int main () { return 0; }
17 #else
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <sys/file.h>
22 #include <sys/time.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <pwd.h>
26 #include <time.h>
27 #include <utmp.h>
28 #include <utmpx.h>
29 #include <lastlog.h>
30 #include <fcntl.h>
31 #include <unistd.h>
32 
33 #define WTMP_FILENAME  "/var/adm/wtmp"
34 #define WTMPX_FILENAME "/var/adm/wtmpx"
35 
36 
37 struct file_utmp_entry
38 {
39     char        ut_user[8];     /* User login name              */
40     char        ut_id[4];       /* /etc/inittab id              */
41     char        ut_line[12];    /* device name (console, lnxx)  */
42     int16_t     ut_pid;         /* process id                   */
43     int16_t     ut_type;        /* type of entry                */
44     struct
45     {
46         int16_t e_termination;  /* Process termination status   */
47         int16_t e_exit;         /* Process exit status          */
48     } ut_exit;                  /* The exit status of a process */
49     uint32_t    ut_time;        /* time entry was made          */
50 };
51 
52 struct timeval_32
53 {
54     uint32_t tv_sec;   /* seconds          */
55     int32_t  tv_usec;  /* and microseconds */
56 };
57 
58 /*
59  * This data structure describes the utmp *file* contents using
60  * fixed-width data types.  It should only be used by the implementation.
61  *
62  * Applications should use the getutxent(3c) family of routines to interact
63  * with this database.
64  */
65 struct file_utmpx_entry
66 {
67     char              ut_user[32];   /* user login name                */
68     char              ut_id[4];      /* inittab id                     */
69     char              ut_line[32];   /* device name (console, lnxx)    */
70     uint32_t          ut_pid;        /* process id                     */
71     int16_t           ut_type;       /* type of entry                  */
72     struct
73     {
74         int16_t e_termination;       /* process termination status     */
75         int16_t e_exit;              /* process exit status            */
76     } ut_exit;                       /* exit status of a process       */
77     struct timeval_32 ut_tv;         /* time entry was made            */
78     int32_t           ut_session;    /* session ID, user for windowing */
79     int32_t           pad[5];        /* reserved for future use        */
80     int16_t           ut_syslen;     /* significant length of ut_host  */
81     char              ut_host[257];  /* remote host name               */
82 };
83 
usage(char * arg)84 static void usage ( char * arg )
85 {
86     fprintf( stderr, " Usage: %s [-h] [-w wtmp] [-x wtmpx]\n", arg );
87     exit( EXIT_FAILURE );
88 }  /* end of usage */
89 
main(int argc,char * argv[])90 int main ( int argc, char * argv[] )
91 {
92     int                     fd_wtmp, fd_wtmpx;
93     char                    filename_wtmp[128]  = WTMP_FILENAME;
94     char                    filename_wtmpx[128] = WTMPX_FILENAME;
95     ssize_t                 wtmp_bytes_read;
96     ssize_t                 wtmpx_bytes_read;
97     uint32_t                wtmp_read_counter   = 0;
98     uint32_t                wtmpx_read_counter  = 0;
99     int                     c;
100     struct file_utmp_entry  utmp_entry;
101     struct file_utmpx_entry utmpx_entry;
102 
103     opterr = 0;  /* Don't want getopt() writing to stderr */
104     while ( ( c = getopt( argc, argv, "hw:x:" ) ) != EOF )
105     {
106         switch ( c )
107         {
108         case 'w':
109             strncpy( filename_wtmp, optarg, 128 );
110             filename_wtmp[127]  = '\0';
111             break;
112         case 'x':
113             strncpy( filename_wtmpx, optarg, 128 );
114             filename_wtmpx[127] = '\0';
115             break;
116         case 'h':
117         case '?':
118             usage( argv[0] );
119             break;
120         }  /* end of switch */
121     }  /* end of while */
122 
123     fd_wtmp = open( filename_wtmp, O_RDONLY );
124     if ( fd_wtmp < 0 )
125     {
126         fprintf( stderr, "Unable to open %s\n", filename_wtmp );
127         return( EXIT_FAILURE );
128     }
129     fd_wtmpx = open( filename_wtmpx, O_RDONLY );
130     if ( fd_wtmpx < 0 )
131     {
132         fprintf( stderr, "Unable to open %s\n", filename_wtmpx );
133         close( fd_wtmp );
134         return( EXIT_FAILURE );
135     }
136     while ( 1 )
137     {
138         wtmpx_bytes_read = read( fd_wtmpx, &utmpx_entry, sizeof( struct file_utmpx_entry ) );
139         if ( wtmpx_bytes_read > 0 )
140         {
141             if ( wtmpx_bytes_read < sizeof( struct file_utmpx_entry ) )
142             {
143                 fprintf( stderr, "wtmpx entry may be corrupted\n" );
144                 break;
145             }
146             wtmpx_read_counter++;
147         }
148         wtmp_bytes_read = read( fd_wtmp, &utmp_entry, sizeof( struct file_utmp_entry ) );
149         if ( wtmp_bytes_read > 0 )
150         {
151             if ( wtmp_bytes_read < sizeof( struct file_utmp_entry ) )
152             {
153                 fprintf( stderr, "wtmp entry may be corrupted\n" );
154                 break;
155             }
156             wtmp_read_counter++;
157         }
158         if ( ( wtmpx_bytes_read <= 0 ) || ( wtmp_bytes_read <= 0 ) )
159         {
160             break;
161         }
162         if ( strncmp( utmp_entry.ut_user, utmpx_entry.ut_user, 8 ) != 0 )
163         {
164             fprintf( stderr, "[ %u ] ut_user %s <-> %s\n", wtmp_read_counter,
165                      utmp_entry.ut_user, utmpx_entry.ut_user );
166             break;
167         }
168         if ( memcmp( utmp_entry.ut_id, utmpx_entry.ut_id, 4 ) != 0 )
169         {
170             fprintf( stderr, "[ %u ] utmp_entry.ut_id != utmpx_entry.ut_id\n", wtmp_read_counter );
171             break;
172         }
173         if ( strcmp( utmp_entry.ut_line, utmpx_entry.ut_line ) != 0 )
174         {
175             fprintf( stderr, "[ %u ] ut_line %s <-> %s\n", wtmp_read_counter,
176                      utmp_entry.ut_line, utmpx_entry.ut_line );
177             break;
178         }
179         if ( utmp_entry.ut_pid != utmpx_entry.ut_pid )
180         {
181             fprintf( stderr, "[ %u ] ut_pid %d <-> %d\n", wtmp_read_counter,
182                      utmp_entry.ut_pid, utmpx_entry.ut_pid );
183             break;
184         }
185         if ( utmp_entry.ut_type != utmpx_entry.ut_type )
186         {
187             fprintf( stderr, "[ %u ] ut_type %d <-> %d\n", wtmp_read_counter,
188                      utmp_entry.ut_type, utmpx_entry.ut_type );
189             break;
190         }
191         if ( utmp_entry.ut_time != utmpx_entry.ut_tv.tv_sec )
192         {
193             fprintf( stderr, "[ %u ] ut_time %08X <-> %08X\n", wtmp_read_counter,
194                      utmp_entry.ut_time, utmpx_entry.ut_tv.tv_sec );
195             break;
196         }
197     }  /* end of while */
198     if ( wtmpx_read_counter != wtmp_read_counter )
199     {
200         fprintf( stderr, "wtmpx or wtmp entry may be deleted\n" );
201     }
202     close( fd_wtmpx );
203     close( fd_wtmp );
204     return( EXIT_SUCCESS );
205 }  /* end of main */
206 #endif
207