ReactOS  0.4.12-dev-18-gf469aca
eventcreate.c
Go to the documentation of this file.
1 /*
2  * COPYRIGHT: See COPYING in the top level directory
3  * PROJECT: ReactOS EventCreate Command
4  * FILE: base/applications/cmdutils/eventcreate/eventcreate.c
5  * PURPOSE: Allows reporting custom user events in event logs,
6  * by using the old-school NT <= 2k3 logging API.
7  * PROGRAMMER: Hermes Belusca-Maito
8  *
9  * RATIONALE AND NOTE ABOUT THE IMPLEMENTATION:
10  *
11  * Contrary to what can be expected, there is no simple way of logging inside
12  * a NT event log an arbitrary string, for example a description text, that
13  * can then be viewed in a human-readable form under an event viewer. Indeed,
14  * a NT log entry is not just a simple arbitrary string, but is instead made
15  * of an identifier (ID), an event "source" and an arbitrary data chunk.
16  * To make things somewhat simpler, the data chunk is divided in two parts:
17  * an array of data strings and a raw (binary) data chunk.
18  *
19  * How then can a log entry be reconstructed? At each NT log is associated
20  * one or many event "sources", which are binary files (PE format) containing
21  * a table of predefined string templates (message table resource), indexed
22  * by identifiers. The ID and event source specified in a given log entry
23  * inside a given log allows to refer to one of the string template inside
24  * the specified event source of the log. A human-readable event description
25  * that is shown by an event viewer is obtained by associating the string
26  * template together with the array of data strings of the log entry.
27  * Each of the data strings is a parameter for the string template (formatted
28  * in a printf-like format).
29  *
30  * Thus we see that the human-readable event description of a log entry is
31  * not completely arbitrary but is dictated by both the string templates and
32  * the data strings of the log entry. Only the data strings can be arbitrary.
33  *
34  * Therefore, what can we do to be able to report arbitrary human-readable
35  * events, the description of which the user specifies at the command-line?
36  * There is actually only one possible way: store the description text as
37  * a string inside the array of data strings of the event. But we need the
38  * event to be displayed correctly. For that it needs to be associated with
39  * an event source, and its ID must point to a suitable string template, the
40  * association of which with the user-specified arbitrary data string should
41  * directly display this arbitrary string. The suitable string template is
42  * therefore the identity template: "%1" (in the format for message strings).
43  * The last problem, that may constitute a limitation of this technique, is
44  * that this string template is tied to a given event ID. What if the user
45  * wants to use a different event ID? The solution is the event source to
46  * contain as many same identity templates as different IDs the user can use.
47  * This is quite a redundant and limiting technique!
48  *
49  * On MS Windows, the EventCreate.exe command contains the identity template
50  * for all IDs from 1 to 1001 included, yet it is only possible to specify
51  * an event ID from 1 to 1000 included.
52  * The Powershell command "Write-EventLog" allows using IDs from 0 to 65535
53  * included, thus covering all of the 2-byte unsigned integer space; its
54  * corresponding event source file "EventLogMessages.dll"
55  * (inside "%SystemRoot%\Microsoft.NET\Framework\vX.Y.ZZZZZ") therefore
56  * contains the identity template for all IDs from 0 to 65535, making it a
57  * large file.
58  *
59  * For ReactOS I want to have a compromise between disk space and usage
60  * flexibility, therefore I choose to include as well the identity template
61  * for all IDs from 0 to 65535 included, as done by Powershell. If somebody
62  * wants to change these limits, one has to perform the following steps:
63  *
64  * 0- Update the "/ID EventID" description in the help string "IDS_HELP"
65  * inside the lang/xx-YY.rc resource files;
66  *
67  * 1- Change in this file the two #defines EVENT_ID_MIN and EVENT_ID_MAX
68  * to other values of one's choice (called 'ID_min' and 'ID_max');
69  *
70  * 2- Regenerate and replace the event message string templates file using
71  * the event message string templates file generator (evtmsggen tool):
72  * $ evtmsggen ID_min ID_max evtmsgstr.mc
73  *
74  * 3- Recompile the EventCreate command.
75  *
76  */
77 
78 #include <stdio.h>
79 #include <stdlib.h> // EXIT_SUCCESS, EXIT_FAILURE
80 
81 #include <windef.h>
82 #include <winbase.h>
83 #include <winreg.h>
84 
85 #include <conutils.h>
86 
87 #include <strsafe.h>
88 
89 #include "resource.h"
90 
91 /*
92  * The minimal and maximal values of the allowed ID range.
93  * See the "NOTE ABOUT THE IMPLEMENTATION" above.
94  *
95  * Here are some examples of values:
96  * Windows' EventCreate.exe command : ID_min = 1 and ID_max = 1000
97  * Powershell "Write-EventLog" command: ID_min = 0 and ID_max = 65535
98  *
99  * ReactOS' EventCreate.exe command uses the same limits as Powershell.
100  */
101 #define EVENT_ID_MIN 0
102 #define EVENT_ID_MAX 65535
103 
104 /*
105  * The EventCreate command internal name (used for both setting the default
106  * event source name and specifying the default event source file path).
107  */
108 #define APPLICATION_NAME L"EventCreate"
109 
110 
112 {
113  if (dwError == ERROR_SUCCESS)
114  return;
115 
117  NULL, dwError, LANG_USER_DEFAULT);
118  ConPuts(StdErr, L"\n");
119 }
120 
121 
122 static BOOL
124  OUT PTOKEN_USER* ppUserToken)
125 {
126  BOOL Success = FALSE;
127  DWORD dwError;
128  HANDLE hToken;
129  DWORD cbTokenBuffer = 0;
130  PTOKEN_USER pUserToken = NULL;
131 
132  *ppUserToken = NULL;
133 
134  /* Get the process token */
136  return FALSE;
137 
138  /* Retrieve token's information */
139  if (!GetTokenInformation(hToken, TokenUser, NULL, 0, &cbTokenBuffer))
140  {
141  dwError = GetLastError();
142  if (dwError != ERROR_INSUFFICIENT_BUFFER)
143  goto Quit;
144  }
145 
146  pUserToken = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbTokenBuffer);
147  if (!pUserToken)
148  {
149  dwError = ERROR_NOT_ENOUGH_MEMORY;
150  goto Quit;
151  }
152 
153  if (!GetTokenInformation(hToken, TokenUser, pUserToken, cbTokenBuffer, &cbTokenBuffer))
154  {
155  dwError = GetLastError();
156  goto Quit;
157  }
158 
159  Success = TRUE;
160  dwError = ERROR_SUCCESS;
161  *ppUserToken = pUserToken;
162 
163 Quit:
164  if (Success == FALSE)
165  {
166  if (pUserToken)
167  HeapFree(GetProcessHeap(), 0, pUserToken);
168  }
169 
170  CloseHandle(hToken);
171 
172  SetLastError(dwError);
173 
174  return Success;
175 }
176 
177 static LONG
179  IN HKEY hEventLogKey,
181 {
182  LONG lRet;
183  HKEY hSourceKey = NULL;
184  DWORD dwDisposition = 0;
185  DWORD dwData;
186 
187  LPCWSTR EventMessageFile;
188  DWORD PathSize;
189  WCHAR ExePath[MAX_PATH];
190 
191  lRet = RegCreateKeyExW(hEventLogKey,
192  EventLogSource,
195  &hSourceKey, &dwDisposition);
196  if (lRet != ERROR_SUCCESS)
197  goto Quit;
198  if (dwDisposition != REG_CREATED_NEW_KEY)
199  {
200  /* The source key already exists, just quit */
201  goto Quit;
202  }
203 
204  /* We just have created the new source. Add the values. */
205 
206  /*
207  * Retrieve the full path of the current running executable.
208  * We need it to install our custom event source.
209  * - In case of success, try to replace the ReactOS installation path
210  * (if present in the executable path) by %SystemRoot%.
211  * - In case of failure, use a default path.
212  */
213  PathSize = GetModuleFileNameW(NULL, ExePath, ARRAYSIZE(ExePath));
214  if ((PathSize == 0) || (GetLastError() == ERROR_INSUFFICIENT_BUFFER))
215  {
216  /* We failed, copy the default value */
217  StringCchCopyW(ExePath, ARRAYSIZE(ExePath),
218  L"%SystemRoot%\\System32\\" APPLICATION_NAME L".exe");
219  }
220  else
221  {
222  /* Alternatively one can use SharedUserData->NtSystemRoot */
223  WCHAR TmpDir[ARRAYSIZE(ExePath)];
224  PathSize = GetSystemWindowsDirectoryW(TmpDir, ARRAYSIZE(TmpDir));
225  if ((PathSize > 0) && (_wcsnicmp(ExePath, TmpDir, PathSize) == 0))
226  {
227  StringCchCopyW(TmpDir, ARRAYSIZE(TmpDir), L"%SystemRoot%");
228  StringCchCatW(TmpDir, ARRAYSIZE(TmpDir), ExePath + PathSize);
229  StringCchCopyW(ExePath, ARRAYSIZE(ExePath), TmpDir);
230  }
231  }
232  EventMessageFile = ExePath;
233 
234  lRet = ERROR_SUCCESS;
235 
236  dwData = 1;
237  RegSetValueExW(hSourceKey, L"CustomSource", 0, REG_DWORD,
238  (LPBYTE)&dwData, sizeof(dwData));
239 
240  // FIXME: Set those flags according to caller's rights?
241  // Or, if we are using the Security log?
243  /* | EVENTLOG_AUDIT_SUCCESS | EVENTLOG_AUDIT_FAILURE */ ;
244  RegSetValueExW(hSourceKey, L"TypesSupported", 0, REG_DWORD,
245  (LPBYTE)&dwData, sizeof(dwData));
246 
247  RegSetValueExW(hSourceKey, L"EventMessageFile", 0, REG_EXPAND_SZ,
248  (LPBYTE)EventMessageFile, (wcslen(EventMessageFile) + 1) * sizeof(WCHAR));
249 
250  RegFlushKey(hSourceKey);
251 
252 Quit:
253  if (hSourceKey)
254  RegCloseKey(hSourceKey);
255 
256  return lRet;
257 }
258 
259 static BOOL
261  IN LPCWSTR UNCServerName OPTIONAL,
262  IN LPCWSTR EventLogName,
264  IN BOOL AllowAppSources OPTIONAL)
265 {
266  /*
267  * The 'AllowAppSources' parameter allows the usage of
268  * application (non-custom) sources, when set to TRUE.
269  * Its default value is FALSE.
270  */
271 
272 #define MAX_KEY_LENGTH 255 // or 256 ??
273 
274  BOOL Success = FALSE;
275  LONG lRet;
276  HKEY hEventLogKey = NULL, hLogKey = NULL;
277  DWORD NameLen;
278  DWORD dwIndex;
279 
280  BOOL LogNameValid, LogSourceValid;
281  BOOL FoundLog = FALSE, FoundSource = FALSE;
282  BOOL SourceAlreadyExists = FALSE, SourceCreated = FALSE, IsCustomSource = FALSE;
283 
284  WCHAR LogName[MAX_KEY_LENGTH]; // Current event log being tested for.
285  WCHAR LogNameErr[MAX_KEY_LENGTH]; // Event log in which the source already exists.
286 
287  UNREFERENCED_PARAMETER(UNCServerName); // FIXME: Use remote server if needed!
288 
289  LogNameValid = (EventLogName && *EventLogName);
290  LogSourceValid = (EventLogSource && *EventLogSource);
291 
292  /*
293  * If neither the log name nor the log source are specified,
294  * there is no need to continue. Just fail.
295  */
296  if (!LogNameValid && !LogSourceValid)
297  return FALSE;
298 
299  lRet = RegOpenKeyExW(HKEY_LOCAL_MACHINE, // FIXME: Use remote server if needed!
300  L"SYSTEM\\CurrentControlSet\\Services\\EventLog",
302  &hEventLogKey);
303  if (lRet != ERROR_SUCCESS)
304  goto Quit;
305 
306  /*
307  * If we just have a valid log name but no specified source, check whether
308  * the log key exist by atttempting to open it. If we fail: no log.
309  * In all cases we do not perform other tests nor create any source.
310  */
311  if (LogNameValid && !LogSourceValid)
312  {
313  lRet = RegOpenKeyExW(hEventLogKey,
314  EventLogName,
315  0, KEY_QUERY_VALUE,
316  &hLogKey);
317  RegCloseKey(hLogKey);
318  FoundLog = (lRet == ERROR_SUCCESS);
319 
320  if (FoundLog)
321  {
322  /* Set the flags to consistent values */
323  SourceCreated = TRUE;
324  IsCustomSource = TRUE;
325  }
326  goto Finalize;
327  }
328 
329  /* Here, LogSourceValid is always TRUE */
330 
331  /*
332  * We now have a valid source and either an event log name or none.
333  * Search for the source existence over all the existing logs:
334  * we loop through the event logs and we will:
335  * - localize whether the specified source exists and in which log it does;
336  * - and at the same time, check whether the specified log does exist.
337  */
338  dwIndex = 0;
339  while (TRUE)
340  {
341  NameLen = ARRAYSIZE(LogName);
342  LogName[0] = L'\0';
343 
344  lRet = RegEnumKeyExW(hEventLogKey, dwIndex, LogName, &NameLen,
345  NULL, NULL, NULL, NULL);
346  if (dwIndex > 0)
347  {
348  if (lRet == ERROR_NO_MORE_ITEMS)
349  {
350  /*
351  * We may/may not have found our log and may/may not have found
352  * our source. Quit the loop, we will check those details after.
353  */
354  break; // goto Finalize;
355  }
356  }
357  if (lRet != ERROR_SUCCESS)
358  {
359  /* A registry error happened, just fail */
360  goto Quit;
361  }
362 
363  /* We will then continue with the next log */
364  ++dwIndex;
365 
366  /* If we have specified a log, check whether we have found it */
367  if (LogNameValid && _wcsicmp(LogName, EventLogName) == 0)
368  {
369  /*
370  * We have found the specified log, but do not break yet: if we have
371  * a specified source, we want to be sure it does not exist elsewhere.
372  */
373  FoundLog = TRUE;
374  }
375 
376  /*
377  * The following case: if (LogNameValid && !LogSourceValid) {...}
378  * was already dealt with before. Here, LogSourceValid is always TRUE.
379  */
380 
381  /* Now determine whether we need to continue */
382  if (/* LogNameValid && */ FoundLog)
383  {
384 #if 0
385  if (!LogSourceValid)
386  {
387  /*
388  * We have found our log and we do not use any source,
389  * we can stop scanning now.
390  */
391  /* Set the flags to consistent values */
392  SourceCreated = TRUE;
393  IsCustomSource = TRUE;
394  break; // goto Finalize;
395  }
396 #endif
397  if (SourceAlreadyExists)
398  {
399  /*
400  * We have finally found our log but the source existed elsewhere,
401  * stop scanning and we will error that the source is not in the
402  * expected log. On the contrary, if our log was not found yet,
403  * continue scanning to attempt to find it and, if the log is not
404  * found at the end we will error that the log does not exist.
405  */
406  break; // goto Finalize;
407  }
408  }
409 
410  /*
411  * If we have specified a source and have not found it so far,
412  * check for its presence in this log.
413  * NOTE: Here, LogSourceValid is always TRUE.
414  */
415  if (LogSourceValid && !FoundSource)
416  {
417  HKEY hKeySource = NULL;
418 
419  /* Check the sources inside this log */
420  lRet = RegOpenKeyExW(hEventLogKey, LogName, 0, KEY_READ, &hLogKey);
421  if (lRet != ERROR_SUCCESS)
422  {
423  /* A registry error happened, just fail */
424  goto Quit;
425  }
426 
427  /*
428  * Attempt to open the source key.
429  *
430  * NOTE: Alternatively we could have scanned each source key
431  * in this log by using RegEnumKeyExW.
432  */
433  lRet = RegOpenKeyExW(hLogKey, EventLogSource,
434  0, KEY_QUERY_VALUE,
435  &hKeySource);
436 
437  /* Get rid of the log key handle */
438  RegCloseKey(hLogKey);
439  hLogKey = NULL;
440 
441  if (lRet == ERROR_SUCCESS) // || lRet == ERROR_ACCESS_DENIED
442  {
443  /*
444  * We have found our source in this log (it can be
445  * in a different log than the one specified).
446  */
447  FoundSource = TRUE;
448  // lRet = ERROR_SUCCESS;
449  }
450  else if (lRet == ERROR_FILE_NOT_FOUND)
451  {
452  /* Our source was not found there */
453  lRet = ERROR_SUCCESS;
454  hKeySource = NULL;
455  }
456  else // if (lRet != ERROR_SUCCESS && lRet != ERROR_FILE_NOT_FOUND)
457  {
458  /* A registry error happened, but we continue scanning the other logs... */
459  hKeySource = NULL;
460  }
461 
462  /* If we have not found our source, continue scanning the other logs */
463  if (!FoundSource)
464  continue;
465 
466  /*
467  * We have found our source, but is it in the correct log?
468  *
469  * NOTE: We check only in the case we have specified a log,
470  * otherwise we just care about the existence of the source
471  * and we do not check for its presence in the other logs.
472  */
473  if (LogNameValid && !(FoundLog && _wcsicmp(LogName, EventLogName) == 0))
474  {
475  /* Now get rid of the source key handle */
476  RegCloseKey(hKeySource);
477  hKeySource = NULL;
478 
479  /* The source is in another log than the specified one */
480  SourceAlreadyExists = TRUE;
481 
482  /* Save the log name in which the source already exists */
483  RtlCopyMemory(LogNameErr, LogName, sizeof(LogName));
484 
485  /*
486  * We continue because we want to also know whether we can
487  * still find our specified log (and we will error that the
488  * source exists elsewhere), or whether the log does not exist
489  * (and we will error accordingly).
490  */
491  continue;
492  }
493 
494  /*
495  * We have found our source, and if we have specified a log,
496  * the source is in the correct log.
497  */
498  SourceCreated = TRUE;
499 
500  /*
501  * Check whether this is one of our custom sources
502  * (application sources do not have this value present).
503  */
504  IsCustomSource = FALSE;
505 
506  lRet = RegQueryValueExW(hKeySource, L"CustomSource", NULL, NULL, NULL, NULL);
507 
508  /* Now get rid of the source key handle */
509  RegCloseKey(hKeySource);
510  hKeySource = NULL;
511 
512  if (lRet == ERROR_SUCCESS)
513  {
514  IsCustomSource = TRUE;
515  }
516  else if (lRet == ERROR_FILE_NOT_FOUND)
517  {
518  // IsCustomSource = FALSE;
519  }
520  else // if (lRet != ERROR_SUCCESS && lRet != ERROR_FILE_NOT_FOUND)
521  {
522  /* A registry error happened, just fail */
523  goto Quit;
524  }
525 
526  /*
527  * We have found our source and it may be (or not) a custom source,
528  * and it is in the correct event log (if we have specified one).
529  * Break the search loop.
530  */
531  break; // goto Finalize;
532  }
533  }
534 
535  /*
536  * No errors happened so far.
537  * Perform last validity checks (the flags are all valid and 'LogName'
538  * contains the name of the last log having been tested for).
539  */
540 Finalize:
541  lRet = ERROR_SUCCESS; // but do not set Success to TRUE yet.
542 
543  // FIXME: Shut up a GCC warning/error about 'SourceCreated' being unused.
544  // We will use it later on.
545  UNREFERENCED_PARAMETER(SourceCreated);
546 
547  /*
548  * The source does not exist (SourceCreated == FALSE), create it.
549  * Note that we then must have a specified log that exists on the system.
550  */
551  // NOTE: IsCustomSource always FALSE here.
552 
553  if (LogNameValid && !FoundLog)
554  {
555  /* We have specified a log but it does not exist! */
556  ConResPrintf(StdErr, IDS_LOG_NOT_FOUND, EventLogName);
557  goto Quit;
558  }
559 
560  //
561  // Here, LogNameValid == TRUE && FoundLog == TRUE, or
562  // LogNameValid == FALSE && FoundLog == FALSE.
563  //
564 
565  if (LogNameValid /* && FoundLog */ && !LogSourceValid /* && !FoundSource && !SourceAlreadyExists */)
566  {
567  /* No source, just use the log */
568  // NOTE: For this case, SourceCreated and IsCustomSource were both set to TRUE.
569  Success = TRUE;
570  goto Quit;
571  }
572 
573  if (/* LogSourceValid && */ FoundSource && SourceAlreadyExists)
574  {
575  /* The source is in another log than the specified one */
576  ConResPrintf(StdErr, IDS_SOURCE_EXISTS, LogNameErr);
577  goto Quit;
578  }
579 
580  if (/* LogSourceValid && */ FoundSource && !SourceAlreadyExists)
581  {
582  /* We can directly use the source */
583 
584  // if (SourceCreated)
585  {
586  /* The source already exists, check whether this is a custom one */
587  if (IsCustomSource || AllowAppSources)
588  {
589  /* This is a custom source, fine! */
590  Success = TRUE;
591  goto Quit;
592  }
593  else
594  {
595  /* This is NOT a custom source, we must return an error! */
597  goto Quit;
598  }
599  }
600  }
601 
602  if (LogSourceValid && !FoundSource)
603  {
604  if (!LogNameValid /* && !FoundLog */)
605  {
606  /* The log name is not specified, we cannot create the source */
608  goto Quit;
609  }
610  else // LogNameValid && FoundLog
611  {
612  /* Create a new source in the specified log */
613 
614  lRet = RegOpenKeyExW(hEventLogKey,
615  EventLogName,
616  0, KEY_CREATE_SUB_KEY, // KEY_WRITE
617  &hLogKey);
618  if (lRet != ERROR_SUCCESS)
619  goto Quit;
620 
621  /* Register the new event source */
622  lRet = InstallEventSource(hLogKey, EventLogSource);
623 
624  RegCloseKey(hLogKey);
625 
626  if (lRet != ERROR_SUCCESS)
627  {
628  PrintError(lRet);
629  ConPrintf(StdErr, L"Impossible to create the source `%s' for log `%s'!\n",
630  EventLogSource, EventLogName);
631  goto Quit;
632  }
633 
634  SourceCreated = TRUE;
635  Success = TRUE;
636  }
637  }
638 
639 Quit:
640  if (hEventLogKey)
641  RegCloseKey(hEventLogKey);
642 
643  SetLastError(lRet);
644 
645  return Success;
646 }
647 
648 
649 /************************** P A R S E R A P I **************************/
650 
651 enum TYPE
652 {
655 // TYPE_U8,
656 // TYPE_U16,
658 };
659 
660 #define OPTION_ALLOWED_LIST 0x01
661 #define OPTION_NOT_EMPTY 0x02
662 #define OPTION_TRIM_SPACE 0x04
663 #define OPTION_EXCLUSIVE 0x08
664 #define OPTION_MANDATORY 0x10
665 
666 typedef struct _OPTION
667 {
668  /* Constant data */
669  PWSTR OptionName; // Option switch name
670  ULONG Type; // Type of data stored in the 'Value' member (UNUSED) (bool, string, int, ..., or function to call)
671  ULONG Flags; // Flags (preprocess the string or not, cache the string, stop processing...)
672  ULONG MaxOfInstances; // Maximum number of times this option can be seen in the command line (or 0: do not care)
673  // PWSTR OptionHelp; // Help string, or resource ID of the (localized) string (use the MAKEINTRESOURCE macro to create this value).
674  // PVOID Callback() ??
675  PWSTR AllowedValues; // Optional list of allowed values, given as a string of values separated by a pipe symbol '|'.
676 
677  /* Parsing data */
678  PWSTR OptionStr; // Pointer to the original option string
679  ULONG Instances; // Number of times this option is seen in the command line
680  ULONG ValueSize; // Size of the buffer pointed by 'Value' ??
681  PVOID Value; // A pointer to part of the command line, or an allocated buffer
682 } OPTION, *POPTION;
683 
684 #define NEW_OPT(Name, Type, Flags, MaxOfInstances, ValueSize, ValueBuffer) \
685  {(Name), (Type), (Flags), (MaxOfInstances), NULL, NULL, 0, (ValueSize), (ValueBuffer)}
686 
687 #define NEW_OPT_EX(Name, Type, Flags, AllowedValues, MaxOfInstances, ValueSize, ValueBuffer) \
688  {(Name), (Type), (Flags), (MaxOfInstances), (AllowedValues), NULL, 0, (ValueSize), (ValueBuffer)}
689 
690 static PWSTR
692  IN PWSTR String)
693 {
694  PWSTR pStr;
695 
696  /* Trim whitespace on left (just advance the pointer) */
697  while (*String && iswspace(*String))
698  ++String;
699 
700  /* Trim whitespace on right (NULL-terminate) */
701  pStr = String + wcslen(String) - 1;
702  while (pStr >= String && iswspace(*pStr))
703  --pStr;
704  *++pStr = L'\0';
705 
706  /* Return the modified pointer */
707  return String;
708 }
709 
710 typedef enum _PARSER_ERROR
711 {
712  Success = 0,
721 } PARSER_ERROR;
722 
724 
725 BOOL
727  IN INT argc,
728  IN WCHAR* argv[],
729  IN OUT POPTION Options,
730  IN ULONG NumOptions,
731  IN PRINT_ERROR_FUNC PrintErrorFunc OPTIONAL)
732 {
733  BOOL ExclusiveOptionPresent = FALSE;
734  PWSTR OptionStr = NULL;
735  UINT i;
736 
737  /*
738  * The 'Option' index is reset to 'NumOptions' (total number of elements in
739  * the 'Options' list) before retrieving a new option. This is done so that
740  * we know it cannot index a valid option at that moment.
741  */
742  UINT Option = NumOptions;
743 
744  /* Parse command line for options */
745  for (i = 1; i < argc; ++i)
746  {
747  /* Check for new options */
748 
749  if (argv[i][0] == L'-' || argv[i][0] == L'/')
750  {
753  if (Option != NumOptions)
754  {
755  if (PrintErrorFunc)
756  PrintErrorFunc(ValueRequired, OptionStr);
757  return FALSE;
758  }
759 
760  /*
761  * If we have already encountered an (unique) exclusive option,
762  * just break now.
763  */
764  if (ExclusiveOptionPresent)
765  break;
766 
767  OptionStr = argv[i];
768 
769  /* Lookup for the option in the list of options */
770  for (Option = 0; Option < NumOptions; ++Option)
771  {
772  if (_wcsicmp(OptionStr + 1, Options[Option].OptionName) == 0)
773  break;
774  }
775 
776  if (Option >= NumOptions)
777  {
778  if (PrintErrorFunc)
779  PrintErrorFunc(InvalidOption, OptionStr);
780  return FALSE;
781  }
782 
783 
784  /* An option is being set */
785 
786  if (Options[Option].MaxOfInstances != 0 &&
787  Options[Option].Instances >= Options[Option].MaxOfInstances)
788  {
789  if (PrintErrorFunc)
790  PrintErrorFunc(TooManySameOption, OptionStr, Options[Option].MaxOfInstances);
791  return FALSE;
792  }
793  ++Options[Option].Instances;
794 
795  Options[Option].OptionStr = OptionStr;
796 
797  /*
798  * If this option is exclusive, remember it for later.
799  * We will then short-circuit the regular validity checks
800  * and instead check whether this is the only option specified
801  * on the command-line.
802  */
803  if (Options[Option].Flags & OPTION_EXCLUSIVE)
804  ExclusiveOptionPresent = TRUE;
805 
806  /* Preprocess the option before setting its value */
807  switch (Options[Option].Type)
808  {
809  case TYPE_None: // ~= TYPE_Bool
810  {
811  /* Set the associated boolean */
812  BOOL* pBool = (BOOL*)Options[Option].Value;
813  *pBool = TRUE;
814 
815  /* No associated value, so reset the index */
816  Option = NumOptions;
817  }
818 
819  /* Fall-back */
820 
821  case TYPE_Str:
822 
823  // case TYPE_U8:
824  // case TYPE_U16:
825  case TYPE_U32:
826  break;
827 
828  default:
829  {
830  wprintf(L"PARSER: Unsupported option type %lu\n", Options[Option].Type);
831  break;
832  }
833  }
834  }
835  else
836  {
837  /* A value for an option is being set */
838  switch (Options[Option].Type)
839  {
840  case TYPE_None:
841  {
842  /* There must be no associated value */
843  if (PrintErrorFunc)
844  PrintErrorFunc(ValueNotAllowed, OptionStr);
845  return FALSE;
846  }
847 
848  case TYPE_Str:
849  {
850  /* Retrieve the string */
851  PWSTR* pStr = (PWSTR*)Options[Option].Value;
852  *pStr = argv[i];
853 
854  /* Trim whitespace if needed */
855  if (Options[Option].Flags & OPTION_TRIM_SPACE)
856  *pStr = TrimLeftRightWhitespace(*pStr);
857 
858  /* Check whether or not the value can be empty */
859  if ((Options[Option].Flags & OPTION_NOT_EMPTY) && !**pStr)
860  {
861  /* Value cannot be empty */
862  if (PrintErrorFunc)
863  PrintErrorFunc(ValueIsEmpty, OptionStr);
864  return FALSE;
865  }
866 
867  /* Check whether the value is part of the allowed list of values */
868  if (Options[Option].Flags & OPTION_ALLOWED_LIST)
869  {
870  PWSTR AllowedValues, Scan;
871  SIZE_T Length;
872 
873  AllowedValues = Options[Option].AllowedValues;
874  if (!AllowedValues)
875  {
876  /* The array is empty, no allowed values */
877  if (PrintErrorFunc)
878  PrintErrorFunc(InvalidValue, *pStr, OptionStr);
879  return FALSE;
880  }
881 
882  Scan = AllowedValues;
883  while (*Scan)
884  {
885  /* Find the values separator */
886  Length = wcscspn(Scan, L"|");
887 
888  /* Check whether this is an allowed value */
889  if ((wcslen(*pStr) == Length) &&
890  (_wcsnicmp(*pStr, Scan, Length) == 0))
891  {
892  /* Found it! */
893  break;
894  }
895 
896  /* Go to the next test value */
897  Scan += Length;
898  if (*Scan) ++Scan; // Skip the separator
899  }
900 
901  if (!*Scan)
902  {
903  /* The value is not allowed */
904  if (PrintErrorFunc)
905  PrintErrorFunc(InvalidValue, *pStr, OptionStr);
906  return FALSE;
907  }
908  }
909 
910  break;
911  }
912 
913  // case TYPE_U8:
914  // case TYPE_U16:
915  case TYPE_U32:
916  {
917  PWCHAR pszNext = NULL;
918 
919  /* The number is specified in base 10 */
920  // NOTE: We might use '0' so that the base is automatically determined.
921  *(ULONG*)Options[Option].Value = wcstoul(argv[i], &pszNext, 10);
922  if (*pszNext)
923  {
924  /* The value is not a valid numeric value and is not allowed */
925  if (PrintErrorFunc)
926  PrintErrorFunc(InvalidValue, argv[i], OptionStr);
927  return FALSE;
928  }
929  break;
930  }
931 
932  default:
933  {
934  wprintf(L"PARSER: Unsupported option type %lu\n", Options[Option].Type);
935  break;
936  }
937  }
938 
939  /* Reset the index */
940  Option = NumOptions;
941  }
942  }
943 
945  if (Option != NumOptions)
946  {
947  if (PrintErrorFunc)
948  PrintErrorFunc(ValueRequired, OptionStr);
949  return FALSE;
950  }
951 
952  /* Finalize options validity checks */
953 
954  if (ExclusiveOptionPresent)
955  {
956  /*
957  * An exclusive option present on the command-line:
958  * check whether this is the only option specified.
959  */
960  for (i = 0; i < NumOptions; ++i)
961  {
962  if (!(Options[i].Flags & OPTION_EXCLUSIVE) && (Options[i].Instances != 0))
963  {
964  /* A non-exclusive option is present on the command-line, fail */
965  if (PrintErrorFunc)
966  PrintErrorFunc(InvalidSyntax);
967  return FALSE;
968  }
969  }
970 
971  /* No other checks needed, we are done */
972  return TRUE;
973  }
974 
975  /* Check whether the required options were specified */
976  for (i = 0; i < NumOptions; ++i)
977  {
978  /* Regular validity checks */
979  if ((Options[i].Flags & OPTION_MANDATORY) && (Options[i].Instances == 0))
980  {
981  if (PrintErrorFunc)
982  PrintErrorFunc(MandatoryOptionAbsent, Options[i].OptionName);
983  return FALSE;
984  }
985  }
986 
987  /* All checks are done */
988  return TRUE;
989 }
990 
991 /******************************************************************************/
992 
993 
994 static VOID
995 __cdecl
997 {
998  /* WARNING: Please keep this lookup table in sync with the resources! */
999  static UINT ErrorIDs[] =
1000  {
1001  0, /* Success */
1002  IDS_BADSYNTAX_0, /* InvalidSyntax */
1003  IDS_INVALIDSWITCH, /* InvalidOption */
1004  IDS_BADSYNTAX_1, /* ValueRequired */
1005  IDS_BADSYNTAX_2, /* ValueIsEmpty */
1006  IDS_BADSYNTAX_3, /* InvalidValue */
1007  IDS_BADSYNTAX_4, /* ValueNotAllowed */
1008  IDS_BADSYNTAX_5, /* TooManySameOption */
1009  IDS_BADSYNTAX_6, /* MandatoryOptionAbsent */
1010  };
1011 
1012  va_list args;
1013 
1014  if (Error < ARRAYSIZE(ErrorIDs))
1015  {
1016  va_start(args, Error);
1017  ConResPrintfV(StdErr, ErrorIDs[Error], args);
1018  va_end(args);
1019 
1020  if (Error != Success)
1022  }
1023  else
1024  {
1025  ConPrintf(StdErr, L"PARSER: Unknown error %d\n", Error);
1026  }
1027 }
1028 
1029 int wmain(int argc, WCHAR* argv[])
1030 {
1031  BOOL Success = FALSE;
1032  HANDLE hEventLog;
1033  PTOKEN_USER pUserToken;
1034 
1035  /* Default option values */
1036  BOOL bDisplayHelp = FALSE;
1037  PWSTR szSystem = NULL;
1038  PWSTR szDomainUser = NULL;
1039  PWSTR szPassword = NULL;
1040  PWSTR szLogName = NULL;
1041  PWSTR szEventSource = NULL;
1042  PWSTR szEventType = NULL;
1044  ULONG ulEventType = EVENTLOG_INFORMATION_TYPE;
1045  ULONG ulEventCategory = 0;
1046  ULONG ulEventIdentifier = 0;
1047 
1048  OPTION Options[] =
1049  {
1050  /* Help */
1051  NEW_OPT(L"?", TYPE_None, // ~= TYPE_Bool,
1053  1,
1054  sizeof(bDisplayHelp), &bDisplayHelp),
1055 
1056  /* System */
1057  NEW_OPT(L"S", TYPE_Str,
1059  1,
1060  sizeof(szSystem), &szSystem),
1061 
1062  /* Domain & User */
1063  NEW_OPT(L"U", TYPE_Str,
1065  1,
1066  sizeof(szDomainUser), &szDomainUser),
1067 
1068  /* Password */
1069  NEW_OPT(L"P", TYPE_Str,
1070  0,
1071  1,
1072  sizeof(szPassword), &szPassword),
1073 
1074  /* Log name */
1075  NEW_OPT(L"L", TYPE_Str,
1077  1,
1078  sizeof(szLogName), &szLogName),
1079 
1080  /* Event source */
1081  NEW_OPT(L"SO", TYPE_Str,
1083  1,
1084  sizeof(szEventSource), &szEventSource),
1085 
1086  /* Event type */
1087  NEW_OPT_EX(L"T", TYPE_Str,
1089  L"SUCCESS|ERROR|WARNING|INFORMATION",
1090  1,
1091  sizeof(szEventType), &szEventType),
1092 
1093  /* Event category (ReactOS additional option) */
1094  NEW_OPT(L"C", TYPE_U32,
1095  0,
1096  1,
1097  sizeof(ulEventCategory), &ulEventCategory),
1098 
1099  /* Event ID */
1100  NEW_OPT(L"ID", TYPE_U32,
1102  1,
1103  sizeof(ulEventIdentifier), &ulEventIdentifier),
1104 
1105  /* Event description */
1106  NEW_OPT(L"D", TYPE_Str,
1108  1,
1109  sizeof(szDescription), &szDescription),
1110  };
1111 #define OPT_SYSTEM (Options[1])
1112 #define OPT_USER (Options[2])
1113 #define OPT_PASSWD (Options[3])
1114 #define OPT_EVTID (Options[8])
1115 
1116  /* Initialize the Console Standard Streams */
1118 
1119  /* Parse command line for options */
1120  if (!DoParse(argc, argv, Options, ARRAYSIZE(Options), PrintParserError))
1121  return EXIT_FAILURE;
1122 
1123  /* Finalize options validity checks */
1124 
1125  if (bDisplayHelp)
1126  {
1127  if (argc > 2)
1128  {
1129  /* Invalid syntax */
1131  return EXIT_FAILURE;
1132  }
1133 
1135  return EXIT_SUCCESS;
1136  }
1137 
1138  if (szSystem || szDomainUser || szPassword)
1139  {
1140  // TODO: Implement!
1141  if (szSystem)
1143  if (szDomainUser)
1145  if (szPassword)
1147  return EXIT_FAILURE;
1148  }
1149 
1150  if (ulEventIdentifier < EVENT_ID_MIN || ulEventIdentifier > EVENT_ID_MAX)
1151  {
1152  /* Invalid event identifier */
1153  ConResPrintf(StdErr, IDS_BADSYNTAX_7, OPT_EVTID.OptionStr, EVENT_ID_MIN, EVENT_ID_MAX);
1155  return EXIT_FAILURE;
1156  }
1157 
1158  /*
1159  * Set the event type. Note that we forbid the user
1160  * to use security auditing types.
1161  */
1162  if (_wcsicmp(szEventType, L"SUCCESS") == 0)
1163  ulEventType = EVENTLOG_SUCCESS;
1164  else
1165  if (_wcsicmp(szEventType, L"ERROR") == 0)
1166  ulEventType = EVENTLOG_ERROR_TYPE;
1167  else
1168  if (_wcsicmp(szEventType, L"WARNING") == 0)
1169  ulEventType = EVENTLOG_WARNING_TYPE;
1170  else
1171  if (_wcsicmp(szEventType, L"INFORMATION") == 0)
1172  ulEventType = EVENTLOG_INFORMATION_TYPE;
1173  else
1174  {
1175  /* Use a default event type */
1176  ulEventType = EVENTLOG_SUCCESS;
1177  }
1178 
1179  /*
1180  * If we have a source, do not care about the log (as long as we will be
1181  * able to find the source later).
1182  * But if we do not have a source, then two cases:
1183  * - either we have a log name so that we will use OpenEventLog (and use
1184  * default log's source), unless this is the Application log in which case
1185  * we use the default source;
1186  * - or we do not have a log name so that we use default log and source names.
1187  */
1188  if (!szEventSource)
1189  {
1190  if (!szLogName)
1191  szLogName = L"Application";
1192 
1193  if (_wcsicmp(szLogName, L"Application") == 0)
1194  szEventSource = APPLICATION_NAME;
1195  }
1196 
1197  // FIXME: Check whether szLogName == L"Security" !!
1198 
1199  /*
1200  * The event APIs OpenEventLog and RegisterEventSource fall back to using
1201  * the 'Application' log when the specified log name or event source do not
1202  * exist on the system.
1203  * To prevent that and be able to error the user that the specified log name
1204  * or event source do not exist, we need to manually perform the existence
1205  * checks by ourselves.
1206  *
1207  * Check whether either the specified event log OR event source exist on
1208  * the system. If the event log does not exist, return an error. Otherwise
1209  * check whether a specified source already exists (everywhere). If found
1210  * in a different log, return an error. If not found, create the source
1211  * in the specified event log.
1212  *
1213  * NOTE: By default we forbid the usage of application (non-custom) sources.
1214  * An optional switch can be added to EventCreate to allow such sources
1215  * to be used.
1216  */
1217  if (!CheckLogOrSourceExistence(szSystem, szLogName, szEventSource, FALSE))
1218  {
1220  return EXIT_FAILURE;
1221  }
1222 
1223  /* Open the event log, by source or by log name */
1224  if (szEventSource) // && *szEventSource
1225  hEventLog = RegisterEventSourceW(szSystem, szEventSource);
1226  else
1227  hEventLog = OpenEventLogW(szSystem, szLogName);
1228 
1229  if (!hEventLog)
1230  {
1232  return EXIT_FAILURE;
1233  }
1234 
1235  /* Retrieve the current user token and report the event */
1236  if (GetUserToken(&pUserToken))
1237  {
1238  Success = ReportEventW(hEventLog,
1239  ulEventType,
1240  ulEventCategory,
1241  ulEventIdentifier,
1242  pUserToken->User.Sid,
1243  1, // One string
1244  0, // No raw data
1245  (LPCWSTR*)&szDescription,
1246  NULL // No raw data
1247  );
1248  if (!Success)
1249  {
1251  ConPuts(StdErr, L"Failed to report event!\n");
1252  }
1253  else
1254  {
1255  /* Show success */
1256  ConPuts(StdOut, L"\n");
1257  if (!szEventSource)
1258  ConResPrintf(StdOut, IDS_SUCCESS_1, szEventType, szLogName);
1259  else if (!szLogName)
1260  ConResPrintf(StdOut, IDS_SUCCESS_2, szEventType, szEventSource);
1261  else
1262  ConResPrintf(StdOut, IDS_SUCCESS_3, szEventType, szLogName, szEventSource);
1263  }
1264 
1265  HeapFree(GetProcessHeap(), 0, pUserToken);
1266  }
1267  else
1268  {
1270  ConPuts(StdErr, L"GetUserToken() failed!\n");
1271  }
1272 
1273  /* Close the event log */
1274  if (szEventSource && *szEventSource)
1275  DeregisterEventSource(hEventLog);
1276  else
1277  CloseEventLog(hEventLog);
1278 
1279  return (Success ? EXIT_SUCCESS : EXIT_FAILURE);
1280 }
HANDLE WINAPI OpenEventLogW(IN LPCWSTR lpUNCServerName, IN LPCWSTR lpSourceName)
Definition: eventlog.c:985
DWORD WINAPI GetModuleFileNameW(HINSTANCE hModule, LPWSTR lpFilename, DWORD nSize)
Definition: loader.c:607
static int argc
Definition: ServiceArgs.c:12
#define APPLICATION_NAME
Definition: eventcreate.c:108
#define IN
Definition: typedefs.h:38
UINT WINAPI GetSystemWindowsDirectoryW(OUT LPWSTR lpBuffer, IN UINT uSize)
Definition: path.c:2396
#define TRUE
Definition: types.h:120
NTSYSAPI VOID NTAPI RtlCopyMemory(VOID UNALIGNED *Destination, CONST VOID UNALIGNED *Source, ULONG Length)
#define CloseHandle
Definition: compat.h:398
ULONG ValueSize
Definition: eventcreate.c:680
Type
Definition: Type.h:6
#define ERROR_SUCCESS
Definition: deptool.c:10
#define OPTION_EXCLUSIVE
Definition: eventcreate.c:663
INT ConResPrintfV(IN PCON_STREAM Stream, IN UINT uID, IN va_list args)
Definition: outstream.c:695
#define KEY_SET_VALUE
Definition: nt_native.h:1017
#define __cdecl
Definition: accygwin.h:79
#define ERROR_NO_MORE_ITEMS
Definition: compat.h:95
#define KEY_READ
Definition: nt_native.h:1023
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:323
#define IDS_SUCCESS_3
Definition: resource.h:22
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define IDS_LOG_NOT_FOUND
Definition: resource.h:15
uint16_t * PWSTR
Definition: typedefs.h:54
#define IDS_SOURCE_EXISTS
Definition: resource.h:17
#define OPTION_NOT_EMPTY
Definition: eventcreate.c:661
#define OPTION_MANDATORY
Definition: eventcreate.c:664
_Check_return_ _CRTIMP size_t __cdecl wcscspn(_In_z_ const wchar_t *_Str, _In_z_ const wchar_t *_Control)
#define IDS_BADSYNTAX_4
Definition: resource.h:10
_Check_return_ _CRTIMP int __cdecl _wcsnicmp(_In_reads_or_z_(_MaxCount) const wchar_t *_Str1, _In_reads_or_z_(_MaxCount) const wchar_t *_Str2, _In_ size_t _MaxCount)
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
static HANDLE ULONG_PTR dwData
Definition: file.c:35
#define ARRAYSIZE(array)
Definition: filtermapper.c:47
#define ERROR_NOT_ENOUGH_MEMORY
Definition: dderror.h:7
DWORD WINAPI GetLastError(VOID)
Definition: except.c:1059
static VOID __cdecl PrintParserError(PARSER_ERROR Error,...)
Definition: eventcreate.c:996
static BOOL GetUserToken(OUT PTOKEN_USER *ppUserToken)
Definition: eventcreate.c:123
#define IDS_USAGE
Definition: resource.h:3
static WCHAR String[]
Definition: stringtable.c:55
uint16_t * PWCHAR
Definition: typedefs.h:54
_Check_return_ unsigned long __cdecl wcstoul(_In_z_ const wchar_t *_Str, _Out_opt_ _Deref_post_z_ wchar_t **_EndPtr, _In_ int _Radix)
#define wprintf(...)
Definition: whoami.c:18
LONG WINAPI RegFlushKey(HKEY hKey)
Definition: reg.c:2988
enum OPTION_FLAGS Options
Definition: stats.c:44
#define IDS_BADSYNTAX_2
Definition: resource.h:8
int32_t INT
Definition: typedefs.h:56
static char ** argv
Definition: ServiceArgs.c:11
LONG WINAPI RegCreateKeyExW(_In_ HKEY hKey, _In_ LPCWSTR lpSubKey, _In_ DWORD Reserved, _In_opt_ LPWSTR lpClass, _In_ DWORD dwOptions, _In_ REGSAM samDesired, _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes, _Out_ PHKEY phkResult, _Out_opt_ LPDWORD lpdwDisposition)
Definition: reg.c:1094
STRSAFEAPI StringCchCatW(STRSAFE_LPWSTR pszDest, size_t cchDest, STRSAFE_LPCWSTR pszSrc)
Definition: strsafe.h:325
#define OPTION_TRIM_SPACE
Definition: eventcreate.c:662
#define MAX_KEY_LENGTH
#define IDS_SWITCH_UNIMPLEMENTED
Definition: resource.h:24
#define EXIT_SUCCESS
Definition: rdjpgcom.c:55
_PARSER_ERROR
Definition: eventcreate.c:710
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170
GLenum GLclampf GLint i
Definition: glfuncs.h:14
static BOOL CheckLogOrSourceExistence(IN LPCWSTR UNCServerName OPTIONAL, IN LPCWSTR EventLogName, IN LPCWSTR EventLogSource, IN BOOL AllowAppSources OPTIONAL)
Definition: eventcreate.c:260
#define EVENT_ID_MAX
Definition: eventcreate.c:102
LONG WINAPI RegCloseKey(HKEY hKey)
Definition: reg.c:423
unsigned char * LPBYTE
Definition: typedefs.h:52
#define IDS_BADSYNTAX_1
Definition: resource.h:7
#define ConInitStdStreams()
Definition: stream.h:122
#define va_end(ap)
Definition: acmsvcex.h:90
#define EVENTLOG_ERROR_TYPE
Definition: winnt_old.h:2630
long LONG
Definition: pedump.c:60
#define IDS_BADSYNTAX_0
Definition: resource.h:6
STRSAFEAPI StringCchCopyW(STRSAFE_LPWSTR pszDest, size_t cchDest, STRSAFE_LPCWSTR pszSrc)
Definition: strsafe.h:149
#define IDS_SUCCESS_2
Definition: resource.h:21
INT __cdecl ConPrintf(IN PCON_STREAM Stream, IN LPWSTR szStr,...)
Definition: outstream.c:520
#define IDS_BADSYNTAX_6
Definition: resource.h:12
smooth NULL
Definition: ftsmooth.c:416
PVOID Value
Definition: eventcreate.c:681
char * va_list
Definition: acmsvcex.h:78
#define REG_CREATED_NEW_KEY
Definition: nt_native.h:1084
#define ERROR_FILE_NOT_FOUND
Definition: disk.h:79
#define FORMAT_MESSAGE_FROM_SYSTEM
Definition: winbase.h:404
int wmain(int argc, WCHAR *argv[])
Definition: eventcreate.c:1029
PWSTR AllowedValues
Definition: eventcreate.c:675
INT __cdecl ConResPrintf(IN PCON_STREAM Stream, IN UINT uID,...)
Definition: outstream.c:781
#define REG_OPTION_NON_VOLATILE
Definition: nt_native.h:1057
LONG WINAPI RegSetValueExW(_In_ HKEY hKey, _In_ LPCWSTR lpValueName, _In_ DWORD Reserved, _In_ DWORD dwType, _In_ CONST BYTE *lpData, _In_ DWORD cbData)
Definition: reg.c:4917
#define EVENTLOG_SUCCESS
Definition: winnt_old.h:2629
unsigned int BOOL
Definition: ntddk_ex.h:94
#define GetProcessHeap()
Definition: compat.h:395
PVOID WINAPI HeapAlloc(HANDLE, DWORD, SIZE_T)
#define EVENTLOG_INFORMATION_TYPE
Definition: winnt_old.h:2632
#define TOKEN_QUERY
Definition: setypes.h:874
LONG WINAPI RegQueryValueExW(_In_ HKEY hkeyorg, _In_ LPCWSTR name, _In_ LPDWORD reserved, _In_ LPDWORD type, _In_ LPBYTE data, _In_ LPDWORD count)
Definition: reg.c:4134
#define EVENTLOG_WARNING_TYPE
Definition: winnt_old.h:2631
PEVENTSOURCE EventLogSource
Definition: eventlog.c:35
HANDLE WINAPI GetCurrentProcess(VOID)
Definition: proc.c:1168
#define MAX_PATH
Definition: compat.h:26
unsigned int UINT
Definition: ndis.h:50
unsigned long DWORD
Definition: ntddk_ex.h:95
#define EXIT_FAILURE
Definition: jerror.c:33
BOOL Error
Definition: chkdsk.c:66
#define SetLastError(x)
Definition: compat.h:409
INT ConMsgPuts(IN PCON_STREAM Stream, IN DWORD dwFlags, IN LPCVOID lpSource OPTIONAL, IN DWORD dwMessageId, IN DWORD dwLanguageId)
Definition: outstream.c:837
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:101
#define StdErr
Definition: stream.h:77
PWSTR OptionName
Definition: eventcreate.c:669
#define iswspace(_c)
Definition: ctype.h:669
INT ConResPuts(IN PCON_STREAM Stream, IN UINT uID)
Definition: outstream.c:610
static const WCHAR L[]
Definition: oid.c:1087
VOID PrintError(DWORD dwError)
Definition: eventcreate.c:111
BOOL WINAPI CloseEventLog(IN HANDLE hEventLog)
Definition: eventlog.c:427
#define VOID
Definition: acefi.h:82
#define NEW_OPT_EX(Name, Type, Flags, AllowedValues, MaxOfInstances, ValueSize, ValueBuffer)
Definition: eventcreate.c:687
static PWSTR TrimLeftRightWhitespace(IN PWSTR String)
Definition: eventcreate.c:691
ULONG MaxOfInstances
Definition: eventcreate.c:672
BOOL WINAPI ReportEventW(IN HANDLE hEventLog, IN WORD wType, IN WORD wCategory, IN DWORD dwEventID, IN PSID lpUserSid, IN WORD wNumStrings, IN DWORD dwDataSize, IN LPCWSTR *lpStrings, IN LPVOID lpRawData)
Definition: eventlog.c:1516
BOOL DoParse(IN INT argc, IN WCHAR *argv[], IN OUT POPTION Options, IN ULONG NumOptions, IN PRINT_ERROR_FUNC PrintErrorFunc OPTIONAL)
Definition: eventcreate.c:726
#define IDS_BADSYNTAX_3
Definition: resource.h:9
ULONG_PTR SIZE_T
Definition: typedefs.h:78
struct _OPTION OPTION
#define IDS_SOURCE_NOT_CUSTOM
Definition: resource.h:18
TYPE
Definition: eventcreate.c:651
#define OPT_USER
#define KEY_QUERY_VALUE
Definition: nt_native.h:1016
#define IDS_BADSYNTAX_5
Definition: resource.h:11
#define REG_EXPAND_SZ
Definition: nt_native.h:1494
static LONG InstallEventSource(IN HKEY hEventLogKey, IN LPCWSTR EventLogSource)
Definition: eventcreate.c:178
#define OPT_PASSWD
#define NEW_OPT(Name, Type, Flags, MaxOfInstances, ValueSize, ValueBuffer)
Definition: eventcreate.c:684
#define IDS_HELP
Definition: resource.h:3
#define va_start(ap, A)
Definition: acmsvcex.h:91
ULONG Type
Definition: eventcreate.c:670
BOOL WINAPI OpenProcessToken(HANDLE ProcessHandle, DWORD DesiredAccess, PHANDLE TokenHandle)
Definition: security.c:292
BOOL WINAPI DeregisterEventSource(IN HANDLE hEventLog)
Definition: eventlog.c:473
#define HEAP_ZERO_MEMORY
Definition: compat.h:123
#define IDS_SOURCE_NOCREATE
Definition: resource.h:16
ULONG Flags
Definition: eventcreate.c:671
INT ConPuts(IN PCON_STREAM Stream, IN LPWSTR szStr)
Definition: outstream.c:427
#define OPTION_ALLOWED_LIST
Definition: eventcreate.c:660
#define OUT
Definition: typedefs.h:39
#define StdOut
Definition: stream.h:76
unsigned int ULONG
Definition: retypes.h:1
BOOL WINAPI GetTokenInformation(HANDLE TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass, LPVOID TokenInformation, DWORD TokenInformationLength, PDWORD ReturnLength)
Definition: security.c:409
LONG WINAPI RegOpenKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult)
Definition: reg.c:3381
#define IDS_INVALIDSWITCH
Definition: resource.h:4
SID_AND_ATTRIBUTES User
Definition: setypes.h:956
#define IDS_BADSYNTAX_7
Definition: resource.h:13
LONG WINAPI RegEnumKeyExW(_In_ HKEY hKey, _In_ DWORD dwIndex, _Out_ LPWSTR lpName, _Inout_ LPDWORD lpcbName, _Reserved_ LPDWORD lpReserved, _Out_opt_ LPWSTR lpClass, _Inout_opt_ LPDWORD lpcbClass, _Out_opt_ PFILETIME lpftLastWriteTime)
Definition: reg.c:2541
#define OPT_EVTID
#define OPT_SYSTEM
HANDLE WINAPI RegisterEventSourceW(IN LPCWSTR lpUNCServerName, IN LPCWSTR lpSourceName)
Definition: eventlog.c:1295
#define REG_DWORD
Definition: sdbapi.c:539
#define KEY_CREATE_SUB_KEY
Definition: nt_native.h:1018
#define IDS_SUCCESS_1
Definition: resource.h:20
#define args
Definition: format.c:66
size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
#define HeapFree(x, y, z)
Definition: compat.h:394
struct _OPTION * POPTION
PWSTR OptionStr
Definition: eventcreate.c:678
ULONG Instances
Definition: eventcreate.c:679
VOID(__cdecl * PRINT_ERROR_FUNC)(IN PARSER_ERROR,...)
Definition: eventcreate.c:723
_Check_return_ _CRTIMP int __cdecl _wcsicmp(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)
enum _PARSER_ERROR PARSER_ERROR
#define LANG_USER_DEFAULT
Definition: tnerror.cpp:50
static const WCHAR szDescription[]
Definition: provider.c:52
#define EVENT_ID_MIN
Definition: eventcreate.c:101
#define HKEY_LOCAL_MACHINE
Definition: winreg.h:12
#define KEY_ENUMERATE_SUB_KEYS
Definition: nt_native.h:1019
#define ERROR_INSUFFICIENT_BUFFER
Definition: dderror.h:10
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68