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