winevt_c 0.10.1 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9d3ebf96df7a93d6d2a4dae15cba8cc7a76617e752f758aeb8c355c43abd988d
4
- data.tar.gz: de33f1ee85dacba17dbe5b32e98a45d4a57fdde7d931db70dd3b4e054f22c82b
3
+ metadata.gz: 53a1d55d20095680cdb54820e8b0b9293fe40e2a16ae74a897ea3f5b0a1cf05d
4
+ data.tar.gz: '080132cb71100664e30b9ef7e9c1f2c49542b7f92f5c78b25d3b893fc459bb5b'
5
5
  SHA512:
6
- metadata.gz: 83bbe0ca77653a773bf29005236478865f1efb9917f312b5fc8f37485a3ddd068962f4eb2bac7da99916fcd0553b78ed140ac1900441c397e767bad39915c09d
7
- data.tar.gz: fdf8aba88fb62518e52ea4dc65d44247706c5a578e078c224a850323737af2d886afc525fd431ca2652a8a65e375bfc2c960b94667e4839c155ab82f5b3462f1
6
+ metadata.gz: dbd64322ff92fb89c723a2d963fb1b706a169d40a620985adf8ea9cb4eb5654a5df206d07346834c68334e157224c6d71fc9e38762c010eca73df34f1dd68662
7
+ data.tar.gz: a514c1c356b1d62c44c19887ce24790cc5efa966a9184470df1fc2317f88d436b24caa61600b62cf5d4d8bddbcf07cccaacd2d2b48fa9b14e0c2adf772db9d11
@@ -8,7 +8,7 @@ jobs:
8
8
  strategy:
9
9
  fail-fast: false
10
10
  matrix:
11
- ruby: [ '2.4', '2.5', '2.6', '2.7', '3.0' ]
11
+ ruby: [ '3.0', '3.1', '3.2' ]
12
12
  os:
13
13
  - ubuntu-latest
14
14
  name: Ruby ${{ matrix.ruby }} building fat gem testing on ${{ matrix.os }}
data/appveyor.yml CHANGED
@@ -38,11 +38,16 @@ for:
38
38
  matrix:
39
39
  only:
40
40
  - ruby_version: "31-x64"
41
+ - ruby_version: "27-x64"
42
+ - ruby_version: "27"
43
+ - ruby_version: "26-x64"
44
+ - ruby_version: "26"
41
45
  install:
46
+ - ps: if ($ENV:ruby_version -ne "31-x64") { .\ruby_install.ps1 }
42
47
  - SET PATH=C:\Ruby%ruby_version%\bin;%PATH%
43
48
  - ruby --version
44
49
  - gem --version
45
50
  - bundle --version
46
- - ridk.cmd install 1 3
51
+ - ps: if ($ENV:ruby_version -eq "31-x64") { ridk.ps1 install 1 3 }
47
52
  - ridk.cmd exec bundle install
48
53
  - ridk.cmd exec bundle exec rake compile
@@ -14,6 +14,9 @@ have_library("wevtapi")
14
14
  have_func("EvtQuery", "winevt.h")
15
15
  have_library("advapi32")
16
16
  have_library("ole32")
17
+ if have_macro("RB_ALLOCV")
18
+ $CFLAGS << " -DHAVE_RB_ALLOCV=1 "
19
+ end
17
20
 
18
21
  $LDFLAGS << " -lwevtapi -ladvapi32 -lole32"
19
22
  $CFLAGS << " -Wall -std=c99 -fPIC -fms-extensions "
data/ext/winevt/winevt.c CHANGED
@@ -7,6 +7,7 @@ VALUE rb_cSubscribe;
7
7
  VALUE rb_eWinevtQueryError;
8
8
  VALUE rb_eChannelNotFoundError;
9
9
  VALUE rb_eRemoteHandlerError;
10
+ VALUE rb_eSubscribeHandlerError;
10
11
 
11
12
  static ID id_call;
12
13
 
@@ -20,6 +21,7 @@ Init_winevt(void)
20
21
  rb_eWinevtQueryError = rb_define_class_under(rb_cQuery, "Error", rb_eStandardError);
21
22
  rb_eChannelNotFoundError = rb_define_class_under(rb_cEventLog, "ChannelNotFoundError", rb_eStandardError);
22
23
  rb_eRemoteHandlerError = rb_define_class_under(rb_cSubscribe, "RemoteHandlerError", rb_eRuntimeError);
24
+ rb_eSubscribeHandlerError = rb_define_class_under(rb_cSubscribe, "SubscribeHandlerError", rb_eRuntimeError);
23
25
 
24
26
  Init_winevt_channel(rb_cEventLog);
25
27
  Init_winevt_bookmark(rb_cEventLog);
@@ -16,6 +16,11 @@
16
16
  #endif /* WIN32_WINNT */
17
17
  #define _WIN32_WINNT MINIMUM_WINDOWS_VERSION
18
18
 
19
+ #if !defined(HAVE_RB_ALLOCV)
20
+ #define ALLOCV RB_ALLOCV
21
+ #define ALLOCV_N RB_ALLOCV_N
22
+ #endif
23
+
19
24
  #include <time.h>
20
25
  #include <winevt.h>
21
26
  #define EventQuery(object) ((struct WinevtQuery*)DATA_PTR(object))
@@ -33,6 +38,9 @@ typedef struct {
33
38
  extern "C" {
34
39
  #endif /* __cplusplus */
35
40
 
41
+ #define WINEVT_UTILS_ERROR_NONE_MAPPED -1
42
+ #define WINEVT_UTILS_ERROR_OTHERS -2
43
+
36
44
  VALUE wstr_to_rb_str(UINT cp, const WCHAR* wstr, int clen);
37
45
  #if defined(__cplusplus)
38
46
  [[ noreturn ]]
@@ -46,7 +54,7 @@ EVT_HANDLE connect_to_remote(LPWSTR computerName, LPWSTR domain,
46
54
  DWORD *error_code);
47
55
  WCHAR* get_description(EVT_HANDLE handle, LANGID langID, EVT_HANDLE hRemote);
48
56
  VALUE get_values(EVT_HANDLE handle);
49
- VALUE render_system_event(EVT_HANDLE handle, BOOL preserve_qualifiers);
57
+ VALUE render_system_event(EVT_HANDLE handle, BOOL preserve_qualifiers, BOOL preserveSID);
50
58
  LocaleInfo* get_locale_info_from_rb_str(VALUE rb_locale_str);
51
59
 
52
60
  #ifdef __cplusplus
@@ -61,6 +69,7 @@ extern VALUE rb_cSubscribe;
61
69
  extern VALUE rb_eWinevtQueryError;
62
70
  extern VALUE rb_eChannelNotFoundError;
63
71
  extern VALUE rb_eRemoteHandlerError;
72
+ extern VALUE rb_eSubscribeHandlerError;
64
73
  extern VALUE rb_cLocale;
65
74
  extern VALUE rb_cSession;
66
75
 
@@ -100,6 +109,7 @@ struct WinevtQuery
100
109
  LONG timeout;
101
110
  BOOL renderAsXML;
102
111
  BOOL preserveQualifiers;
112
+ BOOL preserveSID;
103
113
  LocaleInfo *localeInfo;
104
114
  EVT_HANDLE remoteHandle;
105
115
  };
@@ -121,6 +131,7 @@ struct WinevtSubscribe
121
131
  DWORD currentRate;
122
132
  BOOL renderAsXML;
123
133
  BOOL preserveQualifiers;
134
+ BOOL preserveSID;
124
135
  LocaleInfo* localeInfo;
125
136
  EVT_HANDLE remoteHandle;
126
137
  };
@@ -85,15 +85,15 @@ static VALUE
85
85
  rb_winevt_query_initialize(VALUE argc, VALUE *argv, VALUE self)
86
86
  {
87
87
  PWSTR evtChannel, evtXPath;
88
- VALUE channel, xpath, session;
88
+ VALUE channel, xpath, session, rb_flags;
89
89
  struct WinevtQuery* winevtQuery;
90
90
  struct WinevtSession* winevtSession;
91
91
  EVT_HANDLE hRemoteHandle = NULL;
92
- DWORD len;
92
+ DWORD len, flags = 0;
93
93
  VALUE wchannelBuf, wpathBuf;
94
94
  DWORD err = ERROR_SUCCESS;
95
95
 
96
- rb_scan_args(argc, argv, "21", &channel, &xpath, &session);
96
+ rb_scan_args(argc, argv, "22", &channel, &xpath, &session, &rb_flags);
97
97
  Check_Type(channel, T_STRING);
98
98
  Check_Type(xpath, T_STRING);
99
99
 
@@ -111,6 +111,17 @@ rb_winevt_query_initialize(VALUE argc, VALUE *argv, VALUE self)
111
111
  }
112
112
  }
113
113
 
114
+ switch (TYPE(rb_flags)) {
115
+ case T_FIXNUM:
116
+ flags = NUM2LONG(rb_flags);
117
+ break;
118
+ case T_NIL:
119
+ flags = EvtQueryChannelPath | EvtQueryTolerateQueryErrors;
120
+ break;
121
+ default:
122
+ rb_raise(rb_eArgError, "Expected a String, a Symbol, a Fixnum, or a NilClass instance");
123
+ }
124
+
114
125
  // channel : To wide char
115
126
  len =
116
127
  MultiByteToWideChar(CP_UTF8, 0, RSTRING_PTR(channel), RSTRING_LEN(channel), NULL, 0);
@@ -128,7 +139,7 @@ rb_winevt_query_initialize(VALUE argc, VALUE *argv, VALUE self)
128
139
  TypedData_Get_Struct(self, struct WinevtQuery, &rb_winevt_query_type, winevtQuery);
129
140
 
130
141
  winevtQuery->query = EvtQuery(
131
- hRemoteHandle, evtChannel, evtXPath, EvtQueryChannelPath | EvtQueryTolerateQueryErrors);
142
+ hRemoteHandle, evtChannel, evtXPath, flags);
132
143
  err = GetLastError();
133
144
  if (err != ERROR_SUCCESS) {
134
145
  if (err == ERROR_EVT_CHANNEL_NOT_FOUND) {
@@ -142,6 +153,7 @@ rb_winevt_query_initialize(VALUE argc, VALUE *argv, VALUE self)
142
153
  winevtQuery->preserveQualifiers = FALSE;
143
154
  winevtQuery->localeInfo = &default_locale;
144
155
  winevtQuery->remoteHandle = hRemoteHandle;
156
+ winevtQuery->preserveSID = TRUE;
145
157
 
146
158
  ALLOCV_END(wchannelBuf);
147
159
  ALLOCV_END(wpathBuf);
@@ -263,7 +275,8 @@ rb_winevt_query_render(VALUE self, EVT_HANDLE event)
263
275
  if (winevtQuery->renderAsXML) {
264
276
  return render_to_rb_str(event, EvtRenderEventXml);
265
277
  } else {
266
- return render_system_event(event, winevtQuery->preserveQualifiers);
278
+ return render_system_event(event, winevtQuery->preserveQualifiers,
279
+ winevtQuery->preserveSID);
267
280
  }
268
281
  }
269
282
 
@@ -524,6 +537,40 @@ rb_winevt_query_get_locale(VALUE self)
524
537
  }
525
538
  }
526
539
 
540
+ /*
541
+ * This method specifies whether preserving SID or not.
542
+ *
543
+ * @param rb_preserve_sid_p [Boolean]
544
+ */
545
+ static VALUE
546
+ rb_winevt_query_set_preserve_sid(VALUE self, VALUE rb_preserve_sid_p)
547
+ {
548
+ struct WinevtQuery* winevtQuery;
549
+
550
+ TypedData_Get_Struct(
551
+ self, struct WinevtQuery, &rb_winevt_query_type, winevtQuery);
552
+
553
+ winevtQuery->preserveSID = RTEST(rb_preserve_sid_p);
554
+
555
+ return Qnil;
556
+ }
557
+
558
+ /*
559
+ * This method returns whether preserving SID or not.
560
+ *
561
+ * @return [Boolean]
562
+ */
563
+ static VALUE
564
+ rb_winevt_query_preserve_sid_p(VALUE self)
565
+ {
566
+ struct WinevtQuery* winevtQuery;
567
+
568
+ TypedData_Get_Struct(
569
+ self, struct WinevtQuery, &rb_winevt_query_type, winevtQuery);
570
+
571
+ return winevtQuery->preserveSID ? Qtrue : Qfalse;
572
+ }
573
+
527
574
  /*
528
575
  * This method cancels channel query.
529
576
  *
@@ -613,6 +660,37 @@ Init_winevt_query(VALUE rb_cEventLog)
613
660
  * @see https://msdn.microsoft.com/en-us/windows/desktop/aa385575#EvtSeekStrict
614
661
  */
615
662
  rb_define_const(rb_cFlag, "Strict", LONG2NUM(EvtSeekStrict));
663
+
664
+ /*
665
+ * EVT_QUERY_FLAGS enumeration: EvtQueryChannelPath
666
+ * @since 0.11.0
667
+ * @see https://learn.microsoft.com/en-us/windows/win32/api/winevt/ne-winevt-evt_query_flags
668
+ */
669
+ rb_define_const(rb_cFlag, "ChannelPath", LONG2NUM(EvtQueryChannelPath));
670
+ /*
671
+ * EVT_QUERY_FLAGS enumeration: EvtQueryFilePath
672
+ * @since 0.11.0
673
+ * @see https://learn.microsoft.com/en-us/windows/win32/api/winevt/ne-winevt-evt_query_flags
674
+ */
675
+ rb_define_const(rb_cFlag, "FilePath", LONG2NUM(EvtQueryFilePath));
676
+ /*
677
+ * EVT_QUERY_FLAGS enumeration: EvtQueryForwardDirection
678
+ * @since 0.11.0
679
+ * @see https://learn.microsoft.com/en-us/windows/win32/api/winevt/ne-winevt-evt_query_flags
680
+ */
681
+ rb_define_const(rb_cFlag, "ForwardDirection", LONG2NUM(EvtQueryForwardDirection));
682
+ /*
683
+ * EVT_QUERY_FLAGS enumeration: EvtQueryReverseDirection
684
+ * @since 0.11.0
685
+ * @see https://learn.microsoft.com/en-us/windows/win32/api/winevt/ne-winevt-evt_query_flags
686
+ */
687
+ rb_define_const(rb_cFlag, "ReverseDirection", LONG2NUM(EvtQueryReverseDirection));
688
+ /*
689
+ * EVT_QUERY_FLAGS enumeration: EvtSeekOriginMask
690
+ * @since 0.11.0
691
+ * @see https://learn.microsoft.com/en-us/windows/win32/api/winevt/ne-winevt-evt_query_flags
692
+ */
693
+ rb_define_const(rb_cFlag, "TolerateQueryErrors", LONG2NUM(EvtQueryTolerateQueryErrors));
616
694
  /* clang-format on */
617
695
 
618
696
  rb_define_method(rb_cQuery, "initialize", rb_winevt_query_initialize, -1);
@@ -641,6 +719,14 @@ Init_winevt_query(VALUE rb_cEventLog)
641
719
  * @since 0.8.0
642
720
  */
643
721
  rb_define_method(rb_cQuery, "locale=", rb_winevt_query_set_locale, 1);
722
+ /*
723
+ * @since 0.11.0
724
+ */
725
+ rb_define_method(rb_cQuery, "preserve_sid?", rb_winevt_query_preserve_sid_p, 0);
726
+ /*
727
+ * @since 0.11.0
728
+ */
729
+ rb_define_method(rb_cQuery, "preserve_sid=", rb_winevt_query_set_preserve_sid, 1);
644
730
  /*
645
731
  * @since 0.9.1
646
732
  */
@@ -110,6 +110,7 @@ rb_winevt_subscribe_initialize(VALUE self)
110
110
  winevtSubscribe->readExistingEvents = TRUE;
111
111
  winevtSubscribe->preserveQualifiers = FALSE;
112
112
  winevtSubscribe->localeInfo = &default_locale;
113
+ winevtSubscribe->preserveSID = TRUE;
113
114
 
114
115
  return Qnil;
115
116
  }
@@ -174,7 +175,7 @@ rb_winevt_subscribe_subscribe(int argc, VALUE* argv, VALUE self)
174
175
  struct WinevtSession* winevtSession;
175
176
  struct WinevtSubscribe* winevtSubscribe;
176
177
 
177
- hSignalEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
178
+ hSignalEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
178
179
 
179
180
  TypedData_Get_Struct(
180
181
  self, struct WinevtSubscribe, &rb_winevt_subscribe_type, winevtSubscribe);
@@ -341,6 +342,8 @@ rb_winevt_subscribe_next(VALUE self)
341
342
  EVT_HANDLE hEvents[SUBSCRIBE_ARRAY_SIZE];
342
343
  ULONG count = 0;
343
344
  DWORD status = ERROR_SUCCESS;
345
+ DWORD dwWait = 0;
346
+
344
347
  struct WinevtSubscribe* winevtSubscribe;
345
348
 
346
349
  TypedData_Get_Struct(
@@ -355,6 +358,23 @@ rb_winevt_subscribe_next(VALUE self)
355
358
  return Qfalse;
356
359
  }
357
360
 
361
+ /* If a signalEvent notifies whether a state of processed event(s)
362
+ * is existing or not.
363
+ * For checking for a result of WaitForSingleObject,
364
+ * we need to raise SubscribeHandlerError exception when
365
+ * WAIT_FAILED is detected for further investigations.
366
+ * Note that we don't need to wait explicitly here.
367
+ * Because this function is inside of each enumerator.
368
+ * So, WaitForSingleObject should return immediately and should be
369
+ * processed with the latter each loops if there is no more items.
370
+ * Just intended to check that there is no errors here. */
371
+ dwWait = WaitForSingleObject(winevtSubscribe->signalEvent, 0);
372
+ if (dwWait == WAIT_FAILED) {
373
+ raise_system_error(rb_eSubscribeHandlerError, GetLastError());
374
+ } else if (dwWait != WAIT_OBJECT_0) {
375
+ return Qfalse;
376
+ }
377
+
358
378
  if (!EvtNext(winevtSubscribe->subscription,
359
379
  SUBSCRIBE_ARRAY_SIZE,
360
380
  hEvents,
@@ -368,6 +388,8 @@ rb_winevt_subscribe_next(VALUE self)
368
388
  if (ERROR_NO_MORE_ITEMS != status) {
369
389
  return Qfalse;
370
390
  }
391
+
392
+ ResetEvent(winevtSubscribe->signalEvent);
371
393
  }
372
394
 
373
395
  if (status == ERROR_SUCCESS) {
@@ -396,7 +418,8 @@ rb_winevt_subscribe_render(VALUE self, EVT_HANDLE event)
396
418
  if (winevtSubscribe->renderAsXML) {
397
419
  return render_to_rb_str(event, EvtRenderEventXml);
398
420
  } else {
399
- return render_system_event(event, winevtSubscribe->preserveQualifiers);
421
+ return render_system_event(event, winevtSubscribe->preserveQualifiers,
422
+ winevtSubscribe->preserveSID);
400
423
  }
401
424
  }
402
425
 
@@ -653,6 +676,40 @@ rb_winevt_subscribe_get_locale(VALUE self)
653
676
  }
654
677
  }
655
678
 
679
+ /*
680
+ * This method specifies whether preserving SID or not.
681
+ *
682
+ * @param rb_preserve_sid_p [Boolean]
683
+ */
684
+ static VALUE
685
+ rb_winevt_subscribe_set_preserve_sid(VALUE self, VALUE rb_preserve_sid_p)
686
+ {
687
+ struct WinevtSubscribe* winevtSubscribe;
688
+
689
+ TypedData_Get_Struct(
690
+ self, struct WinevtSubscribe, &rb_winevt_subscribe_type, winevtSubscribe);
691
+
692
+ winevtSubscribe->preserveSID = RTEST(rb_preserve_sid_p);
693
+
694
+ return Qnil;
695
+ }
696
+
697
+ /*
698
+ * This method returns whether preserving SID or not.
699
+ *
700
+ * @return [Boolean]
701
+ */
702
+ static VALUE
703
+ rb_winevt_subscribe_preserve_sid_p(VALUE self)
704
+ {
705
+ struct WinevtSubscribe* winevtSubscribe;
706
+
707
+ TypedData_Get_Struct(
708
+ self, struct WinevtSubscribe, &rb_winevt_subscribe_type, winevtSubscribe);
709
+
710
+ return winevtSubscribe->preserveSID ? Qtrue : Qfalse;
711
+ }
712
+
656
713
  /*
657
714
  * This method cancels channel subscription.
658
715
  *
@@ -750,6 +807,14 @@ Init_winevt_subscribe(VALUE rb_cEventLog)
750
807
  */
751
808
  rb_define_method(
752
809
  rb_cSubscribe, "locale=", rb_winevt_subscribe_set_locale, 1);
810
+ /*
811
+ * @since 0.11.0
812
+ */
813
+ rb_define_method(rb_cSubscribe, "preserve_sid?", rb_winevt_subscribe_preserve_sid_p, 0);
814
+ /*
815
+ * @since 0.11.0
816
+ */
817
+ rb_define_method(rb_cSubscribe, "preserve_sid=", rb_winevt_subscribe_set_preserve_sid, 1);
753
818
  /*
754
819
  * @since 0.9.1
755
820
  */
@@ -17,7 +17,7 @@ wstr_to_rb_str(UINT cp, const WCHAR* wstr, int clen)
17
17
  }
18
18
 
19
19
  int len = WideCharToMultiByte(cp, 0, wstr, clen, nullptr, 0, nullptr, nullptr);
20
- ptr = ALLOCV_N(CHAR, vstr, len);
20
+ ptr = RB_ALLOCV_N(CHAR, vstr, len);
21
21
  // For memory safety.
22
22
  ZeroMemory(ptr, sizeof(CHAR) * len);
23
23
  ret = WideCharToMultiByte(cp, 0, wstr, clen, ptr, len, nullptr, nullptr);
@@ -25,11 +25,11 @@ wstr_to_rb_str(UINT cp, const WCHAR* wstr, int clen)
25
25
  // ref: https://docs.microsoft.com/en-us/windows/win32/api/stringapiset/nf-stringapiset-widechartomultibyte#return-value
26
26
  if (ret == 0) {
27
27
  err = GetLastError();
28
- ALLOCV_END(vstr);
28
+ RB_ALLOCV_END(vstr);
29
29
  raise_system_error(rb_eRuntimeError, err);
30
30
  }
31
31
  VALUE str = rb_utf8_str_new_cstr(ptr);
32
- ALLOCV_END(vstr);
32
+ RB_ALLOCV_END(vstr);
33
33
 
34
34
  return str;
35
35
  }
@@ -85,18 +85,18 @@ render_to_rb_str(EVT_HANDLE handle, DWORD flags)
85
85
  EvtRender(nullptr, handle, flags, 0, NULL, &bufferSize, &count);
86
86
 
87
87
  // bufferSize is in bytes, not characters
88
- buffer = (WCHAR*)ALLOCV(vbuffer, bufferSize);
88
+ buffer = (WCHAR*)RB_ALLOCV(vbuffer, bufferSize);
89
89
 
90
90
  succeeded =
91
91
  EvtRender(nullptr, handle, flags, bufferSize, buffer, &bufferSizeUsed, &count);
92
92
  if (!succeeded) {
93
93
  DWORD status = GetLastError();
94
- ALLOCV_END(vbuffer);
94
+ RB_ALLOCV_END(vbuffer);
95
95
  raise_system_error(rb_eWinevtQueryError, status);
96
96
  }
97
97
 
98
98
  result = wstr_to_rb_str(CP_UTF8, buffer, -1);
99
- ALLOCV_END(vbuffer);
99
+ RB_ALLOCV_END(vbuffer);
100
100
 
101
101
  return result;
102
102
  }
@@ -153,7 +153,7 @@ make_displayable_binary_string(PBYTE bin, size_t length)
153
153
  return rb_str_new2("(NULL)");
154
154
  }
155
155
 
156
- buffer = ALLOCV_N(CHAR, vbuffer, size);
156
+ buffer = RB_ALLOCV_N(CHAR, vbuffer, size);
157
157
 
158
158
  for (i = 0; i < length; i++) {
159
159
  for (j = 0; j < 2; j++) {
@@ -164,7 +164,7 @@ make_displayable_binary_string(PBYTE bin, size_t length)
164
164
  buffer[size - 1] = '\0';
165
165
 
166
166
  VALUE str = rb_str_new2(buffer);
167
- ALLOCV_END(vbuffer);
167
+ RB_ALLOCV_END(vbuffer);
168
168
 
169
169
  return str;
170
170
  }
@@ -380,7 +380,7 @@ get_values(EVT_HANDLE handle)
380
380
  renderContext, handle, EvtRenderEventValues, 0, NULL, &bufferSize, &propCount);
381
381
 
382
382
  // bufferSize is in bytes, not array size
383
- pRenderedValues = (PEVT_VARIANT)ALLOCV(vbuffer, bufferSize);
383
+ pRenderedValues = (PEVT_VARIANT)RB_ALLOCV(vbuffer, bufferSize);
384
384
 
385
385
  succeeded = EvtRender(renderContext,
386
386
  handle,
@@ -391,14 +391,14 @@ get_values(EVT_HANDLE handle)
391
391
  &propCount);
392
392
  if (!succeeded) {
393
393
  DWORD status = GetLastError();
394
- ALLOCV_END(vbuffer);
394
+ RB_ALLOCV_END(vbuffer);
395
395
  EvtClose(renderContext);
396
396
  raise_system_error(rb_eWinevtQueryError, status);
397
397
  }
398
398
 
399
399
  userValues = extract_user_evt_variants(pRenderedValues, propCount);
400
400
 
401
- ALLOCV_END(vbuffer);
401
+ RB_ALLOCV_END(vbuffer);
402
402
  EvtClose(renderContext);
403
403
 
404
404
  return userValues;
@@ -596,8 +596,102 @@ cleanup:
596
596
  return _wcsdup(result.data());
597
597
  }
598
598
 
599
+ static char* convert_wstr(wchar_t *wstr)
600
+ {
601
+ VALUE vstr;
602
+ int len = 0;
603
+ CHAR *ptr = NULL;
604
+ DWORD err = ERROR_SUCCESS;
605
+
606
+ len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL);
607
+ if (len == 0) {
608
+ return NULL;
609
+ }
610
+
611
+ ptr = RB_ALLOCV_N(CHAR, vstr, len);
612
+ // For memory safety.
613
+ ZeroMemory(ptr, sizeof(CHAR) * len);
614
+
615
+ len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, ptr, len, NULL, NULL);
616
+ // return 0 should be failure.
617
+ // ref: https://docs.microsoft.com/en-us/windows/win32/api/stringapiset/nf-stringapiset-widechartomultibyte#return-value
618
+ if (len == 0) {
619
+ err = GetLastError();
620
+ RB_ALLOCV_END(vstr);
621
+ raise_system_error(rb_eRuntimeError, err);
622
+ }
623
+
624
+ return strdup(ptr);
625
+ }
626
+
627
+ static int ExpandSIDWString(PSID sid, CHAR **out_expanded)
628
+ {
629
+ #define MAX_NAME 256
630
+ DWORD len = MAX_NAME, err = ERROR_SUCCESS;
631
+ SID_NAME_USE sid_type = SidTypeUnknown;
632
+ WCHAR wAccount[MAX_NAME];
633
+ WCHAR wDomain[MAX_NAME];
634
+ CHAR *account = NULL, *domain = NULL;
635
+ DWORD result_len = 0;
636
+ CHAR *formatted = NULL;
637
+ VALUE vformatted;
638
+ #undef MAX_NAME
639
+
640
+ if (!LookupAccountSidW(NULL, sid,
641
+ wAccount, &len, wDomain,
642
+ &len, &sid_type)) {
643
+ err = GetLastError();
644
+ if (err == ERROR_NONE_MAPPED) {
645
+ goto none_mapped_error;
646
+ }
647
+ else {
648
+ return WINEVT_UTILS_ERROR_OTHERS;
649
+ }
650
+
651
+ goto error;
652
+ }
653
+
654
+ domain = convert_wstr(wDomain);
655
+ if (domain == NULL) {
656
+ goto error;
657
+ }
658
+ account = convert_wstr(wAccount);
659
+ if (account == NULL) {
660
+ goto error;
661
+ }
662
+
663
+ result_len = strlen(domain) + 1 + strlen(account) + 1;
664
+ formatted = (CHAR *)RB_ALLOCV(vformatted, result_len);
665
+ if (formatted == NULL) {
666
+ goto error;
667
+ }
668
+
669
+ _snprintf_s(formatted, result_len, _TRUNCATE, "%s\\%s", domain, account);
670
+
671
+ *out_expanded = strdup(formatted);
672
+
673
+ free(domain);
674
+ free(account);
675
+ RB_ALLOCV_END(vformatted);
676
+
677
+
678
+ return 0;
679
+
680
+ none_mapped_error:
681
+
682
+ return WINEVT_UTILS_ERROR_NONE_MAPPED;
683
+
684
+ error:
685
+ err = GetLastError();
686
+
687
+ RB_ALLOCV_END(vformatted);
688
+ free(domain);
689
+ free(account);
690
+ raise_system_error(rb_eRuntimeError, err);
691
+ }
692
+
599
693
  VALUE
600
- render_system_event(EVT_HANDLE hEvent, BOOL preserve_qualifiers)
694
+ render_system_event(EVT_HANDLE hEvent, BOOL preserve_qualifiers, BOOL preserveSID_p)
601
695
  {
602
696
  DWORD status = ERROR_SUCCESS;
603
697
  EVT_HANDLE hContext = NULL;
@@ -633,7 +727,7 @@ render_system_event(EVT_HANDLE hEvent, BOOL preserve_qualifiers)
633
727
  status = GetLastError();
634
728
  if (ERROR_INSUFFICIENT_BUFFER == status) {
635
729
  dwBufferSize = dwBufferUsed;
636
- pRenderedValues = (PEVT_VARIANT)ALLOCV(vRenderedValues, dwBufferSize);
730
+ pRenderedValues = (PEVT_VARIANT)RB_ALLOCV(vRenderedValues, dwBufferSize);
637
731
  if (pRenderedValues) {
638
732
  EvtRender(hContext,
639
733
  hEvent,
@@ -651,7 +745,7 @@ render_system_event(EVT_HANDLE hEvent, BOOL preserve_qualifiers)
651
745
 
652
746
  if (ERROR_SUCCESS != status) {
653
747
  EvtClose(hContext);
654
- ALLOCV_END(vRenderedValues);
748
+ RB_ALLOCV_END(vRenderedValues);
655
749
 
656
750
  rb_raise(rb_eWinevtQueryError, "EvtRender failed with %lu\n", status);
657
751
  }
@@ -787,14 +881,23 @@ render_system_event(EVT_HANDLE hEvent, BOOL preserve_qualifiers)
787
881
 
788
882
  if (EvtVarTypeNull != pRenderedValues[EvtSystemUserID].Type) {
789
883
  if (ConvertSidToStringSid(pRenderedValues[EvtSystemUserID].SidVal, &pwsSid)) {
790
- rbstr = rb_utf8_str_new_cstr(pwsSid);
791
- rb_hash_aset(hash, rb_str_new2("UserID"), rbstr);
792
- LocalFree(pwsSid);
884
+ CHAR *expandSID = NULL;
885
+ if (preserveSID_p) {
886
+ rbstr = rb_utf8_str_new_cstr(pwsSid);
887
+ rb_hash_aset(hash, rb_str_new2("UserID"), rbstr);
888
+ LocalFree(pwsSid);
889
+ }
890
+ if (ExpandSIDWString(pRenderedValues[EvtSystemUserID].SidVal,
891
+ &expandSID) == 0) {
892
+ rbstr = rb_utf8_str_new_cstr(expandSID);
893
+ free(expandSID);
894
+ rb_hash_aset(hash, rb_str_new2("User"), rbstr);
895
+ }
793
896
  }
794
897
  }
795
898
 
796
899
  EvtClose(hContext);
797
- ALLOCV_END(vRenderedValues);
900
+ RB_ALLOCV_END(vRenderedValues);
798
901
 
799
902
  return hash;
800
903
  }
@@ -1,3 +1,3 @@
1
1
  module Winevt
2
- VERSION = "0.10.1"
2
+ VERSION = "0.11.0"
3
3
  end
data/ruby_install.ps1 ADDED
@@ -0,0 +1,92 @@
1
+ $rubies = @(
2
+ @{
3
+ "version" = "Ruby 2.6.9-1"
4
+ "install_path" = "C:\Ruby26"
5
+ "download_url" = "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-2.6.9-1/rubyinstaller-2.6.9-1-x86.exe"
6
+ "devkit_url" = ""
7
+ "devkit_paths" = @()
8
+ "bundlerV2" = $true
9
+ }
10
+ @{
11
+ "version" = "Ruby 2.6.9-1 (x64)"
12
+ "install_path" = "C:\Ruby26-x64"
13
+ "download_url" = "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-2.6.9-1/rubyinstaller-2.6.9-1-x64.exe"
14
+ "devkit_url" = ""
15
+ "devkit_paths" = @()
16
+ "bundlerV2" = $true
17
+ }
18
+ @{
19
+ "version" = "Ruby 2.7.8-1"
20
+ "install_path" = "C:\Ruby27"
21
+ "download_url" = "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-2.7.8-1/rubyinstaller-2.7.8-1-x86.exe"
22
+ "devkit_url" = ""
23
+ "devkit_paths" = @()
24
+ "bundlerV2" = $true
25
+ }
26
+ @{
27
+ "version" = "Ruby 2.7.8-1 (x64)"
28
+ "install_path" = "C:\Ruby27-x64"
29
+ "download_url" = "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-2.7.8-1/rubyinstaller-2.7.8-1-x64.exe"
30
+ "devkit_url" = ""
31
+ "devkit_paths" = @()
32
+ "bundlerV2" = $true
33
+ }
34
+ )
35
+
36
+ function UpdateRubyPath($rubyPath) {
37
+ $env:path = ($env:path -split ';' | Where-Object { -not $_.contains('\Ruby') }) -join ';'
38
+ $env:path = "$rubyPath;$env:path"
39
+ }
40
+
41
+ function Install-Ruby($ruby) {
42
+ Write-Host "Installing $($ruby.version)" -ForegroundColor Cyan
43
+
44
+ # uninstall existing
45
+ $rubyUninstallPath = "$ruby.install_path\unins000.exe"
46
+ if ([IO.File]::Exists($rubyUninstallPath)) {
47
+ Write-Host " Uninstalling previous Ruby 2.4..." -ForegroundColor Gray
48
+ "`"$rubyUninstallPath`" /silent" | out-file "$env:temp\uninstall-ruby.cmd" -Encoding ASCII
49
+ & "$env:temp\uninstall-ruby.cmd"
50
+ del "$env:temp\uninstall-ruby.cmd"
51
+ Start-Sleep -s 5
52
+ }
53
+
54
+ if (Test-Path $ruby.install_path) {
55
+ Write-Host " Deleting $($ruby.install_path)" -ForegroundColor Gray
56
+ Remove-Item $ruby.install_path -Force -Recurse
57
+ }
58
+
59
+ $exePath = "$($env:TEMP)\rubyinstaller.exe"
60
+
61
+ Write-Host " Downloading $($ruby.version) from $($ruby.download_url)" -ForegroundColor Gray
62
+ (New-Object Net.WebClient).DownloadFile($ruby.download_url, $exePath)
63
+
64
+ Write-Host "Installing..." -ForegroundColor Gray
65
+ cmd /c start /wait $exePath /verysilent /allusers /dir="$($ruby.install_path.replace('\', '/'))" /tasks="noassocfiles,nomodpath,noridkinstall"
66
+ del $exePath
67
+ Write-Host "Installed" -ForegroundColor Green
68
+
69
+ # setup Ruby
70
+ UpdateRubyPath "$($ruby.install_path)\bin"
71
+ Write-Host "ruby --version" -ForegroundColor Gray
72
+ cmd /c ruby --version
73
+
74
+ Write-Host "gem --version" -ForegroundColor Gray
75
+ cmd /c gem --version
76
+
77
+ # list installed gems
78
+ Write-Host "gem list --local" -ForegroundColor Gray
79
+ cmd /c gem list --local
80
+
81
+ # delete temp path
82
+ if ($tempPath) {
83
+ Write-Host " Cleaning up..." -ForegroundColor Gray
84
+ Remove-Item $tempPath -Force -Recurse
85
+ }
86
+
87
+ Write-Host " Done!" -ForegroundColor Green
88
+ }
89
+
90
+ for ($i = 0; $i -lt $rubies.Count; $i++) {
91
+ Install-Ruby $rubies[$i]
92
+ }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: winevt_c
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.1
4
+ version: 0.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hiroshi Hatake
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-09-21 00:00:00.000000000 Z
11
+ date: 2024-08-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -141,6 +141,7 @@ files:
141
141
  - lib/winevt/session.rb
142
142
  - lib/winevt/subscribe.rb
143
143
  - lib/winevt/version.rb
144
+ - ruby_install.ps1
144
145
  - winevt_c.gemspec
145
146
  homepage: https://github.com/fluent-plugins-nursery/winevt_c
146
147
  licenses: