3 /* Copyright (C) 2009 Trend Micro Inc.
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
11 * License details at the LICENSE file included with OSSEC or
12 * online at: http://www.ossec.net/en/licensing.html
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"
28 #define MAX_KEY_LENGTH 255
30 #define MAX_VALUE_NAME 16383
32 /* Places to story the registry values. */
33 #define SYS_WIN_REG "syscheck/syscheckregistry.db"
34 #define SYS_REG_TMP "syscheck/syscheck_sum.tmp"
38 /* Global variables */
46 /** Function prototypes 8*/
47 void os_winreg_open_key(char *subkey, char *fullkey_name);
50 int os_winreg_changed(char *key, char *md5, char *sha1)
52 char buf[MAX_LINE +1];
57 /* Seeking to the beginning of the db */
58 fseek(syscheck.reg_fp, 0, SEEK_SET);
60 while(fgets(buf, MAX_LINE, syscheck.reg_fp) != NULL)
62 if((buf[0] != '#') && (buf[0] != ' ') && (buf[0] != '\n'))
66 /* Removing the \n before reading */
67 n_buf = strchr(buf, '\n');
73 n_buf = strchr(buf, ' ');
77 if(strcmp(n_buf +1, key) != 0)
80 /* Entry found, checking if checksum is the same */
82 if((strncmp(buf, md5, sizeof(os_md5) -1) == 0)&&
83 (strcmp(buf + sizeof(os_md5) -1, sha1) == 0))
85 /* File didn't change. */
89 /* File did changed */
94 fseek(syscheck.reg_fp, 0, SEEK_END);
95 fprintf(syscheck.reg_fp, "%s%s %s\n", md5, sha1, key);
100 /** int notify_registry(char *msg)
101 * Notifies of registry changes.
103 int notify_registry(char *msg, int send_now)
105 if(SendMSG(syscheck.queue, msg,
106 SYSCHECK_REG, SYSCHECK_MQ) < 0)
108 merror(QUEUE_SEND, ARGV0);
110 if((syscheck.queue = StartMQ(DEFAULTQPATH,WRITE)) < 0)
112 ErrorExit(QUEUE_FATAL, ARGV0, DEFAULTQPATH);
115 /* If we reach here, we can try to send it again */
116 SendMSG(syscheck.queue, msg, SYSCHECK_REG, SYSCHECK_MQ);
123 /** char *os_winreg_sethkey(char *reg_entry)
124 * Checks if the registry entry is valid.
126 char *os_winreg_sethkey(char *reg_entry)
131 /* Getting only the sub tree first */
132 tmp_str = strchr(reg_entry, '\\');
139 /* Setting sub tree */
140 if(strcmp(reg_entry, "HKEY_LOCAL_MACHINE") == 0)
142 sub_tree = HKEY_LOCAL_MACHINE;
144 else if(strcmp(reg_entry, "HKEY_CLASSES_ROOT") == 0)
146 sub_tree = HKEY_CLASSES_ROOT;
148 else if(strcmp(reg_entry, "HKEY_CURRENT_CONFIG") == 0)
150 sub_tree = HKEY_CURRENT_CONFIG;
152 else if(strcmp(reg_entry, "HKEY_USERS") == 0)
154 sub_tree = HKEY_USERS;
158 /* Returning tmp_str to the previous value */
159 if(tmp_str && (*tmp_str == '\0'))
164 /* Checking if ret has nothing else. */
165 if(ret && (*ret == '\0'))
168 /* fixing tmp_str and the real name of the registry */
169 if(tmp_str && (*tmp_str == '\0'))
176 /* void os_winreg_querykey(HKEY hKey, char *p_key)
177 * Query the key and get all its values.
179 void os_winreg_querykey(HKEY hKey, char *p_key, char *full_key_name)
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;
190 /* Number of sub keys */
191 DWORD subkey_count = 0;
193 /* Number of values */
196 /* Variables for RegEnumValue */
197 TCHAR value_buffer[MAX_VALUE_NAME +1];
198 TCHAR data_buffer[MAX_VALUE_NAME +1];
202 /* Data type for RegEnumValue */
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';
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);
219 /* Check return code of QueryInfo */
220 if(rc != ERROR_SUCCESS)
227 /* Checking if we have sub keys */
230 /* We open each subkey and call open_key */
231 for(i=0;i<subkey_count;i++)
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);
237 /* Checking for the rc. */
238 if(rc == ERROR_SUCCESS)
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';
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);
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);
260 os_winreg_open_key(new_key, new_key_full);
265 /* Getting Values (if available) */
268 /* md5 and sha1 sum */
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");
283 printf(FOPEN_ERROR, ARGV0, SYS_REG_TMP);
287 /* Getting each value */
288 for(i=0;i<value_count;i++)
290 value_size = MAX_VALUE_NAME;
291 data_size = MAX_VALUE_NAME;
293 value_buffer[0] = '\0';
294 data_buffer[0] = '\0';
296 rc = RegEnumValue(hKey, i, value_buffer, &value_size,
297 NULL, &data_type, data_buffer, &data_size);
299 /* No more values available */
300 if(rc != ERROR_SUCCESS)
305 /* Checking if no value name is specified */
306 if(value_buffer[0] == '\0')
308 value_buffer[0] = '@';
309 value_buffer[1] = '\0';
312 /* Writing valud name and data in the file (for checksum later) */
313 fprintf(checksum_fp, "%s=", value_buffer);
318 fprintf(checksum_fp, "%s\n", data_buffer);
321 /* Printing multiple strings */
322 mt_data = data_buffer;
326 fprintf(checksum_fp, "%s ", mt_data);
327 mt_data += strlen(mt_data) +1;
329 fprintf(checksum_fp, "\n");
332 fprintf(checksum_fp, "%08x\n",(unsigned int)*data_buffer);
335 for(j = 0;j<data_size;j++)
337 fprintf(checksum_fp, "%02x",
338 (unsigned int)data_buffer[j]);
340 fprintf(checksum_fp, "\n");
345 /* Generating checksum of the values */
348 if(OS_MD5_SHA1_File(SYS_REG_TMP, mf_sum, sf_sum) == -1)
350 merror(FOPEN_ERROR, ARGV0, SYS_REG_TMP);
355 /* Looking for p_key on the reg db */
356 if(os_winreg_changed(full_key_name, mf_sum, sf_sum))
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);
362 /* Notifying server */
363 notify_registry(reg_changed, 0);
371 /* int os_winreg_open_key(char *subkey)
372 * Open the registry key
374 void os_winreg_open_key(char *subkey, char *full_key_name)
379 /* sleep X every Y files */
380 if(ig_count >= syscheck.sleep_after)
382 sleep(syscheck.tsleep +1);
388 /* Registry ignore list */
389 if(full_key_name && syscheck.registry_ignore)
391 while(syscheck.registry_ignore[i] != NULL)
393 if(strcasecmp(syscheck.registry_ignore[i], full_key_name) == 0)
400 else if(full_key_name && syscheck.registry_ignore_regex)
403 while(syscheck.registry_ignore_regex[i] != NULL)
405 if(OSMatch_Execute(full_key_name, strlen(full_key_name),
406 syscheck.registry_ignore_regex[i]))
415 if(RegOpenKeyEx(sub_tree, subkey, 0, KEY_READ, &oshkey) != ERROR_SUCCESS)
417 merror(SK_REG_OPEN, ARGV0, subkey);
421 os_winreg_querykey(oshkey, subkey, full_key_name);
427 /** void os_winreg_check()
428 * Main function to read the registry.
430 void os_winreg_check()
436 debug1("%s: DEBUG: Starting os_winreg_check", ARGV0);
439 /* Zeroing ig_count before checking */
443 /* Checking if the registry fp is open */
444 if(syscheck.reg_fp == NULL)
446 syscheck.reg_fp = fopen(SYS_WIN_REG, "w+");
449 merror(FOPEN_ERROR, ARGV0, SYS_WIN_REG);
455 /* Getting sub class and a valid registry entry */
456 while(syscheck.registry[i] != NULL)
461 /* Ignored entries are zeroed */
462 if(*syscheck.registry[i] == '\0')
469 /* Reading syscheck registry entry */
470 debug1("%s: DEBUG: Attempt to read: %s", ARGV0, syscheck.registry[i]);
473 rk = os_winreg_sethkey(syscheck.registry[i]);
476 merror(SK_INV_REG, ARGV0, syscheck.registry[i]);
477 *syscheck.registry[i] = '\0';
482 os_winreg_open_key(rk, syscheck.registry[i]);
484 sleep(syscheck.tsleep *5);
488 /* Notify of db completed. */
491 sleep(syscheck.tsleep *5);
492 notify_registry(HC_SK_DB_COMPLETED, 1);