new upstream release (3.3.0); modify package compatibility for Stretch
[ossec-hids.git] / src / rootcheck / win-common.c
1 /* Copyright (C) 2009 Trend Micro Inc.
2  * All right 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 #include "shared.h"
11 #include "rootcheck.h"
12
13 #ifdef WIN32
14
15 /* Global variables */
16 HKEY rk_sub_tree;
17
18 /* Default values */
19 #define MAX_KEY_LENGTH   255
20 #define MAX_KEY         2048
21 #define MAX_VALUE_NAME 16383
22
23
24 /* Check if file has NTFS ADS */
25 int os_check_ads(const char *full_path)
26 {
27     HANDLE file_h;
28     WIN32_STREAM_ID sid;
29     void *context = NULL;
30     char stream_name[MAX_PATH + 1];
31     char final_name[MAX_PATH + 1];
32     DWORD dwRead, shs, dw1, dw2;
33
34     /* Open file */
35     file_h = CreateFile(full_path,
36                         GENERIC_READ,
37                         FILE_SHARE_READ,
38                         NULL,
39                         OPEN_EXISTING,
40                         FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_POSIX_SEMANTICS,
41                         NULL);
42
43     if (file_h == INVALID_HANDLE_VALUE) {
44         return 0;
45     }
46
47     /* Zero memory */
48     ZeroMemory(&sid, sizeof(WIN32_STREAM_ID));
49
50     /* Get stream header size -- should be 20 bytes */
51     shs = (LPBYTE)&sid.cStreamName - (LPBYTE)&sid + sid.dwStreamNameSize;
52
53     while (1) {
54         if (BackupRead(file_h, (LPBYTE) &sid, shs, &dwRead,
55                        FALSE, FALSE, &context) == 0) {
56             break;
57         }
58         if (dwRead == 0) {
59             break;
60         }
61
62         stream_name[0] = '\0';
63         stream_name[MAX_PATH] = '\0';
64         if (BackupRead(file_h, (LPBYTE)stream_name,
65                        sid.dwStreamNameSize,
66                        &dwRead, FALSE, FALSE, &context)) {
67             if (dwRead != 0) {
68                 DWORD i = 0;
69                 int max_path_size = 0;
70                 char *tmp_pt;
71                 char op_msg[OS_SIZE_1024 + 1];
72
73                 snprintf(final_name, MAX_PATH, "%s", full_path);
74                 max_path_size = strlen(final_name);
75
76                 /* Copy from wide char to char */
77                 while ((i < dwRead) && (max_path_size < MAX_PATH)) {
78                     if (stream_name[i] != 0) {
79                         final_name[max_path_size] = stream_name[i];
80                         max_path_size++;
81                         final_name[max_path_size] = '\0';
82                     }
83                     i++;
84                 }
85
86                 tmp_pt = strrchr(final_name, ':');
87                 if (tmp_pt) {
88                     *tmp_pt = '\0';
89                 }
90
91                 snprintf(op_msg, OS_SIZE_1024, "NTFS Alternate data stream "
92                          "found: '%s'. Possible hidden"
93                          " content.",
94                          final_name);
95                 notify_rk(ALERT_ROOTKIT_FOUND, op_msg);
96             }
97         }
98
99         /* Get next */
100         if (!BackupSeek(file_h, sid.Size.LowPart, sid.Size.HighPart,
101                         &dw1, &dw2, &context)) {
102             break;
103         }
104     }
105
106     CloseHandle(file_h);
107     return (0);
108 }
109
110 /* Get registry high level key */
111 char *__os_winreg_getkey(char *reg_entry)
112 {
113     char *ret = NULL;
114     char *tmp_str;
115
116     /* Get only the sub tree first */
117     tmp_str = strchr(reg_entry, '\\');
118     if (tmp_str) {
119         *tmp_str = '\0';
120         ret = tmp_str + 1;
121     }
122
123     /* Set sub tree */
124     if ((strcmp(reg_entry, "HKEY_LOCAL_MACHINE") == 0) ||
125             (strcmp(reg_entry, "HKLM") == 0)) {
126         rk_sub_tree = HKEY_LOCAL_MACHINE;
127     } else if (strcmp(reg_entry, "HKEY_CLASSES_ROOT") == 0) {
128         rk_sub_tree = HKEY_CLASSES_ROOT;
129     } else if (strcmp(reg_entry, "HKEY_CURRENT_CONFIG") == 0) {
130         rk_sub_tree = HKEY_CURRENT_CONFIG;
131     } else if (strcmp(reg_entry, "HKEY_USERS") == 0) {
132         rk_sub_tree = HKEY_USERS;
133     } else if ((strcmp(reg_entry, "HKCU") == 0) ||
134                (strcmp(reg_entry, "HKEY_CURRENT_USER") == 0)) {
135         rk_sub_tree = HKEY_CURRENT_USER;
136     } else {
137         /* Set sub tree to null */
138         rk_sub_tree = NULL;
139
140         /* Return tmp_str to the previous value */
141         if (tmp_str && (*tmp_str == '\0')) {
142             *tmp_str = '\\';
143         }
144         return (NULL);
145     }
146
147     /* Check if ret has nothing else */
148     if (ret && (*ret == '\0')) {
149         ret = NULL;
150     }
151
152     /* Fixing tmp_str and the real name of the registry */
153     if (tmp_str && (*tmp_str == '\0')) {
154         *tmp_str = '\\';
155     }
156
157     return (ret);
158 }
159
160 /* Query the key and get the value of a specific entry */
161 int __os_winreg_querykey(HKEY hKey,
162         __attribute__((unused))char *p_key,
163         __attribute__((unused)) char *full_key_name,
164                          char *reg_option, char *reg_value)
165 {
166     int rc;
167     DWORD i, j;
168
169     /* QueryInfo and EnumKey variables */
170     TCHAR class_name_b[MAX_PATH + 1];
171     DWORD class_name_s = MAX_PATH;
172
173     /* Number of sub keys */
174     DWORD subkey_count = 0;
175
176     /* Number of values */
177     DWORD value_count;
178
179     /* Variables for RegEnumValue */
180     TCHAR value_buffer[MAX_VALUE_NAME + 1];
181     TCHAR data_buffer[MAX_VALUE_NAME + 1];
182     DWORD value_size;
183     DWORD data_size;
184
185     /* Data type for RegEnumValue */
186     DWORD data_type = 0;
187
188     /* Storage var */
189     char var_storage[MAX_VALUE_NAME + 1];
190
191     /* Initialize the memory for some variables */
192     class_name_b[0] = '\0';
193     class_name_b[MAX_PATH] = '\0';
194
195     /* We use the class_name, subkey_count and the value count */
196     rc = RegQueryInfoKey(hKey, class_name_b, &class_name_s, NULL,
197                          &subkey_count, NULL, NULL, &value_count,
198                          NULL, NULL, NULL, NULL);
199     if (rc != ERROR_SUCCESS) {
200         return (0);
201     }
202
203     /* Get values (if available) */
204     if (value_count) {
205         char *mt_data;
206
207         /* Clear the values for value_size and data_size */
208         value_buffer[MAX_VALUE_NAME] = '\0';
209         data_buffer[MAX_VALUE_NAME] = '\0';
210         var_storage[MAX_VALUE_NAME] = '\0';
211
212         /* Get each value */
213         for (i = 0; i < value_count; i++) {
214             value_size = MAX_VALUE_NAME;
215             data_size = MAX_VALUE_NAME;
216
217             value_buffer[0] = '\0';
218             data_buffer[0] = '\0';
219             var_storage[0] = '\0';
220
221             rc = RegEnumValue(hKey, i, value_buffer, &value_size,
222                               NULL, &data_type, (LPBYTE)data_buffer, &data_size);
223
224             /* No more values available */
225             if (rc != ERROR_SUCCESS) {
226                 break;
227             }
228
229             /* Check if no value name is specified */
230             if (value_buffer[0] == '\0') {
231                 value_buffer[0] = '@';
232                 value_buffer[1] = '\0';
233             }
234
235             /* Check if the entry name matches the reg_option */
236             if (strcasecmp(value_buffer, reg_option) != 0) {
237                 continue;
238             }
239
240             /* If a value is not present and the option matches,
241              * we can return ok
242              */
243             if (!reg_value) {
244                 return (1);
245             }
246
247             /* Write value into a string */
248             switch (data_type) {
249                     int size_available;
250
251                 case REG_SZ:
252                 case REG_EXPAND_SZ:
253                     snprintf(var_storage, MAX_VALUE_NAME, "%s", data_buffer);
254                     break;
255                 case REG_MULTI_SZ:
256                     /* Printing multiple strings */
257                     size_available = MAX_VALUE_NAME - 3;
258                     mt_data = data_buffer;
259
260                     while (*mt_data) {
261                         if (size_available > 2) {
262                             strncat(var_storage, mt_data, size_available);
263                             strncat(var_storage, " ", 2);
264                             size_available = MAX_VALUE_NAME -
265                                              (strlen(var_storage) + 2);
266                         }
267                         mt_data += strlen(mt_data) + 1;
268                     }
269
270                     break;
271                 case REG_DWORD:
272                     snprintf(var_storage, MAX_VALUE_NAME,
273                              "%x", (unsigned int)*data_buffer);
274                     break;
275                 default:
276                     size_available = MAX_VALUE_NAME - 2;
277                     for (j = 0; j < data_size; j++) {
278                         char tmp_c[12];
279
280                         snprintf(tmp_c, 12, "%02x",
281                                  (unsigned int)data_buffer[j]);
282
283                         if (size_available > 2) {
284                             strncat(var_storage, tmp_c, size_available);
285                             size_available = MAX_VALUE_NAME -
286                                              (strlen(var_storage) + 2);
287                         }
288                     }
289                     break;
290             }
291
292             /* Check if value matches */
293             if (pt_matches(var_storage, reg_value)) {
294                 return (1);
295             }
296
297             return (0);
298         }
299     }
300
301     return (0);
302 }
303
304 /* Open the registry key */
305 int __os_winreg_open_key(char *subkey, char *full_key_name,
306                          char *reg_option, char *reg_value)
307 {
308     int ret = 1;
309     HKEY oshkey;
310
311     int REG64MASK = (KEY_READ | KEY_WOW64_64KEY);
312     int REG32MASK = (KEY_READ | KEY_WOW64_32KEY);
313
314     if((RegOpenKeyEx(rk_sub_tree, subkey, 0, REG64MASK, &oshkey) ||
315         (RegOpenKeyEx(rk_sub_tree, subkey, 0, REG32MASK, &oshkey))
316         ) != ERROR_SUCCESS)
317     {
318         return(0);
319     }
320
321     /* If option is set, return the value of query key */
322     if (reg_option) {
323         ret = __os_winreg_querykey(oshkey, subkey, full_key_name,
324                                    reg_option, reg_value);
325     }
326
327     RegCloseKey(oshkey);
328     return (ret);
329 }
330
331 /* Check if the entry is present in the registry */
332 int is_registry(char *entry_name, char *reg_option, char *reg_value)
333 {
334     char *rk;
335
336     rk = __os_winreg_getkey(entry_name);
337     if (rk_sub_tree == NULL || rk == NULL) {
338         merror(SK_INV_REG, ARGV0, entry_name);
339         return (0);
340     }
341
342     if (__os_winreg_open_key(rk, entry_name, reg_option, reg_value) == 0) {
343         return (0);
344     }
345
346     return (1);
347 }
348
349 #else
350
351 /* Non-Windows defs */
352 int os_check_ads(__attribute__((unused)) const char *full_path)
353 {
354     return (0);
355 }
356 int is_registry(__attribute__((unused)) char *entry_name,
357                 __attribute__((unused)) char *reg_option,
358                 __attribute__((unused)) char *reg_value)
359 {
360     return (0);
361 }
362
363 #endif /* !WIN32 */
364