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.

1662 lines
43 KiB

  1. /*++
  2. Copyright (c) 1992-1997 Microsoft Corporation
  3. Module Name:
  4. query.c
  5. Abstract:
  6. Contains routines for querying subagents.
  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 "varbinds.h"
  20. #include "network.h"
  21. #include "query.h"
  22. #include "snmpmgmt.h"
  23. ///////////////////////////////////////////////////////////////////////////////
  24. // //
  25. // Private procedures //
  26. // //
  27. ///////////////////////////////////////////////////////////////////////////////
  28. BOOL
  29. FindQueryBySLE(
  30. PQUERY_LIST_ENTRY * ppQLE,
  31. PNETWORK_LIST_ENTRY pNLE,
  32. PSUBAGENT_LIST_ENTRY pSLE
  33. )
  34. /*++
  35. Routine Description:
  36. Allocates query list entry.
  37. Arguments:
  38. ppQLE - pointer to receive query entry pointer.
  39. pNLE - pointer to network list entry.
  40. pSLE - pointer to subagent list entry.
  41. Return Values:
  42. Returns true if successful.
  43. --*/
  44. {
  45. PLIST_ENTRY pLE;
  46. PQUERY_LIST_ENTRY pQLE = NULL;
  47. // point to first query
  48. pLE = pNLE->Queries.Flink;
  49. // process each query
  50. while (pLE != &pNLE->Queries) {
  51. // retrieve pointer to query entry from link
  52. pQLE = CONTAINING_RECORD(pLE, QUERY_LIST_ENTRY, Link);
  53. // compare subagents
  54. if (pQLE->pSLE == pSLE) {
  55. // transfer
  56. *ppQLE = pQLE;
  57. // success
  58. return TRUE;
  59. }
  60. // next entry
  61. pLE = pLE->Flink;
  62. }
  63. // initialize
  64. *ppQLE = NULL;
  65. // failure
  66. return FALSE;
  67. }
  68. BOOL
  69. LoadSubagentData(
  70. PNETWORK_LIST_ENTRY pNLE,
  71. PQUERY_LIST_ENTRY pQLE
  72. )
  73. /*++
  74. Routine Description:
  75. Loads data to be passed to the subagent DLL.
  76. Arguments:
  77. pNLE - pointer to network list entry.
  78. pQLE - pointer to current query.
  79. Return Values:
  80. Returns true if successful.
  81. --*/
  82. {
  83. PLIST_ENTRY pLE;
  84. PVARBIND_LIST_ENTRY pVLE;
  85. SNMPDBG((
  86. SNMP_LOG_VERBOSE,
  87. "SNMP: SVC: query 0x%08lx loading.\n", pQLE
  88. ));
  89. // attempt to allocate varbind list
  90. pQLE->SubagentVbl.list = SnmpUtilMemAlloc(
  91. pQLE->nSubagentVbs * sizeof(SnmpVarBind)
  92. );
  93. // validate varbind list pointer
  94. if (pQLE->SubagentVbl.list != NULL) {
  95. // point to first varbind
  96. pLE = pQLE->SubagentVbs.Flink;
  97. // process each outgoing varbind
  98. while (pLE != &pQLE->SubagentVbs) {
  99. // retrieve pointer to varbind entry from query link
  100. pVLE = CONTAINING_RECORD(pLE, VARBIND_LIST_ENTRY, QueryLink);
  101. // transfer varbind
  102. if (SnmpUtilVarBindCpy(
  103. &pQLE->SubagentVbl.list[pQLE->SubagentVbl.len],
  104. &pVLE->ResolvedVb
  105. ) == 0)
  106. {
  107. SNMPDBG((
  108. SNMP_LOG_ERROR,
  109. "SNMP: SVC: could not transfer varbind to subagent.\n"
  110. ));
  111. return FALSE;
  112. }
  113. SNMPDBG((
  114. SNMP_LOG_VERBOSE,
  115. "SNMP: SVC: variable %d copied to query 0x%08lx.\n",
  116. pVLE->nErrorIndex,
  117. pQLE
  118. ));
  119. // increment
  120. pQLE->SubagentVbl.len++;
  121. // next entry
  122. pLE = pLE->Flink;
  123. }
  124. } else {
  125. SNMPDBG((
  126. SNMP_LOG_ERROR,
  127. "SNMP: SVC: could not allocate varbind list.\n"
  128. ));
  129. // failure
  130. return FALSE;
  131. }
  132. // success
  133. return TRUE;
  134. }
  135. BOOL
  136. UnloadSubagentData(
  137. PQUERY_LIST_ENTRY pQLE
  138. )
  139. /*++
  140. Routine Description:
  141. Unloads data passed to the subagent DLL.
  142. Arguments:
  143. pQLE - pointer to current query.
  144. Return Values:
  145. Returns true if successful.
  146. --*/
  147. {
  148. __try {
  149. // release subagent varbind list
  150. SnmpUtilVarBindListFree(&pQLE->SubagentVbl);
  151. } __except (EXCEPTION_EXECUTE_HANDLER) {
  152. SNMPDBG((
  153. SNMP_LOG_ERROR,
  154. "SNMP: SVC: exception 0x%08lx processing structure from %s.\n",
  155. GetExceptionCode(),
  156. (pQLE->pSLE != NULL)
  157. ? pQLE->pSLE->pPathname
  158. : "<unknown>"
  159. ));
  160. // failure
  161. return FALSE;
  162. }
  163. // success
  164. return TRUE;
  165. }
  166. BOOL
  167. UpdateResolvedVarBind(
  168. PQUERY_LIST_ENTRY pQLE,
  169. PVARBIND_LIST_ENTRY pVLE,
  170. UINT iVb
  171. )
  172. /*++
  173. Routine Description:
  174. Updates resolved varbind with data from subagent DLL.
  175. Arguments:
  176. pQLE - pointer to current query.
  177. pVLE - pointer to varbind.
  178. iVb - index of varbind.
  179. Return Values:
  180. Returns true if successful.
  181. --*/
  182. {
  183. // see if this is non-repeater
  184. if (pVLE->nMaxRepetitions == 1) {
  185. // flag varbind as resolved
  186. pVLE->nState = VARBIND_RESOLVED;
  187. // release memory for current varbind
  188. SnmpUtilVarBindFree(&pVLE->ResolvedVb);
  189. // transfer varbind from subagent
  190. if (SnmpUtilVarBindCpy(&pVLE->ResolvedVb,
  191. &pQLE->SubagentVbl.list[iVb]
  192. ) == 0)
  193. {
  194. SNMPDBG((
  195. SNMP_LOG_ERROR,
  196. "SNMP: SVC: could not transfer varbind from subagent.\n"
  197. ));
  198. return FALSE;
  199. }
  200. SNMPDBG((
  201. SNMP_LOG_VERBOSE,
  202. "SNMP: SVC: variable %d name %s.\n",
  203. pVLE->nErrorIndex,
  204. SnmpUtilOidToA(&pVLE->ResolvedVb.name)
  205. ));
  206. SNMPDBG((
  207. SNMP_LOG_VERBOSE,
  208. "SNMP: SVC: variable %d state '%s'.\n",
  209. pVLE->nErrorIndex,
  210. VARBINDSTATESTRING(pVLE->nState)
  211. ));
  212. // success
  213. return TRUE;
  214. }
  215. // see if varbind list allocated
  216. if ((pVLE->ResolvedVbl.len == 0) &&
  217. (pVLE->ResolvedVbl.list == NULL)) {
  218. if (sizeof(SnmpVarBind) > (UINT_MAX/pVLE->nMaxRepetitions))
  219. {
  220. SNMPDBG((
  221. SNMP_LOG_ERROR,
  222. "SNMP: SVC: arithmetic overflow: sizeof(SnmpVarBind) 0x%x, pVLE->nMaxRepetitions 0x%x.\n",
  223. sizeof(SnmpVarBind), pVLE->nMaxRepetitions
  224. ));
  225. return FALSE; // bail...
  226. }
  227. // allocate varbind list to fill in
  228. pVLE->ResolvedVbl.list = SnmpUtilMemAlloc(
  229. pVLE->nMaxRepetitions *
  230. sizeof(SnmpVarBind)
  231. );
  232. // validate pointer before continuing
  233. if (pVLE->ResolvedVbl.list == NULL) {
  234. SNMPDBG((
  235. SNMP_LOG_ERROR,
  236. "SNMP: SVC: could not allocate new varbinds.\n"
  237. ));
  238. // failure
  239. return FALSE;
  240. }
  241. }
  242. SNMPDBG((
  243. SNMP_LOG_VERBOSE,
  244. "SNMP: SVC: pVLE->ResolvedVbl.len %d pVLE->nMaxRepetitions %d.\n",
  245. pVLE->ResolvedVbl.len, pVLE->nMaxRepetitions
  246. ));
  247. // release working varbind name
  248. SnmpUtilOidFree(&pVLE->ResolvedVb.name);
  249. // transfer name for next iteration
  250. if (SnmpUtilOidCpy(&pVLE->ResolvedVb.name,
  251. &pQLE->SubagentVbl.list[iVb].name
  252. ) == 0)
  253. {
  254. SNMPDBG((
  255. SNMP_LOG_ERROR,
  256. "SNMP: SVC: could not transfer name for next iteration.\n"
  257. ));
  258. return FALSE;
  259. }
  260. // transfer varbind
  261. if (SnmpUtilVarBindCpy(
  262. &pVLE->ResolvedVbl.list[pVLE->ResolvedVbl.len],
  263. &pQLE->SubagentVbl.list[iVb]) == 0)
  264. {
  265. SNMPDBG((
  266. SNMP_LOG_ERROR,
  267. "SNMP: SVC: could not transfer varbind from subagent.\n"
  268. ));
  269. return FALSE;
  270. }
  271. // increment count
  272. pVLE->ResolvedVbl.len++;
  273. // see if this is the last varbind to retrieve
  274. pVLE->nState = (pVLE->nMaxRepetitions > pVLE->ResolvedVbl.len)
  275. ? VARBIND_PARTIALLY_RESOLVED
  276. : VARBIND_RESOLVED
  277. ;
  278. SNMPDBG((
  279. SNMP_LOG_VERBOSE,
  280. "SNMP: SVC: variable %d name %s.\n",
  281. pVLE->nErrorIndex,
  282. SnmpUtilOidToA(&pVLE->ResolvedVb.name)
  283. ));
  284. SNMPDBG((
  285. SNMP_LOG_VERBOSE,
  286. "SNMP: SVC: variable %d state '%s'.\n",
  287. pVLE->nErrorIndex,
  288. VARBINDSTATESTRING(pVLE->nState)
  289. ));
  290. // success
  291. return TRUE;
  292. }
  293. BOOL
  294. UpdateVarBind(
  295. PNETWORK_LIST_ENTRY pNLE,
  296. PQUERY_LIST_ENTRY pQLE,
  297. PVARBIND_LIST_ENTRY pVLE,
  298. UINT iVb
  299. )
  300. /*++
  301. Routine Description:
  302. Updates varbind with data from subagent DLL.
  303. Arguments:
  304. pNLE - pointer to network list entry.
  305. pQLE - pointer to current query.
  306. pVLE - pointer to varbind.
  307. iVb - index of varbind.
  308. Return Values:
  309. Returns true if successful.
  310. --*/
  311. {
  312. PLIST_ENTRY pLE;
  313. INT nDiff1;
  314. INT nDiff2;
  315. __try {
  316. // determine order of returned varbind
  317. nDiff1 = SnmpUtilOidCmp(&pQLE->SubagentVbl.list[iVb].name,
  318. &pVLE->ResolvedVb.name
  319. );
  320. // see if this is getnext or getbulk
  321. if ((pNLE->Pdu.nType == SNMP_PDU_GETNEXT) ||
  322. (pNLE->Pdu.nType == SNMP_PDU_GETBULK)) {
  323. // determine whether returned varbind in range
  324. nDiff2 = SnmpUtilOidCmp(&pQLE->SubagentVbl.list[iVb].name,
  325. &pVLE->pCurrentRLE->LimitOid
  326. );
  327. // make sure returned oid in range
  328. if ((nDiff1 > 0) && (nDiff2 < 0)) {
  329. // update resolved variable binding
  330. return UpdateResolvedVarBind(pQLE, pVLE, iVb);
  331. } else if (nDiff2 >= 0) {
  332. SNMPDBG((
  333. SNMP_LOG_VERBOSE,
  334. "SNMP: SVC: %s received getnext request for %s.\n",
  335. pQLE->pSLE->pPathname,
  336. SnmpUtilOidToA(&pVLE->ResolvedVb.name)
  337. ));
  338. SNMPDBG((
  339. SNMP_LOG_VERBOSE,
  340. "SNMP: SVC: %s returned out-of-range oid %s.\n",
  341. pQLE->pSLE->pPathname,
  342. SnmpUtilOidToA(&pQLE->SubagentVbl.list[iVb].name)
  343. ));
  344. // retrieve pointer to next region
  345. pLE = pVLE->pCurrentRLE->Link.Flink;
  346. // see if we exhausted regions
  347. if (pLE != &g_SupportedRegions) {
  348. PMIB_REGION_LIST_ENTRY pNextRLE;
  349. // retrieve pointer to mib region
  350. pNextRLE = CONTAINING_RECORD(pLE,
  351. MIB_REGION_LIST_ENTRY,
  352. Link
  353. );
  354. // see if next region supported by same subagent
  355. if (pVLE->pCurrentRLE->pSLE == pNextRLE->pSLE) {
  356. BOOL retCode;
  357. SNMPDBG((
  358. SNMP_LOG_TRACE,
  359. "SNMP: SVC: next region also supported by %s.\n",
  360. pVLE->pCurrentRLE->pSLE->pPathname
  361. ));
  362. // update resolved variable binding
  363. retCode = UpdateResolvedVarBind(pQLE, pVLE, iVb);
  364. if (pQLE->SubagentVbl.list[iVb].value.asnType != ASN_NULL)
  365. {
  366. return retCode;
  367. }
  368. else
  369. {
  370. SNMPDBG((
  371. SNMP_LOG_VERBOSE,
  372. "SNMP: SVC: pQLE->SubagentVbl.list[%d].name = %s got ASN_NULL value.\n",
  373. iVb, SnmpUtilOidToA(&pQLE->SubagentVbl.list[iVb].name)
  374. ));
  375. // BUG# 610475
  376. if (retCode)
  377. {
  378. // UpdateResolvedVarBind succeeds but
  379. // pQLE->SubagentVbl.list[iVb].value has
  380. // ASN_NULL value.
  381. if (pVLE->nMaxRepetitions > 1)
  382. {
  383. // rollback what has been done in
  384. // UpdateResolvedVarBind when
  385. // (pVLE->nMaxRepetitions > 1).
  386. if (pVLE->ResolvedVbl.len)
  387. {
  388. SNMPDBG((
  389. SNMP_LOG_VERBOSE,
  390. "SNMP: SVC: rollback what has been done in UpdateResolvedVarBind.\n"
  391. ));
  392. // decrement count
  393. pVLE->ResolvedVbl.len--;
  394. // free any resource allocated by UpdateResolvedVarBind
  395. SnmpUtilVarBindFree(&pVLE->ResolvedVbl.list[pVLE->ResolvedVbl.len]);
  396. }
  397. }
  398. // pVLE->nState will set to
  399. // VARBIND_PARTIALLY_RESOLVED to make another
  400. // query below.
  401. }
  402. else
  403. {
  404. SNMPDBG((
  405. SNMP_LOG_ERROR,
  406. "SNMP: SVC: UpdateVarBind: UpdateResolvedVarBind failed. pQLE->SubagentVbl.list[%d].name = %s.\n",
  407. iVb, SnmpUtilOidToA(&pQLE->SubagentVbl.list[iVb].name)
  408. ));
  409. return retCode;
  410. }
  411. }
  412. }
  413. // point to next region
  414. pVLE->pCurrentRLE = pNextRLE;
  415. // change state to partially resolved
  416. pVLE->nState = VARBIND_PARTIALLY_RESOLVED;
  417. SNMPDBG((
  418. SNMP_LOG_VERBOSE,
  419. "SNMP: SVC: variable %d state '%s'.\n",
  420. pVLE->nErrorIndex,
  421. VARBINDSTATESTRING(pVLE->nState)
  422. ));
  423. SNMPDBG((
  424. SNMP_LOG_TRACE,
  425. "SNMP: SVC: variable %d re-assigned to %s.\n",
  426. pVLE->nErrorIndex,
  427. pVLE->pCurrentRLE->pSLE->pPathname
  428. ));
  429. }
  430. else if ((pVLE->ResolvedVbl.len == 0) &&
  431. (pVLE->ResolvedVbl.list == NULL)) {
  432. // flag varbind as resolved
  433. pVLE->nState = VARBIND_RESOLVED;
  434. // set default varbind to eomv
  435. pVLE->ResolvedVb.value.asnType =
  436. SNMP_EXCEPTION_ENDOFMIBVIEW;
  437. // update error status counter for the operation
  438. mgmtCTick(CsnmpOutNoSuchNames);
  439. SNMPDBG((
  440. SNMP_LOG_VERBOSE,
  441. "SNMP: SVC: variable %d state '%s'.\n",
  442. pVLE->nErrorIndex,
  443. VARBINDSTATESTRING(pVLE->nState)
  444. ));
  445. } else {
  446. // transfer name
  447. if (SnmpUtilOidCpy(
  448. &pVLE->ResolvedVbl.list[pVLE->ResolvedVbl.len].name,
  449. &pVLE->ResolvedVb.name) == 0)
  450. {
  451. SNMPDBG((
  452. SNMP_LOG_ERROR,
  453. "SNMP: SVC: could not transfer name at line %d.\n",
  454. __LINE__
  455. ));
  456. return FALSE;
  457. }
  458. // flag varbind as resolved
  459. pVLE->nState = VARBIND_RESOLVED;
  460. // set current varbind to eomv
  461. pVLE->ResolvedVbl.list[pVLE->ResolvedVbl.len].value.asnType =
  462. SNMP_EXCEPTION_ENDOFMIBVIEW;
  463. // increment count
  464. pVLE->ResolvedVbl.len++;
  465. // update error status counter for the operation
  466. mgmtCTick(CsnmpOutNoSuchNames);
  467. SNMPDBG((
  468. SNMP_LOG_VERBOSE,
  469. "SNMP: SVC: variable %d state '%s'.\n",
  470. pVLE->nErrorIndex,
  471. VARBINDSTATESTRING(pVLE->nState)
  472. ));
  473. }
  474. } else {
  475. SNMPDBG((
  476. SNMP_LOG_ERROR,
  477. "SNMP: SVC: %s received getnext request for %s.\n",
  478. pQLE->pSLE->pPathname,
  479. SnmpUtilOidToA(&pVLE->ResolvedVb.name)
  480. ));
  481. SNMPDBG((
  482. SNMP_LOG_ERROR,
  483. "SNMP: SVC: %s returned invalid oid %s.\n",
  484. pQLE->pSLE->pPathname,
  485. SnmpUtilOidToA(&pQLE->SubagentVbl.list[iVb].name)
  486. ));
  487. SNMPDBG((
  488. SNMP_LOG_ERROR,
  489. "SNMP: SVC: Ban %s subagent, forward the request to a different one.\n",
  490. pQLE->pSLE->pPathname
  491. ));
  492. // trying to forward this getnext request to the next region but only if not handled
  493. // by the same subagent!
  494. pLE = pVLE->pCurrentRLE->Link.Flink;
  495. while( pLE != &g_SupportedRegions)
  496. {
  497. PMIB_REGION_LIST_ENTRY pNextRLE;
  498. // retrieve pointer to mib region
  499. pNextRLE = CONTAINING_RECORD(pLE,
  500. MIB_REGION_LIST_ENTRY,
  501. Link
  502. );
  503. // if this 'next' region is handled by the same subagent, skip to the next!
  504. if (pVLE->pCurrentRLE->pSLE == pNextRLE->pSLE)
  505. {
  506. pLE = pNextRLE->Link.Flink;
  507. continue;
  508. }
  509. // ok, we have one, forward the original GetNext request to it
  510. pVLE->pCurrentRLE = pNextRLE;
  511. pVLE->nState = VARBIND_PARTIALLY_RESOLVED;
  512. SNMPDBG((
  513. SNMP_LOG_TRACE,
  514. "SNMP: SVC: variable %d re-assigned to %s.\n",
  515. pVLE->nErrorIndex,
  516. pVLE->pCurrentRLE->pSLE->pPathname
  517. ));
  518. return TRUE;
  519. }
  520. // failure
  521. // here I should emulate a (NO_SUCH_NAME) EndOfMibView, resolve the variable and return TRUE.
  522. pVLE->nState = VARBIND_RESOLVED;
  523. pVLE->ResolvedVb.value.asnType = SNMP_EXCEPTION_ENDOFMIBVIEW;
  524. pVLE->pCurrentRLE = NULL;
  525. // update error status counter
  526. mgmtCTick(CsnmpOutNoSuchNames);
  527. return TRUE;
  528. }
  529. } else if (pNLE->Pdu.nType == SNMP_PDU_GET) {
  530. // must match
  531. if (nDiff1 == 0) {
  532. // flag varbind as resolved
  533. pVLE->nState = VARBIND_RESOLVED;
  534. // release memory for current varbind
  535. SnmpUtilVarBindFree(&pVLE->ResolvedVb);
  536. // transfer varbind from subagent
  537. if (SnmpUtilVarBindCpy(&pVLE->ResolvedVb,
  538. &pQLE->SubagentVbl.list[iVb]) == 0)
  539. {
  540. SNMPDBG((
  541. SNMP_LOG_ERROR,
  542. "SNMP: SVC: could not transfer varbind from subagent at line %d.\n",
  543. __LINE__
  544. ));
  545. return FALSE;
  546. }
  547. SNMPDBG((
  548. SNMP_LOG_VERBOSE,
  549. "SNMP: SVC: variable %d name %s.\n",
  550. pVLE->nErrorIndex,
  551. SnmpUtilOidToA(&pVLE->ResolvedVb.name)
  552. ));
  553. SNMPDBG((
  554. SNMP_LOG_VERBOSE,
  555. "SNMP: SVC: variable %d state '%s'.\n",
  556. pVLE->nErrorIndex,
  557. VARBINDSTATESTRING(pVLE->nState)
  558. ));
  559. } else {
  560. SNMPDBG((
  561. SNMP_LOG_ERROR,
  562. "SNMP: SVC: %s received get request for %s.\n",
  563. pQLE->pSLE->pPathname,
  564. SnmpUtilOidToA(&pVLE->ResolvedVb.name)
  565. ));
  566. SNMPDBG((
  567. SNMP_LOG_ERROR,
  568. "SNMP: SVC: %s returned invalid oid %s.\n",
  569. pQLE->pSLE->pPathname,
  570. SnmpUtilOidToA(&pQLE->SubagentVbl.list[iVb].name)
  571. ));
  572. // failure
  573. return FALSE;
  574. }
  575. } else if (nDiff1 != 0) {
  576. // set request failed -> invalid oid
  577. SNMPDBG((
  578. SNMP_LOG_ERROR,
  579. "SNMP: SVC: %s received set request for %s.\n",
  580. pQLE->pSLE->pPathname,
  581. SnmpUtilOidToA(&pVLE->ResolvedVb.name)
  582. ));
  583. SNMPDBG((
  584. SNMP_LOG_ERROR,
  585. "SNMP: SVC: %s returned invalid oid %s.\n",
  586. pQLE->pSLE->pPathname,
  587. SnmpUtilOidToA(&pQLE->SubagentVbl.list[iVb].name)
  588. ));
  589. // failure
  590. return FALSE;
  591. } else {
  592. // set request, oids match
  593. // WARNING!! - state might be set prematurely on SET_TEST / SET_CLEANUP
  594. pVLE->nState = VARBIND_RESOLVED;
  595. return TRUE;
  596. }
  597. } __except (EXCEPTION_EXECUTE_HANDLER) {
  598. SNMPDBG((
  599. SNMP_LOG_ERROR,
  600. "SNMP: SVC: exception 0x%08lx processing structure from %s.\n",
  601. GetExceptionCode(),
  602. pQLE->pSLE->pPathname
  603. ));
  604. // failure
  605. return FALSE;
  606. }
  607. // success
  608. return TRUE;
  609. }
  610. BOOL
  611. UpdateVarBinds(
  612. PNETWORK_LIST_ENTRY pNLE,
  613. PQUERY_LIST_ENTRY pQLE
  614. )
  615. /*++
  616. Routine Description:
  617. Updates varbind list entries with data from subagent DLL.
  618. Arguments:
  619. pNLE - pointer to network list entry.
  620. pQLE - pointer to current query.
  621. Return Values:
  622. Returns true if successful.
  623. --*/
  624. {
  625. PLIST_ENTRY pLE;
  626. PVARBIND_LIST_ENTRY pVLE;
  627. BOOL fOk = TRUE;
  628. UINT iVb = 0;
  629. // point to first varbind
  630. pLE = pQLE->SubagentVbs.Flink;
  631. // see if error encountered during callback
  632. if (pQLE->nErrorStatus == SNMP_ERRORSTATUS_NOERROR) {
  633. // process each outgoing varbind
  634. while (pLE != &pQLE->SubagentVbs) {
  635. // retrieve pointer to varbind entry from query link
  636. pVLE = CONTAINING_RECORD(pLE, VARBIND_LIST_ENTRY, QueryLink);
  637. // update individual varbind
  638. if (!UpdateVarBind(pNLE, pQLE, pVLE, iVb++)) {
  639. SNMPDBG((
  640. SNMP_LOG_ERROR,
  641. "SNMP: SVC: variable %d could not be updated.\n",
  642. pQLE->nErrorIndex
  643. ));
  644. // update pdu with the proper varbind error index
  645. pNLE->Pdu.Pdu.NormPdu.nErrorStatus = SNMP_ERRORSTATUS_GENERR;
  646. pNLE->Pdu.Pdu.NormPdu.nErrorIndex = pVLE->nErrorIndex;
  647. // failure
  648. return FALSE;
  649. }
  650. // next entry
  651. pLE = pLE->Flink;
  652. }
  653. } else {
  654. SNMPDBG((
  655. SNMP_LOG_VERBOSE,
  656. "SNMP: SVC: searching for errant variable.\n"
  657. ));
  658. // update pdu with status returned from subagent
  659. pNLE->Pdu.Pdu.NormPdu.nErrorStatus = pQLE->nErrorStatus;
  660. // process each outgoing varbind
  661. while (pLE != &pQLE->SubagentVbs) {
  662. // retrieve pointer to varbind entry from query link
  663. pVLE = CONTAINING_RECORD(pLE, VARBIND_LIST_ENTRY, QueryLink);
  664. // see if errant varbind nErrorIndex is starts from 1 !!
  665. if (pQLE->nErrorIndex == ++iVb) {
  666. SNMPDBG((
  667. SNMP_LOG_TRACE,
  668. "SNMP: SVC: variable %d involved in failure.\n",
  669. pVLE->nErrorIndex
  670. ));
  671. // update pdu with the proper varbind error index
  672. pNLE->Pdu.Pdu.NormPdu.nErrorIndex = pVLE->nErrorIndex;
  673. // the error code was successfully identified
  674. return TRUE;
  675. }
  676. // next entry
  677. pLE = pLE->Flink;
  678. }
  679. SNMPDBG((
  680. SNMP_LOG_TRACE,
  681. "SNMP: SVC: no variable involved in failure.\n"
  682. ));
  683. // failure
  684. return FALSE;
  685. }
  686. // success
  687. return TRUE;
  688. }
  689. BOOL
  690. CallSubagent(
  691. PQUERY_LIST_ENTRY pQLE,
  692. UINT nRequestType,
  693. UINT nTransactionId
  694. )
  695. /*++
  696. Routine Description:
  697. Invokes method from subagent DLL.
  698. Arguments:
  699. pNLE - pointer to network list entry.
  700. nRequestType - type of request to post to subagent.
  701. nTransactionId - identifies snmp pdu sent from manager.
  702. Return Values:
  703. Returns true if successful.
  704. --*/
  705. {
  706. BOOL fOk = FALSE;
  707. SNMPDBG((
  708. SNMP_LOG_VERBOSE,
  709. "SNMP: SVC: --- query %s begin ---\n",
  710. pQLE->pSLE->pPathname
  711. ));
  712. __try {
  713. // determine which version of query supported
  714. if (pQLE->pSLE->pfnSnmpExtensionQueryEx != NULL) {
  715. // process query using new interface
  716. fOk = (*pQLE->pSLE->pfnSnmpExtensionQueryEx)(
  717. nRequestType,
  718. nTransactionId,
  719. &pQLE->SubagentVbl,
  720. &pQLE->ContextInfo,
  721. &pQLE->nErrorStatus,
  722. &pQLE->nErrorIndex
  723. );
  724. // see if query is actually valid for downlevel call
  725. } else if ((pQLE->pSLE->pfnSnmpExtensionQuery != NULL) &&
  726. ((nRequestType == SNMP_EXTENSION_GET) ||
  727. (nRequestType == SNMP_EXTENSION_GET_NEXT) ||
  728. (nRequestType == SNMP_EXTENSION_SET_COMMIT))) {
  729. // process query using old interface
  730. fOk = (*pQLE->pSLE->pfnSnmpExtensionQuery)(
  731. (BYTE)(UINT)nRequestType,
  732. &pQLE->SubagentVbl,
  733. &pQLE->nErrorStatus,
  734. &pQLE->nErrorIndex
  735. );
  736. // see if query can be completed successfully anyway
  737. } else if ((nRequestType == SNMP_EXTENSION_SET_TEST) ||
  738. (nRequestType == SNMP_EXTENSION_SET_CLEANUP)) {
  739. // fake it
  740. fOk = TRUE;
  741. }
  742. } __except (EXCEPTION_EXECUTE_HANDLER) {
  743. SNMPDBG((
  744. SNMP_LOG_ERROR,
  745. "SNMP: SVC: exception 0x%08lx calling %s.\n",
  746. GetExceptionCode(),
  747. pQLE->pSLE->pPathname
  748. ));
  749. }
  750. SNMPDBG((
  751. SNMP_LOG_VERBOSE,
  752. "SNMP: SVC: --- query %s end ---\n",
  753. pQLE->pSLE->pPathname
  754. ));
  755. // validate
  756. if (!fOk) {
  757. // identify failing subagent
  758. pQLE->nErrorStatus = SNMP_ERRORSTATUS_GENERR;
  759. pQLE->nErrorIndex = 1;
  760. } else if (pQLE->nErrorStatus != SNMP_ERRORSTATUS_NOERROR) {
  761. // see if error index needs to be adjusted
  762. if ((pQLE->nErrorIndex > pQLE->nSubagentVbs) ||
  763. (pQLE->nErrorIndex == 0)) {
  764. // set to first varbind
  765. pQLE->nErrorIndex = 1;
  766. }
  767. } else {
  768. // re-initialize
  769. pQLE->nErrorIndex = 0;
  770. }
  771. SNMPDBG((
  772. SNMP_LOG_VERBOSE,
  773. "SNMP: SVC: query 0x%08lx %s, errorStatus=%s, errorIndex=%d.\n",
  774. pQLE,
  775. (pQLE->nErrorStatus == SNMP_ERRORSTATUS_NOERROR)
  776. ? "succeeded"
  777. : "failed"
  778. ,
  779. SNMPERRORSTRING(pQLE->nErrorStatus),
  780. pQLE->nErrorIndex
  781. ));
  782. return TRUE;
  783. }
  784. BOOL
  785. ProcessSet(
  786. PNETWORK_LIST_ENTRY pNLE
  787. )
  788. /*++
  789. Routine Description:
  790. Processes SNMP_PDU_SET requests.
  791. Arguments:
  792. pNLE - pointer to network list entry.
  793. Return Values:
  794. Returns true if successful.
  795. --*/
  796. {
  797. PLIST_ENTRY pLE = NULL;
  798. PQUERY_LIST_ENTRY pQLE;
  799. BOOL fOk = TRUE;
  800. // load subagent queries
  801. if (!LoadQueries(pNLE)) {
  802. // unload immediately
  803. UnloadQueries(pNLE);
  804. // failure
  805. return FALSE;
  806. }
  807. // point to first query
  808. pLE = pNLE->Queries.Flink;
  809. // process each subagent query
  810. while (fOk && (pLE != &pNLE->Queries)) {
  811. // retrieve pointer to query entry from link
  812. pQLE = CONTAINING_RECORD(pLE, QUERY_LIST_ENTRY, Link);
  813. // load outgoing varbinds
  814. fOk = LoadSubagentData(pNLE, pQLE);
  815. // validate
  816. if (fOk) {
  817. // dispatch
  818. CallSubagent(
  819. pQLE,
  820. SNMP_EXTENSION_SET_TEST,
  821. pNLE->nTransactionId
  822. );
  823. // process results returned
  824. fOk = UpdateVarBinds(pNLE, pQLE);
  825. }
  826. // next entry (or reverse direction)
  827. pLE = fOk ? pLE->Flink : pLE->Blink;
  828. }
  829. // validate
  830. if (fOk) {
  831. // if this line is missing => GenErr on UpdatePdu()
  832. pLE = pNLE->Queries.Flink;
  833. // process each subagent query
  834. while (fOk && (pLE != &pNLE->Queries)) {
  835. // retrieve pointer to query entry from link
  836. pQLE = CONTAINING_RECORD(pLE, QUERY_LIST_ENTRY, Link);
  837. // dispatch
  838. CallSubagent(
  839. pQLE,
  840. SNMP_EXTENSION_SET_COMMIT,
  841. pNLE->nTransactionId
  842. );
  843. // process results returned
  844. fOk = UpdateVarBinds(pNLE, pQLE);
  845. // next entry (or reverse direction)
  846. pLE = fOk ? pLE->Flink : pLE->Blink;
  847. }
  848. // validate
  849. if (!fOk) {
  850. // process each subagent query
  851. while (pLE != &pNLE->Queries) {
  852. // retrieve pointer to query entry from link
  853. pQLE = CONTAINING_RECORD(pLE, QUERY_LIST_ENTRY, Link);
  854. // dispatch
  855. CallSubagent(
  856. pQLE,
  857. SNMP_EXTENSION_SET_UNDO,
  858. pNLE->nTransactionId
  859. );
  860. // process results returned
  861. UpdateVarBinds(pNLE, pQLE);
  862. // previous entry
  863. pLE = pLE->Blink;
  864. }
  865. }
  866. // point to last query
  867. pLE = pNLE->Queries.Blink;
  868. }
  869. // process each subagent query
  870. while (pLE != &pNLE->Queries) {
  871. // retrieve pointer to query entry from link
  872. pQLE = CONTAINING_RECORD(pLE, QUERY_LIST_ENTRY, Link);
  873. // dispatch
  874. CallSubagent(
  875. pQLE,
  876. SNMP_EXTENSION_SET_CLEANUP,
  877. pNLE->nTransactionId
  878. );
  879. // process results returned
  880. UpdateVarBinds(pNLE, pQLE);
  881. // previous entry
  882. pLE = pLE->Blink;
  883. }
  884. // cleanup queries
  885. UnloadQueries(pNLE);
  886. return TRUE;
  887. }
  888. BOOL
  889. ProcessGet(
  890. PNETWORK_LIST_ENTRY pNLE
  891. )
  892. /*++
  893. Routine Description:
  894. Queries subagents to resolve varbinds.
  895. Arguments:
  896. pNLE - pointer to network list entry.
  897. Return Values:
  898. Returns true if successful.
  899. --*/
  900. {
  901. PLIST_ENTRY pLE;
  902. PQUERY_LIST_ENTRY pQLE = NULL;
  903. BOOL fOk = TRUE;
  904. // load subagent queries
  905. if (!LoadQueries(pNLE)) {
  906. // unload immediately
  907. UnloadQueries(pNLE);
  908. // failure
  909. return FALSE;
  910. }
  911. // point to first query
  912. pLE = pNLE->Queries.Flink;
  913. // process each subagent query
  914. while (fOk && (pLE != &pNLE->Queries)) {
  915. // retrieve pointer to query entry from link
  916. pQLE = CONTAINING_RECORD(pLE, QUERY_LIST_ENTRY, Link);
  917. // load outgoing varbinds
  918. fOk = LoadSubagentData(pNLE, pQLE);
  919. // validate
  920. if (fOk) {
  921. // dispatch
  922. CallSubagent(
  923. pQLE,
  924. SNMP_EXTENSION_GET,
  925. pNLE->nTransactionId
  926. );
  927. // process results returned
  928. fOk = UpdateVarBinds(pNLE, pQLE);
  929. }
  930. // next entry
  931. pLE = pLE->Flink;
  932. }
  933. // cleanup queries
  934. UnloadQueries(pNLE);
  935. return fOk;
  936. }
  937. BOOL
  938. ProcessGetBulk(
  939. PNETWORK_LIST_ENTRY pNLE
  940. )
  941. /*++
  942. Routine Description:
  943. Queries subagents to resolve varbinds.
  944. Arguments:
  945. pNLE - pointer to network list entry.
  946. Return Values:
  947. Returns true if successful.
  948. --*/
  949. {
  950. PLIST_ENTRY pLE;
  951. PQUERY_LIST_ENTRY pQLE = NULL;
  952. BOOL fOk = TRUE;
  953. SNMPDBG((
  954. SNMP_LOG_VERBOSE,
  955. "SNMP: SVC: getbulk request, non-repeaters %d, max-repetitions %d.\n",
  956. pNLE->Pdu.Pdu.BulkPdu.nNonRepeaters,
  957. pNLE->Pdu.Pdu.BulkPdu.nMaxRepetitions
  958. ));
  959. // loop
  960. while (fOk) {
  961. // load subagent queries
  962. fOk = LoadQueries(pNLE);
  963. // validate
  964. if (fOk && !IsListEmpty(&pNLE->Queries)) {
  965. // point to first query
  966. pLE = pNLE->Queries.Flink;
  967. // process each subagent query
  968. while (fOk && (pLE != &pNLE->Queries)) {
  969. // retrieve pointer to query entry from link
  970. pQLE = CONTAINING_RECORD(pLE, QUERY_LIST_ENTRY, Link);
  971. // load outgoing varbinds
  972. fOk = LoadSubagentData(pNLE, pQLE);
  973. // validate
  974. if (fOk) {
  975. // dispatch
  976. CallSubagent(
  977. pQLE,
  978. SNMP_EXTENSION_GET_NEXT,
  979. pNLE->nTransactionId
  980. );
  981. // process results returned
  982. fOk = UpdateVarBinds(pNLE, pQLE);
  983. }
  984. // next entry
  985. pLE = pLE->Flink;
  986. }
  987. } else if (IsListEmpty(&pNLE->Queries)) {
  988. SNMPDBG((
  989. SNMP_LOG_VERBOSE,
  990. "SNMP: SVC: no more queries to process.\n"
  991. ));
  992. break; // finished...
  993. }
  994. // cleanup queries
  995. UnloadQueries(pNLE);
  996. }
  997. return fOk;
  998. }
  999. ///////////////////////////////////////////////////////////////////////////////
  1000. // //
  1001. // Public procedures //
  1002. // //
  1003. ///////////////////////////////////////////////////////////////////////////////
  1004. BOOL
  1005. AllocQLE(
  1006. PQUERY_LIST_ENTRY * ppQLE
  1007. )
  1008. /*++
  1009. Routine Description:
  1010. Allocates query list entry.
  1011. Arguments:
  1012. ppQLE - pointer to receive list entry pointer.
  1013. Return Values:
  1014. Returns true if successful.
  1015. --*/
  1016. {
  1017. BOOL fOk = FALSE;
  1018. PQUERY_LIST_ENTRY pQLE = NULL;
  1019. // attempt to allocate structure
  1020. pQLE = AgentMemAlloc(sizeof(QUERY_LIST_ENTRY));
  1021. // validate
  1022. if (pQLE != NULL) {
  1023. // initialize outgoing varbind list
  1024. InitializeListHead(&pQLE->SubagentVbs);
  1025. // success
  1026. fOk = TRUE;
  1027. } else {
  1028. SNMPDBG((
  1029. SNMP_LOG_ERROR,
  1030. "SNMP: SVC: could not allocate query.\n"
  1031. ));
  1032. }
  1033. // transfer
  1034. *ppQLE = pQLE;
  1035. return fOk;
  1036. }
  1037. BOOL
  1038. FreeQLE(
  1039. PQUERY_LIST_ENTRY pQLE
  1040. )
  1041. /*++
  1042. Routine Description:
  1043. Creates queries from varbind list entries.
  1044. Arguments:
  1045. pNLE - pointer to network list entry with SNMP message.
  1046. Return Values:
  1047. Returns true if successful.
  1048. --*/
  1049. {
  1050. // validate pointer
  1051. if (pQLE != NULL) {
  1052. // release subagent info
  1053. UnloadSubagentData(pQLE);
  1054. // release structure
  1055. AgentMemFree(pQLE);
  1056. }
  1057. return TRUE;
  1058. }
  1059. BOOL
  1060. LoadQueries(
  1061. PNETWORK_LIST_ENTRY pNLE
  1062. )
  1063. /*++
  1064. Routine Description:
  1065. Creates queries from varbind list entries.
  1066. Arguments:
  1067. pNLE - pointer to network list entry.
  1068. Return Values:
  1069. Returns true if successful.
  1070. --*/
  1071. {
  1072. PLIST_ENTRY pLE;
  1073. PVARBIND_LIST_ENTRY pVLE;
  1074. PQUERY_LIST_ENTRY pQLE = NULL;
  1075. // point to first varbind
  1076. pLE = pNLE->Bindings.Flink;
  1077. // process each binding
  1078. while (pLE != &pNLE->Bindings) {
  1079. // retrieve pointer to varbind entry from link
  1080. pVLE = CONTAINING_RECORD(pLE, VARBIND_LIST_ENTRY, Link);
  1081. // analyze current state of varbind
  1082. if ((pVLE->nState == VARBIND_INITIALIZED) ||
  1083. (pVLE->nState == VARBIND_PARTIALLY_RESOLVED)) {
  1084. // attempt to locate existing query
  1085. if (FindQueryBySLE(&pQLE, pNLE, pVLE->pCurrentRLE->pSLE)) {
  1086. // attach varbind entry to query via query link
  1087. InsertTailList(&pQLE->SubagentVbs, &pVLE->QueryLink);
  1088. // change varbind state
  1089. pVLE->nState = VARBIND_RESOLVING;
  1090. // increment total
  1091. pQLE->nSubagentVbs++;
  1092. SNMPDBG((
  1093. SNMP_LOG_VERBOSE,
  1094. "SNMP: SVC: variable %d added to existing query 0x%08lx.\n",
  1095. pVLE->nErrorIndex,
  1096. pQLE
  1097. ));
  1098. SNMPDBG((
  1099. SNMP_LOG_VERBOSE,
  1100. "SNMP: SVC: variable %d state '%s'.\n",
  1101. pVLE->nErrorIndex,
  1102. VARBINDSTATESTRING(pVLE->nState)
  1103. ));
  1104. // attempt to allocate entry
  1105. } else if (AllocQLE(&pQLE)) {
  1106. // obtain subagent pointer
  1107. pQLE->pSLE = pVLE->pCurrentRLE->pSLE;
  1108. // insert into query list
  1109. InsertTailList(&pNLE->Queries, &pQLE->Link);
  1110. // attach varbind entry to query via query link
  1111. InsertTailList(&pQLE->SubagentVbs, &pVLE->QueryLink);
  1112. // change varbind state
  1113. pVLE->nState = VARBIND_RESOLVING;
  1114. // increment total
  1115. pQLE->nSubagentVbs++;
  1116. SNMPDBG((
  1117. SNMP_LOG_VERBOSE,
  1118. "SNMP: SVC: variable %d added to new query 0x%08lx.\n",
  1119. pVLE->nErrorIndex,
  1120. pQLE
  1121. ));
  1122. SNMPDBG((
  1123. SNMP_LOG_VERBOSE,
  1124. "SNMP: SVC: variable %d state '%s'.\n",
  1125. pVLE->nErrorIndex,
  1126. VARBINDSTATESTRING(pVLE->nState)
  1127. ));
  1128. } else {
  1129. SNMPDBG((
  1130. SNMP_LOG_ERROR,
  1131. "SNMP: SVC: could not contruct query.\n"
  1132. ));
  1133. // failure
  1134. return FALSE;
  1135. }
  1136. }
  1137. // next entry
  1138. pLE = pLE->Flink;
  1139. }
  1140. // success
  1141. return TRUE;
  1142. }
  1143. BOOL
  1144. UnloadQueries(
  1145. PNETWORK_LIST_ENTRY pNLE
  1146. )
  1147. /*++
  1148. Routine Description:
  1149. Destroys queries from varbind list entries.
  1150. Arguments:
  1151. pNLE - pointer to network list entry with SNMP message.
  1152. Return Values:
  1153. Returns true if successful.
  1154. --*/
  1155. {
  1156. PLIST_ENTRY pLE;
  1157. PQUERY_LIST_ENTRY pQLE;
  1158. // process each query entry
  1159. while (!IsListEmpty(&pNLE->Queries)) {
  1160. // point to first query
  1161. pLE = RemoveHeadList(&pNLE->Queries);
  1162. // retrieve pointer to query from link
  1163. pQLE = CONTAINING_RECORD(pLE, QUERY_LIST_ENTRY, Link);
  1164. // release
  1165. FreeQLE(pQLE);
  1166. }
  1167. return TRUE;
  1168. }
  1169. BOOL
  1170. ProcessQueries(
  1171. PNETWORK_LIST_ENTRY pNLE
  1172. )
  1173. /*++
  1174. Routine Description:
  1175. Queries subagents to resolve varbinds.
  1176. Arguments:
  1177. pNLE - pointer to network list entry.
  1178. Return Values:
  1179. Returns true if successful.
  1180. --*/
  1181. {
  1182. // determine pdu
  1183. switch (pNLE->Pdu.nType) {
  1184. case SNMP_PDU_GETNEXT:
  1185. case SNMP_PDU_GETBULK:
  1186. // multiple non-exact reads
  1187. return ProcessGetBulk(pNLE);
  1188. case SNMP_PDU_GET:
  1189. // single exact read
  1190. return ProcessGet(pNLE);
  1191. case SNMP_PDU_SET:
  1192. // single exact write
  1193. return ProcessSet(pNLE);
  1194. }
  1195. // failure
  1196. return FALSE;
  1197. }