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.

887 lines
22 KiB

  1. /*++
  2. Copyright (c) 1992-1997 Microsoft Corporation
  3. Module Name:
  4. snmpmgrs.c
  5. Abstract:
  6. Contains routines for manipulating manager structures.
  7. Environment:
  8. User Mode - Win32
  9. Revision History:
  10. 10-Feb-1997 DonRyan
  11. Rewrote to implement SNMPv2 support.
  12. --*/
  13. ///////////////////////////////////////////////////////////////////////////////
  14. // //
  15. // Header files //
  16. // //
  17. ///////////////////////////////////////////////////////////////////////////////
  18. #include "globals.h"
  19. #include "snmpmgrs.h"
  20. #include "network.h"
  21. ///////////////////////////////////////////////////////////////////////////////
  22. // //
  23. // Public procedures //
  24. // //
  25. ///////////////////////////////////////////////////////////////////////////////
  26. BOOL
  27. AllocMLE(
  28. PMANAGER_LIST_ENTRY * ppMLE,
  29. LPSTR pManager
  30. )
  31. /*++
  32. Routine Description:
  33. Allocates manager structure and initializes.
  34. Arguments:
  35. pManager - pointer to manager string.
  36. ppMLE - pointer to receive pointer to entry.
  37. Return Values:
  38. Returns true if successful.
  39. --*/
  40. {
  41. BOOL fOk = FALSE;
  42. PMANAGER_LIST_ENTRY pMLE = NULL;
  43. DWORD dwIpAddr;
  44. LPSTR pszManager;
  45. // attempt to allocate structure
  46. pMLE = AgentMemAlloc(sizeof(MANAGER_LIST_ENTRY));
  47. // validate
  48. if (pMLE != NULL) {
  49. // allocate memory for manager string
  50. pMLE->pManager = AgentMemAlloc(strlen(pManager)+1);
  51. // validate
  52. if (pMLE->pManager != NULL) {
  53. // transfer manager string
  54. strcpy(pMLE->pManager, pManager);
  55. // Attempt to resolve manager network address
  56. // For IPX addresses, this call always succeeds
  57. // When SnmpSvcAddrToSocket fails, this means we deal with a dynamic IP Address
  58. // for which the gethostbyname() failed.
  59. if (SnmpSvcAddrToSocket(pMLE->pManager, &pMLE->SockAddr)) {
  60. // see if tcpip address
  61. if (pMLE->SockAddr.sa_family == AF_INET) {
  62. // save structure size for later use
  63. pMLE->SockAddrLen = sizeof(struct sockaddr_in);
  64. pszManager = pMLE->pManager;
  65. // attempt to convert address directly
  66. dwIpAddr = inet_addr(pMLE->pManager);
  67. // assume address is dynamic if error occurs
  68. pMLE->fDynamicName = (dwIpAddr == SOCKET_ERROR);
  69. // note time manager addr updated
  70. pMLE->dwLastUpdate = GetCurrentTime();
  71. // success
  72. fOk = TRUE;
  73. } else if (pMLE->SockAddr.sa_family == AF_IPX) {
  74. // save structure size for later use
  75. pMLE->SockAddrLen = sizeof(struct sockaddr_ipx);
  76. // no name lookup for ipx
  77. pMLE->fDynamicName = FALSE;
  78. // success
  79. fOk = TRUE;
  80. }
  81. pMLE->dwAge = MGRADDR_ALIVE;
  82. } else {
  83. LPTSTR tcsManager;
  84. #ifdef UNICODE
  85. SnmpUtilUTF8ToUnicode(&tcsManager, pMLE->pManager, TRUE);
  86. #else
  87. tcsManager=pMLE->pManager;
  88. #endif
  89. // at this point the address can be only an IP address!
  90. // so we know pMLE->SockAddrLen as the size of the struct sockaddr_in!
  91. pMLE->SockAddrLen = sizeof(struct sockaddr_in);
  92. // since SnmpSvcAddrToSocket failed, that means inet_addr() failed hence
  93. // we deal with a dynamic IP address
  94. pMLE->fDynamicName = TRUE;
  95. // set 'age' to dying
  96. pMLE->dwAge = snmpMgmtBase.AsnIntegerPool[IsnmpNameResolutionRetries].asnValue.number;
  97. // if the registry parameter is -1 this stands for 'keep retrying forever'
  98. // in this case set the dwAge to the default MGRADDR_DYING(16) and never decrement it
  99. if (pMLE->dwAge == (DWORD)-1)
  100. pMLE->dwAge = MGRADDR_DYING;
  101. // report a warning to the system log
  102. ReportSnmpEvent(
  103. SNMP_EVENT_NAME_RESOLUTION_FAILURE,
  104. 1,
  105. &tcsManager,
  106. 0);
  107. #ifdef UNICODE
  108. SnmpUtilMemFree(tcsManager);
  109. #endif
  110. // success
  111. fOk = TRUE;
  112. }
  113. }
  114. // cleanup
  115. if (!fOk) {
  116. // release
  117. FreeMLE(pMLE);
  118. // re-init
  119. pMLE = NULL;
  120. }
  121. }
  122. // transfer
  123. *ppMLE = pMLE;
  124. return fOk;
  125. }
  126. BOOL
  127. FreeMLE(
  128. PMANAGER_LIST_ENTRY pMLE
  129. )
  130. /*++
  131. Routine Description:
  132. Releases manager structure.
  133. Arguments:
  134. pMLE - pointer to manager list entry to be freed.
  135. Return Values:
  136. Returns true if successful.
  137. --*/
  138. {
  139. BOOL fOk = TRUE;
  140. // validate pointer
  141. if (pMLE != NULL) {
  142. // release string
  143. AgentMemFree(pMLE->pManager);
  144. // release structure
  145. AgentMemFree(pMLE);
  146. }
  147. return TRUE;
  148. }
  149. BOOL
  150. UpdateMLE(
  151. PMANAGER_LIST_ENTRY pMLE
  152. )
  153. /*++
  154. Routine Description:
  155. Updates manager structure.
  156. An address will be resolved only if it is not marked as being 'DEAD'. A 'DEAD' address failed to be resolved for
  157. more than MGRADDR_DYING times. A 'DEAD' address will no longer be used as a trap destination, but it will still
  158. be validating the incoming SNMP requests if it could be resolve at least once since the service started up.
  159. Arguments:
  160. pMLE - pointer to manager list entry to be updated.
  161. Return Values:
  162. Returns true if successful.
  163. --*/
  164. {
  165. BOOL fOk = TRUE;
  166. DWORD dwElaspedTime;
  167. struct sockaddr SockAddr;
  168. SNMPDBG((SNMP_LOG_TRACE,
  169. "SNMP: SVC: Update manager '%s' with age %d.\n",
  170. pMLE->pManager,
  171. pMLE->dwAge));
  172. // don't try to resolve this address if it is already dead
  173. if (pMLE->dwAge == MGRADDR_DEAD)
  174. return FALSE;
  175. // see if name dynamic
  176. if (pMLE->fDynamicName) {
  177. // determine elasped time since last update
  178. dwElaspedTime = GetCurrentTime() - pMLE->dwLastUpdate;
  179. // resolve the address only if it failed to be resolved on last update
  180. // or its update time expired.
  181. if (pMLE->dwAge != MGRADDR_ALIVE || dwElaspedTime > DEFAULT_NAME_TIMEOUT) {
  182. // attempt to resolve manager network address
  183. // for IPX addresses, this call always succeeds
  184. fOk = SnmpSvcAddrToSocket(pMLE->pManager, &SockAddr);
  185. // validate
  186. if (fOk) {
  187. // update entry with new address
  188. memcpy(&pMLE->SockAddr, &SockAddr, sizeof(SockAddr));
  189. // note time dynamic name resolved
  190. pMLE->dwLastUpdate = GetCurrentTime();
  191. // make sure manager age is 'ALIVE'
  192. pMLE->dwAge = MGRADDR_ALIVE;
  193. } else if (pMLE->dwAge == MGRADDR_ALIVE) {
  194. // Previously 'ALIVE' address cannot be resolved anymore
  195. // set its age to the one specified by 'NameResolutionRetries' parameter in
  196. // order to give some more chances.
  197. pMLE->dwAge = snmpMgmtBase.AsnIntegerPool[IsnmpNameResolutionRetries].asnValue.number;
  198. // if the registry parameter is -1 this stands for 'keep retrying forever'
  199. // in this case set the dwAge to the default MGRADDR_DYING(16) which will never be decremented
  200. if (pMLE->dwAge == (DWORD)-1)
  201. pMLE->dwAge = MGRADDR_DYING;
  202. } else if (pMLE->dwAge != MGRADDR_DEAD) {
  203. // the address could not be resolved before and it still cannot be resolved
  204. // decrement its retry counter only if the 'NameResolutionRetries' parameter says so
  205. if (snmpMgmtBase.AsnIntegerPool[IsnmpNameResolutionRetries].asnValue.number != -1)
  206. pMLE->dwAge--;
  207. }
  208. }
  209. }
  210. return fOk;
  211. }
  212. BOOL
  213. FindManagerByName(
  214. PMANAGER_LIST_ENTRY * ppMLE,
  215. PLIST_ENTRY pListHead,
  216. LPSTR pManager
  217. )
  218. /*++
  219. Routine Description:
  220. Locates manager in list.
  221. Arguments:
  222. ppMLE - pointer to receive pointer to entry.
  223. pListHead - pointer to head of manager list.
  224. pManager - pointer to manager to find.
  225. Return Values:
  226. Returns true if successful.
  227. --*/
  228. {
  229. PLIST_ENTRY pLE;
  230. PMANAGER_LIST_ENTRY pMLE;
  231. // initialize
  232. *ppMLE = NULL;
  233. // obtain pointer to list head
  234. pLE = pListHead->Flink;
  235. // process all entries in list
  236. while (pLE != pListHead) {
  237. // retrieve pointer to community structure
  238. pMLE = CONTAINING_RECORD(pLE, MANAGER_LIST_ENTRY, Link);
  239. // compare community string with entry
  240. if (!strcmp(pMLE->pManager, pManager)) {
  241. // transfer
  242. *ppMLE = pMLE;
  243. // success
  244. return TRUE;
  245. }
  246. // next entry
  247. pLE = pLE->Flink;
  248. }
  249. // failure
  250. return FALSE;
  251. }
  252. BOOL
  253. IsManagerAddrLegal(
  254. struct sockaddr_in * pAddr
  255. )
  256. {
  257. DWORD dwHostMask;
  258. DWORD dwAddress = ntohl(pAddr->sin_addr.S_un.S_addr);
  259. // check address legality only for Ip addresses
  260. if (pAddr->sin_family != AF_INET)
  261. return TRUE;
  262. // disallow multicast (or future use) source addresses
  263. // local broadcast will be filtered out here as well
  264. if ((dwAddress & 0xe0000000) == 0xe0000000)
  265. return FALSE;
  266. // get hostmask for class 'C' addresses
  267. if ((dwAddress & 0xc0000000) == 0xc0000000)
  268. dwHostMask = 0x000000ff;
  269. // get hostmask for class 'B' addresses
  270. else if ((dwAddress & 0x80000000) == 0x80000000)
  271. dwHostMask = 0x0000ffff;
  272. // get hostidmask for class 'A' addresses
  273. else
  274. dwHostMask = 0x00ffffff;
  275. SNMPDBG((SNMP_LOG_TRACE,"SNMP: dwAddress=%08x, dwHostMask=%08x, port=%d\n",
  276. dwAddress, dwHostMask, ntohs(pAddr->sin_port)));
  277. return ((dwAddress & dwHostMask) != 0 // check against net address
  278. && ((dwAddress & dwHostMask) != (0x00ffffff & dwHostMask)) // check against broadcast address
  279. // && ntohs(pAddr->sin_port) >= 1024 // check against reserved port
  280. );
  281. }
  282. BOOL
  283. FindManagerByAddr(
  284. PMANAGER_LIST_ENTRY * ppMLE,
  285. struct sockaddr * pSockAddr
  286. )
  287. /*++
  288. Routine Description:
  289. Locates permitted manager in list.
  290. Arguments:
  291. ppMLE - pointer to receive pointer to entry.
  292. pSockAddr - pointer to socket address to find.
  293. Return Values:
  294. Returns true if successful.
  295. --*/
  296. {
  297. PLIST_ENTRY pLE;
  298. PMANAGER_LIST_ENTRY pMLE;
  299. DWORD dwSockAddrLen;
  300. enum
  301. {
  302. SRCH_ALIVE,
  303. SRCH_DYING,
  304. SRCH_DONE
  305. } state;
  306. // initialize
  307. *ppMLE = NULL;
  308. // loop twice through the list of permitted managers
  309. // in the first loop look only through 'ALIVE' managers
  310. // in the second loop look through the 'DYING' or 'DEAD' managers.
  311. // ... this logic minimizes the response time for regular SNMP requests,
  312. // as far as there is a bigger chance to have the request comming from an 'ALIVE' manager.
  313. // otherwise, gethostbyname() called in UpdateMLE() lasts about 1/2 sec!!!
  314. for (state = SRCH_ALIVE, pLE = g_PermittedManagers.Flink;
  315. state != SRCH_DONE;
  316. pLE=pLE->Flink)
  317. {
  318. // retrieve pointer to manager structure
  319. pMLE = CONTAINING_RECORD(pLE, MANAGER_LIST_ENTRY, Link);
  320. // if we are in the first loop ..
  321. if (state == SRCH_ALIVE)
  322. {
  323. // .. but reached its end ..
  324. if (pLE == &g_PermittedManagers)
  325. {
  326. // .. go further with the second loop
  327. state = SRCH_DYING;
  328. continue;
  329. }
  330. // .. pass over the managers that are not 'ALIVE'
  331. if (pMLE->dwAge != MGRADDR_ALIVE)
  332. continue;
  333. }
  334. // if we are in the second loop ..
  335. if (state == SRCH_DYING)
  336. {
  337. // .. but reached its end ..
  338. if (pLE == &g_PermittedManagers)
  339. {
  340. // .. mark the end of scanning
  341. state = SRCH_DONE;
  342. continue;
  343. }
  344. // .. pass over the managers that are 'ALIVE'
  345. if (pMLE->dwAge == MGRADDR_ALIVE || pMLE->dwAge == MGRADDR_DEAD)
  346. continue;
  347. }
  348. // update name:
  349. // 'DEAD' addresses will no longer be resolved,
  350. // 'DYING' addresses will be given another chance to resolve until they become 'DEAD'
  351. // 'ALIVE' addresses that fail to resolve will become 'DYING'
  352. // next, all managers with a valid address will participate to validation (see below)
  353. UpdateMLE(pMLE);
  354. // compare address families
  355. if (IsValidSockAddr(&pMLE->SockAddr) &&
  356. pMLE->SockAddr.sa_family == pSockAddr->sa_family)
  357. {
  358. // determine address family
  359. if (pMLE->SockAddr.sa_family == AF_INET)
  360. {
  361. struct sockaddr_in * pSockAddrIn1;
  362. struct sockaddr_in * pSockAddrIn2;
  363. // obtain pointer to protocol specific structure
  364. pSockAddrIn1= (struct sockaddr_in *)pSockAddr;
  365. pSockAddrIn2= (struct sockaddr_in *)&pMLE->SockAddr;
  366. // acknowledge this manager only if its address matches
  367. // a permitted manager with a valid (not NULL) IP address.
  368. // This is tested regardless the 'dwAge' of the permitted manager.
  369. if (!memcmp(&pSockAddrIn1->sin_addr,
  370. &pSockAddrIn2->sin_addr,
  371. sizeof(pSockAddrIn2->sin_addr)))
  372. {
  373. // transfer
  374. *ppMLE = pMLE;
  375. // success
  376. return TRUE;
  377. }
  378. }
  379. else if (pMLE->SockAddr.sa_family == AF_IPX)
  380. {
  381. struct sockaddr_ipx * pSockAddrIpx1;
  382. struct sockaddr_ipx * pSockAddrIpx2;
  383. // obtain pointer to protocol specific structure
  384. pSockAddrIpx1= (struct sockaddr_ipx *)pSockAddr;
  385. pSockAddrIpx2= (struct sockaddr_ipx *)&pMLE->SockAddr;
  386. // acknowledge this manager only if its ipx address matches a
  387. // permitted manager with a valid (nodenum != 0) IPX address.
  388. // This is tested regardless the 'dwAge' of the permitted manager.
  389. if (!memcmp(pSockAddrIpx1->sa_netnum,
  390. pSockAddrIpx2->sa_netnum,
  391. sizeof(pSockAddrIpx2->sa_netnum)) &&
  392. !memcmp(pSockAddrIpx1->sa_nodenum,
  393. pSockAddrIpx2->sa_nodenum,
  394. sizeof(pSockAddrIpx2->sa_nodenum)))
  395. {
  396. // transfer
  397. *ppMLE = pMLE;
  398. // success
  399. return TRUE;
  400. }
  401. }
  402. }
  403. }
  404. // failure
  405. return FALSE;
  406. }
  407. BOOL
  408. AddManager(
  409. PLIST_ENTRY pListHead,
  410. LPSTR pManager
  411. )
  412. /*++
  413. Routine Description:
  414. Adds manager structure to list.
  415. Arguments:
  416. pListHead - pointer to head of list.
  417. pManager - pointer to manager to add.
  418. Return Values:
  419. Returns true if successful.
  420. --*/
  421. {
  422. BOOL fOk = FALSE;
  423. PMANAGER_LIST_ENTRY pMLE = NULL;
  424. // attempt to locate in list
  425. if (FindManagerByName(&pMLE, pListHead, pManager)) {
  426. SNMPDBG((
  427. SNMP_LOG_TRACE,
  428. "SNMP: SVC: updating manager %s.\n",
  429. pManager
  430. ));
  431. // success
  432. fOk = TRUE;
  433. } else {
  434. // allocate manager structure
  435. if (AllocMLE(&pMLE, pManager)) {
  436. SNMPDBG((
  437. SNMP_LOG_TRACE,
  438. "SNMP: SVC: adding manager %s.\n",
  439. pManager
  440. ));
  441. // insert into managers list
  442. InsertTailList(pListHead, &pMLE->Link);
  443. // success
  444. fOk = TRUE;
  445. }
  446. }
  447. return fOk;
  448. }
  449. BOOL
  450. LoadManagers(
  451. HKEY hKey,
  452. PLIST_ENTRY pListHead
  453. )
  454. /*++
  455. Routine Description:
  456. Constructs list of permitted managers.
  457. Arguments:
  458. hKey - registry key containing manager values.
  459. pListHead - pointer to head of list.
  460. Return Values:
  461. Returns true if successful.
  462. --*/
  463. {
  464. LONG lStatus;
  465. DWORD dwIndex;
  466. DWORD dwNameSize;
  467. DWORD dwValueSize;
  468. DWORD dwValueType;
  469. CHAR szName[MAX_PATH];
  470. CHAR szValue[MAX_PATH]; // buffer for holding the translation UNICODE->UTF8
  471. BOOL fOk = FALSE;
  472. // initialize
  473. dwIndex = 0;
  474. lStatus = ERROR_SUCCESS;
  475. // loop until error or end of list
  476. while (lStatus == ERROR_SUCCESS)
  477. {
  478. // initialize buffer sizes
  479. dwNameSize = sizeof(szName)/sizeof(szName[0]); // size in TCHARs
  480. dwValueSize = sizeof(szValue); // size in bytes
  481. szValue[0] = '\0';
  482. // read next value
  483. lStatus = RegEnumValueA(
  484. hKey,
  485. dwIndex,
  486. szName,
  487. &dwNameSize,
  488. NULL,
  489. &dwValueType,
  490. szValue,
  491. &dwValueSize
  492. );
  493. // validate return code
  494. if (lStatus == ERROR_SUCCESS)
  495. {
  496. szValue[dwValueSize]='\0';
  497. if (AddManager(pListHead, szValue)) // add valid manager to manager list
  498. dwIndex++; //next
  499. else
  500. lStatus = ERROR_NOT_ENOUGH_MEMORY; // reset status to reflect failure
  501. }
  502. else if (lStatus == ERROR_NO_MORE_ITEMS)
  503. fOk = TRUE; // success
  504. }
  505. return fOk;
  506. }
  507. BOOL
  508. UnloadManagers(
  509. PLIST_ENTRY pListHead
  510. )
  511. /*++
  512. Routine Description:
  513. Destroys list of permitted managers.
  514. Arguments:
  515. pListHead - pointer to head of list.
  516. Return Values:
  517. Returns true if successful.
  518. --*/
  519. {
  520. PLIST_ENTRY pLE;
  521. PMANAGER_LIST_ENTRY pMLE;
  522. // process entries until empty
  523. while (!IsListEmpty(pListHead)) {
  524. // extract next entry
  525. pLE = RemoveHeadList(pListHead);
  526. // retrieve pointer to manager structure
  527. pMLE = CONTAINING_RECORD(pLE, MANAGER_LIST_ENTRY, Link);
  528. // release
  529. FreeMLE(pMLE);
  530. }
  531. return TRUE;
  532. }
  533. BOOL
  534. LoadPermittedManagers(
  535. BOOL bFirstCall
  536. )
  537. /*++
  538. Routine Description:
  539. Constructs list of permitted managers.
  540. Arguments:
  541. None.
  542. Return Values:
  543. Returns true if successful.
  544. --*/
  545. {
  546. HKEY hKey;
  547. LONG lStatus;
  548. BOOL fPolicy;
  549. LPTSTR pszKey;
  550. BOOL fOk = FALSE;
  551. SNMPDBG((
  552. SNMP_LOG_TRACE,
  553. "SNMP: SVC: loading permitted managers.\n"
  554. ));
  555. #ifdef _POLICY
  556. // we need to provide precedence to the parameters set through the policy
  557. fPolicy = TRUE;
  558. #else
  559. fPolicy = FALSE;
  560. #endif
  561. do
  562. {
  563. // if the policy is to be enforced, check the policy registry location first
  564. pszKey = fPolicy ? REG_POLICY_PERMITTED_MANAGERS : REG_KEY_PERMITTED_MANAGERS;
  565. // open registry subkey
  566. lStatus = RegOpenKeyEx(
  567. HKEY_LOCAL_MACHINE,
  568. pszKey,
  569. 0,
  570. KEY_READ,
  571. &hKey
  572. );
  573. // if the call succeeded or we were not checking the policy, break the loop
  574. if (lStatus == ERROR_SUCCESS || !fPolicy)
  575. break;
  576. // being at this point, this means we were checking for the policy parameters.
  577. // If and only if the policy is not defined (registry key is missing) we
  578. // reset the error, mark 'fPolicy already tried' and go back into the loop
  579. if (lStatus == ERROR_FILE_NOT_FOUND)
  580. {
  581. lStatus = ERROR_SUCCESS;
  582. fPolicy = FALSE;
  583. }
  584. } while (lStatus == ERROR_SUCCESS);
  585. // validate return code
  586. if (lStatus == ERROR_SUCCESS) {
  587. // call routine to load managers into global list
  588. LoadManagers(hKey, &g_PermittedManagers);
  589. // close key
  590. RegCloseKey(hKey);
  591. // at this point consider success (errors localized at particular managers were logged already)
  592. fOk = TRUE;
  593. }
  594. else
  595. // it doesn't matter how the values are, the key has to exist,
  596. // so mark as bFirstCall in order to log an event if this is not true.
  597. bFirstCall = TRUE;
  598. if (!fOk) {
  599. SNMPDBG((
  600. SNMP_LOG_ERROR,
  601. "SNMP: SVC: error %d processing PermittedManagers subkey.\n",
  602. lStatus
  603. ));
  604. // report an error only if on first call (service initialization)
  605. // otherwise, due to registry operations through regedit, the event log
  606. // might be flooded with records
  607. if (bFirstCall)
  608. // report event
  609. ReportSnmpEvent(
  610. SNMP_EVENT_INVALID_REGISTRY_KEY,
  611. 1,
  612. &pszKey,
  613. lStatus
  614. );
  615. }
  616. return fOk;
  617. }
  618. BOOL
  619. UnloadPermittedManagers(
  620. )
  621. /*++
  622. Routine Description:
  623. Destroys list of permitted managers.
  624. Arguments:
  625. None.
  626. Return Values:
  627. Returns true if successful.
  628. --*/
  629. {
  630. // call common routine with global list
  631. return UnloadManagers(&g_PermittedManagers);
  632. }