Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1190 lines
35 KiB

  1. // *********************************************************************************
  2. //
  3. // Copyright (c) Microsoft Corporation. All rights reserved.
  4. //
  5. // Module Name:
  6. //
  7. // EventCreate.c
  8. //
  9. // Abstract:
  10. //
  11. // This modules implements creation of event in the user specified log / application
  12. //
  13. // Syntax:
  14. // ------
  15. // EventCreate [-s server [-u username [-p password]]]
  16. // [-log name] [-source name] -id eventid -description description -type eventtype
  17. //
  18. // Author:
  19. //
  20. // Sunil G.V.N. Murali ([email protected]) 24-Sep-2000
  21. //
  22. // Revision History:
  23. //
  24. // Sunil G.V.N. Murali ([email protected]) 24-Sep-2000 : Created It.
  25. //
  26. // *********************************************************************************
  27. #include "pch.h"
  28. #include "EvcrtMsg.h"
  29. #include "EventCreate.h"
  30. //
  31. // local type definitions
  32. //
  33. typedef TCHAR __OPTION_VALUE[ 256 ];
  34. //
  35. // constants / defines / enumerators
  36. //
  37. #define FULL_SUCCESS 0
  38. #define PARTIALLY_SUCCESS 128
  39. #define COMPLETELY_FAILED 255
  40. #define MAX_KEY_LENGTH 256
  41. #define EVENT_LOG_NAMES_LOCATION _T( "SYSTEM\\CurrentControlSet\\Services\\EventLog" )
  42. // constants
  43. const TCHAR g_szDefaultLog[] = _T( "Application" );
  44. const TCHAR g_szDefaultSource[] = _T( "EventCreate" );
  45. //
  46. // function prototypes
  47. //
  48. VOID Usage();
  49. BOOL AddEventSource( HKEY hLogsKey, LPCTSTR pszSource );
  50. BOOL CheckExistence( LPCTSTR szServer,
  51. LPCTSTR szLog, LPCTSTR szSource, PBOOL pbCustom );
  52. BOOL CreateLogEvent( LPCTSTR szServer,
  53. LPCTSTR szLog, LPCTSTR szSource,
  54. WORD wType, DWORD dwEventID, LPCTSTR szDescription );
  55. BOOL ProcessOptions( LONG argc,
  56. LPCTSTR argv[],
  57. PBOOL pbShowUsage,
  58. PTARRAY parrServer, LPTSTR ppszUserName, LPTSTR ppszPassword,
  59. LPTSTR ppszLogName, LPTSTR ppszLogSource, LPTSTR ppszLogType,
  60. PDWORD pdwEventID, LPTSTR ppszDescription, PBOOL pbNeedPwd );
  61. // ***************************************************************************
  62. // Routine Description:
  63. // This the entry point to this utility.
  64. //
  65. // Arguments:
  66. // [ in ] argc : argument(s) count specified at the command prompt
  67. // [ in ] argv : argument(s) specified at the command prompt
  68. //
  69. // Return Value:
  70. // The below are actually not return values but are the exit values
  71. // returned to the OS by this application
  72. // 0 : utility successfully created the events
  73. // 255 : utility completely failed in creating events
  74. // 128 : utility has partially successfull in creating events
  75. // ***************************************************************************
  76. DWORD _cdecl _tmain( LONG argc, LPCTSTR argv[] )
  77. {
  78. // local variables
  79. DWORD dw = 0;
  80. WORD wEventType = 0;
  81. BOOL bResult = FALSE;
  82. LPCTSTR pszServer = NULL;
  83. BOOL bNeedPassword = FALSE;
  84. BOOL bCloseConnection = FALSE;
  85. DWORD dwServers = 0, dwSuccess = 0;
  86. __STRING_512 szBuffer = NULL_STRING;
  87. // variables to hold the command line inputs
  88. BOOL bUsage = FALSE; // usage
  89. DWORD dwEventID = 0; // event id
  90. TARRAY arrServers = NULL; // holds the list of server names
  91. __OPTION_VALUE szLogName = NULL_STRING; // log file name
  92. __OPTION_VALUE szSource = NULL_STRING; // source name
  93. __OPTION_VALUE szType = NULL_STRING; // event type
  94. __OPTION_VALUE szUserName = NULL_STRING; // user name
  95. __OPTION_VALUE szPassword = NULL_STRING; // password
  96. __OPTION_VALUE szDescription = NULL_STRING; // description of the event
  97. // create a dynamic array
  98. arrServers = CreateDynamicArray();
  99. if ( arrServers == NULL )
  100. {
  101. SetLastError( E_OUTOFMEMORY );
  102. ShowLastError( stderr );
  103. EXIT_PROCESS( 1 );
  104. }
  105. // process the command-line options
  106. bResult = ProcessOptions( argc, argv, &bUsage,
  107. &arrServers, szUserName, szPassword, szLogName,
  108. szSource, szType, &dwEventID, szDescription, &bNeedPassword );
  109. // check the result of the parsing
  110. if ( bResult == FALSE )
  111. {
  112. // invalid syntax
  113. DISPLAY_MESSAGE2( stderr, szBuffer, _T( "%s %s" ), TAG_ERROR, GetReason() );
  114. // release memory
  115. DestroyDynamicArray( &arrServers );
  116. // exit from program
  117. EXIT_PROCESS( 1 );
  118. }
  119. // check whether usage has to be displayed or not
  120. if ( bUsage == TRUE )
  121. {
  122. // show the usage of the utility
  123. Usage();
  124. // release memory
  125. DestroyDynamicArray( &arrServers );
  126. // finally exit from the program
  127. EXIT_PROCESS( 0 );
  128. }
  129. // determine the actual event type
  130. if ( StringCompare( szType, LOGTYPE_ERROR, TRUE, 0 ) == 0 )
  131. wEventType = EVENTLOG_ERROR_TYPE;
  132. else if ( StringCompare( szType, LOGTYPE_WARNING, TRUE, 0 ) == 0 )
  133. wEventType = EVENTLOG_WARNING_TYPE;
  134. else if ( StringCompare( szType, LOGTYPE_INFORMATION, TRUE, 0 ) == 0 )
  135. wEventType = EVENTLOG_INFORMATION_TYPE;
  136. // ******
  137. // actual creation of events in respective log files will start from here
  138. // get the no. of servers specified
  139. dwServers = DynArrayGetCount( arrServers );
  140. // now traverse thru the list of servers, and do the needed operations
  141. dwSuccess = 0;
  142. for( dw = 0; dw < dwServers; dw++ )
  143. {
  144. // get the system name
  145. pszServer = DynArrayItemAsString( arrServers, dw );
  146. if ( pszServer == NULL )
  147. continue;
  148. // try establishing connection to the required terminal
  149. bCloseConnection = TRUE;
  150. bResult = EstablishConnection(
  151. pszServer, szUserName, SIZE_OF_ARRAY( szUserName ),
  152. szPassword, SIZE_OF_ARRAY( szPassword ), bNeedPassword );
  153. bNeedPassword = FALSE; // from next time onwards, we shouldn't prompt for passwd
  154. if ( bResult == FALSE )
  155. {
  156. //
  157. // failed in establishing n/w connection
  158. SHOW_RESULT_MESSAGE( NULL, TAG_ERROR, GetReason() );
  159. // try with next server
  160. continue;
  161. }
  162. else
  163. {
  164. // though the connection is successfull, some conflict might have occured
  165. switch( GetLastError() )
  166. {
  167. case I_NO_CLOSE_CONNECTION:
  168. bCloseConnection = FALSE;
  169. break;
  170. case E_LOCAL_CREDENTIALS:
  171. case ERROR_SESSION_CREDENTIAL_CONFLICT:
  172. {
  173. bCloseConnection = FALSE;
  174. SHOW_RESULT_MESSAGE( NULL, TAG_WARNING, GetReason() );
  175. break;
  176. }
  177. }
  178. }
  179. // report the log message
  180. bResult = CreateLogEvent( pszServer, szLogName,
  181. szSource, wEventType, dwEventID, szDescription );
  182. if ( bResult == TRUE )
  183. {
  184. // display the message depending on the mode of conncetivity
  185. if ( lstrlen( szSource ) != 0 )
  186. {
  187. DISPLAY_MESSAGE( stdout, _T( "\n" ) );
  188. DISPLAY_MESSAGE2(stdout, szBuffer, EVENTCREATE_SUCCESS, szType, szSource);
  189. }
  190. else
  191. {
  192. DISPLAY_MESSAGE( stdout, _T( "\n" ) );
  193. DISPLAY_MESSAGE2(stdout, szBuffer, EVENTCREATE_SUCCESS, szType, szLogName);
  194. }
  195. // update the success count
  196. dwSuccess++;
  197. }
  198. else
  199. {
  200. // display the message depending on the mode of conncetivity
  201. // SHOW_RESULT_MESSAGE( pszServer, TAG_ERROR, GetReason() );
  202. // ( we are temporarily displaying only the error message )
  203. SHOW_RESULT_MESSAGE( NULL, TAG_ERROR, GetReason() );
  204. }
  205. // close the connection that was established by the utility
  206. if ( bCloseConnection == TRUE )
  207. CloseConnection( pszServer );
  208. }
  209. // destroy the dynamic array
  210. DestroyDynamicArray( &arrServers );
  211. // depending the success count, determine whether the exit value
  212. // FULL SUCCESS / PARTIAL SUCCESS / COMPLETELY FAILED
  213. return (dwSuccess == dwServers) ? FULL_SUCCESS :
  214. ((dwSuccess == 0) ? COMPLETELY_FAILED : PARTIALLY_SUCCESS);
  215. }
  216. // ***************************************************************************
  217. // Routine Description:
  218. // This function connects to the specified server's event log (or) source
  219. // and appropriately creates the needed event in it.
  220. //
  221. // Arguments:
  222. // [ in ] szServer : server name on which event has to be created.
  223. // null string has to be passed in order to create
  224. // event on a local system.
  225. // [ in ] szLog : Log name in which event has to be created.
  226. // [ in ] szSource : Source name in which event has to be created.
  227. // if log name is also specified, log name will be
  228. // given priority and value in this variable is ignored.
  229. // [ in ] wType : specifies type of the event that has to be created
  230. // [ in ] dwEventID : event id for the event is being created
  231. // [ in ] szDescription : description to the event
  232. //
  233. // Return Value:
  234. // TRUE : if the event creation is successful
  235. // FALSE : if failed in creating the event
  236. // ***************************************************************************
  237. BOOL CreateLogEvent( LPCTSTR szServer, LPCTSTR szLog, LPCTSTR szSource,
  238. WORD wType, DWORD dwEventID, LPCTSTR szDescription )
  239. {
  240. // local variables
  241. BOOL bReturn = 0; // return value
  242. BOOL bCustom = FALSE;
  243. DWORD dwSeverity = 0;
  244. HANDLE hEventLog = NULL; // points to the event log
  245. LPCTSTR lpszDescriptions[ 1 ] = { NULL }; // building descriptions
  246. __MAX_SIZE_STRING szBuffer = NULL_STRING;
  247. //
  248. // start the process
  249. // check whether the log / source exists in the registry or not
  250. bCustom = FALSE;
  251. if ( CheckExistence( szServer, szLog, szSource, &bCustom ) == FALSE )
  252. return FALSE; // return failure
  253. // check whether the source is custom create or pre-existing source
  254. if ( bCustom == FALSE )
  255. {
  256. // we wont create events in a non-custom source
  257. SetReason( ERROR_NONCUSTOM_SOURCE );
  258. return FALSE;
  259. }
  260. // open the appropriate event log using the specified 'source' or 'log file'
  261. // and check the result of the operation
  262. // Note: At one time, we will make use of log name (or) source but not both
  263. if ( lstrlen( szSource ) != 0 )
  264. hEventLog = RegisterEventSource( szServer, szSource ); // open log using source name
  265. else
  266. hEventLog = OpenEventLog( szServer, szLog ); // open log
  267. // check the log open/register result
  268. if ( hEventLog == NULL )
  269. {
  270. // opening/registering is failed
  271. SaveLastError();
  272. return FALSE;
  273. }
  274. // determine the severity code
  275. dwSeverity = 0;
  276. if ( wType == EVENTLOG_ERROR_TYPE )
  277. dwSeverity = 3;
  278. else if ( wType == EVENTLOG_WARNING_TYPE )
  279. dwSeverity = 2;
  280. else if ( wType == EVENTLOG_INFORMATION_TYPE )
  281. dwSeverity = 1;
  282. // report event
  283. lpszDescriptions[ 0 ] = szDescription;
  284. if ( bCustom == TRUE )
  285. {
  286. // validate the range of the event id specified
  287. if ( dwEventID >= MSG_EVENTID_START && dwEventID <= MSG_EVENTID_END )
  288. {
  289. // valid event id
  290. bReturn = ReportEvent( hEventLog, wType, 0, dwEventID, NULL, 1, 0, lpszDescriptions, NULL);
  291. // check the result
  292. if ( bReturn == FALSE )
  293. SaveLastError(); // save the error info
  294. }
  295. else
  296. {
  297. // format the error message
  298. bReturn = FALSE;
  299. _stprintf( szBuffer, ERROR_ID_OUTOFRANGE, MSG_EVENTID_START, MSG_EVENTID_END - 1 );
  300. SetReason( szBuffer );
  301. }
  302. }
  303. else
  304. {
  305. //
  306. // we are stopping from creating the events in a non-custom source
  307. // ********************************************************************
  308. // bReturn = ReportEvent( hEventLog, wType, 0,
  309. // (((unsigned long)(dwSeverity)<<30) | ((unsigned long)(dwEventID))), NULL, 1, 0, lpszDescriptions, NULL);
  310. // check the result
  311. // if ( bReturn == FALSE )
  312. // SaveLastError(); // save the error info
  313. }
  314. // close the event source
  315. if ( lstrlen( szSource ) != 0 )
  316. DeregisterEventSource( hEventLog );
  317. else
  318. CloseEventLog( hEventLog );
  319. // return the result
  320. return bReturn;
  321. }
  322. // ***************************************************************************
  323. // Routine Description:
  324. // This function checks wether the log name or source name specified
  325. // actually exists in the registry
  326. //
  327. // Arguments:
  328. // [ in ] szServer - server name
  329. // [ in ] szLog - log name
  330. // [ in ] szSource - source name
  331. //
  332. // Return Value:
  333. // TRUE : If log / source exists in the registry
  334. // FALSE : if failed find the match
  335. // ***************************************************************************
  336. BOOL CheckExistence( LPCTSTR szServer, LPCTSTR szLog, LPCTSTR szSource, PBOOL pbCustom )
  337. {
  338. // local variables
  339. DWORD dwSize = 0;
  340. DWORD dwLogsIndex = 0;
  341. DWORD dwDisposition = 0;
  342. DWORD dwSourcesIndex = 0;
  343. LONG lResult = 0L;
  344. HKEY hKey = NULL;
  345. HKEY hLogsKey = NULL;
  346. HKEY hSourcesKey = NULL;
  347. BOOL bFoundMatch = FALSE;
  348. BOOL bDuplicating = FALSE;
  349. FILETIME ftLastWriteTime; // variable that will hold the last write info
  350. BOOL bErrorOccurred = FALSE;
  351. BOOL bLog = FALSE, bLogMatched = FALSE;
  352. BOOL bSource = FALSE, bSourceMatched = FALSE;
  353. __MAX_SIZE_STRING szBuffer = NULL_STRING;
  354. TCHAR szRLog[ MAX_KEY_LENGTH ] = NULL_STRING;
  355. TCHAR szRSource[ MAX_KEY_LENGTH ] = NULL_STRING;
  356. // prepare the server name into UNC format
  357. lstrcpy( szBuffer, szServer );
  358. if ( lstrlen( szServer ) != 0 && IsUNCFormat( szServer ) == FALSE )
  359. {
  360. // format the server name in UNC format
  361. FORMAT_STRING( szBuffer, _T( "\\\\%s" ), szServer );
  362. }
  363. // Connect to the registry
  364. lResult = RegConnectRegistry( szBuffer, HKEY_LOCAL_MACHINE, &hKey );
  365. if ( lResult != ERROR_SUCCESS)
  366. {
  367. // save the error information and return FAILURE
  368. SetLastError( lResult );
  369. SaveLastError();
  370. return FALSE;
  371. }
  372. // open the "EventLogs" registry key for enumerating its sub-keys (which are log names)
  373. lResult = RegOpenKeyEx( hKey, EVENT_LOG_NAMES_LOCATION, 0, KEY_READ, &hLogsKey );
  374. if ( lResult != ERROR_SUCCESS )
  375. {
  376. switch( lResult )
  377. {
  378. case ERROR_FILE_NOT_FOUND:
  379. SetLastError( ERROR_REGISTRY_CORRUPT );
  380. break;
  381. default:
  382. // save the error information and return FAILURE
  383. SetLastError( lResult );
  384. break;
  385. }
  386. // close the key and return
  387. SaveLastError();
  388. RegCloseKey( hKey );
  389. return FALSE;
  390. }
  391. // start enumerating the logs present
  392. dwLogsIndex = 0; // initialize the logs index
  393. bFoundMatch = FALSE; // assume neither log (or) source doesn't match
  394. bErrorOccurred = FALSE; // assume error is not occured
  395. dwSize = MAX_KEY_LENGTH; // max. size of the key buffer
  396. bLogMatched = FALSE;
  397. bSourceMatched = FALSE;
  398. bDuplicating = FALSE;
  399. ////////////////////////////////////////////////////////////////////////
  400. // Logic:-
  401. // 1. determine whether user has supplied the log name or not
  402. // 2. determine whether user has supplied the source name or not
  403. // 3. Start enumerating all the logs present in the system
  404. // 4. check whether log is supplied or not, if yes, check whether
  405. // the current log matches with user supplied one.
  406. // 5. check whether source is supplied or not, if yes, enumerate the
  407. // sources available under the current log
  408. // determine whether searching has to be done of LOG (or) SOURCE
  409. bLog = ( szLog != NULL && lstrlen( szLog ) != 0 ) ? TRUE : FALSE; // #1
  410. bSource = ( szSource != NULL && lstrlen( szSource ) != 0 ) ? TRUE : FALSE; // #2
  411. // initiate the enumeration of log present in the system -- #3
  412. ZeroMemory( szRLog, MAX_KEY_LENGTH * sizeof( TCHAR ) ); // init to 0's - safe check
  413. lResult = RegEnumKeyEx( hLogsKey, 0, szRLog, &dwSize, NULL, NULL, NULL, &ftLastWriteTime );
  414. // traverse thru the sub-keys until there are no more items -- #3
  415. do
  416. {
  417. // check the result
  418. if ( lResult != ERROR_SUCCESS )
  419. {
  420. // save the error and break from the loop
  421. bErrorOccurred = TRUE;
  422. SetLastError( lResult );
  423. SaveLastError();
  424. break;
  425. }
  426. // if log name is passed, compare the current key value
  427. // compare the log name with the current key -- #4
  428. if ( bLog == TRUE && StringCompare( szLog, szRLog, TRUE, 0 ) == 0 )
  429. bLogMatched = TRUE;
  430. // if source name is passed ... -- #5
  431. if ( bSource == TRUE && bSourceMatched == FALSE )
  432. {
  433. // open the current log name to enumerate the sources under this log
  434. lResult = RegOpenKeyEx( hLogsKey, szRLog, 0, KEY_READ, &hSourcesKey );
  435. if ( lResult != ERROR_SUCCESS )
  436. {
  437. // save the error and break from the loop
  438. bErrorOccurred = TRUE;
  439. SetLastError( lResult );
  440. SaveLastError();
  441. break;
  442. }
  443. // start enumerating the sources present
  444. dwSourcesIndex = 0; // initialize the sources index
  445. dwSize = MAX_KEY_LENGTH; // max. size of the key buffer
  446. ZeroMemory( szRSource, MAX_KEY_LENGTH * sizeof( TCHAR ) );
  447. lResult = RegEnumKeyEx( hSourcesKey, 0,
  448. szRSource, &dwSize, NULL, NULL, NULL, &ftLastWriteTime );
  449. // traverse thru the sub-keys until there are no more items
  450. do
  451. {
  452. if ( lResult != ERROR_SUCCESS )
  453. {
  454. // save the error and break from the loop
  455. bErrorOccurred = TRUE;
  456. SetLastError( lResult );
  457. SaveLastError();
  458. break;
  459. }
  460. // check whether this key matches with the required source or not
  461. if ( StringCompare( szSource, szRSource, TRUE, 0 ) == 0 )
  462. {
  463. // source matched
  464. bSourceMatched = TRUE;
  465. break; // break from the loop
  466. }
  467. // update the sources index and fetch the next source key
  468. dwSourcesIndex += 1;
  469. dwSize = MAX_KEY_LENGTH; // max. size of the key buffer
  470. ZeroMemory( szRSource, MAX_KEY_LENGTH * sizeof( TCHAR ) );
  471. lResult = RegEnumKeyEx( hSourcesKey, dwSourcesIndex, szRSource, &dwSize, NULL,
  472. NULL, NULL, &ftLastWriteTime );
  473. } while( lResult != ERROR_NO_MORE_ITEMS );
  474. // close the sources registry key
  475. RegCloseKey( hSourcesKey );
  476. hSourcesKey = NULL; // clear the key value
  477. // check how the loop ended
  478. // 1. Source might have found
  479. // Action:- we found required key .. exit from the main loop
  480. // 2. Error might have occured
  481. // Action:- ignore the error and continue fetching other log's sources
  482. // 3. End of sources reached in this log
  483. // Action:- check if log name is supplied or not.
  484. // if log specified, then source if not found, break
  485. // for cases 2 & 3, clear the contents of lResult for smooth processing
  486. // Case #2 & #3
  487. lResult = 0; // we are not much bothered abt the errors
  488. bErrorOccurred = FALSE; // occured while traversing thru the source under logs
  489. // Case #1
  490. if ( bSourceMatched == TRUE )
  491. {
  492. // check whether log is specified or not
  493. // if log is specified, it should have matched .. otherwise
  494. // error ... because duplicate source should not be created
  495. if ( bLog == FALSE || ( bLog && bLogMatched && lstrcmpi( szLog, szRLog ) == 0 ) )
  496. {
  497. // no problem ...
  498. bFoundMatch = TRUE;
  499. //
  500. // determine whether this is custom created source or not
  501. // mark this as custom source
  502. if ( pbCustom != NULL )
  503. *pbCustom = FALSE;
  504. // open the source registry key
  505. _stprintf( szBuffer, _T( "%s\\%s\\%s" ), EVENT_LOG_NAMES_LOCATION, szRLog, szRSource );
  506. lResult = RegOpenKeyEx( hKey, szBuffer, 0, KEY_QUERY_VALUE, &hSourcesKey );
  507. if ( lResult != ERROR_SUCCESS )
  508. {
  509. SetLastError( lResult );
  510. SaveLastError();
  511. bErrorOccurred = TRUE;
  512. break;
  513. }
  514. // now query for the value
  515. lResult = RegQueryValueEx( hSourcesKey, _T( "CustomSource" ), NULL, NULL, NULL, NULL );
  516. if ( lResult != ERROR_SUCCESS && lResult != ERROR_FILE_NOT_FOUND )
  517. {
  518. RegCloseKey( hSourcesKey );
  519. SetLastError( lResult );
  520. SaveLastError();
  521. bErrorOccurred = TRUE;
  522. break;
  523. }
  524. // close the souces key
  525. RegCloseKey( hSourcesKey );
  526. // mark this as custom source
  527. if ( pbCustom != NULL && lResult == ERROR_SUCCESS )
  528. *pbCustom = TRUE;
  529. // break from the loop
  530. break;
  531. }
  532. else
  533. {
  534. // this should not be the case .. sources should not be duplicated
  535. FORMAT_STRING( szBuffer, ERROR_SOURCE_DUPLICATING, szRLog );
  536. SetReason( szBuffer );
  537. bDuplicating = TRUE;
  538. }
  539. }
  540. }
  541. else if ( bLogMatched == TRUE && bSource == FALSE )
  542. {
  543. // mark this as a custom event source
  544. if ( pbCustom != NULL )
  545. *pbCustom = TRUE;
  546. // ...
  547. bFoundMatch = TRUE;
  548. break;
  549. }
  550. else if ( bLogMatched == TRUE && bDuplicating == TRUE )
  551. {
  552. bErrorOccurred = TRUE;
  553. break;
  554. }
  555. // update the sources index and fetch the next log key
  556. dwLogsIndex += 1;
  557. dwSize = MAX_KEY_LENGTH; // max. size of the key buffer
  558. ZeroMemory( szRLog, MAX_KEY_LENGTH * sizeof( TCHAR ) );
  559. lResult = RegEnumKeyEx( hLogsKey, dwLogsIndex, szRLog, &dwSize, NULL,
  560. NULL, NULL, &ftLastWriteTime );
  561. } while( lResult != ERROR_NO_MORE_ITEMS );
  562. // close the logs registry key
  563. RegCloseKey( hLogsKey );
  564. hLogsKey = NULL;
  565. // check whether any error has occured or not in doing above tasks
  566. if ( bErrorOccurred )
  567. {
  568. // close the still opened registry keys
  569. RegCloseKey( hKey );
  570. // return failure
  571. return FALSE;
  572. }
  573. // now check whether location for creating the event is found or not
  574. // if not, check for the possibilities to create the source at appropriate location
  575. // NOTE:-
  576. // we won't create the logs. also to create the source, user needs to specify
  577. // the log name in which this source needs to be created.
  578. if ( bFoundMatch == FALSE )
  579. {
  580. if ( bLog == TRUE && bLogMatched == FALSE )
  581. {
  582. // log itself was not found ... error message
  583. FORMAT_STRING( szBuffer, ERROR_LOG_NOTEXISTS, szLog );
  584. SetReason( szBuffer );
  585. }
  586. else if ( bLog && bSource && bLogMatched && bSourceMatched == FALSE )
  587. {
  588. //
  589. // log name and source both were supplied but only log was found
  590. // so create the source in it
  591. // open the "EventLogs\{logname}" registry key for creating new source
  592. FORMAT_STRING2( szBuffer, _T( "%s\\%s" ), EVENT_LOG_NAMES_LOCATION, szLog );
  593. lResult = RegOpenKeyEx( hKey, szBuffer, 0, KEY_WRITE, &hLogsKey );
  594. if ( lResult != ERROR_SUCCESS )
  595. {
  596. switch( lResult )
  597. {
  598. case ERROR_FILE_NOT_FOUND:
  599. SetLastError( ERROR_REGISTRY_CORRUPT );
  600. break;
  601. default:
  602. // save the error information and return FAILURE
  603. SetLastError( lResult );
  604. break;
  605. }
  606. // close the key and return
  607. SaveLastError();
  608. RegCloseKey( hKey );
  609. return FALSE;
  610. }
  611. // now create the subkey with the source name given
  612. if ( AddEventSource( hLogsKey, szSource ) == FALSE )
  613. {
  614. RegCloseKey( hKey );
  615. RegCloseKey( hLogsKey );
  616. return FALSE;
  617. }
  618. // creation of new source is successfull
  619. bFoundMatch = TRUE;
  620. RegCloseKey( hSourcesKey );
  621. RegCloseKey( hLogsKey );
  622. // mark this as a custom event source
  623. if ( pbCustom != NULL )
  624. *pbCustom = TRUE;
  625. }
  626. else if ( bLog == FALSE && bSource == TRUE && bSourceMatched == FALSE )
  627. {
  628. // else we need both log name and source in order to create the source
  629. SetReason( ERROR_NEED_LOG_ALSO );
  630. }
  631. }
  632. // close the currently open registry keys
  633. RegCloseKey( hKey );
  634. // return the result
  635. return bFoundMatch;
  636. }
  637. // ***************************************************************************
  638. // Routine Description:
  639. // This function adds a new source to under the specifie log
  640. //
  641. // Arguments:
  642. //
  643. // Return Value:
  644. // TRUE : on success
  645. // FALSE : on failure
  646. // ***************************************************************************
  647. BOOL AddEventSource( HKEY hLogsKey, LPCTSTR pszSource )
  648. {
  649. // local variables
  650. HKEY hSourcesKey;
  651. LONG lResult = 0;
  652. DWORD dwData = 0;
  653. DWORD dwLength = 0;
  654. DWORD dwDisposition = 0;
  655. LPTSTR pszBuffer = NULL;
  656. // validate the inputs
  657. if ( hLogsKey == NULL || pszSource == NULL )
  658. {
  659. SetLastError( ERROR_INVALID_PARAMETER );
  660. SaveLastError();
  661. return FALSE;
  662. }
  663. // create the custom source
  664. lResult = RegCreateKeyEx( hLogsKey, pszSource, 0, _T( "" ),
  665. REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hSourcesKey, &dwDisposition );
  666. if ( lResult != ERROR_SUCCESS )
  667. {
  668. SetLastError( lResult );
  669. SaveLastError();
  670. return FALSE;
  671. }
  672. // set the name of the message file.
  673. dwLength = lstrlen( _T( "%SystemRoot%\\System32\\EventCreate.exe" ) );
  674. pszBuffer = calloc( dwLength + 1, sizeof( TCHAR ) );
  675. if ( pszBuffer == NULL )
  676. {
  677. // set the error
  678. SetLastError( E_OUTOFMEMORY );
  679. SaveLastError();
  680. // close the created registry key
  681. RegCloseKey( hSourcesKey );
  682. hSourcesKey = NULL;
  683. // return
  684. return FALSE;
  685. }
  686. // copy the required value into buffer
  687. lstrcpy( pszBuffer, _T( "%SystemRoot%\\System32\\EventCreate.exe" ) );
  688. // add the name to the EventMessageFile subkey.
  689. lResult = RegSetValueEx( hSourcesKey,
  690. _T( "EventMessageFile" ), 0, REG_EXPAND_SZ, (LPBYTE) pszBuffer, (dwLength + 1) * sizeof( TCHAR ) );
  691. if ( lResult != ERROR_SUCCESS )
  692. {
  693. // save the error
  694. SetLastError( lResult );
  695. SaveLastError();
  696. // release the memories allocated till this point
  697. RegCloseKey( hSourcesKey );
  698. hSourcesKey = NULL;
  699. // free the allocated memory
  700. if ( pszBuffer != NULL )
  701. {
  702. free( pszBuffer );
  703. pszBuffer = NULL;
  704. }
  705. // return
  706. return FALSE;
  707. }
  708. // set the supported event types in the TypesSupported subkey.
  709. dwData = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE;
  710. lResult = RegSetValueEx( hSourcesKey, _T( "TypesSupported" ), 0, REG_DWORD, (LPBYTE) &dwData, sizeof( DWORD ) );
  711. if ( lResult != ERROR_SUCCESS )
  712. {
  713. // save the error
  714. SetLastError( lResult );
  715. SaveLastError();
  716. // release the memories allocated till this point
  717. RegCloseKey( hSourcesKey );
  718. hSourcesKey = NULL;
  719. // free the allocated memory
  720. if ( pszBuffer != NULL )
  721. {
  722. free( pszBuffer );
  723. pszBuffer = NULL;
  724. }
  725. // return
  726. return FALSE;
  727. }
  728. // mark this source as custom created source
  729. dwData = 1;
  730. lResult = RegSetValueEx( hSourcesKey, _T( "CustomSource" ), 0, REG_DWORD, (LPBYTE) &dwData, sizeof( DWORD ) );
  731. if ( lResult != ERROR_SUCCESS )
  732. {
  733. // save the error
  734. SetLastError( lResult );
  735. SaveLastError();
  736. // release the memories allocated till this point
  737. RegCloseKey( hSourcesKey );
  738. hSourcesKey = NULL;
  739. // free the allocated memory
  740. if ( pszBuffer != NULL )
  741. {
  742. free( pszBuffer );
  743. pszBuffer = NULL;
  744. }
  745. // return
  746. return FALSE;
  747. }
  748. // close the key
  749. RegCloseKey( hSourcesKey );
  750. // free the allocated memory
  751. if ( pszBuffer != NULL )
  752. {
  753. free( pszBuffer );
  754. pszBuffer = NULL;
  755. }
  756. // return success
  757. return TRUE;
  758. }
  759. // ***************************************************************************
  760. // Routine Description:
  761. // This function parses the options specified at the command prompt
  762. //
  763. // Arguments:
  764. // [ in ] argc : count of elements in argv
  765. // [ in ] argv : command-line parameterd specified by the user
  766. // [ out ] pbShowUsage : sets to TRUE if -? exists in 'argv'
  767. // [ out ] parrServers : value(s) specified with -s ( server ) option in 'argv'
  768. // [ out ] pszUserName : value of -u ( username ) option in 'argv'
  769. // [ out ] pszPassword : value of -p ( password ) option in 'argv'
  770. // [ out ] pszLogName : value of -log ( log name ) option in 'argv'
  771. // [ out ] pszLogSource : value of -source ( source name ) option in 'argv'
  772. // [ out ] pszLogType : value of -type ( log type ) option in 'argv'
  773. // [ out ] pdwEventID : value of -id ( event id ) option in 'argv'
  774. // [ out ] pszDescription : value of -description ( description ) option in 'argv'
  775. // [ out ] pbNeedPwd : sets to TRUE if -s exists without -p in 'argv'
  776. //
  777. // Return Value:
  778. // TRUE : the parsing is successful
  779. // FALSE : errors occured in parsing
  780. // ***************************************************************************
  781. BOOL ProcessOptions( LONG argc,
  782. LPCTSTR argv[],
  783. PBOOL pbShowUsage,
  784. PTARRAY parrServers, LPTSTR pszUserName, LPTSTR pszPassword,
  785. LPTSTR pszLogName, LPTSTR pszLogSource, LPTSTR pszLogType,
  786. PDWORD pdwEventID, LPTSTR pszDescription, PBOOL pbNeedPwd )
  787. {
  788. // local variables
  789. LPTSTR pszDup = NULL;
  790. LPCTSTR pszServer = NULL;
  791. PTCMDPARSER pcmdOption = NULL;
  792. TCMDPARSER cmdOptions[ MAX_OPTIONS ];
  793. //
  794. // prepare the command options
  795. ZeroMemory( cmdOptions, sizeof( TCMDPARSER ) * MAX_OPTIONS );
  796. // init the password with "*"
  797. if ( pszPassword != NULL )
  798. {
  799. lstrcpy( pszPassword, _T( "*" ) );
  800. }
  801. // -?
  802. pcmdOption = &cmdOptions[ OI_HELP ];
  803. pcmdOption->dwCount = 1;
  804. pcmdOption->dwActuals = 0;
  805. pcmdOption->dwFlags = CP_USAGE;
  806. pcmdOption->pValue = pbShowUsage;
  807. pcmdOption->pFunction = NULL;
  808. pcmdOption->pFunctionData = NULL;
  809. lstrcpy( pcmdOption->szValues, NULL_STRING );
  810. lstrcpy( pcmdOption->szOption, OPTION_HELP );
  811. // -s
  812. pcmdOption = &cmdOptions[ OI_SERVER ];
  813. pcmdOption->dwCount = 1;
  814. pcmdOption->dwActuals = 0;
  815. pcmdOption->dwFlags =
  816. CP_TYPE_TEXT | CP_VALUE_NODUPLICATES | CP_MODE_ARRAY | CP_VALUE_MANDATORY;
  817. pcmdOption->pValue = parrServers;
  818. pcmdOption->pFunction = NULL;
  819. pcmdOption->pFunctionData = NULL;
  820. lstrcpy( pcmdOption->szValues, NULL_STRING );
  821. lstrcpy( pcmdOption->szOption, OPTION_SERVER );
  822. // -u
  823. pcmdOption = &cmdOptions[ OI_USERNAME ];
  824. pcmdOption->dwCount = 1;
  825. pcmdOption->dwActuals = 0;
  826. pcmdOption->dwFlags = CP_TYPE_TEXT | CP_VALUE_MANDATORY;
  827. pcmdOption->pValue = pszUserName;
  828. pcmdOption->pFunction = NULL;
  829. pcmdOption->pFunctionData = NULL;
  830. lstrcpy( pcmdOption->szValues, NULL_STRING );
  831. lstrcpy( pcmdOption->szOption, OPTION_USERNAME );
  832. // -p
  833. pcmdOption = &cmdOptions[ OI_PASSWORD ];
  834. pcmdOption->dwCount = 1;
  835. pcmdOption->dwActuals = 0;
  836. pcmdOption->dwFlags = CP_TYPE_TEXT | CP_VALUE_OPTIONAL;
  837. pcmdOption->pValue = pszPassword;
  838. pcmdOption->pFunction = NULL;
  839. pcmdOption->pFunctionData = NULL;
  840. lstrcpy( pcmdOption->szValues, NULL_STRING );
  841. lstrcpy( pcmdOption->szOption, OPTION_PASSWORD );
  842. // -log
  843. pcmdOption = &cmdOptions[ OI_LOG ];
  844. pcmdOption->dwCount = 1;
  845. pcmdOption->dwActuals = 0;
  846. pcmdOption->dwFlags = CP_TYPE_TEXT | CP_VALUE_MANDATORY;
  847. pcmdOption->pValue = pszLogName;
  848. pcmdOption->pFunction = NULL;
  849. pcmdOption->pFunctionData = NULL;
  850. lstrcpy( pcmdOption->szValues, NULL_STRING );
  851. lstrcpy( pcmdOption->szOption, OPTION_LOG );
  852. // -type
  853. pcmdOption = &cmdOptions[ OI_TYPE ];
  854. pcmdOption->dwCount = 1;
  855. pcmdOption->dwActuals = 0;
  856. pcmdOption->dwFlags = CP_TYPE_TEXT | CP_VALUE_MANDATORY | CP_MODE_VALUES | CP_MANDATORY;
  857. pcmdOption->pValue = pszLogType;
  858. pcmdOption->pFunction = NULL;
  859. pcmdOption->pFunctionData = NULL;
  860. lstrcpy( pcmdOption->szValues, OVALUES_TYPE );
  861. lstrcpy( pcmdOption->szOption, OPTION_TYPE );
  862. // -source
  863. pcmdOption = &cmdOptions[ OI_SOURCE ];
  864. pcmdOption->dwCount = 1;
  865. pcmdOption->dwActuals = 0;
  866. pcmdOption->dwFlags = CP_TYPE_TEXT | CP_VALUE_MANDATORY;
  867. pcmdOption->pValue = pszLogSource;
  868. pcmdOption->pFunction = NULL;
  869. pcmdOption->pFunctionData = NULL;
  870. lstrcpy( pcmdOption->szValues, NULL_STRING );
  871. lstrcpy( pcmdOption->szOption, OPTION_SOURCE );
  872. // -id
  873. pcmdOption = &cmdOptions[ OI_ID ];
  874. pcmdOption->dwCount = 1;
  875. pcmdOption->dwActuals = 0;
  876. pcmdOption->dwFlags = CP_TYPE_UNUMERIC | CP_VALUE_MANDATORY | CP_MANDATORY;
  877. pcmdOption->pValue = pdwEventID;
  878. pcmdOption->pFunction = NULL;
  879. pcmdOption->pFunctionData = NULL;
  880. lstrcpy( pcmdOption->szValues, NULL_STRING );
  881. lstrcpy( pcmdOption->szOption, OPTION_ID );
  882. // -description
  883. pcmdOption = &cmdOptions[ OI_DESCRIPTION ];
  884. pcmdOption->dwCount = 1;
  885. pcmdOption->dwActuals = 0;
  886. pcmdOption->dwFlags = CP_TYPE_TEXT | CP_VALUE_MANDATORY | CP_MANDATORY;
  887. pcmdOption->pValue = pszDescription;
  888. pcmdOption->pFunction = NULL;
  889. pcmdOption->pFunctionData = NULL;
  890. lstrcpy( pcmdOption->szValues, NULL_STRING );
  891. lstrcpy( pcmdOption->szOption, OPTION_DESCRIPTION );
  892. //
  893. // do the parsing
  894. if ( DoParseParam( argc, argv, MAX_OPTIONS, cmdOptions ) == FALSE )
  895. return FALSE; // invalid syntax
  896. //
  897. // now, check the mutually exclusive options
  898. // check the usage option
  899. if ( *pbShowUsage == TRUE )
  900. {
  901. if ( argc > 2 )
  902. {
  903. // no other options are accepted along with -? option
  904. SetLastError( MK_E_SYNTAX );
  905. SetReason( ERROR_INVALID_USAGE_REQUEST );
  906. return FALSE;
  907. }
  908. else
  909. {
  910. // no need of furthur checking of the values
  911. return TRUE;
  912. }
  913. }
  914. // empty system is not valid
  915. if ( cmdOptions[ OI_SERVER ].dwActuals != 0 )
  916. {
  917. // get the server name
  918. pszServer = DynArrayItemAsString( *parrServers, 0 );
  919. if ( pszServer != NULL )
  920. {
  921. // get the duplicate of this server name
  922. // we need to trim the value and then check
  923. pszDup = _tcsdup( pszServer );
  924. if ( pszDup == NULL )
  925. {
  926. SetLastError( E_OUTOFMEMORY );
  927. SaveLastError();
  928. return FALSE;
  929. }
  930. // trim the string value
  931. TrimString( pszDup, TRIM_ALL );
  932. // check the length now
  933. if ( lstrlen( pszDup ) == 0 )
  934. {
  935. // release the memory and return error
  936. free( pszDup );
  937. pszDup = NULL;
  938. SetLastError( MK_E_SYNTAX );
  939. SetReason( ERROR_SYSTEM_EMPTY );
  940. return FALSE;
  941. }
  942. // release memory
  943. free( pszDup );
  944. pszDup = NULL;
  945. }
  946. }
  947. // "-u" should not be specified without "-s"
  948. if ( cmdOptions[ OI_SERVER ].dwActuals == 0 &&
  949. cmdOptions[ OI_USERNAME ].dwActuals != 0 )
  950. {
  951. // invalid syntax
  952. SetReason( ERROR_USERNAME_BUT_NOMACHINE );
  953. return FALSE; // indicate failure
  954. }
  955. // empty user is not valid
  956. TrimString( pszUserName, TRIM_ALL ); // trim the string
  957. if ( cmdOptions[ OI_USERNAME ].dwActuals != 0 && lstrlen( pszUserName ) == 0 )
  958. {
  959. // invalid syntax
  960. SetReason( ERROR_USERNAME_EMPTY );
  961. return FALSE;
  962. }
  963. // "-p" should not be specified without "-u"
  964. if ( cmdOptions[ OI_USERNAME ].dwActuals == 0 &&
  965. cmdOptions[ OI_PASSWORD ].dwActuals != 0 )
  966. {
  967. // invalid syntax
  968. SetReason( ERROR_PASSWORD_BUT_NOUSERNAME );
  969. return FALSE; // indicate failure
  970. }
  971. // check whether caller should accept the password or not
  972. // if -s ( server ) or -u ( username ) is specified
  973. // but no "-p", then utility should accept password
  974. // provided if establish connection is failed without the credentials information
  975. if ( cmdOptions[ OI_PASSWORD ].dwActuals != 0 &&
  976. pszPassword != NULL && lstrcmp( pszPassword, _T( "*" ) ) == 0 )
  977. {
  978. // user wants the utility to prompt for the password before trying to connect
  979. *pbNeedPwd = TRUE;
  980. }
  981. else if ( cmdOptions[ OI_PASSWORD ].dwActuals == 0 &&
  982. ( cmdOptions[ OI_SERVER ].dwActuals != 0 || cmdOptions[ OI_USERNAME ].dwActuals != 0 ) )
  983. {
  984. // -s, -u is specified without password ...
  985. // utility needs to try to connect first and if it fails then prompt for the password
  986. *pbNeedPwd = TRUE;
  987. if ( pszPassword != NULL )
  988. {
  989. lstrcpy( pszPassword, _T( "" ) );
  990. }
  991. }
  992. // event id should be greater than 0 ( zero ) and less than 65536
  993. if ( *pdwEventID <= 0 || *pdwEventID >= 65536 )
  994. {
  995. // invalid numeric value
  996. SetReason( ERROR_INVALID_EVENT_ID );
  997. return FALSE;
  998. }
  999. // description should not be empty
  1000. TrimString( pszDescription, TRIM_ALL ); // trim the string
  1001. if ( lstrlen( pszDescription ) == 0 )
  1002. {
  1003. // description is null
  1004. SetReason( ERROR_DESCRIPTION_IS_EMPTY );
  1005. return FALSE;
  1006. }
  1007. // either -source (or) -log must be specified ( both can also be specified )
  1008. if ( cmdOptions[ OI_SOURCE ].dwActuals == 0 && cmdOptions[ OI_LOG ].dwActuals == 0 )
  1009. {
  1010. // if log name and application were not specified, we will set to defaults
  1011. lstrcpy( pszLogName, g_szDefaultLog );
  1012. lstrcpy( pszLogSource, g_szDefaultSource );
  1013. }
  1014. // -source option value should not be empty ( if specified )
  1015. TrimString( pszLogSource, TRIM_ALL ); // trim the string
  1016. if ( cmdOptions[ OI_SOURCE ].dwActuals != 0 && lstrlen( pszLogSource ) == 0 )
  1017. {
  1018. // description is null
  1019. SetReason( ERROR_LOGSOURCE_IS_EMPTY );
  1020. return FALSE;
  1021. }
  1022. // -log option value should not be empty ( if specified )
  1023. TrimString( pszLogName, TRIM_ALL ); // trim the string
  1024. if ( cmdOptions[ OI_LOG ].dwActuals != 0 && lstrlen( pszLogName ) == 0 )
  1025. {
  1026. // description is null
  1027. SetReason( ERROR_LOGSOURCE_IS_EMPTY );
  1028. return FALSE;
  1029. }
  1030. // check whether atleast one -s is specified or not ... if not, add 'null string' to
  1031. // the servers array so that default it will work for local system
  1032. if ( cmdOptions[ OI_SERVER ].dwActuals == 0 )
  1033. DynArrayAppendString( *parrServers, NULL_STRING, 0 );
  1034. // command-line parsing is successfull
  1035. return TRUE;
  1036. }
  1037. // ***************************************************************************
  1038. // Routine Description:
  1039. // This function fetches usage information from resource file and shows it
  1040. //
  1041. // Arguments:
  1042. // None
  1043. //
  1044. // Return Value:
  1045. // None
  1046. // ***************************************************************************
  1047. VOID Usage()
  1048. {
  1049. // local variables
  1050. DWORD dw = 0;
  1051. // start displaying the usage
  1052. for( dw = ID_USAGE_START; dw <= ID_USAGE_END; dw++ )
  1053. ShowMessage( stdout, GetResString( dw ) );
  1054. }