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.

656 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 dwDataType;
  244. // make sure the update was not tried (and breaked) before
  245. lStatus = RegQueryValueExW(
  246. hKey,
  247. wszCommunity,
  248. 0,
  249. &dwDataType,
  250. NULL,
  251. NULL);
  252. // if no previous (breaked) update, convert community to the new format
  253. if (lStatus != ERROR_SUCCESS || dwDataType != REG_DWORD)
  254. {
  255. // permissions to be assigned to community
  256. DWORD dwPermissionMask;
  257. // all communities that are converted to new format at this point,
  258. // are converted to READ-ONLY permissions to tighten the security
  259. dwPermissionMask = 1 << SNMP_ACCESS_READ_ONLY;
  260. // set the new format value
  261. lStatus = RegSetValueExW(
  262. hKey,
  263. wszCommunity,
  264. 0,
  265. REG_DWORD,
  266. (CONST BYTE *)&dwPermissionMask,
  267. sizeof(DWORD));
  268. if (lStatus != ERROR_SUCCESS)
  269. return lStatus;
  270. }
  271. // delete the old format value
  272. lStatus = RegDeleteValueW(
  273. hKey,
  274. wszBogus);
  275. return lStatus;
  276. }
  277. #endif
  278. BOOL
  279. LoadValidCommunities(
  280. BOOL bFirstCall
  281. )
  282. /*++
  283. Routine Description:
  284. Constructs list of valid communities.
  285. Arguments:
  286. None.
  287. Return Values:
  288. Returns true if successful.
  289. --*/
  290. {
  291. HKEY hKey;
  292. LONG lStatus;
  293. DWORD dwIndex;
  294. WCHAR wszName[MAX_PATH]; // get the UNICODE encoding for szName
  295. DWORD dwNameSize;
  296. DWORD dwDataType;
  297. WCHAR wszData[MAX_PATH]; // get the UNICODE encoding for szData
  298. DWORD dwDataSize;
  299. BOOL fPolicy;
  300. LPTSTR pszKey;
  301. BOOL fOk = FALSE;
  302. SNMPDBG((
  303. SNMP_LOG_TRACE,
  304. "SNMP: SVC: loading valid communities.\n"
  305. ));
  306. #ifdef _POLICY
  307. // we need to provide precedence to the parameters set through the policy
  308. fPolicy = TRUE;
  309. #else
  310. fPolicy = FALSE;
  311. #endif
  312. do
  313. {
  314. // if the policy is to be enforced, check the policy registry location first
  315. pszKey = fPolicy ? REG_POLICY_VALID_COMMUNITIES : REG_KEY_VALID_COMMUNITIES;
  316. // open registry subkey
  317. lStatus = RegOpenKeyEx(
  318. HKEY_LOCAL_MACHINE,
  319. pszKey,
  320. 0,
  321. #ifdef DYN_REGISTRY_UPDATE
  322. bFirstCall ? KEY_READ | KEY_SET_VALUE : KEY_READ,
  323. #else
  324. KEY_READ,
  325. #endif
  326. &hKey
  327. );
  328. // if the call succeeded or we were not checking the policy, break the loop
  329. if (lStatus == ERROR_SUCCESS || !fPolicy)
  330. break;
  331. // being at this point, this means we were checking for the policy parameters.
  332. // If and only if the policy is not defined (registry key is missing) we
  333. // reset the error, mark 'fPolicy already tried' and go back into the loop
  334. if (lStatus == ERROR_FILE_NOT_FOUND)
  335. {
  336. lStatus = ERROR_SUCCESS;
  337. fPolicy = FALSE;
  338. }
  339. } while (lStatus == ERROR_SUCCESS);
  340. // validate return code
  341. if (lStatus == ERROR_SUCCESS) {
  342. // initialize
  343. dwIndex = 0;
  344. // loop until error or end of list
  345. for (dwIndex = 0;
  346. lStatus == ERROR_SUCCESS;
  347. dwIndex++)
  348. {
  349. // initialize buffer sizes
  350. dwNameSize = sizeof(wszName) / sizeof(wszName[0]); // size in number of WCHARs, not the size in bytes
  351. dwDataSize = sizeof(wszData); // size in number of bytes
  352. // read next value
  353. lStatus = RegEnumValueW(
  354. hKey,
  355. dwIndex,
  356. wszName,
  357. &dwNameSize,
  358. NULL,
  359. &dwDataType,
  360. (LPBYTE)wszData,
  361. &dwDataSize
  362. );
  363. // validate return code
  364. if (lStatus == ERROR_SUCCESS) {
  365. // dynamically update values that are not of DWORD type
  366. if (dwDataType != REG_DWORD)
  367. {
  368. #ifdef DYN_REGISTRY_UPDATE
  369. if (dwDataType == REG_SZ)
  370. {
  371. // BUG# 638837, do not update ValidCommunities
  372. // registry format in case we're working with policy
  373. if (bFirstCall && !fPolicy)
  374. {
  375. if(UpdateRegistry(hKey, wszName, wszData) == ERROR_SUCCESS)
  376. {
  377. SNMPDBG((
  378. SNMP_LOG_WARNING,
  379. "SNMP: SVC: updated community registration\n"
  380. ));
  381. // current value has been deleted, need to keep the index
  382. dwIndex--;
  383. continue;
  384. }
  385. }
  386. else
  387. {
  388. SNMPDBG((
  389. SNMP_LOG_WARNING,
  390. "SNMP: SVC: old format community to be considered with read-only right"));
  391. wcscpy(wszName, wszData);
  392. *(DWORD *)wszData = (1 << SNMP_ACCESS_READ_ONLY);
  393. }
  394. }
  395. else
  396. #endif
  397. {
  398. SNMPDBG((
  399. SNMP_LOG_WARNING,
  400. "SNMP: SVC: wrong format in ValidCommunities[%d] registry entry\n",
  401. dwIndex
  402. ));
  403. continue;
  404. }
  405. }
  406. // add valid community to list with related permissions
  407. if (AddValidCommunity(wszName, ParsePermissionMask(*(DWORD *)wszData)))
  408. {
  409. SNMPDBG((
  410. SNMP_LOG_WARNING,
  411. "SNMP: SVC: rights set to %d for community '%s'\n",
  412. *(DWORD *)wszData,
  413. StaticUnicodeToString(wszName)
  414. ));
  415. }
  416. else
  417. {
  418. // reset status to reflect failure
  419. lStatus = ERROR_NOT_ENOUGH_MEMORY;
  420. }
  421. }
  422. else if (lStatus == ERROR_NO_MORE_ITEMS)
  423. {
  424. // success
  425. fOk = TRUE;
  426. }
  427. }
  428. RegCloseKey(hKey);
  429. }
  430. else
  431. // it doesn't matter how the values are, the key has to exist,
  432. // so mark as bFirstCall in order to log an event if this is not true.
  433. bFirstCall = TRUE;
  434. if (!fOk) {
  435. SNMPDBG((
  436. SNMP_LOG_ERROR,
  437. "SNMP: SVC: error %d processing ValidCommunities subkey.\n",
  438. lStatus
  439. ));
  440. // report an event only for the first call (initialization of the service).
  441. // otherwise subsequent registry ops through regedit might flood the event log with
  442. // unsignificant records
  443. if (bFirstCall)
  444. // report event
  445. ReportSnmpEvent(
  446. SNMP_EVENT_INVALID_REGISTRY_KEY,
  447. 1,
  448. &pszKey,
  449. lStatus
  450. );
  451. }
  452. return fOk;
  453. }
  454. BOOL
  455. UnloadValidCommunities(
  456. )
  457. /*++
  458. Routine Description:
  459. Destroys list of valid communities.
  460. Arguments:
  461. None.
  462. Return Values:
  463. Returns true if successful.
  464. --*/
  465. {
  466. PLIST_ENTRY pLE;
  467. PCOMMUNITY_LIST_ENTRY pCLE;
  468. // process entries until list is empty
  469. while (!IsListEmpty(&g_ValidCommunities)) {
  470. // extract next entry from head of list
  471. pLE = RemoveHeadList(&g_ValidCommunities);
  472. // retrieve pointer to community structure
  473. pCLE = CONTAINING_RECORD(pLE, COMMUNITY_LIST_ENTRY, Link);
  474. // release
  475. FreeCLE(pCLE);
  476. }
  477. return TRUE;
  478. }