1 /* @(#) $Id: ./src/syscheckd/win-registry.c, 2011/09/08 dcid Exp $
4 /* Copyright (C) 2009 Trend Micro Inc.
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
12 * License details at the LICENSE file included with OSSEC or
13 * online at: http://www.ossec.net/en/licensing.html
23 #include "os_crypto/md5/md5_op.h"
24 #include "os_crypto/sha1/sha1_op.h"
25 #include "os_crypto/md5_sha1/md5_sha1_op.h"
29 #define MAX_KEY_LENGTH 255
31 #define MAX_VALUE_NAME 16383
33 /* Places to story the registry values. */
34 #define SYS_WIN_REG "syscheck/syscheckregistry.db"
35 #define SYS_REG_TMP "syscheck/syscheck_sum.tmp"
39 /* Global variables */
47 /** Function prototypes 8*/
48 void os_winreg_open_key(char *subkey, char *fullkey_name);
51 int os_winreg_changed(char *key, char *md5, char *sha1)
53 char buf[MAX_LINE +1];
58 /* Seeking to the beginning of the db */
59 fseek(syscheck.reg_fp, 0, SEEK_SET);
61 while(fgets(buf, MAX_LINE, syscheck.reg_fp) != NULL)
63 if((buf[0] != '#') && (buf[0] != ' ') && (buf[0] != '\n'))
67 /* Removing the \n before reading */
68 n_buf = strchr(buf, '\n');
74 n_buf = strchr(buf, ' ');
78 if(strcmp(n_buf +1, key) != 0)
81 /* Entry found, checking if checksum is the same */
83 if((strncmp(buf, md5, sizeof(os_md5) -1) == 0)&&
84 (strcmp(buf + sizeof(os_md5) -1, sha1) == 0))
86 /* File didn't change. */
90 /* File did changed */
95 fseek(syscheck.reg_fp, 0, SEEK_END);
96 fprintf(syscheck.reg_fp, "%s%s %s\n", md5, sha1, key);
101 /** int notify_registry(char *msg)
102 * Notifies of registry changes.
104 int notify_registry(char *msg, int send_now)
106 if(SendMSG(syscheck.queue, msg,
107 SYSCHECK_REG, SYSCHECK_MQ) < 0)
109 merror(QUEUE_SEND, ARGV0);
111 if((syscheck.queue = StartMQ(DEFAULTQPATH,WRITE)) < 0)
113 ErrorExit(QUEUE_FATAL, ARGV0, DEFAULTQPATH);
116 /* If we reach here, we can try to send it again */
117 SendMSG(syscheck.queue, msg, SYSCHECK_REG, SYSCHECK_MQ);
124 /** char *os_winreg_sethkey(char *reg_entry)
125 * Checks if the registry entry is valid.
127 char *os_winreg_sethkey(char *reg_entry)
132 /* Getting only the sub tree first */
133 tmp_str = strchr(reg_entry, '\\');
140 /* Setting sub tree */
141 if(strcmp(reg_entry, "HKEY_LOCAL_MACHINE") == 0)
143 sub_tree = HKEY_LOCAL_MACHINE;
145 else if(strcmp(reg_entry, "HKEY_CLASSES_ROOT") == 0)
147 sub_tree = HKEY_CLASSES_ROOT;
149 else if(strcmp(reg_entry, "HKEY_CURRENT_CONFIG") == 0)
151 sub_tree = HKEY_CURRENT_CONFIG;
153 else if(strcmp(reg_entry, "HKEY_USERS") == 0)
155 sub_tree = HKEY_USERS;
159 /* Returning tmp_str to the previous value */
160 if(tmp_str && (*tmp_str == '\0'))
165 /* Checking if ret has nothing else. */
166 if(ret && (*ret == '\0'))
169 /* fixing tmp_str and the real name of the registry */
170 if(tmp_str && (*tmp_str == '\0'))
177 /* void os_winreg_querykey(HKEY hKey, char *p_key)
178 * Query the key and get all its values.
180 void os_winreg_querykey(HKEY hKey, char *p_key, char *full_key_name)
185 /* QueryInfo and EnumKey variables */
186 TCHAR sub_key_name_b[MAX_KEY_LENGTH +2];
187 TCHAR class_name_b[MAX_PATH +1];
188 DWORD sub_key_name_s;
189 DWORD class_name_s = MAX_PATH;
191 /* Number of sub keys */
192 DWORD subkey_count = 0;
194 /* Number of values */
197 /* Variables for RegEnumValue */
198 TCHAR value_buffer[MAX_VALUE_NAME +1];
199 TCHAR data_buffer[MAX_VALUE_NAME +1];
203 /* Data type for RegEnumValue */
207 /* Initializing the memory for some variables */
208 class_name_b[0] = '\0';
209 class_name_b[MAX_PATH] = '\0';
210 sub_key_name_b[0] = '\0';
211 sub_key_name_b[MAX_KEY_LENGTH] = '\0';
212 sub_key_name_b[MAX_KEY_LENGTH +1] = '\0';
215 /* We use the class_name, subkey_count and the value count. */
216 rc = RegQueryInfoKey(hKey, class_name_b, &class_name_s, NULL,
217 &subkey_count, NULL, NULL, &value_count,
218 NULL, NULL, NULL, NULL);
220 /* Check return code of QueryInfo */
221 if(rc != ERROR_SUCCESS)
228 /* Checking if we have sub keys */
231 /* We open each subkey and call open_key */
232 for(i=0;i<subkey_count;i++)
234 sub_key_name_s = MAX_KEY_LENGTH;
235 rc = RegEnumKeyEx(hKey, i, sub_key_name_b, &sub_key_name_s,
236 NULL, NULL, NULL, NULL);
238 /* Checking for the rc. */
239 if(rc == ERROR_SUCCESS)
241 char new_key[MAX_KEY + 2];
242 char new_key_full[MAX_KEY + 2];
243 new_key[MAX_KEY +1] = '\0';
244 new_key_full[MAX_KEY +1] = '\0';
248 snprintf(new_key, MAX_KEY,
249 "%s\\%s", p_key, sub_key_name_b);
250 snprintf(new_key_full, MAX_KEY,
251 "%s\\%s", full_key_name, sub_key_name_b);
255 snprintf(new_key, MAX_KEY, "%s", sub_key_name_b);
256 snprintf(new_key_full, MAX_KEY,
257 "%s\\%s", full_key_name, sub_key_name_b);
261 os_winreg_open_key(new_key, new_key_full);
266 /* Getting Values (if available) */
269 /* md5 and sha1 sum */
278 /* Clearing the values for value_size and data_size */
279 value_buffer[MAX_VALUE_NAME] = '\0';
280 data_buffer[MAX_VALUE_NAME] = '\0';
281 checksum_fp = fopen(SYS_REG_TMP, "w");
284 printf(FOPEN_ERROR, ARGV0, SYS_REG_TMP);
288 /* Getting each value */
289 for(i=0;i<value_count;i++)
291 value_size = MAX_VALUE_NAME;
292 data_size = MAX_VALUE_NAME;
294 value_buffer[0] = '\0';
295 data_buffer[0] = '\0';
297 rc = RegEnumValue(hKey, i, value_buffer, &value_size,
298 NULL, &data_type, (LPBYTE)data_buffer, &data_size);
300 /* No more values available */
301 if(rc != ERROR_SUCCESS)
306 /* Checking if no value name is specified */
307 if(value_buffer[0] == '\0')
309 value_buffer[0] = '@';
310 value_buffer[1] = '\0';
313 /* Writing valud name and data in the file (for checksum later) */
314 fprintf(checksum_fp, "%s=", value_buffer);
319 fprintf(checksum_fp, "%s\n", data_buffer);
322 /* Printing multiple strings */
323 mt_data = data_buffer;
327 fprintf(checksum_fp, "%s ", mt_data);
328 mt_data += strlen(mt_data) +1;
330 fprintf(checksum_fp, "\n");
333 fprintf(checksum_fp, "%08x\n",(unsigned int)*data_buffer);
336 for(j = 0;j<data_size;j++)
338 fprintf(checksum_fp, "%02x",
339 (unsigned int)data_buffer[j]);
341 fprintf(checksum_fp, "\n");
346 /* Generating checksum of the values */
349 if(OS_MD5_SHA1_File(SYS_REG_TMP, syscheck.prefilter_cmd, mf_sum, sf_sum) == -1)
351 merror(FOPEN_ERROR, ARGV0, SYS_REG_TMP);
356 /* Looking for p_key on the reg db */
357 if(os_winreg_changed(full_key_name, mf_sum, sf_sum))
359 char reg_changed[MAX_LINE +1];
360 snprintf(reg_changed, MAX_LINE, "0:0:0:0:%s:%s %s",
361 mf_sum, sf_sum, full_key_name);
363 /* Notifying server */
364 notify_registry(reg_changed, 0);
372 /* int os_winreg_open_key(char *subkey)
373 * Open the registry key
375 void os_winreg_open_key(char *subkey, char *full_key_name)
380 /* sleep X every Y files */
381 if(ig_count >= syscheck.sleep_after)
383 sleep(syscheck.tsleep +1);
389 /* Registry ignore list */
390 if(full_key_name && syscheck.registry_ignore)
392 while(syscheck.registry_ignore[i] != NULL)
394 if(strcasecmp(syscheck.registry_ignore[i], full_key_name) == 0)
401 else if(full_key_name && syscheck.registry_ignore_regex)
404 while(syscheck.registry_ignore_regex[i] != NULL)
406 if(OSMatch_Execute(full_key_name, strlen(full_key_name),
407 syscheck.registry_ignore_regex[i]))
416 if(RegOpenKeyEx(sub_tree, subkey, 0, KEY_READ, &oshkey) != ERROR_SUCCESS)
418 merror(SK_REG_OPEN, ARGV0, subkey);
422 os_winreg_querykey(oshkey, subkey, full_key_name);
428 /** void os_winreg_check()
429 * Main function to read the registry.
431 void os_winreg_check()
437 debug1("%s: DEBUG: Starting os_winreg_check", ARGV0);
440 /* Zeroing ig_count before checking */
444 /* Checking if the registry fp is open */
445 if(syscheck.reg_fp == NULL)
447 syscheck.reg_fp = fopen(SYS_WIN_REG, "w+");
450 merror(FOPEN_ERROR, ARGV0, SYS_WIN_REG);
456 /* Getting sub class and a valid registry entry */
457 while(syscheck.registry[i] != NULL)
462 /* Ignored entries are zeroed */
463 if(*syscheck.registry[i] == '\0')
470 /* Reading syscheck registry entry */
471 debug1("%s: DEBUG: Attempt to read: %s", ARGV0, syscheck.registry[i]);
474 rk = os_winreg_sethkey(syscheck.registry[i]);
477 merror(SK_INV_REG, ARGV0, syscheck.registry[i]);
478 *syscheck.registry[i] = '\0';
483 os_winreg_open_key(rk, syscheck.registry[i]);
485 sleep(syscheck.tsleep *5);
489 /* Notify of db completed. */
492 sleep(syscheck.tsleep *5);
493 notify_registry(HC_SK_DB_COMPLETED, 1);