Imported Upstream version 2.7
[ossec-hids.git] / src / rootcheck / win-common.c
1 /* @(#) $Id: ./src/rootcheck/win-common.c, 2011/09/08 dcid Exp $
2  */
3
4 /* Copyright (C) 2009 Trend Micro Inc.
5  * All right reserved.
6  *
7  * This program is a free software; you can redistribute it
8  * and/or modify it under the terms of the GNU General Public
9  * License (version 2) as published by the FSF - Free Software
10  * Foundation
11  */
12
13
14 #include "shared.h"
15 #include "rootcheck.h"
16
17 #ifdef WIN32
18
19
20 /** Registry checking values **/
21
22 /* Global variables */
23 HKEY rk_sub_tree;
24
25 /* Default values */
26 #define MAX_KEY_LENGTH 255
27 #define MAX_KEY 2048
28 #define MAX_VALUE_NAME 16383
29
30
31
32 /* os_check_ads.
33  * Check if file has NTFS ADS.
34  */
35 int os_check_ads(char *full_path)
36 {
37     HANDLE file_h;
38     WIN32_STREAM_ID sid;
39     void *context = NULL;
40
41     char stream_name[MAX_PATH +1];
42     char final_name[MAX_PATH +1];
43
44     DWORD dwRead, shs, dw1, dw2;
45
46
47     /* Opening file */
48     file_h = CreateFile(full_path,
49             GENERIC_READ,
50             FILE_SHARE_READ,
51             NULL,
52             OPEN_EXISTING,
53             FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_POSIX_SEMANTICS,
54             NULL);
55
56     if (file_h == INVALID_HANDLE_VALUE)
57     {
58         return 0;
59     }
60
61
62     /* Zeroing memory */
63     ZeroMemory(&sid, sizeof(WIN32_STREAM_ID));
64
65     /* Getting stream header size -- should be 20 bytes */
66     shs = (LPBYTE)&sid.cStreamName - (LPBYTE)&sid+ sid.dwStreamNameSize;
67
68
69     while(1)
70     {
71         if(BackupRead(file_h, (LPBYTE) &sid, shs, &dwRead,
72                     FALSE, FALSE, &context) == 0)
73         {
74             break;
75         }
76         if(dwRead == 0)
77         {
78             break;
79         }
80
81         stream_name[0] = '\0';
82         stream_name[MAX_PATH] = '\0';
83         if(BackupRead(file_h, (LPBYTE)stream_name,
84                     sid.dwStreamNameSize,
85                     &dwRead, FALSE, FALSE, &context))
86         {
87             if(dwRead != 0)
88             {
89                 int i = 0, max_path_size = 0;
90                 char *tmp_pt;
91                 char op_msg[OS_SIZE_1024 +1];
92
93                 snprintf(final_name, MAX_PATH, "%s", full_path);
94
95                 max_path_size = strlen(final_name);
96
97
98                 /* Copying from wide char to char. */
99                 while((i < dwRead) && (max_path_size < MAX_PATH))
100                 {
101                     if(stream_name[i] != 0)
102                     {
103                         final_name[max_path_size] = stream_name[i];
104                         max_path_size++;
105                         final_name[max_path_size] = '\0';
106                     }
107                     i++;
108                 }
109
110
111                 tmp_pt = strrchr(final_name, ':');
112                 if(tmp_pt)
113                 {
114                     *tmp_pt = '\0';
115                 }
116
117                 snprintf(op_msg, OS_SIZE_1024, "NTFS Alternate data stream "
118                                                "found: '%s'. Possible hidden"
119                                                " content.",
120                                                final_name);
121                 notify_rk(ALERT_ROOTKIT_FOUND, op_msg);
122             }
123         }
124
125         /* Getting next */                      
126         if(!BackupSeek(file_h, sid.Size.LowPart, sid.Size.HighPart,
127                     &dw1, &dw2, &context))
128         {
129             break;
130         }
131     }
132
133     CloseHandle(file_h);
134     return(0);
135 }
136
137
138
139 /** char *__os_winreg_getkey(char *reg_entry)
140  * Gets registry high level key.
141  */
142 char *__os_winreg_getkey(char *reg_entry)
143 {
144     char *ret = NULL;
145     char *tmp_str;
146
147     /* Getting only the sub tree first */
148     tmp_str = strchr(reg_entry, '\\');
149     if(tmp_str)
150     {
151         *tmp_str = '\0';
152         ret = tmp_str+1;
153     }
154
155     /* Setting sub tree */
156     if((strcmp(reg_entry, "HKEY_LOCAL_MACHINE") == 0) ||
157        (strcmp(reg_entry, "HKLM") == 0))
158     {
159         rk_sub_tree = HKEY_LOCAL_MACHINE;
160     }
161     else if(strcmp(reg_entry, "HKEY_CLASSES_ROOT") == 0)
162     {
163         rk_sub_tree = HKEY_CLASSES_ROOT;
164     }
165     else if(strcmp(reg_entry, "HKEY_CURRENT_CONFIG") == 0)
166     {
167         rk_sub_tree = HKEY_CURRENT_CONFIG;
168     }
169     else if(strcmp(reg_entry, "HKEY_USERS") == 0)
170     {
171         rk_sub_tree = HKEY_USERS;
172     }
173     else if((strcmp(reg_entry, "HKCU") == 0) ||
174             (strcmp(reg_entry, "HKEY_CURRENT_USER") == 0))
175     {
176         rk_sub_tree = HKEY_CURRENT_USER;
177     }
178     else
179     {
180         /* Setting sub tree to null */
181         rk_sub_tree = NULL;
182
183         /* Returning tmp_str to the previous value */
184         if(tmp_str && (*tmp_str == '\0'))
185             *tmp_str = '\\';
186         return(NULL);
187     }
188
189     /* Checking if ret has nothing else. */
190     if(ret && (*ret == '\0'))
191         ret = NULL;
192
193     /* fixing tmp_str and the real name of the registry */
194     if(tmp_str && (*tmp_str == '\0'))
195         *tmp_str = '\\';
196
197     return(ret);
198 }
199
200
201
202 /* int __os_winreg_querykey
203  * Query the key and get the value of a specific entry.
204   */
205 int __os_winreg_querykey(HKEY hKey, char *p_key, char *full_key_name,
206                                     char *reg_option, char *reg_value)
207 {
208     int i, rc;
209     DWORD j;
210
211     /* QueryInfo and EnumKey variables */
212     TCHAR sub_key_name_b[MAX_KEY_LENGTH +1];
213     TCHAR class_name_b[MAX_PATH +1];
214     DWORD class_name_s = MAX_PATH;
215
216     /* Number of sub keys */
217     DWORD subkey_count = 0;
218
219     /* Number of values */
220     DWORD value_count;
221
222     /* Variables for RegEnumValue */
223     TCHAR value_buffer[MAX_VALUE_NAME +1];
224     TCHAR data_buffer[MAX_VALUE_NAME +1];
225     DWORD value_size;
226     DWORD data_size;
227
228     /* Data type for RegEnumValue */
229     DWORD data_type = 0;
230
231
232     /* Storage var */
233     char var_storage[MAX_VALUE_NAME +1];
234
235
236     /* Initializing the memory for some variables */
237     class_name_b[0] = '\0';
238     class_name_b[MAX_PATH] = '\0';
239     sub_key_name_b[0] = '\0';
240     sub_key_name_b[MAX_KEY_LENGTH] = '\0';
241
242
243     /* We use the class_name, subkey_count and the value count. */
244     rc = RegQueryInfoKey(hKey, class_name_b, &class_name_s, NULL,
245             &subkey_count, NULL, NULL, &value_count,
246             NULL, NULL, NULL, NULL);
247
248
249     /* Check return code of QueryInfo */
250     if(rc != ERROR_SUCCESS)
251     {
252         return(0);
253     }
254
255
256
257     /* Getting Values (if available) */
258     if (value_count)
259     {
260         char *mt_data;
261
262
263         /* Clearing the values for value_size and data_size */
264         value_buffer[MAX_VALUE_NAME] = '\0';
265         data_buffer[MAX_VALUE_NAME] = '\0';
266         var_storage[MAX_VALUE_NAME] = '\0';
267
268
269         /* Getting each value */
270         for(i=0;i<value_count;i++)
271         {
272             value_size = MAX_VALUE_NAME;
273             data_size = MAX_VALUE_NAME;
274
275             value_buffer[0] = '\0';
276             data_buffer[0] = '\0';
277             var_storage[0] = '\0';
278
279             rc = RegEnumValue(hKey, i, value_buffer, &value_size,
280                               NULL, &data_type, (LPBYTE)data_buffer, &data_size);
281
282
283             /* No more values available */
284             if(rc != ERROR_SUCCESS)
285             {
286                 break;
287             }
288
289             /* Checking if no value name is specified */
290             if(value_buffer[0] == '\0')
291             {
292                 value_buffer[0] = '@';
293                 value_buffer[1] = '\0';
294             }
295
296
297             /* Check if the entry name matches the reg_option */
298             if(strcasecmp(value_buffer, reg_option) != 0)
299             {
300                 continue;
301             }
302
303
304             /* If a value is not present and the option matches,
305              * we can return ok.
306              */
307             if(!reg_value)
308             {
309                 return(1);
310             }
311
312
313
314             /* Writing value into a string */
315             switch(data_type)
316             {
317                 int size_available;
318
319                 case REG_SZ:
320                 case REG_EXPAND_SZ:
321                     snprintf(var_storage, MAX_VALUE_NAME, "%s", data_buffer);
322                     break;
323                 case REG_MULTI_SZ:
324
325                     /* Printing multiple strings */
326                     size_available = MAX_VALUE_NAME -3;
327                     mt_data = data_buffer;
328
329                     while(*mt_data)
330                     {
331                         if(size_available > 2)
332                         {
333                             strncat(var_storage, mt_data, size_available);
334                             strncat(var_storage, " ", 2);
335                             size_available = MAX_VALUE_NAME -
336                                              (strlen(var_storage) +2);
337                         }
338                         mt_data += strlen(mt_data) +1;
339                     }
340
341                     break;
342                 case REG_DWORD:
343                     snprintf(var_storage, MAX_VALUE_NAME,
344                             "%x",(unsigned int)*data_buffer);
345                     break;
346                 default:
347
348                     size_available = MAX_VALUE_NAME -2;
349                     for(j = 0;j<data_size;j++)
350                     {
351                         char tmp_c[12];
352
353                         snprintf(tmp_c, 12, "%02x",
354                                 (unsigned int)data_buffer[j]);
355
356                         if(size_available > 2)
357                         {
358                             strncat(var_storage, tmp_c, size_available);
359                             size_available = MAX_VALUE_NAME -
360                                 (strlen(var_storage) +2);
361                         }
362                     }
363                     break;
364             }
365
366             /* Checking if value matches */
367             if(pt_matches(var_storage, reg_value))
368             {
369                 return(1);
370             }
371
372             return(0);
373         }
374     }
375
376     return(0);
377 }
378
379
380
381 /* int __os_winreg_open_key(char *subkey)
382  * Open the registry key
383  */
384 int __os_winreg_open_key(char *subkey, char *full_key_name,
385                          char *reg_option, char *reg_value)
386 {
387     int ret = 1;
388     HKEY oshkey;
389
390
391     if(RegOpenKeyEx(rk_sub_tree, subkey, 0, KEY_READ,&oshkey) != ERROR_SUCCESS)
392     {
393         return(0);
394     }
395
396
397     /* If option is set, return the value of query key */
398     if(reg_option)
399     {
400         ret = __os_winreg_querykey(oshkey, subkey, full_key_name,
401                                    reg_option, reg_value);
402     }
403
404
405     RegCloseKey(oshkey);
406     return(ret);
407 }
408
409
410
411 /* is_registry: Check if the entry is present in the registry
412  */
413 int is_registry(char *entry_name, char *reg_option, char *reg_value)
414 {
415
416     char *rk;
417
418     rk = __os_winreg_getkey(entry_name);
419     if(rk_sub_tree == NULL || rk == NULL)
420     {
421         merror(SK_INV_REG, ARGV0, entry_name);
422         return(0);
423     }
424
425     if(__os_winreg_open_key(rk, entry_name, reg_option, reg_value) == 0)
426     {
427         return(0);
428     }
429
430     return(1);
431 }
432
433
434 #else /* WIN32 */
435
436
437 /* Non windows defs for them. */
438 int os_check_ads(char *full_path)
439 {
440     return(0);
441 }
442 int is_registry(char *entry_name, char *reg_option, char *reg_value)
443 {
444     return(0);
445 }
446
447
448 #endif
449 /* EOF */