source: trunk/src/sh_registry.c@ 480

Last change on this file since 480 was 422, checked in by katerina, 12 years ago

Fix for tickets #326, #327.

File size: 24.5 KB
RevLine 
[294]1/* SAMHAIN file system integrity testing */
2/* Copyright (C) 2010 Rainer Wichmann */
3/* */
4/* This program is free software; you can redistribute it */
5/* and/or modify */
6/* it under the terms of the GNU General Public License as */
7/* published by */
8/* the Free Software Foundation; either version 2 of the License, or */
9/* (at your option) any later version. */
10/* */
11/* This program is distributed in the hope that it will be useful, */
12/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
13/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
14/* GNU General Public License for more details. */
15/* */
16/* You should have received a copy of the GNU General Public License */
17/* along with this program; if not, write to the Free Software */
18/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20/***************************************************************************
21 *
22 * This file provides a module for samhain to check the MS Windows registry.
23 *
24 */
25
26#include "config_xor.h"
27
28#ifdef USE_REGISTRY_CHECK
29
30#include <windows.h>
31#include <stdio.h>
32#include <time.h>
33
34#define FIL__ _("sh_registry.c")
35
36/* We don't want to build this into yule
37 */
38#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
39
40#include <sys/types.h>
41#include <regex.h>
42
43#include "samhain.h"
44#include "sh_pthread.h"
45#include "sh_utils.h"
46#include "sh_unix.h"
47#include "sh_modules.h"
48#include "sh_hash.h"
49#include "sh_tiger.h"
50
51static int check_key (char * name, int isSingle);
52
53static int sh_reg_set_active (const char *s);
54static int sh_reg_set_interval (const char * c);
55static int sh_reg_set_severity (const char *s);
56static int sh_reg_add_key (const char *s);
57static int sh_reg_add_hierarchy (const char *s);
58static int sh_reg_add_stop (const char *s);
59static int sh_reg_add_ign (const char *s);
[422]60static int sh_reg_ign_time (const char *s);
[294]61
62#define STOP_FALSE 0
63#define STOP_CHECK 1
64#define STOP_IGN 2
65
66sh_rconf sh_reg_check_table[] = {
67 {
68 N_("severitychange"),
69 sh_reg_set_severity,
70 },
71 {
72 N_("registrycheckactive"),
73 sh_reg_set_active,
74 },
75 {
76 N_("registrycheckinterval"),
77 sh_reg_set_interval,
78 },
79 {
[422]80 N_("ignoretimestamponly"),
81 sh_reg_ign_time,
82 },
83 {
[294]84 N_("singlekey"),
85 sh_reg_add_key,
86 },
87 {
88 N_("hierarchy"),
89 sh_reg_add_hierarchy,
90 },
91 {
92 N_("stopatkey"),
93 sh_reg_add_stop,
94 },
95 {
96 N_("ignorekey"),
97 sh_reg_add_ign,
98 },
99 {
100 NULL,
101 NULL
102 }
103};
104
105/* Runtime configuration */
106
107#define SH_REGISTRY_INTERVAL 300
108
109static int ShRegCheckActive = S_FALSE;
110static time_t sh_reg_check_interval = SH_REGISTRY_INTERVAL;
111static int sh_reg_check_severity = SH_ERR_SEVERE;
[422]112static int ShRegIgnTime = S_FALSE;
[294]113
114struct regkeylist {
115 char * name;
116 int stop;
117 int single;
118#ifdef HAVE_REGEX_H
119 regex_t preg;
120#endif
121
122 struct regkeylist *next;
123};
124
125static struct regkeylist * keylist = NULL;
126
127static int sh_reg_set_active(const char *s)
128{
129 int value;
130
131 SL_ENTER(_("sh_reg_set_active"));
132
133 value = sh_util_flagval(s, &ShRegCheckActive);
134
135 SL_RETURN((value), _("sh_reg_set_active"));
136}
137
[422]138static int sh_reg_ign_time(const char *s)
139{
140 int value;
141
142 SL_ENTER(_("sh_reg_ign_time"));
143
144 value = sh_util_flagval(s, &ShRegIgnTime);
145
146 SL_RETURN((value), _("sh_reg_ign_time"));
147}
148
[294]149static int sh_reg_set_interval (const char * c)
150{
151 int retval = 0;
152 long val;
153
154 SL_ENTER(_("sh_reg_set_interval"));
155 val = strtol (c, (char **)NULL, 10);
156 if (val <= 0)
157 {
158 SH_MUTEX_LOCK(mutex_thread_nolog);
159 sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
160 _("registry check interval"), c);
161 SH_MUTEX_UNLOCK(mutex_thread_nolog);
162 retval = -1;
163 }
164
165 sh_reg_check_interval = (time_t) val;
166 SL_RETURN(0, _("sh_reg_set_interval"));
167}
168
169static int sh_reg_set_severity (const char *s)
170{
171 char tmp[32];
172 tmp[0] = '='; tmp[1] = '\0';
173 sl_strlcat (tmp, s, 32);
174 return sh_error_set_level (tmp, &sh_reg_check_severity);
175}
176
177static int sh_reg_add_key_int (const char *s, int isSingle, int isStop)
178{
179 struct regkeylist * newkey;
180 size_t len = sl_strlen(s);
181
182 if (len > 0)
183 {
184 newkey = SH_ALLOC(sizeof(struct regkeylist));
185 newkey->single = isSingle;
186 newkey->stop = isStop;
187 newkey->name = NULL;
188
189 if (STOP_FALSE == isStop)
190 {
191 newkey->name = SH_ALLOC(len + 1);
192 sl_strlcpy(newkey->name, s, len+1);
193 }
194 else
195 {
196#ifdef HAVE_REGEX_H
197 int status = regcomp(&(newkey->preg), s, REG_NOSUB|REG_EXTENDED);
198 if (status != 0)
199 {
[403]200 char errbuf[512];
201 char *p;
[294]202 regerror(status, &(newkey->preg), errbuf, sizeof(errbuf));
[403]203
204 sl_strlcat(errbuf, ": ", sizeof(errbuf));
205 p = sh_util_safe_name_keepspace(s);
206 sl_strlcat(errbuf, p, sizeof(errbuf));
207 SH_FREE(p);
208
[294]209 SH_MUTEX_LOCK(mutex_thread_nolog);
210 sh_error_handle((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
211 errbuf, _("sh_reg_add_key_int"));
212 SH_MUTEX_UNLOCK(mutex_thread_nolog);
213 SH_FREE(newkey);
214 return -1;
215 }
216#else
217 newkey->name = SH_ALLOC(len + 1);
218 sl_strlcpy(newkey->name, s, len+1);
219#endif
220 }
221 newkey->next = keylist;
222 keylist = newkey;
223 return 0;
224 }
225 return -1;
226}
227
228static int sh_reg_add_key (const char *s)
229{
230 return sh_reg_add_key_int (s, S_TRUE, STOP_FALSE);
231}
232static int sh_reg_add_hierarchy (const char *s)
233{
234 return sh_reg_add_key_int (s, S_FALSE, STOP_FALSE);
235}
236static int sh_reg_add_stop (const char *s)
237{
238 return sh_reg_add_key_int (s, S_FALSE, STOP_CHECK);
239}
240static int sh_reg_add_ign (const char *s)
241{
242 return sh_reg_add_key_int (s, S_FALSE, STOP_IGN);
243}
244
245/* Module functions */
246
247int sh_reg_check_init(struct mod_type * arg)
248{
249#ifndef HAVE_PTHREAD
250 (void) arg;
251#endif
252
253 if (ShRegCheckActive == S_FALSE)
254 return SH_MOD_FAILED;
255#ifdef HAVE_PTHREAD
256 if (arg != NULL && arg->initval < 0 &&
257 (sh.flag.isdaemon == S_TRUE || sh.flag.loop == S_TRUE))
258 {
259 if (0 == sh_pthread_create(sh_threaded_module_run, (void *)arg))
260 return SH_MOD_THREAD;
261 else
262 return SH_MOD_FAILED;
263 }
[335]264 else if (arg != NULL && arg->initval == SH_MOD_THREAD &&
265 (sh.flag.isdaemon == S_TRUE || sh.flag.loop == S_TRUE))
266 {
267 return SH_MOD_THREAD;
268 }
[294]269#endif
270 return 0;
271}
272
273int sh_reg_check_timer(time_t tcurrent)
274{
275 static time_t lastcheck = 0;
276
277 SL_ENTER(_("sh_reg_check_timer"));
278 if ((time_t) (tcurrent - lastcheck) >= sh_reg_check_interval)
279 {
280 lastcheck = tcurrent;
281 SL_RETURN((-1), _("sh_reg_check_timer"));
282 }
283 SL_RETURN(0, _("sh_reg_check_timer"));
284}
285
286#define SH_REGFORM_NEW 1
287#define SH_REGFORM_OLD 2
288
289static char * format_changes(int flag, char * buf, size_t len,
290 time_t time_old, unsigned long size_old,
291 unsigned long keys_old, unsigned long values_old,
292 char * hash_old,
293 time_t time_new, unsigned long size_new,
294 unsigned long keys_new, unsigned long values_new,
295 char * hash_new)
296{
297 char timestr1[32];
298 char timestr2[32];
299 char timestr3[32];
300
301 char buf_old[512] = "";
302 char buf_new[512] = "";
303
304 if ((0 != (flag & SH_REGFORM_NEW)) && (NULL != hash_new))
305 {
306 (void) sh_unix_gmttime (time_new, timestr1, sizeof(timestr1));
307 (void) sh_unix_gmttime (keys_new, timestr2, sizeof(timestr2));
308 (void) sh_unix_gmttime (values_new, timestr3, sizeof(timestr3));
309
310#ifdef SH_USE_XML
311 sl_snprintf(buf_new, sizeof(buf_new),
312 "size_new=\"%lu\" mtime_new=\"%s\" ctime_new=\"%s\" atime_new=\"%s\" chksum_new=\"%s\"",
313 size_new, timestr1, timestr2, timestr3, hash_new);
314#else
315 sl_snprintf(buf_new, sizeof(buf_new),
316 "size_new=<%lu>, mtime_new=<%s>, ctime_new=<%s>, atime_new=<%s>, chksum_new=<%s>",
317 size_new, timestr1, timestr2, timestr3, hash_new);
318#endif
319 }
320
321 if ((0 != (flag & SH_REGFORM_OLD)) && (NULL != hash_old))
322 {
323 (void) sh_unix_gmttime (time_old, timestr1, sizeof(timestr1));
324 (void) sh_unix_gmttime (keys_old, timestr2, sizeof(timestr2));
325 (void) sh_unix_gmttime (values_old, timestr3, sizeof(timestr3));
326
327#ifdef SH_USE_XML
328 sl_snprintf(buf_old, sizeof(buf_old),
329 " size_old=\"%lu\" mtime_old=\"%s\" ctime_old=\"%s\" atime_old=\"%s\" chksum_old=\"%s\"",
330 size_old, timestr1, timestr2, timestr3, hash_old);
331#else
332 sl_snprintf(buf_old, sizeof(buf_old),
333 " size_old=<%lu>, mtime_old=<%s>, ctime_old=<%s>, atime_old=<%s>, chksum_old=<%s>",
334 size_old, timestr1, timestr2, timestr3, hash_old);
335#endif
336 }
337
338 sl_strlcpy(buf, buf_new, len);
339 sl_strlcat(buf, buf_old, len);
340
341 return buf;
342}
343
344static void report_missing_entry(const char * path)
345{
346 char * infobuf = SH_ALLOC(1024);
347 char * errbuf = SH_ALLOC(1024);
348 char * tmp = sh_util_safe_name (path);
349 char timestr[32];
350 struct store2db save;
351
352 memset(&save, '\0', sizeof(struct store2db));
353 sh_hash_db2pop (path, &save);
354
355 (void) sh_unix_gmttime (save.val1, timestr, sizeof(timestr));
356
357 sl_snprintf(infobuf, 1024, _("mtime=%s size=%lu subkeys=%lu values=%lu"),
358 timestr,
359 (unsigned long) save.val0,
360 (unsigned long) save.val2,
361 (unsigned long) save.val3);
362
363 (void) format_changes (SH_REGFORM_OLD, errbuf, 1024,
364 save.val1, save.val0, save.val2, save.val3, save.checksum,
365 0, 0, 0, 0, NULL);
366
367 SH_MUTEX_LOCK(mutex_thread_nolog);
368 sh_error_handle(sh_reg_check_severity, FIL__, __LINE__, 0, MSG_REG_MISS,
369 infobuf, tmp, errbuf);
370 SH_MUTEX_UNLOCK(mutex_thread_nolog);
371
372 SH_FREE(tmp);
373 SH_FREE(errbuf);
374 SH_FREE(infobuf);
375 return;
376}
377
378int sh_reg_check_run(void)
379{
380 struct regkeylist *this = keylist;
381
382 if (this)
383 {
384 SH_MUTEX_LOCK(mutex_thread_nolog);
385 sh_error_handle(SH_ERR_INFO, FIL__, __LINE__, 0, MSG_E_SUBGEN,
386 _("Checking the registry"),
387 _("sh_reg_check_run"));
388 SH_MUTEX_UNLOCK(mutex_thread_nolog);
389
390 while (this)
391 {
392 if (STOP_FALSE == this->stop)
393 {
394 /*
395 * -- Check key --
396 */
397 check_key (this->name, this->single);
398 }
399 this = this->next;
400 }
401 }
402 sh_hash_unvisited_custom ('H', report_missing_entry);
403
404 return 0;
405}
406
407int sh_reg_check_reconf(void)
408{
409 struct regkeylist *this;
410
411 while (keylist)
412 {
413 this = keylist;
414 keylist = keylist->next;
415
416 if (this->name)
417 SH_FREE(this->name);
418#ifdef HAVE_REGEX_H
419 if (STOP_FALSE != this->stop)
420 regfree(&(this->preg));
421#endif
422 SH_FREE(this);
423 }
424
425 sh_reg_check_interval = SH_REGISTRY_INTERVAL;
426
427 return 0;
428}
429
430int sh_reg_check_cleanup(void)
431{
432 sh_reg_check_reconf();
433 return 0;
434}
435
436/* >>>>>>>>>>>> Main check function <<<<<<<<<<<< */
437
438
439#include <windows.h>
440
441#define MAX_KEY_LENGTH (2*256)
442#define MAX_VALUE_NAME (2*16384)
443
444CHAR achValue[MAX_VALUE_NAME];
445
446unsigned long nKeys = 0;
447unsigned long nVals = 0;
448
[312]449static int CheckThisSubkey (HKEY key, char * subkey, char * path,
450 int isSingle, int view);
[294]451
452static time_t convertTime(FILETIME * ft)
453{
454 time_t result;
455
456 /* Shift high part up by 2^32
457 */
458 UINT64 date = ((UINT64)ft->dwHighDateTime) << 32;
459
460 /* Add low part
461 */
462 date |= (UINT64)ft->dwLowDateTime;
463
464 /* Subtract difference between Jan 1, 1601 and Jan 1, 1970
465 */
466 date -= ((UINT64)116444736) * ((UINT64)100) * ((UINT64)10000000);
467
468 /* Divide by number of 100-nanosecond intervals per second
469 */
470 date /= ((UINT64)10000000);
471
472 /* Convert to a time_t
473 */
474 result = (time_t) date;
475
476 return result;
477}
478
[295]479#if !defined(KEY_WOW64_64KEY)
480#define KEY_WOW64_64KEY 0x0100;
481#endif
482#if !defined(KEY_WOW64_32KEY)
483#define KEY_WOW64_32KEY 0x0200;
484#endif
[294]485
486
487#define SH_KEY_NULL _("000000000000000000000000000000000000000000000000")
488
489int QueryKey(HKEY hKey, char * path, size_t pathlen, int isSingle)
490{
491 CHAR achKey[MAX_KEY_LENGTH]; /* buffer for subkey name */
492 DWORD cbName; /* size of name string */
493 /* CHAR achClass[MAX_PATH] = ""; *//* buffer for class name */
494 /* DWORD cchClassName = MAX_PATH/2;*//* size of class string */
495 DWORD cSubKeys=0; /* number of subkeys */
496 DWORD cbMaxSubKey; /* longest subkey size */
497 DWORD cchMaxClass; /* longest class string */
498 DWORD cValues; /* number of values for key */
499 DWORD cchMaxValue; /* longest value name */
500 DWORD cbMaxValueData; /* longest value data */
501 DWORD cbSecurityDescriptor; /* size of security descriptor */
502 FILETIME ftLastWriteTime; /* last write time */
503 DWORD lpType; /* type of data stored in value */
504 BYTE lpData[256]; /* buffer for data in value */
505 DWORD lpcbData; /* size of lpData buffer */
506 DWORD i, retCode;
507 DWORD cchValue = MAX_VALUE_NAME/2;
508
509 char hashbuf[KEYBUF_SIZE];
510 unsigned long totalSize = 0;
511 time_t fTime = 0;
512
513 char * tPath = NULL;
514 int doUpdate = S_FALSE;
515
516 retCode = RegQueryInfoKey(
517 hKey, /* key handle */
518 NULL /* achClass */, /* buffer for class name */
519 NULL /* &cchClassName */,/* size of class string */
520 NULL, /* reserved */
521 &cSubKeys, /* number of subkeys */
522 &cbMaxSubKey, /* longest subkey size */
523 &cchMaxClass, /* longest class string */
524 &cValues, /* number of values for this key */
525 &cchMaxValue, /* longest value name */
526 &cbMaxValueData, /* longest value data */
527 &cbSecurityDescriptor, /* security descriptor */
528 &ftLastWriteTime); /* last write time */
529
530 if (retCode != ERROR_SUCCESS)
531 {
532 return -1;
533 }
534
535 ++nKeys;
536
537 fTime = convertTime (&ftLastWriteTime);
538
539 /* Enumerate the subkeys, until RegEnumKeyEx fails. */
540
541 if (cSubKeys)
542 {
543 /*
544 * printf( "\nNumber of subkeys: %lu\n", (unsigned long) cSubKeys);
545 */
546
547 for (i=0; i<cSubKeys; i++)
548 {
549 cbName = MAX_KEY_LENGTH/2;
550 retCode = RegEnumKeyEx(hKey, i,
551 achKey,
552 &cbName,
553 NULL,
554 NULL,
555 NULL,
556 &ftLastWriteTime);
557
558 if (retCode == ERROR_SUCCESS && S_TRUE != isSingle)
559 {
560 /*
561 * _tprintf(TEXT("(%lu) %s\\%s\n"), (unsigned long) i+1,
562 * path, achKey);
563 */
[312]564 CheckThisSubkey (hKey, achKey, path, isSingle, 0);
[294]565 }
566 }
567 }
568
569 /* Enumerate the key values. */
570
571 if (cValues)
572 {
573 char hashtmp[3][KEYBUF_SIZE];
574
575 memset(hashbuf, '0', sizeof(hashbuf));
576
577 /* Loop over values and build checksum */
578
579 for (i=0, retCode=ERROR_SUCCESS; i<cValues; i++)
580 {
581 LPBYTE lpDataAlloc = NULL;
582
583 cchValue = MAX_VALUE_NAME/2;
584 achValue[0] = '\0';
585 lpcbData = sizeof(lpData);
586 retCode = RegEnumValue(hKey, i,
587 achValue,
588 &cchValue,
589 NULL,
590 &lpType,
591 lpData,
592 &lpcbData);
593
594 if (retCode == ERROR_MORE_DATA)
595 {
596 lpDataAlloc = SH_ALLOC(lpcbData);
597
598 retCode = RegEnumValue(hKey, i,
599 achValue,
600 &cchValue,
601 NULL,
602 &lpType,
603 lpDataAlloc,
604 &lpcbData);
605 }
606
607 if (retCode == ERROR_SUCCESS)
608 {
609 totalSize += lpcbData;
610
611 /* checksum(valuename) */
612 sh_tiger_hash (achValue, TIGER_DATA, cchValue,
613 hashtmp[0], KEYBUF_SIZE);
614
615 /* checksum(valuedata) */
616 if (NULL == lpDataAlloc)
617 {
618 sh_tiger_hash ((char*) lpData, TIGER_DATA, lpcbData,
619 hashtmp[1], KEYBUF_SIZE);
620 }
621 else
622 {
623 sh_tiger_hash ((char*) lpDataAlloc, TIGER_DATA, lpcbData,
624 hashtmp[1], KEYBUF_SIZE);
625 }
626
627 /* old_checksum */
628 memcpy(hashtmp[2], hashbuf, KEYBUF_SIZE);
629
630 /* hash(hash(valuename)+hash(valuedata)+old_hash) */
631 sh_tiger_hash ((char*) hashtmp, TIGER_DATA,
632 sizeof(hashtmp), hashbuf, sizeof(hashbuf));
633
634 ++nVals;
635 }
636
637 if (lpDataAlloc)
638 {
639 SH_FREE(lpDataAlloc);
640 }
641 }
642 }
643 else
644 {
645 /* no values */
646 sl_strlcpy(hashbuf, SH_KEY_NULL, sizeof(hashbuf));
647 }
648
649 /* Here we have:
650 * hashbuf [checksum over values],
651 * fTime [last write time],
652 * totalSize [size of all value data],
653 * cSubKeys [number of subkeys],
654 * cValues [number of values],
655 * path, pathlen [which may be up to 131072 (256*512) bytes]
656 */
657
658 if (pathlen > (PATH_MAX-1))
659 {
660 char hashbuf2[KEYBUF_SIZE];
661 char * p = strchr(path, '\\');
662
663 if (p)
664 {
665 char *q = p;
666
667 ++p;
668
669 tPath = SH_ALLOC(256 + KEYBUF_SIZE);
670 *q = '\0';
671 sl_strlcpy(tPath, path, 256); /* truncates */
672 *q = '\\';
673 sl_strlcat(tPath, "\\", 257);
674 (void) sh_tiger_hash(p, TIGER_DATA, sl_strlen(p),
675 hashbuf2, sizeof(hashbuf2));
676 sl_strlcat(tPath, hashbuf2, 256 + KEYBUF_SIZE);
677 }
678 }
679
680 if (sh.flag.checkSum == SH_CHECK_CHECK || sh.flag.update == S_TRUE)
681 {
682 struct store2db save;
683
684 memset(&save, '\0', sizeof(struct store2db));
685
686 if (tPath)
687 {
688 sh_hash_db2pop (tPath, &save);
689 }
690 else
691 {
692 sh_hash_db2pop (path, &save);
693 }
694
695 if (save.size == -1)
696 {
697 /* Not in database */
698
699 char * infobuf = SH_ALLOC(1024);
700 char * errbuf = SH_ALLOC(1024);
701 char * tmp = sh_util_safe_name ((tPath == NULL) ? path : tPath);
702 char timestr[32];
703
704 (void) sh_unix_gmttime (fTime, timestr, sizeof(timestr));
705
706 sl_snprintf(infobuf, 1024,
707 _("mtime=%s size=%lu subkeys=%lu values=%lu"),
708 timestr,
709 (unsigned long) totalSize,
710 (unsigned long) cSubKeys,
711 (unsigned long) cValues);
712
713 (void) format_changes (SH_REGFORM_NEW, errbuf, 1024,
714 0, 0, 0, 0, NULL,
715 fTime, totalSize, cSubKeys, cValues, hashbuf);
716
717 SH_MUTEX_LOCK(mutex_thread_nolog);
718 sh_error_handle(sh_reg_check_severity, FIL__, __LINE__,
719 0, MSG_REG_NEW,
720 infobuf, tmp, errbuf);
721 SH_MUTEX_UNLOCK(mutex_thread_nolog);
722
723 SH_FREE(tmp);
724 SH_FREE(errbuf);
725 SH_FREE(infobuf);
726
727 doUpdate = S_TRUE;
728 }
[422]729 else if (save.val0 != totalSize ||
[294]730 save.val2 != cSubKeys ||
731 save.val3 != cValues ||
[422]732 0 != strcmp(save.checksum, hashbuf) ||
733 ( (((time_t) save.val1) != fTime) && (ShRegIgnTime == S_FALSE)) )
[294]734 {
735 /* Change detected */
736 char * infobuf = SH_ALLOC(1024);
737 char * errbuf = SH_ALLOC(1024);
738 char * tmp = sh_util_safe_name ((tPath == NULL) ? path : tPath);
739 char timestr_new[32];
740
741 (void) sh_unix_gmttime (fTime, timestr_new, sizeof(timestr_new));
742
743 sl_snprintf(infobuf, 1024,
744 _("mtime=%s size %lu->%lu subkeys %lu->%lu values %lu->%lu checksum %s"),
745 timestr_new,
746 (unsigned long) save.val0, (unsigned long) totalSize,
747 (unsigned long) save.val2, (unsigned long) cSubKeys,
748 (unsigned long) save.val3, (unsigned long) cValues,
749 (0 == strcmp(save.checksum, hashbuf)) ? _("good") : _("bad"));
750
751 (void) format_changes (SH_REGFORM_OLD|SH_REGFORM_NEW, errbuf, 1024,
752 save.val1, save.val0,
753 save.val2, save.val3, save.checksum,
754 fTime, totalSize,
755 cSubKeys, cValues, hashbuf);
756
757 SH_MUTEX_LOCK(mutex_thread_nolog);
758 sh_error_handle(sh_reg_check_severity, FIL__, __LINE__,
759 0, MSG_REG_CHANGE,
760 infobuf, tmp, errbuf);
761 SH_MUTEX_UNLOCK(mutex_thread_nolog);
762
763 SH_FREE(tmp);
764 SH_FREE(errbuf);
765 SH_FREE(infobuf);
766
767 doUpdate = S_TRUE;
768 }
[403]769
[294]770 }
771
[403]772 if ( sh.flag.checkSum == SH_CHECK_INIT || doUpdate == S_TRUE /* change detected */ )
[294]773 {
774 struct store2db save;
775
776 memset(&save, '\0', sizeof(struct store2db));
777
778 save.val0 = totalSize;
779 save.val1 = fTime;
780 save.val2 = cSubKeys;
781 save.val3 = cValues;
782 sl_strlcpy(save.checksum, hashbuf, KEY_LEN+1);
783
784 if (tPath)
785 {
786 sh_hash_push2db (tPath, &save);
787 }
788 else
789 {
790 sh_hash_push2db (path, &save);
791 }
792 }
793
[403]794 /* Without this, freshly updated entries would get deleted
795 * as 'not seen'.
796 */
797 if (sh.flag.checkSum != SH_CHECK_INIT)
798 {
799 if (tPath)
800 sh_hash_set_visited (tPath);
801 else
802 sh_hash_set_visited (path);
803 }
[294]804
805 if (tPath)
806 {
807 SH_FREE(tPath);
808 }
809
810 return 0;
811}
812
813static int check_for_stop (char * name)
814{
815 struct regkeylist *this = keylist;
816
817 while (this)
818 {
819 if (STOP_FALSE != this->stop)
820 {
821#ifdef HAVE_REGEX_H
822 if (0 == regexec(&(this->preg), name, 0, NULL, 0))
823 return this->stop;
824#else
825 if (0 == strcmp(this->name, name))
826 return this->stop;
827#endif
828 }
829 this = this->next;
830 }
831 return STOP_FALSE;
832}
833
834
[295]835int CheckThisSubkey (HKEY key, char * subkey, char * path, int isSingle,
836 int view)
[294]837{
838 HKEY hTestKey;
[403]839 LONG qError;
[294]840 char * newpath;
841 size_t len;
842 int retval = -1;
843
844 len = strlen(path) + 1 + strlen(subkey) + 1;
845 newpath = SH_ALLOC(len);
846 snprintf(newpath, len, "%s\\%s", path, subkey);
847
848 /* Check for stop condition, if not single key.
849 * Set flag to isSingle = S_TRUE if we should stop here.
850 */
851 if (S_TRUE != isSingle)
852 {
853 int isStop = check_for_stop(newpath);
854
855 if (STOP_CHECK == isStop)
856 {
857 isSingle = S_TRUE;
858 }
859 else if (STOP_IGN == isStop)
860 {
861 SH_FREE(newpath);
862 return 0;
863 }
864 }
865
866 len = strlen(path) + 1 + strlen(subkey) + 1;
867 newpath = SH_ALLOC(len);
868 snprintf(newpath, len, "%s\\%s", path, subkey);
869
[403]870 qError = RegOpenKeyEx( key,
871 subkey,
872 0,
873 (KEY_READ | view),
874 &hTestKey);
875
876
877 if (qError == ERROR_SUCCESS)
[294]878 {
879 QueryKey(hTestKey, newpath, len-1, isSingle);
880 RegCloseKey(hTestKey);
881 retval = 0;
882 }
883 else
884 {
885 /* Error message */
[403]886 LPVOID lpMsgBuf;
887
888 char * tmp = sh_util_safe_name (newpath);
889 size_t tlen = sl_strlen(tmp);
890
[294]891 if (SL_TRUE == sl_ok_adds(64, tlen))
892 {
[403]893 char * errbuf;
894 size_t elen;
895
896 tlen += 64;
897
898 elen = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
899 FORMAT_MESSAGE_FROM_SYSTEM |
900 FORMAT_MESSAGE_IGNORE_INSERTS,
901 NULL,
902 qError,
903 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
904 (LPTSTR) &lpMsgBuf,
905 0, NULL );
906
907 if (elen > 0 && SL_TRUE == sl_ok_adds(elen, tlen))
908 {
909 tlen += elen;
910
911 errbuf = SH_ALLOC(elen + tlen);
912 sl_snprintf(errbuf, 64+tlen, _("Failed to open key %s: %s"),
913 tmp, lpMsgBuf);
914 LocalFree(lpMsgBuf);
915
916 SH_MUTEX_LOCK(mutex_thread_nolog);
917 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
918 errbuf, _("CheckThisSubkey"));
919 SH_MUTEX_UNLOCK(mutex_thread_nolog);
920
921 SH_FREE(errbuf);
922 }
[294]923 }
[403]924 sh_reg_add_ign (newpath);
[294]925 SH_FREE(tmp);
926 }
927
928 SH_FREE(newpath);
929 return retval;
930}
931
932
933int check_key (char * key, int isSingle)
934{
935 HKEY topKey;
936 char * subkey;
937 char path[20] = "";
938 int pos = 0;
939
940 if (0 == strncmp(key, _("HKEY_CLASSES_ROOT"), 17))
941 {
942 topKey = HKEY_CLASSES_ROOT;
943 pos = 17;
944 strncpy(path, _("HKEY_CLASSES_ROOT"), sizeof(path));
945 }
946 else if (0 == strncmp(key, _("HKEY_CURRENT_USER"), 17))
947 {
948 topKey = HKEY_CURRENT_USER;
949 pos = 17;
950 strncpy(path, _("HKEY_CURRENT_USER"), sizeof(path));
951 }
952 else if (0 == strncmp(key, _("HKEY_LOCAL_MACHINE"), 18))
953 {
954 topKey = HKEY_LOCAL_MACHINE;
955 pos = 18;
956 strncpy(path, _("HKEY_LOCAL_MACHINE"), sizeof(path));
957 }
958 else if (0 == strncmp(key, _("HKEY_USERS"), 10))
959 {
960 topKey = HKEY_USERS;
961 pos = 10;
962 strncpy(path, _("HKEY_USERS"), sizeof(path));
963 }
964
965
966 if (pos > 0)
967 {
968 if (key[pos] == '\\')
969 {
970 ++pos;
971 subkey = &key[pos];
972 }
973 }
974 else
975 {
976
977 char * tmp = sh_util_safe_name_keepspace(key);
978 size_t tlen = sl_strlen(tmp);
979
980 if (SL_TRUE == sl_ok_adds(64, tlen))
981 {
982 char * errbuf = SH_ALLOC(64 + tlen);
983
984 sl_snprintf(errbuf, 64+tlen, _("Invalid key %s"), tmp);
985
986 SH_MUTEX_LOCK(mutex_thread_nolog);
987 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
988 errbuf, _("check_key"));
989 SH_MUTEX_UNLOCK(mutex_thread_nolog);
990
991 SH_FREE(errbuf);
992 }
993 SH_FREE(tmp);
994 return -1;
995 }
[295]996
997 /************************
998 if (ShCheckBothViews)
999 {
1000 CheckThisSubkey (topKey, subkey, path, isSingle, KEY_WOW64_32KEY);
1001 return CheckThisSubkey (topKey, subkey, path, isSingle, KEY_WOW64_64KEY);
1002 }
1003 *************************/
1004
1005 return CheckThisSubkey (topKey, subkey, path, isSingle, 0);
[294]1006}
1007
1008/* #if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE) */
1009#endif
1010
1011/* #ifdef USE_REGISTRY_CHECK */
1012#endif
1013
Note: See TracBrowser for help on using the repository browser.