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.

680 lines
16 KiB

  1. /*++
  2. Copyright (c) 1992-1997 Microsoft Corporation
  3. Module Name:
  4. contexts.c
  5. Abstract:
  6. Contains routines for manipulating SNMP community 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. // Include files //
  16. // //
  17. ///////////////////////////////////////////////////////////////////////////////
  18. #include "globals.h"
  19. #include "contexts.h"
  20. #include "snmpthrd.h"
  21. #define DYN_REGISTRY_UPDATE 1
  22. ///////////////////////////////////////////////////////////////////////////////
  23. // //
  24. // Private procedures //
  25. // //
  26. ///////////////////////////////////////////////////////////////////////////////
  27. BOOL
  28. AddValidCommunity(
  29. LPWSTR pCommunity,
  30. DWORD dwAccess
  31. )
  32. /*++
  33. Routine Description:
  34. Adds valid community to list.
  35. Arguments:
  36. pCommunity - pointer to community to add.
  37. dwAccess - access rights for community.
  38. Return Values:
  39. Returns true if successful.
  40. --*/
  41. {
  42. BOOL fOk = FALSE;
  43. PCOMMUNITY_LIST_ENTRY pCLE = NULL;
  44. AsnOctetString CommunityOctets;
  45. // initialize octet string info
  46. CommunityOctets.length = wcslen(pCommunity) * sizeof(WCHAR);
  47. CommunityOctets.stream = (LPBYTE)pCommunity;
  48. CommunityOctets.dynamic = FALSE;
  49. // attempt to locate in list
  50. if (FindValidCommunity(&pCLE, &CommunityOctets)) {
  51. SNMPDBG((
  52. SNMP_LOG_TRACE,
  53. "SNMP: SVC: updating community %s.\n",
  54. StaticUnicodeToString((LPWSTR)pCommunity)
  55. ));
  56. // update access rights
  57. pCLE->dwAccess = dwAccess;
  58. // success
  59. fOk = TRUE;
  60. } else {
  61. // allocate community structure
  62. if (AllocCLE(&pCLE, pCommunity)) {
  63. SNMPDBG((
  64. SNMP_LOG_TRACE,
  65. "SNMP: SVC: adding community %s.\n",
  66. CommunityOctetsToString(&(pCLE->Community), TRUE)
  67. ));
  68. // insert into valid communities list
  69. InsertTailList(&g_ValidCommunities, &pCLE->Link);
  70. // update access rights
  71. pCLE->dwAccess = dwAccess;
  72. // success
  73. fOk = TRUE;
  74. }
  75. }
  76. return fOk;
  77. }
  78. ///////////////////////////////////////////////////////////////////////////////
  79. // //
  80. // Public procedures //
  81. // //
  82. ///////////////////////////////////////////////////////////////////////////////
  83. BOOL
  84. AllocCLE(
  85. PCOMMUNITY_LIST_ENTRY * ppCLE,
  86. LPWSTR pCommunity
  87. )
  88. /*++
  89. Routine Description:
  90. Allocates community structure and initializes.
  91. Arguments:
  92. ppCLE - pointer to receive pointer to entry.
  93. pCommunity - pointer to community string.
  94. Return Values:
  95. Returns true if successful.
  96. --*/
  97. {
  98. BOOL fOk = FALSE;
  99. PCOMMUNITY_LIST_ENTRY pCLE = NULL;
  100. // attempt to allocate structure
  101. pCLE = AgentMemAlloc(sizeof(COMMUNITY_LIST_ENTRY));
  102. // validate
  103. if (pCLE != NULL) {
  104. // determine string length
  105. DWORD nBytes = wcslen(pCommunity) * sizeof(WCHAR);
  106. // allocate memory for string (include terminator)
  107. pCLE->Community.stream = SnmpUtilMemAlloc(nBytes + sizeof(WCHAR));
  108. // validate community string stream
  109. if (pCLE->Community.stream != NULL) {
  110. // set length of manager string
  111. pCLE->Community.length = nBytes;
  112. // set memory allocation flag
  113. pCLE->Community.dynamic = TRUE;
  114. // transfer community string into octets
  115. wcscpy((LPWSTR)(pCLE->Community.stream), pCommunity);
  116. // success
  117. fOk = TRUE;
  118. } else {
  119. SNMPDBG((
  120. SNMP_LOG_ERROR,
  121. "SNMP: SVC: could not copy community string %s.\n",
  122. StaticUnicodeToString(pCommunity)
  123. ));
  124. // release
  125. FreeCLE(pCLE);
  126. // re-init
  127. pCLE = NULL;
  128. }
  129. } else {
  130. SNMPDBG((
  131. SNMP_LOG_ERROR,
  132. "SNMP: SVC: could not allocate context entry for %s.\n",
  133. StaticUnicodeToString(pCommunity)
  134. ));
  135. }
  136. // transfer
  137. *ppCLE = pCLE;
  138. return fOk;
  139. }
  140. BOOL
  141. FreeCLE(
  142. PCOMMUNITY_LIST_ENTRY pCLE
  143. )
  144. /*++
  145. Routine Description:
  146. Releases community structure.
  147. Arguments:
  148. pCLE - pointer to community list entry to be freed.
  149. Return Values:
  150. Returns true if successful.
  151. --*/
  152. {
  153. // validate pointer
  154. if (pCLE != NULL) {
  155. // release octet string contents
  156. SnmpUtilOctetsFree(&pCLE->Community);
  157. // release structure
  158. AgentMemFree(pCLE);
  159. }
  160. return TRUE;
  161. }
  162. BOOL
  163. FindValidCommunity(
  164. PCOMMUNITY_LIST_ENTRY * ppCLE,
  165. AsnOctetString * pCommunity
  166. )
  167. /*++
  168. Routine Description:
  169. Locates valid community in list.
  170. Arguments:
  171. ppCLE - pointer to receive pointer to entry.
  172. pCommunity - pointer to community to find.
  173. Return Values:
  174. Returns true if successful.
  175. --*/
  176. {
  177. PLIST_ENTRY pLE;
  178. PCOMMUNITY_LIST_ENTRY pCLE;
  179. // initialize
  180. *ppCLE = NULL;
  181. // obtain pointer to list head
  182. pLE = g_ValidCommunities.Flink;
  183. // process all entries in list
  184. while (pLE != &g_ValidCommunities) {
  185. // retrieve pointer to community structure
  186. pCLE = CONTAINING_RECORD(pLE, COMMUNITY_LIST_ENTRY, Link);
  187. // compare community string with entry
  188. if (!SnmpUtilOctetsCmp(&pCLE->Community, pCommunity)) {
  189. // transfer
  190. *ppCLE = pCLE;
  191. // success
  192. return TRUE;
  193. }
  194. // next entry
  195. pLE = pLE->Flink;
  196. }
  197. // failure
  198. return FALSE;
  199. }
  200. DWORD
  201. ParsePermissionMask(
  202. DWORD bitMask
  203. )
  204. /*++
  205. Routine Description:
  206. Translates the permission mask from the bit-mask format (registry)
  207. into the internal constant value (constants from public\sdk\inc\snmp.h).
  208. The function works no longer if:
  209. - more than sizeof(DWORD)*8 permission values are defined
  210. - constant values (access policy) changes
  211. Arguments:
  212. bit-mask.
  213. Return Values:
  214. permission's constant value.
  215. --*/
  216. {
  217. DWORD dwPermission;
  218. for(dwPermission = 0; (bitMask & ((DWORD)(-1)^1)) != 0; bitMask>>=1, dwPermission++);
  219. return dwPermission;
  220. }
  221. #ifdef DYN_REGISTRY_UPDATE
  222. LONG UpdateRegistry(
  223. HKEY hKey,
  224. LPWSTR wszBogus,
  225. LPWSTR wszCommunity
  226. )
  227. /*++
  228. Routine Description:
  229. Updates the registry configuration in order to be able to associate
  230. permission masks to each community:
  231. name type data
  232. old format: <whatever> REG_SZ community_name
  233. new format: community_name REG_DWORD permission_mask
  234. Arguments:
  235. hKey - open handle to the key that contains the value
  236. szBogus - old format value name; useless data
  237. szCommunity - pointer to community name, as it was specified in the old format.
  238. Return Values:
  239. Returns ERROR_SUCCESS if successful.
  240. --*/
  241. {
  242. LONG lStatus;
  243. DWORD dwDataSize = MAX_PATH;
  244. DWORD dwDataType;
  245. // make sure the update was not tried (and breaked) before
  246. dwDataSize = sizeof(DWORD);
  247. lStatus = RegQueryValueExW(
  248. hKey,
  249. wszCommunity,
  250. 0,
  251. &dwDataType,
  252. NULL,
  253. &dwDataSize);
  254. // if no previous (breaked) update, convert community to the new format
  255. if (lStatus != ERROR_SUCCESS || dwDataType != REG_DWORD)
  256. {
  257. // permissions to be assigned to community
  258. DWORD dwPermissionMask;
  259. // all communities that are converted to new format at this point,
  260. // are converted to READ-CREATE permissions to ensure same functionality as
  261. // the permisionless communities.
  262. dwPermissionMask = 1 << SNMP_ACCESS_READ_CREATE;
  263. // set the new format value
  264. lStatus = RegSetValueExW(
  265. hKey,
  266. wszCommunity,
  267. 0,
  268. REG_DWORD,
  269. (CONST BYTE *)&dwPermissionMask,
  270. sizeof(DWORD));
  271. if (lStatus != ERROR_SUCCESS)
  272. return lStatus;
  273. }
  274. // delete the old format value
  275. lStatus = RegDeleteValueW(
  276. hKey,
  277. wszBogus);
  278. return lStatus;
  279. }
  280. #endif
  281. BOOL
  282. LoadValidCommunities(
  283. BOOL bFirstCall
  284. )
  285. /*++
  286. Routine Description:
  287. Constructs list of valid communities.
  288. Arguments:
  289. None.
  290. Return Values:
  291. Returns true if successful.
  292. --*/
  293. {
  294. HKEY hKey;
  295. LONG lStatus;
  296. DWORD dwIndex;
  297. WCHAR wszName[MAX_PATH]; // get the UNICODE encoding for szName
  298. CHAR szName[3*MAX_PATH]; // buffer for holding the translation UNICODE->UTF8
  299. DWORD dwNameSize;
  300. DWORD dwDataType;
  301. WCHAR wszData[MAX_PATH]; // get the UNICODE encoding for szData
  302. DWORD dwDataSize;
  303. BOOL fPolicy;
  304. LPTSTR pszKey;
  305. BOOL fOk = FALSE;
  306. SNMPDBG((
  307. SNMP_LOG_TRACE,
  308. "SNMP: SVC: loading valid communities.\n"
  309. ));
  310. #ifdef _POLICY
  311. // we need to provide precedence to the parameters set through the policy
  312. fPolicy = TRUE;
  313. #else
  314. fPolicy = FALSE;
  315. #endif
  316. do
  317. {
  318. // if the policy is to be enforced, check the policy registry location first
  319. pszKey = fPolicy ? REG_POLICY_VALID_COMMUNITIES : REG_KEY_VALID_COMMUNITIES;
  320. // open registry subkey
  321. lStatus = RegOpenKeyEx(
  322. HKEY_LOCAL_MACHINE,
  323. pszKey,
  324. 0,
  325. #ifdef DYN_REGISTRY_UPDATE
  326. bFirstCall ? KEY_READ | KEY_SET_VALUE : KEY_READ,
  327. #else
  328. KEY_READ,
  329. #endif
  330. &hKey
  331. );
  332. // if the call succeeded or we were not checking the policy, break the loop
  333. if (lStatus == ERROR_SUCCESS || !fPolicy)
  334. break;
  335. // being at this point, this means we were checking for the policy parameters.
  336. // If and only if the policy is not defined (registry key is missing) we
  337. // reset the error, mark 'fPolicy already tried' and go back into the loop
  338. if (lStatus == ERROR_FILE_NOT_FOUND)
  339. {
  340. lStatus = ERROR_SUCCESS;
  341. fPolicy = FALSE;
  342. }
  343. } while (lStatus == ERROR_SUCCESS);
  344. // validate return code
  345. if (lStatus == ERROR_SUCCESS) {
  346. // initialize
  347. dwIndex = 0;
  348. // loop until error or end of list
  349. for (dwIndex = 0;
  350. lStatus == ERROR_SUCCESS;
  351. dwIndex++)
  352. {
  353. // initialize buffer sizes
  354. dwNameSize = sizeof(wszName) / sizeof(wszName[0]); // size in number of WCHARs, not the size in bytes
  355. dwDataSize = sizeof(wszData); // size in number of bytes
  356. // read next value
  357. lStatus = RegEnumValueW(
  358. hKey,
  359. dwIndex,
  360. wszName,
  361. &dwNameSize,
  362. NULL,
  363. &dwDataType,
  364. (LPBYTE)wszData,
  365. &dwDataSize
  366. );
  367. // validate return code
  368. if (lStatus == ERROR_SUCCESS) {
  369. // dynamically update values that are not of DWORD type
  370. if (dwDataType != REG_DWORD)
  371. {
  372. #ifdef DYN_REGISTRY_UPDATE
  373. if (dwDataType == REG_SZ)
  374. {
  375. if (bFirstCall)
  376. {
  377. if(UpdateRegistry(hKey, wszName, wszData) == ERROR_SUCCESS)
  378. {
  379. SNMPDBG((
  380. SNMP_LOG_WARNING,
  381. "SNMP: SVC: updated community registration\n"
  382. ));
  383. // current value has been deleted, need to keep the index
  384. dwIndex--;
  385. continue;
  386. }
  387. }
  388. else
  389. {
  390. SNMPDBG((
  391. SNMP_LOG_WARNING,
  392. "SNMP: SVC: old format community to be considered with full rights"));
  393. wcscpy(wszName, wszData);
  394. *(DWORD *)wszData = (1 << SNMP_ACCESS_READ_CREATE);
  395. }
  396. }
  397. else
  398. #endif
  399. {
  400. SNMPDBG((
  401. SNMP_LOG_WARNING,
  402. "SNMP: SVC: wrong format in ValidCommunities[%d] registry entry\n",
  403. dwIndex
  404. ));
  405. continue;
  406. }
  407. }
  408. // convert the UNICODE representation to UTF8 representation
  409. //dwNameSize = WideCharToMultiByte(
  410. // CP_UTF8,
  411. // 0,
  412. // wszName,
  413. // wcslen(wszName),
  414. // szName,
  415. // sizeof(szName),
  416. // NULL,
  417. // NULL);
  418. // if error, just skip this community
  419. //if (dwNameSize == 0)
  420. //{
  421. // SNMPDBG((
  422. // SNMP_LOG_WARNING,
  423. // "SNMP: SVC: community conversion to UTF8 failed with error %d.\n", GetLastError()));
  424. // continue;
  425. //}
  426. // put the '\0' terminator to the string
  427. //szName[dwNameSize] = '\0';
  428. // add valid community to list with related permissions
  429. //if (AddValidCommunity(szName, ParsePermissionMask(*(DWORD *)wszData)))
  430. if (AddValidCommunity(wszName, ParsePermissionMask(*(DWORD *)wszData)))
  431. {
  432. SNMPDBG((
  433. SNMP_LOG_WARNING,
  434. "SNMP: SVC: rights set to %d for community '%s'\n",
  435. *(DWORD *)wszData,
  436. StaticUnicodeToString(wszName)
  437. ));
  438. }
  439. else
  440. {
  441. // reset status to reflect failure
  442. lStatus = ERROR_NOT_ENOUGH_MEMORY;
  443. }
  444. }
  445. else if (lStatus == ERROR_NO_MORE_ITEMS)
  446. {
  447. // success
  448. fOk = TRUE;
  449. }
  450. }
  451. }
  452. else
  453. // it doesn't matter how the values are, the key has to exist,
  454. // so mark as bFirstCall in order to log an event if this is not true.
  455. bFirstCall = TRUE;
  456. if (!fOk) {
  457. SNMPDBG((
  458. SNMP_LOG_ERROR,
  459. "SNMP: SVC: error %d processing ValidCommunities subkey.\n",
  460. lStatus
  461. ));
  462. // report an event only for the first call (initialization of the service).
  463. // otherwise subsequent registry ops through regedit might flood the event log with
  464. // unsignificant records
  465. if (bFirstCall)
  466. // report event
  467. ReportSnmpEvent(
  468. SNMP_EVENT_INVALID_REGISTRY_KEY,
  469. 1,
  470. &pszKey,
  471. lStatus
  472. );
  473. }
  474. return fOk;
  475. }
  476. BOOL
  477. UnloadValidCommunities(
  478. )
  479. /*++
  480. Routine Description:
  481. Destroys list of valid communities.
  482. Arguments:
  483. None.
  484. Return Values:
  485. Returns true if successful.
  486. --*/
  487. {
  488. PLIST_ENTRY pLE;
  489. PCOMMUNITY_LIST_ENTRY pCLE;
  490. // process entries until list is empty
  491. while (!IsListEmpty(&g_ValidCommunities)) {
  492. // extract next entry from head of list
  493. pLE = RemoveHeadList(&g_ValidCommunities);
  494. // retrieve pointer to community structure
  495. pCLE = CONTAINING_RECORD(pLE, COMMUNITY_LIST_ENTRY, Link);
  496. // release
  497. FreeCLE(pCLE);
  498. }
  499. return TRUE;
  500. }