Imported Upstream version 2.5.1
[ossec-hids.git] / src / syscheckd / win-registry.c
1 /* @(#) $Id$ */
2
3 /* Copyright (C) 2009 Trend Micro Inc.
4  * All rights 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  * License details at the LICENSE file included with OSSEC or 
12  * online at: http://www.ossec.net/en/licensing.html
13  */
14
15        
16 /* Windows only */
17 #ifdef WIN32
18
19        
20 #include "shared.h"
21 #include "syscheck.h"
22 #include "os_crypto/md5/md5_op.h"
23 #include "os_crypto/sha1/sha1_op.h"
24 #include "os_crypto/md5_sha1/md5_sha1_op.h"       
25
26
27 /* Default values */
28 #define MAX_KEY_LENGTH 255
29 #define MAX_KEY 2048
30 #define MAX_VALUE_NAME 16383
31
32 /* Places to story the registry values. */
33 #define SYS_WIN_REG     "syscheck/syscheckregistry.db"
34 #define SYS_REG_TMP     "syscheck/syscheck_sum.tmp"
35
36  
37  
38 /* Global variables */
39 HKEY sub_tree;
40 int ig_count = 0;
41 int run_count = 0;
42
43
44
45
46 /** Function prototypes 8*/
47 void os_winreg_open_key(char *subkey, char *fullkey_name);
48
49
50 int os_winreg_changed(char *key, char *md5, char *sha1)
51 {
52     char buf[MAX_LINE +1];
53     
54     buf[MAX_LINE] = '\0';
55
56
57     /* Seeking to the beginning of the db */
58     fseek(syscheck.reg_fp, 0, SEEK_SET);
59
60     while(fgets(buf, MAX_LINE, syscheck.reg_fp) != NULL)
61     {
62         if((buf[0] != '#') && (buf[0] != ' ') && (buf[0] != '\n'))
63         {
64             char *n_buf;
65
66             /* Removing the \n before reading */
67             n_buf = strchr(buf, '\n');
68             if(n_buf == NULL)
69                 continue;
70
71             *n_buf = '\0';    
72             
73             n_buf = strchr(buf, ' ');
74             if(n_buf == NULL)
75                 continue;
76             
77             if(strcmp(n_buf +1, key) != 0)
78                 continue;
79             
80             /* Entry found, checking if checksum is the same */
81             *n_buf = '\0';    
82             if((strncmp(buf, md5, sizeof(os_md5) -1) == 0)&&
83                (strcmp(buf + sizeof(os_md5) -1, sha1) == 0))
84             {
85                 /* File didn't change. */
86                 return(0);
87             }
88
89             /* File did changed */
90             return(1);
91         }
92     }
93
94     fseek(syscheck.reg_fp, 0, SEEK_END);
95     fprintf(syscheck.reg_fp, "%s%s %s\n", md5, sha1, key);
96     return(1);
97 }
98
99
100 /** int notify_registry(char *msg)
101  * Notifies of registry changes.
102  */
103 int notify_registry(char *msg, int send_now)
104 {
105     if(SendMSG(syscheck.queue, msg,
106                SYSCHECK_REG, SYSCHECK_MQ) < 0)
107     {
108         merror(QUEUE_SEND, ARGV0);
109
110         if((syscheck.queue = StartMQ(DEFAULTQPATH,WRITE)) < 0)
111         {
112             ErrorExit(QUEUE_FATAL, ARGV0, DEFAULTQPATH);
113         }
114
115         /* If we reach here, we can try to send it again */
116         SendMSG(syscheck.queue, msg, SYSCHECK_REG, SYSCHECK_MQ);
117     }
118
119     return(0);
120 }
121
122
123 /** char *os_winreg_sethkey(char *reg_entry)
124  * Checks if the registry entry is valid.
125  */
126 char *os_winreg_sethkey(char *reg_entry)
127 {
128     char *ret = NULL;
129     char *tmp_str;
130
131     /* Getting only the sub tree first */
132     tmp_str = strchr(reg_entry, '\\');
133     if(tmp_str)
134     {
135         *tmp_str = '\0';
136         ret = tmp_str+1;
137     }
138
139     /* Setting sub tree */
140     if(strcmp(reg_entry, "HKEY_LOCAL_MACHINE") == 0)
141     {
142         sub_tree = HKEY_LOCAL_MACHINE;
143     }
144     else if(strcmp(reg_entry, "HKEY_CLASSES_ROOT") == 0)
145     {
146         sub_tree = HKEY_CLASSES_ROOT;
147     }
148     else if(strcmp(reg_entry, "HKEY_CURRENT_CONFIG") == 0)
149     {
150         sub_tree = HKEY_CURRENT_CONFIG;
151     }
152     else if(strcmp(reg_entry, "HKEY_USERS") == 0)
153     {
154         sub_tree = HKEY_USERS;
155     }
156     else
157     {
158         /* Returning tmp_str to the previous value */
159         if(tmp_str && (*tmp_str == '\0'))
160             *tmp_str = '\\';
161         return(NULL);
162     }
163
164     /* Checking if ret has nothing else. */
165     if(ret && (*ret == '\0'))
166         ret = NULL;
167     
168     /* fixing tmp_str and the real name of the registry */    
169     if(tmp_str && (*tmp_str == '\0'))
170             *tmp_str = '\\';
171             
172     return(ret);
173 }
174
175
176 /* void os_winreg_querykey(HKEY hKey, char *p_key)
177  * Query the key and get all its values.
178  */
179 void os_winreg_querykey(HKEY hKey, char *p_key, char *full_key_name) 
180 {
181     int i, rc;
182     DWORD j;
183
184     /* QueryInfo and EnumKey variables */
185     TCHAR sub_key_name_b[MAX_KEY_LENGTH +2];
186     TCHAR class_name_b[MAX_PATH +1];
187     DWORD sub_key_name_s;
188     DWORD class_name_s = MAX_PATH;
189
190     /* Number of sub keys */
191     DWORD subkey_count = 0;
192
193     /* Number of values */
194     DWORD value_count;
195
196     /* Variables for RegEnumValue */
197     TCHAR value_buffer[MAX_VALUE_NAME +1]; 
198     TCHAR data_buffer[MAX_VALUE_NAME +1]; 
199     DWORD value_size;
200     DWORD data_size;
201
202     /* Data type for RegEnumValue */
203     DWORD data_type = 0;
204
205
206     /* Initializing the memory for some variables */
207     class_name_b[0] = '\0';
208     class_name_b[MAX_PATH] = '\0';
209     sub_key_name_b[0] = '\0';
210     sub_key_name_b[MAX_KEY_LENGTH] = '\0';
211     sub_key_name_b[MAX_KEY_LENGTH +1] = '\0';
212     
213
214     /* We use the class_name, subkey_count and the value count. */
215     rc = RegQueryInfoKey(hKey, class_name_b, &class_name_s, NULL,
216             &subkey_count, NULL, NULL, &value_count,
217             NULL, NULL, NULL, NULL);
218
219     /* Check return code of QueryInfo */
220     if(rc != ERROR_SUCCESS)
221     {
222         return;
223     }
224
225
226
227     /* Checking if we have sub keys */
228     if(subkey_count)
229     {
230         /* We open each subkey and call open_key */
231         for(i=0;i<subkey_count;i++) 
232         { 
233             sub_key_name_s = MAX_KEY_LENGTH;
234             rc = RegEnumKeyEx(hKey, i, sub_key_name_b, &sub_key_name_s,
235                               NULL, NULL, NULL, NULL); 
236             
237             /* Checking for the rc. */
238             if(rc == ERROR_SUCCESS) 
239             {
240                 char new_key[MAX_KEY + 2];
241                 char new_key_full[MAX_KEY + 2];
242                 new_key[MAX_KEY +1] = '\0';
243                 new_key_full[MAX_KEY +1] = '\0';
244
245                 if(p_key)
246                 {
247                     snprintf(new_key, MAX_KEY, 
248                              "%s\\%s", p_key, sub_key_name_b);
249                     snprintf(new_key_full, MAX_KEY, 
250                              "%s\\%s", full_key_name, sub_key_name_b);
251                 }
252                 else
253                 {
254                     snprintf(new_key, MAX_KEY, "%s", sub_key_name_b);
255                     snprintf(new_key_full, MAX_KEY, 
256                              "%s\\%s", full_key_name, sub_key_name_b);
257                 }
258
259                 /* Opening subkey */
260                 os_winreg_open_key(new_key, new_key_full);
261             }
262         }
263     }
264     
265     /* Getting Values (if available) */
266     if (value_count) 
267     {
268         /* md5 and sha1 sum */
269         os_md5 mf_sum;
270         os_sha1 sf_sum;
271
272         FILE *checksum_fp;
273
274         char *mt_data;
275
276
277         /* Clearing the values for value_size and data_size */
278         value_buffer[MAX_VALUE_NAME] = '\0';
279         data_buffer[MAX_VALUE_NAME] = '\0';
280         checksum_fp = fopen(SYS_REG_TMP, "w");
281         if(!checksum_fp)
282         {
283             printf(FOPEN_ERROR, ARGV0, SYS_REG_TMP);
284             return;
285         }
286
287         /* Getting each value */
288         for(i=0;i<value_count;i++) 
289         { 
290             value_size = MAX_VALUE_NAME; 
291             data_size = MAX_VALUE_NAME;
292
293             value_buffer[0] = '\0';
294             data_buffer[0] = '\0';
295
296             rc = RegEnumValue(hKey, i, value_buffer, &value_size,
297                     NULL, &data_type, data_buffer, &data_size);
298
299             /* No more values available */
300             if(rc != ERROR_SUCCESS)
301             {
302                 break;
303             }
304
305             /* Checking if no value name is specified */
306             if(value_buffer[0] == '\0')
307             {
308                 value_buffer[0] = '@';
309                 value_buffer[1] = '\0';
310             }
311
312             /* Writing valud name and data in the file (for checksum later) */
313             fprintf(checksum_fp, "%s=", value_buffer);
314             switch(data_type)
315             {
316                 case REG_SZ:
317                 case REG_EXPAND_SZ:
318                     fprintf(checksum_fp, "%s\n", data_buffer);
319                     break;
320                 case REG_MULTI_SZ:
321                     /* Printing multiple strings */
322                     mt_data = data_buffer;
323
324                     while(*mt_data)
325                     {
326                         fprintf(checksum_fp, "%s ", mt_data);
327                         mt_data += strlen(mt_data) +1;
328                     }
329                     fprintf(checksum_fp, "\n");
330                     break;
331                 case REG_DWORD:
332                     fprintf(checksum_fp, "%08x\n",(unsigned int)*data_buffer);
333                     break;
334                 default:
335                     for(j = 0;j<data_size;j++)
336                     {
337                         fprintf(checksum_fp, "%02x",
338                                 (unsigned int)data_buffer[j]);
339                     }
340                     fprintf(checksum_fp, "\n");
341                     break;      
342             }
343         }
344
345         /* Generating checksum of the values */
346         fclose(checksum_fp);
347
348         if(OS_MD5_SHA1_File(SYS_REG_TMP, mf_sum, sf_sum) == -1)
349         {
350             merror(FOPEN_ERROR, ARGV0, SYS_REG_TMP);
351             return;
352         }
353
354
355         /* Looking for p_key on the reg db */
356         if(os_winreg_changed(full_key_name, mf_sum, sf_sum))
357         {
358             char reg_changed[MAX_LINE +1];
359             snprintf(reg_changed, MAX_LINE, "0:0:0:0:%s:%s %s",
360                                   mf_sum, sf_sum, full_key_name); 
361
362             /* Notifying server */
363             notify_registry(reg_changed, 0);
364         }
365
366         ig_count++;
367     }
368 }
369
370
371 /* int os_winreg_open_key(char *subkey)
372  * Open the registry key
373  */
374 void os_winreg_open_key(char *subkey, char *full_key_name)
375 {
376     int i = 0;  
377     HKEY oshkey;
378
379     /* sleep X every Y files */
380     if(ig_count >= syscheck.sleep_after)
381     {
382         sleep(syscheck.tsleep +1);
383         ig_count = 1;
384     }
385     ig_count++;
386
387     
388     /* Registry ignore list */
389     if(full_key_name && syscheck.registry_ignore)
390     {
391         while(syscheck.registry_ignore[i] != NULL)
392         {
393             if(strcasecmp(syscheck.registry_ignore[i], full_key_name) == 0)
394             {
395                 return;
396             }
397             i++;
398         }
399     }
400     else if(full_key_name && syscheck.registry_ignore_regex)
401     {
402         i = 0;
403         while(syscheck.registry_ignore_regex[i] != NULL)
404         {
405             if(OSMatch_Execute(full_key_name, strlen(full_key_name),
406                                syscheck.registry_ignore_regex[i]))
407             {
408                 return;
409             }
410             i++;
411         }
412     }
413
414
415     if(RegOpenKeyEx(sub_tree, subkey, 0, KEY_READ, &oshkey) != ERROR_SUCCESS)
416     {
417         merror(SK_REG_OPEN, ARGV0, subkey);
418         return;
419     }
420
421     os_winreg_querykey(oshkey, subkey, full_key_name);
422     RegCloseKey(oshkey);
423     return;
424 }
425
426
427 /** void os_winreg_check()
428  * Main function to read the registry.
429  */
430 void os_winreg_check()
431 {
432     int i = 0;
433     char *rk;
434
435     /* Debug entries */
436     debug1("%s: DEBUG: Starting os_winreg_check", ARGV0);
437     
438     
439     /* Zeroing ig_count before checking */
440     ig_count = 1;
441     
442
443     /* Checking if the registry fp is open */
444     if(syscheck.reg_fp == NULL)
445     {
446         syscheck.reg_fp = fopen(SYS_WIN_REG, "w+");
447         if(!syscheck.reg_fp)
448         {
449             merror(FOPEN_ERROR, ARGV0, SYS_WIN_REG);
450             return;
451         }
452     }
453
454
455     /* Getting sub class and a valid registry entry */
456     while(syscheck.registry[i] != NULL)
457     {
458         sub_tree = NULL;
459         rk = NULL;
460         
461         /* Ignored entries are zeroed */
462         if(*syscheck.registry[i] == '\0')
463         {
464             i++;
465             continue;
466         }
467         
468             
469         /* Reading syscheck registry entry */
470         debug1("%s: DEBUG: Attempt to read: %s", ARGV0, syscheck.registry[i]);
471         
472         
473         rk = os_winreg_sethkey(syscheck.registry[i]);
474         if(sub_tree == NULL)
475         {
476             merror(SK_INV_REG, ARGV0, syscheck.registry[i]);
477             *syscheck.registry[i] = '\0';
478             i++;
479             continue;
480         }
481
482         os_winreg_open_key(rk, syscheck.registry[i]);
483         i++;
484         sleep(syscheck.tsleep *5);
485     }
486
487
488     /* Notify of db completed. */
489     if(run_count > 1)
490     {
491         sleep(syscheck.tsleep *5);
492         notify_registry(HC_SK_DB_COMPLETED, 1);
493     }
494
495     run_count++;
496     return;
497 }
498
499
500 #endif /* WIN32 */
501
502 /* EOF */