Leaked source code of windows server 2003
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.

764 lines
20 KiB

  1. /*++
  2. Copyright (c) 1992-1997 Microsoft Corporation
  3. Module Name:
  4. startup.c
  5. Abstract:
  6. Contains routines for starting SNMP master agent.
  7. Environment:
  8. User Mode - Win32
  9. Revision History:
  10. 10-Feb-1997 DonRyan
  11. Rewrote to implement SNMPv2 support.
  12. --*/
  13. ///////////////////////////////////////////////////////////////////////////////
  14. // //
  15. // Include files //
  16. // //
  17. ///////////////////////////////////////////////////////////////////////////////
  18. #include "globals.h"
  19. #include "startup.h"
  20. #include "network.h"
  21. #include "registry.h"
  22. #include "snmpthrd.h"
  23. #include "regthrd.h"
  24. #include "trapthrd.h"
  25. #include "args.h"
  26. #include "mem.h"
  27. #include "snmpmgmt.h"
  28. ///////////////////////////////////////////////////////////////////////////////
  29. // //
  30. // Global variables //
  31. // //
  32. ///////////////////////////////////////////////////////////////////////////////
  33. HANDLE g_hAgentThread = NULL;
  34. HANDLE g_hRegistryThread = NULL; // Used to track registry changes
  35. CRITICAL_SECTION g_RegCriticalSectionA;
  36. CRITICAL_SECTION g_RegCriticalSectionB;
  37. CRITICAL_SECTION g_RegCriticalSectionC; // protect the generation of trap from
  38. // registry changes
  39. // All CriticalSection inited or not, this flag is only used in this file.
  40. static BOOL g_fCriticalSectionsInited = FALSE;
  41. // privileges that we want to keep
  42. static const LPCWSTR c_arrszPrivilegesToKeep[] = {
  43. L"SeChangeNotifyPrivilege",
  44. L"SeSecurityPrivilege"
  45. };
  46. ///////////////////////////////////////////////////////////////////////////////
  47. // //
  48. // Private procedures //
  49. // //
  50. ///////////////////////////////////////////////////////////////////////////////
  51. BOOL
  52. LoadWinsock(
  53. )
  54. /*++
  55. Routine Description:
  56. Startup winsock.
  57. Arguments:
  58. None.
  59. Return Values:
  60. Returns true if successful.
  61. --*/
  62. {
  63. WSADATA WsaData;
  64. WORD wVersionRequested = MAKEWORD(2,0);
  65. INT nStatus;
  66. // attempt to startup winsock
  67. nStatus = WSAStartup(wVersionRequested, &WsaData);
  68. // validate return code
  69. if (nStatus == SOCKET_ERROR) {
  70. SNMPDBG((
  71. SNMP_LOG_ERROR,
  72. "SNMP: SVC: error %d starting winsock.\n",
  73. WSAGetLastError()
  74. ));
  75. // failure
  76. return FALSE;
  77. }
  78. // success
  79. return TRUE;
  80. }
  81. BOOL
  82. UnloadWinsock(
  83. )
  84. /*++
  85. Routine Description:
  86. Shutdown winsock.
  87. Arguments:
  88. None.
  89. Return Values:
  90. Returns true if successful.
  91. --*/
  92. {
  93. INT nStatus;
  94. // cleanup
  95. nStatus = WSACleanup();
  96. // validate return code
  97. if (nStatus == SOCKET_ERROR) {
  98. SNMPDBG((
  99. SNMP_LOG_ERROR,
  100. "SNMP: SVC: error %d stopping winsock.\n",
  101. WSAGetLastError()
  102. ));
  103. // failure
  104. return FALSE;
  105. }
  106. // success
  107. return TRUE;
  108. }
  109. /*++
  110. Routine Description:
  111. Get all privileges to be removed except the ones specified in
  112. c_arrszPrivilegesToKeep.
  113. Arguments:
  114. hToken [IN] An opened access token
  115. ppPrivs [OUT] An array of privileges to be returned
  116. pdwNumPrivs [OUT] Number of privileges in ppPrivs
  117. Return Values:
  118. Returns ERROR_SUCCESS if successful.
  119. Note: It is caller's responsibility to call AgentMemFree on *ppPrivs if
  120. ERROR_SUCCESS is returned and *ppPrivs is not NULL
  121. --*/
  122. static DWORD GetAllPrivilegesToRemoveExceptNeeded(
  123. HANDLE hToken,
  124. PLUID_AND_ATTRIBUTES* ppPrivs,
  125. PDWORD pdwNumPrivs)
  126. {
  127. DWORD dwRet = ERROR_SUCCESS;
  128. PTOKEN_PRIVILEGES pTokenPrivs = NULL;
  129. PLUID_AND_ATTRIBUTES pPrivsToRemove = NULL;
  130. DWORD dwPrivsToDel = 0;
  131. DWORD dwPrivNameSize = 0;
  132. // init return values
  133. *ppPrivs = NULL;
  134. *pdwNumPrivs = 0;
  135. do
  136. {
  137. LPWSTR pszPrivName = NULL;
  138. DWORD i, dwSize = 0;
  139. GetTokenInformation(hToken,
  140. TokenPrivileges,
  141. NULL,
  142. 0,
  143. &dwSize);
  144. if (0 == dwSize)
  145. {
  146. // process has no privileges to be removed
  147. return dwRet;
  148. }
  149. pTokenPrivs = (PTOKEN_PRIVILEGES) AgentMemAlloc(dwSize);
  150. if (NULL == pTokenPrivs)
  151. {
  152. dwRet = ERROR_OUTOFMEMORY;
  153. break;
  154. }
  155. if (!GetTokenInformation(
  156. hToken,
  157. TokenPrivileges,
  158. pTokenPrivs,
  159. dwSize, &dwSize))
  160. {
  161. dwRet = GetLastError();
  162. break;
  163. }
  164. pPrivsToRemove = (PLUID_AND_ATTRIBUTES) AgentMemAlloc(
  165. sizeof(LUID_AND_ATTRIBUTES) * pTokenPrivs->PrivilegeCount);
  166. if (NULL == pPrivsToRemove)
  167. {
  168. dwRet = ERROR_OUTOFMEMORY;
  169. break;
  170. }
  171. // LookupPrivilegeName need the buffer size in char and NOT including
  172. // the NULL terminator
  173. dwPrivNameSize = MAX_PATH;
  174. pszPrivName = (LPWSTR) AgentMemAlloc((dwPrivNameSize + 1) * sizeof(WCHAR));
  175. if (NULL == pszPrivName)
  176. {
  177. dwRet = ERROR_OUTOFMEMORY;
  178. break;
  179. }
  180. for (i=0; i < pTokenPrivs->PrivilegeCount; i++)
  181. {
  182. BOOL bFound;
  183. DWORD j;
  184. DWORD dwTempSize = dwPrivNameSize;
  185. ZeroMemory(pszPrivName, (dwPrivNameSize + 1) * sizeof(WCHAR));
  186. if (!LookupPrivilegeNameW(NULL,
  187. &pTokenPrivs->Privileges[i].Luid,
  188. pszPrivName,
  189. &dwTempSize))
  190. {
  191. dwRet = GetLastError();
  192. if (ERROR_INSUFFICIENT_BUFFER == dwRet && dwTempSize > dwPrivNameSize)
  193. {
  194. //reallocate a bigger buffer
  195. dwRet = ERROR_SUCCESS;
  196. AgentMemFree(pszPrivName);
  197. pszPrivName = (LPWSTR) AgentMemAlloc((dwTempSize + 1) * sizeof(WCHAR));
  198. if (NULL == pszPrivName)
  199. {
  200. dwRet = ERROR_OUTOFMEMORY;
  201. break;
  202. }
  203. // AgentMemAlloc zero'ed the allocated memory
  204. dwPrivNameSize = dwTempSize;
  205. //try it again
  206. if (!LookupPrivilegeNameW(NULL,
  207. &pTokenPrivs->Privileges[i].Luid,
  208. pszPrivName,
  209. &dwTempSize))
  210. {
  211. dwRet = GetLastError();
  212. break;
  213. }
  214. }
  215. else
  216. {
  217. break;
  218. }
  219. }
  220. bFound = FALSE;
  221. for (j = 0;
  222. j < sizeof(c_arrszPrivilegesToKeep)/sizeof(c_arrszPrivilegesToKeep[0]);
  223. ++j)
  224. {
  225. if (0 == lstrcmpiW(pszPrivName, c_arrszPrivilegesToKeep[j]))
  226. {
  227. bFound = TRUE;
  228. break;
  229. }
  230. }
  231. if (bFound)
  232. continue;
  233. pPrivsToRemove[dwPrivsToDel] = pTokenPrivs->Privileges[i];
  234. dwPrivsToDel++;
  235. }
  236. // free memory if necessary
  237. AgentMemFree(pszPrivName);
  238. } while (FALSE);
  239. // free memory if necessary
  240. AgentMemFree(pTokenPrivs);
  241. if (ERROR_SUCCESS == dwRet)
  242. {
  243. // transfer values
  244. *pdwNumPrivs = dwPrivsToDel;
  245. *ppPrivs = pPrivsToRemove;
  246. }
  247. else if (pPrivsToRemove)
  248. {
  249. AgentMemFree(pPrivsToRemove);
  250. }
  251. return dwRet;
  252. }
  253. /*++
  254. Routine Description:
  255. BuildTokenPrivileges
  256. Arguments:
  257. pPrivs [IN] An array of privileges
  258. dwNumPrivs [IN] Number of privileges in pPrivs
  259. ppTokenPrivs [OUT] Pointer to TOKEN_PRIVILEGES to be returned
  260. pdwTokenPrivsBufferSize [OUT] Buffer size in bytes that *ppTokenPrivs has
  261. Return Values:
  262. Returns ERROR_SUCCESS if successful.
  263. Note: It's caller's responsibility to call AgentMemFree on *ppPrivs if
  264. ERROR_SUCCESS is returned and *ppPrivs is not NULL
  265. --*/
  266. static DWORD BuildTokenPrivileges(
  267. PLUID_AND_ATTRIBUTES pPrivs,
  268. DWORD dwNumPrivs,
  269. DWORD dwAttributes,
  270. PTOKEN_PRIVILEGES* ppTokenPrivs,
  271. PDWORD pdwTokenPrivsBufferSize)
  272. {
  273. PTOKEN_PRIVILEGES pTokenPrivs = NULL;
  274. DWORD i, dwBufferSize;
  275. // design by contract, parameters have to be valid. e.g.
  276. // dwNumPrivs > 0
  277. // *ppTokenPrivs == NULL
  278. // *pdwTokenPrivsBufferSize == 0
  279. // allocate the privilege buffer
  280. dwBufferSize = sizeof(TOKEN_PRIVILEGES) +
  281. ((dwNumPrivs-1) * sizeof(LUID_AND_ATTRIBUTES));
  282. pTokenPrivs = (PTOKEN_PRIVILEGES) AgentMemAlloc(dwBufferSize);
  283. if (NULL == pTokenPrivs)
  284. {
  285. return ERROR_OUTOFMEMORY;
  286. }
  287. // build the desired TOKEN_PRIVILEGES
  288. pTokenPrivs->PrivilegeCount = dwNumPrivs;
  289. for (i = 0; i < dwNumPrivs; ++i)
  290. {
  291. pTokenPrivs->Privileges[i].Luid = pPrivs[i].Luid;
  292. pTokenPrivs->Privileges[i].Attributes = dwAttributes;
  293. }
  294. // transfer values
  295. *ppTokenPrivs = pTokenPrivs;
  296. *pdwTokenPrivsBufferSize = dwBufferSize;
  297. return ERROR_SUCCESS;
  298. }
  299. /*++
  300. Routine Description:
  301. RemoveUnnecessaryTokenPrivileges
  302. Arguments:
  303. Return Values:
  304. Returns TRUE if successful.
  305. --*/
  306. static BOOL RemoveUnnecessaryTokenPrivileges()
  307. {
  308. DWORD dwRet = ERROR_SUCCESS;
  309. HANDLE hProcessToken = NULL;
  310. PLUID_AND_ATTRIBUTES pPrivsToRemove = NULL;
  311. DWORD dwNumPrivs = 0;
  312. PTOKEN_PRIVILEGES pTokenPrivs = NULL;
  313. DWORD dwTokenPrivsBufferSize = 0;
  314. do
  315. {
  316. if (!OpenProcessToken( GetCurrentProcess(),
  317. TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
  318. &hProcessToken ))
  319. {
  320. dwRet = GetLastError();
  321. break;
  322. }
  323. dwRet = GetAllPrivilegesToRemoveExceptNeeded(hProcessToken,
  324. &pPrivsToRemove,
  325. &dwNumPrivs);
  326. if (ERROR_SUCCESS != dwRet )
  327. {
  328. break;
  329. }
  330. // Assert: dwRet == ERROR_SUCCESS
  331. if ( (NULL==pPrivsToRemove) || (0==dwNumPrivs) )
  332. {
  333. SNMPDBG((
  334. SNMP_LOG_VERBOSE,
  335. "SNMP: SVC: No privileges need to be removed.\n"
  336. ));
  337. break;
  338. }
  339. dwRet = BuildTokenPrivileges(pPrivsToRemove,
  340. dwNumPrivs,
  341. SE_PRIVILEGE_REMOVED,
  342. &pTokenPrivs,
  343. &dwTokenPrivsBufferSize);
  344. if (ERROR_SUCCESS != dwRet )
  345. {
  346. break;
  347. }
  348. if (!AdjustTokenPrivileges(hProcessToken,
  349. FALSE,
  350. pTokenPrivs,
  351. dwTokenPrivsBufferSize,
  352. NULL,
  353. NULL))
  354. {
  355. dwRet = GetLastError();
  356. break;
  357. }
  358. } while(FALSE);
  359. // free resources if necessary
  360. if (hProcessToken)
  361. CloseHandle(hProcessToken);
  362. AgentMemFree(pPrivsToRemove);
  363. AgentMemFree(pTokenPrivs);
  364. if (dwRet != ERROR_SUCCESS)
  365. {
  366. SNMPDBG((
  367. SNMP_LOG_ERROR,
  368. "SNMP: SVC: RemoveUnnecessaryTokenPrivileges failed 0x%x\n",
  369. dwRet));
  370. return FALSE;
  371. }
  372. else
  373. return TRUE;
  374. }
  375. ///////////////////////////////////////////////////////////////////////////////
  376. // //
  377. // Public procedures //
  378. // //
  379. ///////////////////////////////////////////////////////////////////////////////
  380. BOOL
  381. StartupAgent(
  382. )
  383. /*++
  384. Routine Description:
  385. Performs essential initialization of master agent.
  386. Arguments:
  387. None.
  388. Return Values:
  389. Returns true if successful.
  390. --*/
  391. {
  392. BOOL fOk = TRUE;
  393. DWORD dwThreadId = 0;
  394. DWORD regThreadId = 0;
  395. INT nCSOk = 0; // counts the number of CS that were successfully initialized
  396. // initialize management variables
  397. mgmtInit();
  398. // initialize list heads
  399. InitializeListHead(&g_Subagents);
  400. InitializeListHead(&g_SupportedRegions);
  401. InitializeListHead(&g_ValidCommunities);
  402. InitializeListHead(&g_TrapDestinations);
  403. InitializeListHead(&g_PermittedManagers);
  404. InitializeListHead(&g_IncomingTransports);
  405. InitializeListHead(&g_OutgoingTransports);
  406. __try
  407. {
  408. InitializeCriticalSection(&g_RegCriticalSectionA); nCSOk++;
  409. InitializeCriticalSection(&g_RegCriticalSectionB); nCSOk++;
  410. InitializeCriticalSection(&g_RegCriticalSectionC); nCSOk++;
  411. }
  412. __except(EXCEPTION_EXECUTE_HANDLER)
  413. {
  414. if (nCSOk == 1)
  415. DeleteCriticalSection(&g_RegCriticalSectionA);
  416. if (nCSOk == 2)
  417. {
  418. DeleteCriticalSection(&g_RegCriticalSectionA);
  419. DeleteCriticalSection(&g_RegCriticalSectionB);
  420. }
  421. // nCSOk can't be 3 as far as we are here
  422. fOk = FALSE;
  423. }
  424. SNMPDBG((
  425. SNMP_LOG_TRACE,
  426. "SNMP: SVC: Initialize critical sections...%s\n", fOk? "Ok" : "Failed"));
  427. if (fOk)
  428. {
  429. g_fCriticalSectionsInited = TRUE;
  430. }
  431. fOk = fOk &&
  432. (g_hRegistryEvent = CreateEvent(NULL, FALSE, TRUE, NULL)) != NULL;
  433. g_dwUpTimeReference = SnmpSvcInitUptime();
  434. // retreive system uptime reference
  435. SNMPDBG((
  436. SNMP_LOG_TRACE,
  437. "SNMP: SVC: Getting system uptime...%d\n", g_dwUpTimeReference));
  438. // allocate essentials
  439. fOk = fOk && AgentHeapCreate();
  440. SNMPDBG((
  441. SNMP_LOG_TRACE,
  442. "SNMP: SVC: Creating agent heap...%s\n", fOk? "Ok" : "Failed"));
  443. if (fOk)
  444. {
  445. // Remove unnecessary privileges from the service
  446. RemoveUnnecessaryTokenPrivileges();
  447. // any error is ignored
  448. }
  449. fOk = fOk && LoadWinsock();
  450. SNMPDBG((
  451. SNMP_LOG_TRACE,
  452. "SNMP: SVC: Loading Winsock stack...%s\n", fOk? "Ok" : "Failed"));
  453. fOk = fOk && LoadIncomingTransports();
  454. SNMPDBG((
  455. SNMP_LOG_TRACE,
  456. "SNMP: SVC: Loading Incoming transports...%s\n", fOk? "Ok" : "Failed"));
  457. fOk = fOk && LoadOutgoingTransports();
  458. SNMPDBG((
  459. SNMP_LOG_TRACE,
  460. "SNMP: SVC: Loading Outgoing transports...%s\n", fOk? "Ok" : "Failed"));
  461. fOk = fOk &&
  462. // attempt to start main thread
  463. (g_hAgentThread = CreateThread(
  464. NULL, // lpThreadAttributes
  465. 0, // dwStackSize
  466. ProcessSnmpMessages,
  467. NULL, // lpParameter
  468. CREATE_SUSPENDED, // dwCreationFlags
  469. &dwThreadId
  470. )) != NULL;
  471. SNMPDBG((
  472. SNMP_LOG_TRACE,
  473. "SNMP: SVC: Starting ProcessSnmpMessages thread...%s\n", fOk? "Ok" : "Failed"));
  474. fOk = fOk &&
  475. // attempt to start registry listener thread
  476. (g_hRegistryThread = CreateThread(
  477. NULL,
  478. 0,
  479. ProcessRegistryMessage,
  480. NULL,
  481. CREATE_SUSPENDED,
  482. &regThreadId)) != NULL;
  483. SNMPDBG((
  484. SNMP_LOG_TRACE,
  485. "SNMP: SVC: Starting ProcessRegistryMessages thread...%s\n", fOk? "Ok" : "Failed"));
  486. return fOk;
  487. }
  488. BOOL
  489. ShutdownAgent(
  490. )
  491. /*++
  492. Routine Description:
  493. Performs final cleanup of master agent.
  494. Arguments:
  495. None.
  496. Return Values:
  497. Returns true if successful.
  498. --*/
  499. {
  500. BOOL fOk;
  501. DWORD dwStatus;
  502. // make sure shutdown signalled
  503. fOk = SetEvent(g_hTerminationEvent);
  504. if (!fOk) {
  505. SNMPDBG((
  506. SNMP_LOG_ERROR,
  507. "SNMP: SVC: error %d signalling termination.\n",
  508. GetLastError()
  509. ));
  510. }
  511. // check if thread created
  512. if ((g_hAgentThread != NULL) && (g_hRegistryThread != NULL)) {
  513. HANDLE hEvntArray[2];
  514. hEvntArray[0] = g_hAgentThread;
  515. hEvntArray[1] = g_hRegistryThread;
  516. dwStatus = WaitForMultipleObjects(2, hEvntArray, TRUE, SHUTDOWN_WAIT_HINT);
  517. // validate return status
  518. if ((dwStatus != WAIT_OBJECT_0) &&
  519. (dwStatus != WAIT_OBJECT_0 + 1) &&
  520. (dwStatus != WAIT_TIMEOUT)) {
  521. SNMPDBG((
  522. SNMP_LOG_ERROR,
  523. "SNMP: SVC: error %d waiting for thread(s) termination.\n",
  524. GetLastError()
  525. ));
  526. }
  527. } else if (g_hAgentThread != NULL) {
  528. // wait for pdu processing thread to terminate
  529. dwStatus = WaitForSingleObject(g_hAgentThread, SHUTDOWN_WAIT_HINT);
  530. // validate return status
  531. if ((dwStatus != WAIT_OBJECT_0) &&
  532. (dwStatus != WAIT_TIMEOUT)) {
  533. SNMPDBG((
  534. SNMP_LOG_ERROR,
  535. "SNMP: SVC: error %d waiting for main thread termination.\n",
  536. GetLastError()
  537. ));
  538. }
  539. } else if (g_hRegistryThread != NULL) {
  540. // wait for registry processing thread to terminate
  541. dwStatus = WaitForSingleObject(g_hRegistryThread, SHUTDOWN_WAIT_HINT);
  542. // validate return status
  543. if ((dwStatus != WAIT_OBJECT_0) &&
  544. (dwStatus != WAIT_TIMEOUT)) {
  545. SNMPDBG((
  546. SNMP_LOG_ERROR,
  547. "SNMP: SVC: error %d waiting for registry thread termination.\n",
  548. GetLastError()
  549. ));
  550. }
  551. }
  552. if (g_fCriticalSectionsInited)
  553. {
  554. // in case registry processing thread hasn't terminated yet, we need
  555. // to make sure critical section are safe for deletion and
  556. // common resources in UnloadRegistryParameters() are still protected.
  557. EnterCriticalSection(&g_RegCriticalSectionA);
  558. EnterCriticalSection(&g_RegCriticalSectionB);
  559. EnterCriticalSection(&g_RegCriticalSectionC);
  560. }
  561. // unload incoming transports
  562. UnloadIncomingTransports();
  563. // unload outgoing transports
  564. UnloadOutgoingTransports();
  565. // unload registry info
  566. UnloadRegistryParameters();
  567. // unload the winsock stack
  568. UnloadWinsock();
  569. // cleanup the internal management buffers
  570. mgmtCleanup();
  571. // nuke private heap
  572. AgentHeapDestroy();
  573. if (g_fCriticalSectionsInited)
  574. {
  575. LeaveCriticalSection(&g_RegCriticalSectionC);
  576. LeaveCriticalSection(&g_RegCriticalSectionB);
  577. LeaveCriticalSection(&g_RegCriticalSectionA);
  578. // clean up critical section resources
  579. DeleteCriticalSection(&g_RegCriticalSectionA);
  580. DeleteCriticalSection(&g_RegCriticalSectionB);
  581. DeleteCriticalSection(&g_RegCriticalSectionC);
  582. }
  583. ReportSnmpEvent(
  584. SNMP_EVENT_SERVICE_STOPPED,
  585. 0,
  586. NULL,
  587. 0);
  588. return TRUE;
  589. }