ReactOS  0.4.13-dev-540-g8f04a09
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,
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[],
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 */
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 */
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
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 }
_In_opt_ ULONG _Out_ PULONG Value
Definition: rtlfuncs.h:2327
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
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
#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
#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)
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
#define argv
Definition: mplay32.c:18
LONG WINAPI RegFlushKey(HKEY hKey)
Definition: reg.c:2974
enum OPTION_FLAGS Options
Definition: stats.c:44
Definition: match.c:390
#define IDS_BADSYNTAX_2
Definition: resource.h:8
int32_t INT
Definition: typedefs.h:56
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:1091
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
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
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
unsigned int BOOL
Definition: ntddk_ex.h:94
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:4895
#define EVENTLOG_SUCCESS
Definition: winnt_old.h:2629
#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:4116
__wchar_t WCHAR
Definition: xmlstorage.h:180
#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 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:1250
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
unsigned int UINT
Definition: ndis.h:50
BOOL WINAPI OpenProcessToken(HANDLE ProcessHandle, DWORD DesiredAccess, PHANDLE TokenHandle)
Definition: security.c:296
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:413
LONG WINAPI RegOpenKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult)
Definition: reg.c:3366
#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:2527
#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:596
#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