1 /**************************************
2  **
3  ** PARSER RULES
4  **
5  ** (a) must set record->host
6  **     (eventually to dummy value)
7  **
8  ** (b) must set record->prefix
9  **     (command)
10  **
11  **
12  **************************************/
13 
14 /* Based on the GNU Accounting Utilities, which is distributed with the
15  * following copyright:
16  */
17 
18 /* Copyright (C) 1993, 1996, 1997, 2003, 2005 Free Software Foundation, Inc.
19  *
20  * This file is part of the GNU Accounting Utilities
21  *
22  * The GNU Accounting Utilities are free software; you can redistribute
23  * them and/or modify them under the terms of the GNU General Public
24  * License as published by the Free Software Foundation; either version
25  * 2, or (at your option) any later version.
26  *
27  * The GNU Accounting Utilities are distributed in the hope that they will
28  * be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
29  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
30  * General Public License for more details.
31  *
32  * You should have received a copy of the GNU General Public License
33  * along with the GNU Accounting Utilities; see the file COPYING.  If
34  * not, write to the Free Software Foundation, 675 Mass Ave, Cambridge,
35  * MA 02139, USA.  */
36 
37 #include "config_xor.h"
38 
39 #include <ctype.h>
40 #include <string.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <sys/types.h>
44 #include <sys/stat.h>
45 #include <unistd.h>
46 #include <pwd.h>
47 #include <dirent.h>
48 
49 #if defined(USE_LOGFILE_MONITOR) && defined(HAVE_SYS_ACCT_H)
50 
51 #include <sys/acct.h>
52 
53 #include "samhain.h"
54 #include "sh_pthread.h"
55 #include "sh_log_check.h"
56 #include "sh_utils.h"
57 #include "sh_string.h"
58 
59 #undef  FIL__
60 #define FIL__  _("sh_log_parse_pacct.c")
61 
62 extern int flag_err_debug;
63 
64 #ifndef ACCT_COMM
65 #define ACCT_COMM 16
66 #endif
67 #ifndef AHZ
68 #define AHZ 100
69 #endif
70 
71 #if defined(ACUTIME_COMPT) || defined(ACSTIME_COMPT) || defined(ACETIME_COMPT)
comp_t_2_double(comp_t ct)72 static double comp_t_2_double (comp_t ct)
73 {
74   unsigned long out = 0;
75 
76   out = ct & 017777;
77   ct >>= 13;
78 
79   while (ct) {
80     ct--;
81     out <<= 3;
82   }
83 
84   return (double) out;
85 }
86 #endif
87 
88 #ifdef ACUTIME_COMPT
89 # define ACUTIME_2_DOUBLE(x) (comp_t_2_double(x))
90 #else
91 # define ACUTIME_2_DOUBLE(x) ((double)(x))
92 #endif
93 
94 #ifdef ACSTIME_COMPT
95 # define ACSTIME_2_DOUBLE(x) (comp_t_2_double(x))
96 #else
97 # define ACSTIME_2_DOUBLE(x) ((double)(x))
98 #endif
99 
100 #ifdef ACETIME_COMPT
101 # define ACETIME_2_DOUBLE(x) (comp_t_2_double(x))
102 #else
103 # define ACETIME_2_DOUBLE(x) ((double)(x))
104 #endif
105 
106 
expand_flags(char flag,char * out)107 static void expand_flags(char flag, char * out)
108 {
109   int i = 0;
110 
111 #define	BIT(flg, ch)	if (flag & flg) out[i] = ch; else out[i] = ' '; ++i
112 
113   BIT(ASU, 'S');
114   BIT(AFORK, 'F');
115 #ifdef ACOMPAT
116   BIT(ACOMPAT, 'C');
117 #endif
118 #ifdef ACORE
119   BIT(ACORE, 'D');
120 #endif
121 #ifdef AXSIG
122   BIT(AXSIG, 'X');
123 #endif
124 
125   out[i] = '\0';
126   return;
127 }
128 
uid_name(int uid)129 static char * uid_name (int uid)
130 {
131   static int  userid   = 0;
132   static char user[16] = "";
133 
134   if (uid == userid && user[0] != '\0')
135     {
136       return user;
137     }
138   else
139     {
140       struct passwd *thispw = getpwuid (uid);
141       if (thispw)
142 	sl_strlcpy (user, thispw->pw_name, sizeof(user));
143       else
144 	sl_snprintf(user, sizeof(user), "%d", uid);
145       user[sizeof(user)-1] = '\0';
146       userid = uid;
147     }
148   return user;
149 }
150 
151 struct dev_struct {
152   char * device;
153   long   dev_id;
154   struct dev_struct * next;
155 };
156 static struct dev_struct * devicelist = NULL;
157 
add_devices(const char * dir)158 static void add_devices(const char * dir)
159 {
160   DIR *  mdir;
161   char   dirl[256];
162 
163   sl_strlcpy(dirl, dir, sizeof(dirl));
164   dirl[sizeof(dirl)-1] = '\0';
165 
166   mdir = opendir(dir);
167 
168   if (mdir)
169     {
170       char * path;
171       size_t len;
172       struct dirent * dent;
173       struct stat buf;
174 
175       while (NULL != (dent = readdir(mdir)))
176 	{
177 	  if (0 == strcmp(dent->d_name, "."))
178 	    continue;
179 	  if (0 == strcmp(dent->d_name, ".."))
180 	    continue;
181 	  len = strlen(dir) + strlen(dent->d_name) + 2;
182 	  path = SH_ALLOC(len);
183 	  snprintf(path, len, "%s/%s", dir, dent->d_name);
184 	  if (0 == lstat(path, &buf) && S_ISCHR(buf.st_mode))
185 	    {
186 	      struct dev_struct * dstruct;
187 	      dstruct = SH_ALLOC(sizeof(struct dev_struct));
188 	      /* eliminate leading '/dev/' */
189 	      memmove(path, &path[5], strlen(path)-4);
190 	      dstruct->device = path;
191 	      dstruct->dev_id = buf.st_rdev;
192 	      dstruct->next   = devicelist;
193 	      devicelist      = dstruct;
194 	    }
195 	  else
196 	    {
197 	      SH_FREE(path);
198 	    }
199 	}
200       closedir(mdir);
201     }
202   return;
203 }
204 
dev_name(long tty)205 static char * dev_name(long tty)
206 {
207   struct dev_struct * dstruct;
208 
209   if (!devicelist)
210     {
211       add_devices("/dev");
212       add_devices("/dev/pts");
213       add_devices("/dev/pty");
214       add_devices("/dev/ptym");
215     }
216 
217   dstruct = devicelist;
218   while (dstruct)
219     {
220       if (dstruct->dev_id == tty)
221 	return dstruct->device;
222       dstruct = dstruct->next;
223     }
224   return "??";
225 }
226 
227 #if defined(__linux__) && defined(HAVE_ACCT_V3)
228 #  define STRUCT_ACCT struct acct_v3
229 #elif defined(__FreeBSD__) && defined(HAVE_ACCTV2)
230 #  define STRUCT_ACCT struct acctv2
231 #else
232 #  define STRUCT_ACCT struct acct
233 #endif
234 
235 /* This looks strange, but it's real ANSI C. */
236 extern STRUCT_ACCT pacct_rd_never_used;
237 #define COMM_LEN ((int) sizeof (pacct_rd_never_used.ac_comm))
238 
sh_read_pacct(sh_string * record,struct sh_logfile * logfile)239 sh_string * sh_read_pacct (sh_string * record, struct sh_logfile * logfile)
240 {
241   STRUCT_ACCT rec;
242 
243   if (NULL != sh_binary_reader ((void*) &rec, sizeof(STRUCT_ACCT), logfile))
244     {
245       time_t btime = (time_t) rec.ac_btime;
246       double ut    = ACUTIME_2_DOUBLE (rec.ac_utime);
247       double st    = ACSTIME_2_DOUBLE (rec.ac_stime);
248       char   fl[6];
249       char   comm[COMM_LEN+1];
250       int    i;
251       char   out[64+COMM_LEN+1+5+8+8+32+4+19+7]; /* see printf format below */
252 
253 #if defined(ac_flagx)
254       expand_flags(rec.ac_flagx, fl);
255 #else
256       expand_flags(rec.ac_flag,  fl);
257 #endif
258 
259       /* ac_comm may not be null terminated
260        */
261       for (i = 0; i < COMM_LEN; i++)
262 	{
263 	  if (rec.ac_comm[i] == '\0')
264 	    {
265 	      comm[i] = '\0';
266 	      break;
267 	    }
268 	  if (! isprint (rec.ac_comm[i]))
269 	    comm[i] = '?';
270 	  else
271 	    comm[i] = rec.ac_comm[i];
272 	}
273       comm[COMM_LEN] = '\0';
274 
275       sl_snprintf (out, sizeof(out),
276 		   "%ld:%-*.*s %5.5s %-8.8s %-8.8s %6.2f secs %-19.19s",
277 		   btime,
278 		   COMM_LEN, COMM_LEN, comm, fl,
279 		   uid_name(rec.ac_uid),
280 		   dev_name((long)rec.ac_tty),
281 		   ((ut + st) / (double) AHZ),
282 		   ctime (&btime));
283 
284 
285       sh_string_set_from_char(record, out);
286       return record;
287     }
288 
289   if (record)
290     sh_string_destroy(&record);
291   return NULL;
292 }
293 
294 void * sh_dummy_294_record = NULL;
295 
sh_parse_pacct(sh_string * logline,void * fileinfo)296 struct sh_logrecord * sh_parse_pacct (sh_string * logline, void * fileinfo)
297 {
298   char * p;
299   char * endptr;
300   unsigned long ltime;
301   struct sh_logrecord * record = NULL;
302 
303   (void) fileinfo;
304 
305   sh_dummy_294_record = (void *) &record;
306 
307   if (sh_string_len(logline) > 0 && flag_err_debug == S_TRUE)
308     {
309       SH_MUTEX_LOCK(mutex_thread_nolog);
310       sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, 0, MSG_E_SUBGEN,
311 		      sh_string_str(logline),
312 		      _("sh_parse_pacct"));
313       SH_MUTEX_UNLOCK(mutex_thread_nolog);
314     }
315 
316   p = strchr(sh_string_str(logline), ':');
317 
318   if (!p || p == sh_string_str(logline))
319     return NULL;
320 
321   ltime = strtoul(sh_string_str(logline), &endptr, 10);
322   if (p != endptr)
323     return NULL;
324 
325   ++p; /* points to first char of pacct record */
326 
327   if (*p != '\0')
328     {
329       size_t lengths[7];
330       unsigned int  fields = 7;
331       char ** array;
332       sh_string * message = sh_string_new_from_lchar(p, strlen(p));
333       array = split_array_ws(p, &fields, lengths);
334 
335       if (fields == 7)
336 	{
337 	  record = SH_ALLOC(sizeof(struct sh_logrecord));
338 
339 	  record->timestamp = ltime;
340 	  record->timestr   = sh_string_new_from_lchar(array[6], lengths[6]);
341 	  record->message   = message;
342 	  record->pid       = 0;
343 	  record->host      = sh_string_new_from_lchar(sh.host.name, strlen(sh.host.name));
344 	}
345       else
346 	{
347 	  sh_string_destroy(&message);
348 	}
349       SH_FREE(array);
350     }
351   return record;
352 }
353 /* USE_LOGFILE_MONITOR */
354 #endif
355