winevt_c 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,220 @@
1
+ #include <winevt_c.h>
2
+
3
+ static void subscribe_free(void *ptr);
4
+
5
+ static const rb_data_type_t rb_winevt_subscribe_type = {
6
+ "winevt/subscribe", {
7
+ 0, subscribe_free, 0,
8
+ }, NULL, NULL,
9
+ RUBY_TYPED_FREE_IMMEDIATELY
10
+ };
11
+
12
+ static void
13
+ subscribe_free(void *ptr)
14
+ {
15
+ struct WinevtSubscribe *winevtSubscribe = (struct WinevtSubscribe *)ptr;
16
+ if (winevtSubscribe->signalEvent)
17
+ CloseHandle(winevtSubscribe->signalEvent);
18
+
19
+ if (winevtSubscribe->subscription)
20
+ EvtClose(winevtSubscribe->subscription);
21
+
22
+ if (winevtSubscribe->bookmark)
23
+ EvtClose(winevtSubscribe->bookmark);
24
+
25
+ if (winevtSubscribe->event)
26
+ EvtClose(winevtSubscribe->event);
27
+
28
+ xfree(ptr);
29
+ }
30
+
31
+ static VALUE
32
+ rb_winevt_subscribe_alloc(VALUE klass)
33
+ {
34
+ VALUE obj;
35
+ struct WinevtSubscribe *winevtSubscribe;
36
+ obj = TypedData_Make_Struct(klass,
37
+ struct WinevtSubscribe,
38
+ &rb_winevt_subscribe_type,
39
+ winevtSubscribe);
40
+ return obj;
41
+ }
42
+
43
+ static VALUE
44
+ rb_winevt_subscribe_initialize(VALUE self)
45
+ {
46
+ return Qnil;
47
+ }
48
+
49
+ static VALUE
50
+ rb_winevt_subscribe_set_tail(VALUE self, VALUE rb_tailing_p)
51
+ {
52
+ struct WinevtSubscribe *winevtSubscribe;
53
+
54
+ TypedData_Get_Struct(self, struct WinevtSubscribe, &rb_winevt_subscribe_type, winevtSubscribe);
55
+
56
+ winevtSubscribe->tailing = RTEST(rb_tailing_p);
57
+
58
+ return Qnil;
59
+ }
60
+
61
+ static VALUE
62
+ rb_winevt_subscribe_tail_p(VALUE self, VALUE rb_flag)
63
+ {
64
+ struct WinevtSubscribe *winevtSubscribe;
65
+
66
+ TypedData_Get_Struct(self, struct WinevtSubscribe, &rb_winevt_subscribe_type, winevtSubscribe);
67
+
68
+ return winevtSubscribe->tailing ? Qtrue : Qfalse;
69
+ }
70
+
71
+ static VALUE
72
+ rb_winevt_subscribe_subscribe(int argc, VALUE argv, VALUE self)
73
+ {
74
+ VALUE rb_path, rb_query, rb_bookmark;
75
+ EVT_HANDLE hSubscription = NULL, hBookmark = NULL;
76
+ HANDLE hSignalEvent;
77
+ DWORD len, flags;
78
+ VALUE wpathBuf, wqueryBuf;
79
+ PWSTR path, query;
80
+ DWORD status = ERROR_SUCCESS;
81
+ struct WinevtBookmark *winevtBookmark;
82
+ struct WinevtSubscribe *winevtSubscribe;
83
+
84
+ hSignalEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
85
+
86
+ TypedData_Get_Struct(self, struct WinevtSubscribe, &rb_winevt_subscribe_type, winevtSubscribe);
87
+
88
+ rb_scan_args(argc, argv, "21", &rb_path, &rb_query, &rb_bookmark);
89
+ Check_Type(rb_path, T_STRING);
90
+ Check_Type(rb_query, T_STRING);
91
+
92
+ if (rb_obj_is_kind_of(rb_bookmark, rb_cBookmark)) {
93
+ hBookmark = EventBookMark(rb_bookmark)->bookmark;
94
+ }
95
+
96
+ // path : To wide char
97
+ len = MultiByteToWideChar(CP_UTF8, 0, RSTRING_PTR(rb_path), RSTRING_LEN(rb_path), NULL, 0);
98
+ path = ALLOCV_N(WCHAR, wpathBuf, len+1);
99
+ MultiByteToWideChar(CP_UTF8, 0, RSTRING_PTR(rb_path), RSTRING_LEN(rb_path), path, len);
100
+ path[len] = L'\0';
101
+
102
+ // query : To wide char
103
+ len = MultiByteToWideChar(CP_UTF8, 0, RSTRING_PTR(rb_query), RSTRING_LEN(rb_query), NULL, 0);
104
+ query = ALLOCV_N(WCHAR, wqueryBuf, len+1);
105
+ MultiByteToWideChar(CP_UTF8, 0, RSTRING_PTR(rb_query), RSTRING_LEN(rb_query), query, len);
106
+ query[len] = L'\0';
107
+
108
+ if (hBookmark){
109
+ flags |= EvtSubscribeStartAfterBookmark;
110
+ } else if (winevtSubscribe->tailing) {
111
+ flags |= EvtSubscribeToFutureEvents;
112
+ } else {
113
+ flags |= EvtSubscribeStartAtOldestRecord;
114
+ }
115
+
116
+ hSubscription = EvtSubscribe(NULL, hSignalEvent, path, query, hBookmark, NULL, NULL, flags);
117
+
118
+ winevtSubscribe->signalEvent = hSignalEvent;
119
+ winevtSubscribe->subscription = hSubscription;
120
+ if (hBookmark) {
121
+ winevtSubscribe->bookmark = hBookmark;
122
+ } else {
123
+ winevtSubscribe->bookmark = EvtCreateBookmark(NULL);
124
+ }
125
+
126
+ status = GetLastError();
127
+
128
+ if (status == ERROR_SUCCESS)
129
+ return Qtrue;
130
+
131
+ return Qfalse;
132
+ }
133
+
134
+ static VALUE
135
+ rb_winevt_subscribe_next(VALUE self)
136
+ {
137
+ EVT_HANDLE event;
138
+ ULONG count;
139
+ struct WinevtSubscribe *winevtSubscribe;
140
+
141
+ TypedData_Get_Struct(self, struct WinevtSubscribe, &rb_winevt_subscribe_type, winevtSubscribe);
142
+
143
+ if (EvtNext(winevtSubscribe->subscription, 1, &event, INFINITE, 0, &count) != FALSE) {
144
+ winevtSubscribe->event = event;
145
+ EvtUpdateBookmark(winevtSubscribe->bookmark, winevtSubscribe->event);
146
+
147
+ return Qtrue;
148
+ }
149
+
150
+ return Qfalse;
151
+ }
152
+
153
+ static VALUE
154
+ rb_winevt_subscribe_render(VALUE self)
155
+ {
156
+ char* result;
157
+ struct WinevtSubscribe *winevtSubscribe;
158
+
159
+ TypedData_Get_Struct(self, struct WinevtSubscribe, &rb_winevt_subscribe_type, winevtSubscribe);
160
+ result = render_event(winevtSubscribe->event, EvtRenderEventXml);
161
+
162
+ return rb_str_new2(result);
163
+ }
164
+
165
+ static VALUE
166
+ rb_winevt_subscribe_message(VALUE self)
167
+ {
168
+ char* result;
169
+ struct WinevtSubscribe *winevtSubscribe;
170
+
171
+ TypedData_Get_Struct(self, struct WinevtSubscribe, &rb_winevt_subscribe_type, winevtSubscribe);
172
+ result = get_description(winevtSubscribe->event);
173
+
174
+ return rb_str_new2(result);
175
+ }
176
+
177
+ static VALUE
178
+ rb_winevt_subscribe_each(VALUE self)
179
+ {
180
+ struct WinevtSubscribe *winevtSubscribe;
181
+
182
+ RETURN_ENUMERATOR(self, 0, 0);
183
+
184
+ TypedData_Get_Struct(self, struct WinevtSubscribe, &rb_winevt_subscribe_type, winevtSubscribe);
185
+
186
+ while (rb_winevt_subscribe_next(self)) {
187
+ rb_yield_values(2, rb_winevt_subscribe_render(self), rb_winevt_subscribe_message(self));
188
+ }
189
+
190
+ return Qnil;
191
+ }
192
+
193
+ static VALUE
194
+ rb_winevt_subscribe_get_bookmark(VALUE self)
195
+ {
196
+ char* result;
197
+ struct WinevtSubscribe *winevtSubscribe;
198
+
199
+ TypedData_Get_Struct(self, struct WinevtSubscribe, &rb_winevt_subscribe_type, winevtSubscribe);
200
+
201
+ result = render_event(winevtSubscribe->bookmark, EvtRenderBookmark);
202
+
203
+ return rb_str_new2(result);
204
+ }
205
+
206
+ void Init_winevt_subscribe(VALUE rb_cEventLog)
207
+ {
208
+ rb_cSubscribe = rb_define_class_under(rb_cEventLog, "Subscribe", rb_cObject);
209
+
210
+ rb_define_alloc_func(rb_cSubscribe, rb_winevt_subscribe_alloc);
211
+ rb_define_method(rb_cSubscribe, "initialize", rb_winevt_subscribe_initialize, 0);
212
+ rb_define_method(rb_cSubscribe, "subscribe", rb_winevt_subscribe_subscribe, -1);
213
+ rb_define_method(rb_cSubscribe, "next", rb_winevt_subscribe_next, 0);
214
+ rb_define_method(rb_cSubscribe, "render", rb_winevt_subscribe_render, 0);
215
+ rb_define_method(rb_cSubscribe, "message", rb_winevt_subscribe_message, 0);
216
+ rb_define_method(rb_cSubscribe, "each", rb_winevt_subscribe_each, 0);
217
+ rb_define_method(rb_cSubscribe, "bookmark", rb_winevt_subscribe_get_bookmark, 0);
218
+ rb_define_method(rb_cSubscribe, "tail?", rb_winevt_subscribe_tail_p, 0);
219
+ rb_define_method(rb_cSubscribe, "tail=", rb_winevt_subscribe_set_tail, 1);
220
+ }
@@ -0,0 +1,236 @@
1
+ #include <winevt_c.h>
2
+
3
+ char*
4
+ wstr_to_mbstr(UINT cp, const WCHAR *wstr, int clen)
5
+ {
6
+ char *ptr;
7
+ int len = WideCharToMultiByte(cp, 0, wstr, clen, NULL, 0, NULL, NULL);
8
+ if (!(ptr = malloc(len))) return 0;
9
+ WideCharToMultiByte(cp, 0, wstr, clen, ptr, len, NULL, NULL);
10
+
11
+ return ptr;
12
+ }
13
+
14
+ char* render_event(EVT_HANDLE handle, DWORD flags)
15
+ {
16
+ PWSTR buffer = NULL;
17
+ ULONG bufferSize = 0;
18
+ ULONG bufferSizeNeeded = 0;
19
+ EVT_HANDLE event;
20
+ ULONG status, count;
21
+ char* errBuf;
22
+ char* result;
23
+ LPTSTR msgBuf;
24
+
25
+ do {
26
+ if (bufferSizeNeeded > bufferSize) {
27
+ free(buffer);
28
+ bufferSize = bufferSizeNeeded;
29
+ buffer = malloc(bufferSize);
30
+ if (buffer == NULL) {
31
+ status = ERROR_OUTOFMEMORY;
32
+ bufferSize = 0;
33
+ rb_raise(rb_eWinevtQueryError, "Out of memory");
34
+ break;
35
+ }
36
+ }
37
+
38
+ if (EvtRender(NULL,
39
+ handle,
40
+ flags,
41
+ bufferSize,
42
+ buffer,
43
+ &bufferSizeNeeded,
44
+ &count) != FALSE) {
45
+ status = ERROR_SUCCESS;
46
+ } else {
47
+ status = GetLastError();
48
+ }
49
+ } while (status == ERROR_INSUFFICIENT_BUFFER);
50
+
51
+ if (status != ERROR_SUCCESS) {
52
+ FormatMessage(
53
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
54
+ FORMAT_MESSAGE_FROM_SYSTEM |
55
+ FORMAT_MESSAGE_IGNORE_INSERTS,
56
+ NULL, status,
57
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
58
+ &msgBuf, 0, NULL);
59
+ result = wstr_to_mbstr(CP_ACP, msgBuf, -1);
60
+
61
+ rb_raise(rb_eWinevtQueryError, "ErrorCode: %d\nError: %s\n", status, result);
62
+ }
63
+
64
+ result = wstr_to_mbstr(CP_UTF8, buffer, -1);
65
+
66
+ if (buffer)
67
+ free(buffer);
68
+
69
+ return result;
70
+ }
71
+
72
+ char* get_description(EVT_HANDLE handle)
73
+ {
74
+ #define MAX_BUFFER 65535
75
+ WCHAR buffer[4096], file[4096];
76
+ WCHAR descriptionBuffer[MAX_BUFFER];
77
+ ULONG bufferSize = 0;
78
+ ULONG bufferSizeNeeded = 0;
79
+ EVT_HANDLE event;
80
+ ULONG status, count;
81
+ char* errBuf;
82
+ char* result = "";
83
+ LPTSTR msgBuf;
84
+ TCHAR publisherName[MAX_PATH];
85
+ TCHAR fileName[MAX_PATH];
86
+ EVT_HANDLE hMetadata = NULL;
87
+ PEVT_VARIANT values = NULL;
88
+ PEVT_VARIANT pProperty = NULL;
89
+ PEVT_VARIANT pTemp = NULL;
90
+ TCHAR paramEXE[MAX_PATH], messageEXE[MAX_PATH];
91
+ HMODULE hModule = NULL;
92
+
93
+ static PCWSTR eventProperties[] = {L"Event/System/Provider/@Name", L"Event/System/EventID"};
94
+ EVT_HANDLE renderContext = EvtCreateRenderContext(2, eventProperties, EvtRenderContextValues);
95
+ if (renderContext == NULL) {
96
+ rb_raise(rb_eWinevtQueryError, "Failed to create renderContext");
97
+ }
98
+
99
+ if (EvtRender(renderContext,
100
+ handle,
101
+ EvtRenderEventValues,
102
+ _countof(buffer),
103
+ buffer,
104
+ &bufferSizeNeeded,
105
+ &count) != FALSE) {
106
+ status = ERROR_SUCCESS;
107
+ } else {
108
+ status = GetLastError();
109
+ }
110
+
111
+ if (status != ERROR_SUCCESS) {
112
+ FormatMessage(
113
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
114
+ FORMAT_MESSAGE_FROM_SYSTEM |
115
+ FORMAT_MESSAGE_IGNORE_INSERTS,
116
+ NULL, status,
117
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
118
+ &msgBuf, 0, NULL);
119
+ result = wstr_to_mbstr(CP_ACP, msgBuf, -1);
120
+
121
+ rb_raise(rb_eWinevtQueryError, "ErrorCode: %d\nError: %s\n", status, result);
122
+ }
123
+
124
+ // Obtain buffer as EVT_VARIANT pointer. To avoid ErrorCide 87 in EvtRender.
125
+ values = (PEVT_VARIANT)buffer;
126
+ if ((values[0].Type == EvtVarTypeString) && (values[0].StringVal != NULL)) {
127
+ WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR, values[0].StringVal, -1, publisherName, MAX_PATH, NULL, NULL);
128
+ }
129
+
130
+ DWORD eventId = 0;
131
+ if (values[1].Type == EvtVarTypeUInt16) {
132
+ eventId = values[1].UInt16Val;
133
+ }
134
+
135
+ // Open publisher metadata
136
+ hMetadata = EvtOpenPublisherMetadata(NULL, values[0].StringVal, NULL, MAKELCID(MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), SORT_DEFAULT), 0);
137
+ if (hMetadata == NULL) {
138
+ // When winevt_c cannot open metadata, then give up to obtain
139
+ // message file and clean up immediately.
140
+ goto cleanup;
141
+ }
142
+
143
+ /* TODO: Should we implement parameter file reading in C?
144
+ // Get the metadata property. If the buffer is not big enough, reallocate the buffer.
145
+ // Get parameter file first.
146
+ if (!EvtGetPublisherMetadataProperty(hMetadata, EvtPublisherMetadataParameterFilePath, 0, bufferSize, pProperty, &count)) {
147
+ status = GetLastError();
148
+ if (ERROR_INSUFFICIENT_BUFFER == status) {
149
+ bufferSize = count;
150
+ pTemp = (PEVT_VARIANT)realloc(pProperty, bufferSize);
151
+ if (pTemp) {
152
+ pProperty = pTemp;
153
+ pTemp = NULL;
154
+ EvtGetPublisherMetadataProperty(hMetadata, EvtPublisherMetadataParameterFilePath, 0, bufferSize, pProperty, &count);
155
+ } else {
156
+ rb_raise(rb_eWinevtQueryError, "realloc failed");
157
+ }
158
+ }
159
+
160
+ if (ERROR_SUCCESS != (status = GetLastError())) {
161
+ rb_raise(rb_eWinevtQueryError, "EvtGetPublisherMetadataProperty for parameter file failed with %d\n", GetLastError());
162
+ }
163
+ }
164
+
165
+ if ((pProperty->Type == EvtVarTypeString) && (pProperty->StringVal != NULL)) {
166
+ WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR, pProperty->StringVal, -1, fileName, MAX_PATH, NULL, NULL);
167
+ }
168
+ if (paramEXE) {
169
+ ExpandEnvironmentStrings(fileName, paramEXE, _countof(paramEXE));
170
+ }
171
+ */
172
+
173
+ // Get the metadata property. If the buffer is not big enough, reallocate the buffer.
174
+ // Get message file contents.
175
+ if (!EvtGetPublisherMetadataProperty(hMetadata, EvtPublisherMetadataMessageFilePath, 0, bufferSize, pProperty, &count)) {
176
+ status = GetLastError();
177
+ if (ERROR_INSUFFICIENT_BUFFER == status) {
178
+ bufferSize = count;
179
+ pTemp = (PEVT_VARIANT)realloc(pProperty, bufferSize);
180
+ if (pTemp) {
181
+ pProperty = pTemp;
182
+ pTemp = NULL;
183
+ EvtGetPublisherMetadataProperty(hMetadata, EvtPublisherMetadataMessageFilePath, 0, bufferSize, pProperty, &count);
184
+ } else {
185
+ rb_raise(rb_eWinevtQueryError, "realloc failed");
186
+ }
187
+ }
188
+
189
+ if (ERROR_SUCCESS != (status = GetLastError())) {
190
+ rb_raise(rb_eWinevtQueryError, "EvtGetPublisherMetadataProperty for message file failed with %d\n", GetLastError());
191
+ }
192
+ }
193
+
194
+ if ((pProperty->Type == EvtVarTypeString) && (pProperty->StringVal != NULL)) {
195
+ WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR, pProperty->StringVal, -1, fileName, MAX_PATH, NULL, NULL);
196
+ }
197
+ if (messageEXE) {
198
+ ExpandEnvironmentStrings(fileName, messageEXE, _countof(messageEXE));
199
+ }
200
+
201
+ if (messageEXE != NULL) {
202
+ hModule = LoadLibraryEx(messageEXE, NULL,
203
+ DONT_RESOLVE_DLL_REFERENCES | LOAD_LIBRARY_AS_DATAFILE);
204
+
205
+ if (FormatMessageW(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS,
206
+ hModule,
207
+ eventId,
208
+ 0, // Use current code page. Users must specify character encoding in Ruby side.
209
+ descriptionBuffer,
210
+ MAX_BUFFER,
211
+ NULL)) {
212
+ } else if (!FormatMessageW(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS,
213
+ hModule,
214
+ 0xB0000000 | eventId,
215
+ 0, // Use current code page. Users must specify character encoding in Ruby side.
216
+ descriptionBuffer,
217
+ MAX_BUFFER,
218
+ NULL)){
219
+ goto cleanup;
220
+ }
221
+ }
222
+
223
+ result = wstr_to_mbstr(CP_ACP, descriptionBuffer, -1);
224
+
225
+ #undef MAX_BUFFER
226
+
227
+ cleanup:
228
+
229
+ if (hMetadata)
230
+ EvtClose(hMetadata);
231
+
232
+ if (hModule)
233
+ FreeLibrary(hModule);
234
+
235
+ return result;
236
+ }
@@ -1,3 +1,3 @@
1
- module Winevt
2
- VERSION = "0.1.1"
3
- end
1
+ module Winevt
2
+ VERSION = "0.2.0"
3
+ end
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.1.1
4
+ version: 0.2.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: 2019-06-13 00:00:00.000000000 Z
11
+ date: 2019-06-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -107,6 +107,12 @@ files:
107
107
  - example/tailing.rb
108
108
  - ext/winevt/extconf.rb
109
109
  - ext/winevt/winevt.c
110
+ - ext/winevt/winevt_bookmark.c
111
+ - ext/winevt/winevt_c.h
112
+ - ext/winevt/winevt_channel.c
113
+ - ext/winevt/winevt_query.c
114
+ - ext/winevt/winevt_subscribe.c
115
+ - ext/winevt/winevt_utils.c
110
116
  - lib/winevt.rb
111
117
  - lib/winevt/query.rb
112
118
  - lib/winevt/version.rb