1 /* Copyright (C) 2009 Trend Micro Inc.
2  * All rights reserved.
3  *
4  * This program is a free software; you can redistribute it
5  * and/or modify it under the terms of the GNU General Public
6  * License (version 2) as published by the FSF - Free Software
7  * Foundation.
8  */
9 
10 /* Read DJB multilog */
11 
12 #include "shared.h"
13 #include "logcollector.h"
14 
15 
16 /* To translate between month (int) to month (char) */
17 static const char *(djb_month[]) = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
18                                     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
19                                    };
20 static char djb_host[512 + 1];
21 
22 
23 /* Initialize multilog */
init_djbmultilog(int pos)24 int init_djbmultilog(int pos)
25 {
26     char *djbp_name = NULL;
27     char *tmp_str = NULL;
28 
29     logff[pos].djb_program_name = NULL;
30 
31     /* Initialize hostname */
32     memset(djb_host, '\0', 512 + 1);
33 
34 #ifndef WIN32
35     if (gethostname(djb_host, 512 - 1) != 0) {
36         strncpy(djb_host, "unknown", 512 - 1);
37     } else {
38         char *_ltmp;
39 
40         /* Remove domain part if available */
41         _ltmp = strchr(djb_host, '.');
42         if (_ltmp) {
43             *_ltmp = '\0';
44         }
45     }
46 #else
47     strncpy(djb_host, "win32", 512 - 1);
48 #endif
49 
50     /* Multilog must be in the following format: /path/program_name/current */
51     tmp_str = strrchr(logff[pos].file, '/');
52     if (!tmp_str) {
53         return (0);
54     }
55 
56     /* Must end with /current and must not be in the beginning of the string */
57     if ((strcmp(tmp_str, "/current") != 0) || (tmp_str == logff[pos].file)) {
58         return (0);
59     }
60 
61     tmp_str[0] = '\0';
62 
63     /* Get final name */
64     djbp_name = strrchr(logff[pos].file, '/');
65     if (djbp_name == logff[pos].file) {
66         tmp_str[0] = '/';
67         return (0);
68     }
69 
70     os_strdup(djbp_name + 1, logff[pos].djb_program_name);
71     tmp_str[0] = '/';
72 
73     verbose("%s: INFO: Using program name '%s' for DJB multilog file: '%s'.",
74             ARGV0, logff[pos].djb_program_name, logff[pos].file);
75 
76     return (1);
77 }
78 
read_djbmultilog(int pos,int * rc,int drop_it)79 void *read_djbmultilog(int pos, int *rc, int drop_it)
80 {
81     size_t str_len = 0;
82     int need_clear = 0;
83     char *p;
84     char str[OS_MAXSTR + 1];
85     char buffer[OS_MAXSTR + 1];
86 
87     str[OS_MAXSTR] = '\0';
88     *rc = 0;
89 
90     /* Must have a valid program name */
91     if (!logff[pos].djb_program_name) {
92         return (NULL);
93     }
94 
95     /* Get new entry */
96     while (fgets(str, OS_MAXSTR - OS_LOG_HEADER, logff[pos].fp) != NULL) {
97         /* Get buffer size */
98         str_len = strlen(str);
99 
100         /* Getting the last occurrence of \n */
101         if ((p = strrchr(str, '\n')) != NULL) {
102             *p = '\0';
103 
104             /* If need_clear is set, we just get the line and ignore it */
105             if (need_clear) {
106                 need_clear = 0;
107                 continue;
108             }
109         } else {
110             need_clear = 1;
111         }
112 
113         /* Multilog messages have the following format:
114          * @40000000463246020c2ca16c xx...
115          */
116         if ((str_len > 26) &&
117                 (str[0] == '@') &&
118                 isalnum((int)str[1]) &&
119                 isalnum((int)str[2]) &&
120                 isalnum((int)str[3]) &&
121                 isalnum((int)str[24]) &&
122                 (str[25] == ' ')) {
123             /* Remove spaces and tabs */
124             p = str + 26;
125             while (*p == ' ' || *p == '\t') {
126                 p++;
127             }
128 
129             /* If message has a valid syslog header, send as is */
130             if ((str_len > 44) &&
131                     (p[3] == ' ') &&
132                     (p[6] == ' ') &&
133                     (p[9] == ':') &&
134                     (p[12] == ':') &&
135                     (p[15] == ' ')) {
136                 p += 16;
137                 strncpy(buffer, p, OS_MAXSTR);
138             } else {
139                 /* We will add a proper syslog header */
140                 time_t djbtime;
141                 struct tm *pt;
142 
143                 djbtime = time(NULL);
144                 pt = localtime(&djbtime);
145 
146                 /* Syslog time: Apr 27 14:50:32  */
147                 snprintf(buffer, OS_MAXSTR, "%s %02d %02d:%02d:%02d %s %s: %s",
148                          djb_month[pt->tm_mon],
149                          pt->tm_mday,
150                          pt->tm_hour,
151                          pt->tm_min,
152                          pt->tm_sec,
153                          djb_host,
154                          logff[pos].djb_program_name,
155                          p);
156             }
157         }
158 
159         else {
160             debug2("%s: DEBUG: Invalid DJB log: '%s'", ARGV0, str);
161             continue;
162         }
163 
164         debug2("%s: DEBUG: Reading DJB multilog message: '%s'", ARGV0, buffer);
165 
166         /* Send message to queue */
167         if (drop_it == 0) {
168             if (SendMSG(logr_queue, buffer, logff[pos].file, MYSQL_MQ) < 0) {
169                 merror(QUEUE_SEND, ARGV0);
170                 if ((logr_queue = StartMQ(DEFAULTQPATH, WRITE)) < 0) {
171                     ErrorExit(QUEUE_FATAL, ARGV0, DEFAULTQPATH);
172                 }
173             }
174         }
175 
176         continue;
177     }
178 
179     return (NULL);
180 }
181 
182