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.

2576 lines
52 KiB

  1. /*
  2. Copyright (c) 1992-1997 Microsoft Corporation
  3. Module Name:
  4. snmppdus.c
  5. Abstract:
  6. Contains routines for manipulating SNMP PDUs.
  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 "snmppdus.h"
  20. #include "snmpmgmt.h"
  21. ///////////////////////////////////////////////////////////////////////////////
  22. // //
  23. // Private definitions //
  24. // //
  25. ///////////////////////////////////////////////////////////////////////////////
  26. #define BERERR ((LONG)-1)
  27. ///////////////////////////////////////////////////////////////////////////////
  28. // //
  29. // Private procedures //
  30. // //
  31. ///////////////////////////////////////////////////////////////////////////////
  32. LONG
  33. DoLenLen(
  34. LONG lLen
  35. )
  36. /*
  37. Routine Description:
  38. Calculates number of bytes required to encode length.
  39. Arguments:
  40. lLen - length of interest.
  41. Return Values:
  42. Returns BERERR if unsuccessful.
  43. */
  44. {
  45. // determine len length
  46. if (0x80 > lLen) return (1);
  47. if (0x100 > lLen) return (2);
  48. if (0x10000 > lLen) return (3);
  49. if (0x1000000 > lLen) return (4);
  50. SNMPDBG((
  51. SNMP_LOG_ERROR,
  52. "SNMP: SVC: length field too large.\n"
  53. ));
  54. // failure
  55. return BERERR;
  56. }
  57. LONG
  58. FindLenInt(
  59. AsnInteger32 nValue
  60. )
  61. /*
  62. Routine Description:
  63. Calculates length of integer.
  64. Arguments:
  65. nValue - integer data.
  66. Return Values:
  67. Returns BERERR if unsuccessful.
  68. */
  69. {
  70. // negative?
  71. if (nValue < 0) {
  72. // determine length of negative int
  73. if ((ULONG)0x80 >= -nValue) return (1);
  74. if ((ULONG)0x8000 >= -nValue) return (2);
  75. if ((ULONG)0x800000 >= -nValue) return (3);
  76. } else {
  77. // determine length of positive int
  78. if ((ULONG)0x80 > nValue) return (1);
  79. if ((ULONG)0x8000 > nValue) return (2);
  80. if ((ULONG)0x800000 > nValue) return (3);
  81. }
  82. // default
  83. return (4);
  84. }
  85. LONG
  86. FindLenIntEx(
  87. AsnInteger32 nValue
  88. )
  89. /*
  90. Routine Description:
  91. Calculates length of integer (including type and lenlen).
  92. Arguments:
  93. nValue - integer data.
  94. Return Values:
  95. Returns BERERR if unsuccessful.
  96. */
  97. {
  98. // negative?
  99. if (nValue < 0) {
  100. // determine length of negative int
  101. if ((ULONG)0x80 >= -nValue) return (3);
  102. if ((ULONG)0x8000 >= -nValue) return (4);
  103. if ((ULONG)0x800000 >= -nValue) return (5);
  104. } else {
  105. // determine length of positive int
  106. if ((ULONG)0x80 > nValue) return (3);
  107. if ((ULONG)0x8000 > nValue) return (4);
  108. if ((ULONG)0x800000 > nValue) return (5);
  109. }
  110. // default
  111. return (6);
  112. }
  113. LONG
  114. FindLenUInt(
  115. AsnUnsigned32 nValue
  116. )
  117. /*
  118. Routine Description:
  119. Calculates encoded length of unsigned integer.
  120. Arguments:
  121. nValue - integer data.
  122. Return Values:
  123. Returns BERERR if unsuccessful.
  124. */
  125. {
  126. // determine length of unsigned int
  127. if ((ULONG)0x80 > nValue) return (1);
  128. if ((ULONG)0x8000 > nValue) return (2);
  129. if ((ULONG)0x800000 > nValue) return (3);
  130. if ((ULONG)0x80000000 > nValue) return (4);
  131. // default
  132. return (5);
  133. }
  134. LONG
  135. FindLenUIntEx(
  136. AsnUnsigned32 nValue
  137. )
  138. /*
  139. Routine Description:
  140. Calculates encoded length of unsigned integer (including type and lenlen).
  141. Arguments:
  142. nValue - integer data.
  143. Return Values:
  144. Returns BERERR if unsuccessful.
  145. */
  146. {
  147. // determine length of unsigned int
  148. if ((ULONG)0x80 > nValue) return (3);
  149. if ((ULONG)0x8000 > nValue) return (4);
  150. if ((ULONG)0x800000 > nValue) return (5);
  151. if ((ULONG)0x80000000 > nValue) return (6);
  152. // default
  153. return (7);
  154. }
  155. LONG
  156. FindLenCntr64(
  157. AsnCounter64 * pCntr64
  158. )
  159. /*
  160. Routine Description:
  161. Calculates encoded length of 64-bit counter.
  162. Arguments:
  163. pCntr64 - counter data.
  164. Return Values:
  165. Returns BERERR if unsuccessful.
  166. */
  167. {
  168. // retrieve 64-bit unsigned value
  169. ULONGLONG nValue = pCntr64->QuadPart;
  170. // determine length of unsigned int
  171. if ((ULONGLONG)0x80 > nValue) return (1);
  172. if ((ULONGLONG)0x8000 > nValue) return (2);
  173. if ((ULONGLONG)0x800000 > nValue) return (3);
  174. if ((ULONGLONG)0x80000000 > nValue) return (4);
  175. if ((ULONGLONG)0x8000000000 > nValue) return (5);
  176. if ((ULONGLONG)0x800000000000 > nValue) return (6);
  177. if ((ULONGLONG)0x80000000000000 > nValue) return (7);
  178. if ((ULONGLONG)0x8000000000000000 > nValue) return (8);
  179. // default
  180. return (9);
  181. }
  182. LONG
  183. FindLenCntr64Ex(
  184. AsnCounter64 * pCntr64
  185. )
  186. /*
  187. Routine Description:
  188. Calculates encoded length of 64-bit counter (including type and lenlen).
  189. Arguments:
  190. pCntr64 - counter data.
  191. Return Values:
  192. Returns BERERR if unsuccessful.
  193. */
  194. {
  195. // retrieve 64-bit unsigned value
  196. ULONGLONG nValue = pCntr64->QuadPart;
  197. // determine length of unsigned int
  198. if ((ULONGLONG)0x80 > nValue) return (3);
  199. if ((ULONGLONG)0x8000 > nValue) return (4);
  200. if ((ULONGLONG)0x800000 > nValue) return (5);
  201. if ((ULONGLONG)0x80000000 > nValue) return (6);
  202. if ((ULONGLONG)0x8000000000 > nValue) return (7);
  203. if ((ULONGLONG)0x800000000000 > nValue) return (8);
  204. if ((ULONGLONG)0x80000000000000 > nValue) return (9);
  205. if ((ULONGLONG)0x8000000000000000 > nValue) return (10);
  206. // default
  207. return (11);
  208. }
  209. LONG
  210. FindLenOctets(
  211. AsnOctetString * pOctets
  212. )
  213. /*
  214. Routine Description:
  215. Calculates length of octet string.
  216. Arguments:
  217. pOctets - pointer to octet string.
  218. Return Values:
  219. Returns BERERR if unsuccessful.
  220. */
  221. {
  222. // return size
  223. return pOctets->length;
  224. }
  225. LONG
  226. FindLenOctetsEx(
  227. AsnOctetString * pOctets
  228. )
  229. /*
  230. Routine Description:
  231. Calculates length of octet string (including type and lenlen).
  232. Arguments:
  233. pOctets - pointer to octet string.
  234. Return Values:
  235. Returns BERERR if unsuccessful.
  236. */
  237. {
  238. LONG lLenLen;
  239. // calculate bytes needed to encode
  240. lLenLen = DoLenLen(pOctets->length);
  241. // return total size
  242. return (lLenLen != BERERR)
  243. ? (pOctets->length + lLenLen + 1)
  244. : BERERR
  245. ;
  246. }
  247. LONG
  248. FindLenOid(
  249. AsnObjectIdentifier * pOid
  250. )
  251. /*
  252. Routine Description:
  253. Calculates length of object identifier.
  254. Arguments:
  255. pOid - pointer object identifier.
  256. Return Values:
  257. Returns BERERR if unsuccessful.
  258. */
  259. {
  260. UINT i;
  261. LONG lDataLen;
  262. // first two
  263. lDataLen = 1;
  264. // assume first two oids present
  265. for (i = 2; i < pOid->idLength; i++) {
  266. if (0x80 > pOid->ids[i]) {
  267. lDataLen += 1;
  268. } else if (0x4000 > pOid->ids[i]) {
  269. lDataLen += 2;
  270. } else if (0x200000 > pOid->ids[i]) {
  271. lDataLen += 3;
  272. } else if (0x10000000 > pOid->ids[i]) {
  273. lDataLen += 4;
  274. } else {
  275. lDataLen += 5;
  276. }
  277. }
  278. // return size
  279. return (pOid->idLength >= 2) ? lDataLen : BERERR;
  280. }
  281. LONG
  282. FindLenOidEx(
  283. AsnObjectIdentifier * pOid
  284. )
  285. /*
  286. Routine Description:
  287. Calculates length of object identifier (including type and lenlen).
  288. Arguments:
  289. pOid - pointer object identifier.
  290. Return Values:
  291. Returns BERERR if unsuccessful.
  292. */
  293. {
  294. UINT i;
  295. LONG lLenLen;
  296. LONG lDataLen;
  297. // first two
  298. lDataLen = 1;
  299. // assume first two oids present
  300. for (i = 2; i < pOid->idLength; i++) {
  301. if (0x80 > pOid->ids[i]) {
  302. lDataLen += 1;
  303. } else if (0x4000 > pOid->ids[i]) {
  304. lDataLen += 2;
  305. } else if (0x200000 > pOid->ids[i]) {
  306. lDataLen += 3;
  307. } else if (0x10000000 > pOid->ids[i]) {
  308. lDataLen += 4;
  309. } else {
  310. lDataLen += 5;
  311. }
  312. }
  313. // calculate len length
  314. lLenLen = DoLenLen(lDataLen);
  315. // return total size
  316. return ((lLenLen != BERERR) &&
  317. (pOid->idLength >= 2))
  318. ? (lDataLen + lLenLen + 1)
  319. : BERERR
  320. ;
  321. }
  322. LONG
  323. FindLenAsnAny(
  324. AsnAny * pAny
  325. )
  326. /*
  327. Routine Description:
  328. Find length of variable binding value.
  329. Arguments:
  330. pAny - pointer to variable binding value.
  331. Return Values:
  332. Returns BERERR if unsuccessful.
  333. */
  334. {
  335. // determine syntax
  336. switch (pAny->asnType) {
  337. case ASN_OCTETSTRING:
  338. case ASN_IPADDRESS:
  339. case ASN_OPAQUE:
  340. return FindLenOctets(&pAny->asnValue.string);
  341. case ASN_OBJECTIDENTIFIER:
  342. return FindLenOid(&pAny->asnValue.object);
  343. case ASN_NULL:
  344. case SNMP_EXCEPTION_NOSUCHOBJECT:
  345. case SNMP_EXCEPTION_NOSUCHINSTANCE:
  346. case SNMP_EXCEPTION_ENDOFMIBVIEW:
  347. return (0);
  348. case ASN_INTEGER32:
  349. return FindLenInt(pAny->asnValue.number);
  350. case ASN_COUNTER32:
  351. case ASN_GAUGE32:
  352. case ASN_TIMETICKS:
  353. case ASN_UNSIGNED32:
  354. return FindLenUInt(pAny->asnValue.unsigned32);
  355. case ASN_COUNTER64:
  356. return FindLenCntr64(&pAny->asnValue.counter64);
  357. }
  358. return BERERR;
  359. }
  360. LONG
  361. FindLenAsnAnyEx(
  362. AsnAny * pAny
  363. )
  364. /*
  365. Routine Description:
  366. Find length of variable binding value (including type and lenlen).
  367. Arguments:
  368. pAny - pointer to variable binding value.
  369. Return Values:
  370. Returns BERERR if unsuccessful.
  371. */
  372. {
  373. // determine syntax
  374. switch (pAny->asnType) {
  375. case ASN_OCTETSTRING:
  376. case ASN_IPADDRESS:
  377. case ASN_OPAQUE:
  378. return FindLenOctetsEx(&pAny->asnValue.string);
  379. case ASN_OBJECTIDENTIFIER:
  380. return FindLenOidEx(&pAny->asnValue.object);
  381. case ASN_NULL:
  382. case SNMP_EXCEPTION_NOSUCHOBJECT:
  383. case SNMP_EXCEPTION_NOSUCHINSTANCE:
  384. case SNMP_EXCEPTION_ENDOFMIBVIEW:
  385. return (2);
  386. case ASN_INTEGER32:
  387. return FindLenIntEx(pAny->asnValue.number);
  388. case ASN_COUNTER32:
  389. case ASN_GAUGE32:
  390. case ASN_TIMETICKS:
  391. case ASN_UNSIGNED32:
  392. return FindLenUIntEx(pAny->asnValue.unsigned32);
  393. case ASN_COUNTER64:
  394. return FindLenCntr64Ex(&pAny->asnValue.counter64);
  395. }
  396. return BERERR;
  397. }
  398. LONG
  399. FindLenVarBind(
  400. SnmpVarBind * pVb
  401. )
  402. /*
  403. Routine Description:
  404. Find length of variable binding.
  405. Arguments:
  406. pVb - pointer to variable binding.
  407. Return Values:
  408. Returns BERERR if unsuccessful.
  409. */
  410. {
  411. LONG lLenLen;
  412. LONG lOidLen;
  413. LONG lValueLen;
  414. // determine length of name
  415. lOidLen = FindLenOidEx(&pVb->name);
  416. // determine length of value
  417. lValueLen = FindLenAsnAnyEx(&pVb->value);
  418. // return total size
  419. return ((lOidLen != BERERR) &&
  420. (lValueLen != BERERR))
  421. ? (lOidLen + lValueLen)
  422. : BERERR
  423. ;
  424. }
  425. LONG
  426. FindLenVarBindEx(
  427. SnmpVarBind * pVb
  428. )
  429. /*
  430. Routine Description:
  431. Find length of variable binding (including type and lenlen).
  432. Arguments:
  433. pVb - pointer to variable binding.
  434. Return Values:
  435. Returns BERERR if unsuccessful.
  436. */
  437. {
  438. LONG lLenLen;
  439. LONG lOidLen;
  440. LONG lValueLen;
  441. // determine length of name
  442. lOidLen = FindLenOidEx(&pVb->name);
  443. // determine length of value
  444. lValueLen = FindLenAsnAnyEx(&pVb->value);
  445. // determine length of varbind length
  446. lLenLen = DoLenLen(lOidLen + lValueLen);
  447. // return total size
  448. return ((lLenLen != BERERR) &&
  449. (lOidLen != BERERR) &&
  450. (lValueLen != BERERR))
  451. ? (lOidLen + lValueLen + lLenLen + 1)
  452. : BERERR
  453. ;
  454. }
  455. LONG
  456. FindLenVarBindList(
  457. SnmpVarBindList * pVbl
  458. )
  459. /*
  460. Routine Description:
  461. Find length of variable binding list.
  462. Arguments:
  463. pVbl - pointer to variable binding list.
  464. Return Values:
  465. Returns BERERR if unsuccessful.
  466. */
  467. {
  468. UINT i;
  469. LONG lVbLen = 0;
  470. LONG lVblLen = 0;
  471. // process each variable binding in the list
  472. for (i = 0; (lVbLen != BERERR) && (i < pVbl->len); i++) {
  473. // determine length of variable binding
  474. lVbLen = FindLenVarBindEx(&pVbl->list[i]);
  475. // add to total
  476. lVblLen += lVbLen;
  477. }
  478. // return total size
  479. return (lVbLen != BERERR)
  480. ? lVblLen
  481. : BERERR
  482. ;
  483. }
  484. LONG
  485. FindLenVarBindListEx(
  486. SnmpVarBindList * pVbl
  487. )
  488. /*
  489. Routine Description:
  490. Find length of variable binding list (including type and lenlen).
  491. Arguments:
  492. pVbl - pointer to variable binding list.
  493. Return Values:
  494. Returns BERERR if unsuccessful.
  495. */
  496. {
  497. UINT i;
  498. LONG lVbLen = 0;
  499. LONG lVblLen = 0;
  500. LONG lLenLen;
  501. // process each variable binding in the list
  502. for (i = 0; (lVbLen != BERERR) && (i < pVbl->len); i++) {
  503. // determine length of variable binding
  504. lVbLen = FindLenVarBindEx(&pVbl->list[i]);
  505. // add to total
  506. lVblLen += lVbLen;
  507. }
  508. // determine list length
  509. lLenLen = DoLenLen(lVblLen);
  510. // return total size
  511. return ((lVbLen != BERERR) &&
  512. (lLenLen != BERERR))
  513. ? (lVblLen + lLenLen + 1)
  514. : BERERR
  515. ;
  516. }
  517. VOID
  518. AddNull(
  519. LPBYTE * ppByte,
  520. INT nType
  521. )
  522. /*
  523. Routine Description:
  524. Adds null into stream.
  525. Arguments:
  526. ppByte - pointer to pointer to current stream.
  527. nType - exact syntax.
  528. Return Values:
  529. None.
  530. */
  531. {
  532. // encode actual syntax
  533. *(*ppByte)++ = (BYTE)(0xFF & nType);
  534. *(*ppByte)++ = 0x00;
  535. }
  536. VOID
  537. AddLen(
  538. LPBYTE * ppByte,
  539. LONG lLenLen,
  540. LONG lDataLen
  541. )
  542. /*
  543. Routine Description:
  544. Adds data length field to current stream.
  545. Arguments:
  546. ppByte - pointer to pointer to current stream.
  547. lLenLen - length of data length.
  548. lDataLen - actual data length.
  549. Return Values:
  550. None.
  551. */
  552. {
  553. LONG i;
  554. if (lLenLen == 1) {
  555. *(*ppByte)++ = (BYTE)lDataLen;
  556. } else {
  557. *(*ppByte)++ = (BYTE)(0x80 + lLenLen - 1);
  558. for (i = 1; i < lLenLen; i++) {
  559. *(*ppByte)++ = (BYTE)((lDataLen >>
  560. (8 * (lLenLen - i - 1))) & 0xFF);
  561. }
  562. }
  563. }
  564. LONG
  565. AddInt(
  566. LPBYTE * ppByte,
  567. INT nType,
  568. AsnInteger32 nInteger32
  569. )
  570. /*
  571. Routine Description:
  572. Adds integer to current stream.
  573. Arguments:
  574. ppByte - pointer to pointer to current stream.
  575. nType - exact syntax of integer.
  576. nInteger32 - actual data.
  577. Return Values:
  578. Returns BERERR if unsuccessful.
  579. */
  580. {
  581. LONG i;
  582. LONG lDataLen;
  583. LONG lLenLen;
  584. // determine length of integer
  585. lDataLen = FindLenInt(nInteger32);
  586. // lenlen
  587. lLenLen = 1;
  588. // encode nType of integer
  589. *(*ppByte)++ = (BYTE)(0xFF & nType);
  590. // encode length of integer
  591. AddLen(ppByte, lLenLen, lDataLen);
  592. // add encoded integer
  593. for (i = 0; i < lDataLen; i++) {
  594. *(*ppByte)++ = (BYTE)(nInteger32 >>
  595. (8 * ((lDataLen - 1) - i) & 0xFF));
  596. }
  597. return (0);
  598. }
  599. LONG
  600. AddUInt(
  601. LPBYTE * ppByte,
  602. INT nType,
  603. AsnUnsigned32 nUnsigned32
  604. )
  605. /*
  606. Routine Description:
  607. Adds unsigned integer to current stream.
  608. Arguments:
  609. ppByte - pointer to pointer to current stream.
  610. nType - exact syntax of integer.
  611. nUnsigned32 - actual data.
  612. Return Values:
  613. Returns BERERR if unsuccessful.
  614. */
  615. {
  616. LONG i;
  617. LONG lDataLen;
  618. LONG lLenLen;
  619. // determine length of integer
  620. lDataLen = FindLenUInt(nUnsigned32);
  621. // < 127 octets
  622. lLenLen = 1;
  623. // encode actual syntax
  624. *(*ppByte)++ = (BYTE)(0xFF & nType);
  625. // encode data length
  626. AddLen(ppByte, lLenLen, lDataLen);
  627. // analyze length
  628. if (lDataLen == 5) {
  629. // put 00 in first octet
  630. *(*ppByte)++ = (BYTE)0;
  631. // encode unsigned integer
  632. for (i = 1; i < lDataLen; i++) {
  633. *(*ppByte)++ = (BYTE)(nUnsigned32 >>
  634. (8 * ((lDataLen - 1) - i) & 0xFF));
  635. }
  636. } else {
  637. // encode unsigned integer
  638. for (i = 0; i < lDataLen; i++) {
  639. *(*ppByte)++ = (BYTE)(nUnsigned32 >>
  640. (8 * ((lDataLen - 1) - i) & 0xFF));
  641. }
  642. }
  643. return (0);
  644. }
  645. LONG
  646. AddCntr64(
  647. LPBYTE * ppByte,
  648. INT nType,
  649. AsnCounter64 * pCntr64
  650. )
  651. /*
  652. Routine Description:
  653. Adds 64-bit counter to current stream.
  654. Arguments:
  655. ppByte - pointer to pointer to current stream.
  656. nType - exact syntax of counter.
  657. pCntr64 - actual data.
  658. Return Values:
  659. Returns BERERR if unsuccessful.
  660. */
  661. {
  662. LONG i;
  663. LONG lDataLen;
  664. LONG lLenLen;
  665. // determine length of counter64
  666. lDataLen = FindLenCntr64(pCntr64);
  667. // < 127 octets
  668. lLenLen = 1;
  669. // encode actual syntax
  670. *(*ppByte)++ = (BYTE)(0xFF & nType);
  671. // encode data length
  672. AddLen(ppByte, lLenLen, lDataLen);
  673. // adjust lDataLen
  674. if (lDataLen == 9) {
  675. // put 00 in first octet
  676. *(*ppByte)++ = (BYTE)0;
  677. lDataLen--;
  678. }
  679. // encode counter data
  680. for (i = lDataLen; i > 4; i--) {
  681. *(*ppByte)++ = (BYTE)(pCntr64->HighPart >>
  682. (8 * (i - 5) & 0xFF));
  683. }
  684. for (; i > 0; i--) {
  685. *(*ppByte)++ = (BYTE)(pCntr64->LowPart >>
  686. (8 * (i - 1) & 0xFF));
  687. }
  688. return (0);
  689. }
  690. LONG
  691. AddOctets(
  692. LPBYTE * ppByte,
  693. INT nType,
  694. AsnOctetString * pOctets
  695. )
  696. /*
  697. Routine Description:
  698. Adds octet string to current stream.
  699. Arguments:
  700. ppByte - pointer to pointer to current stream.
  701. nType - exact syntax of string.
  702. pOctets - actual data.
  703. Return Values:
  704. Returns BERERR if unsuccessful.
  705. */
  706. {
  707. UINT i;
  708. LONG lLenLen;
  709. LONG lDataLen;
  710. // determine oid length
  711. if ((lDataLen = FindLenOctets(pOctets)) == BERERR)
  712. return BERERR;
  713. // calculate octet string length
  714. if ((lLenLen = DoLenLen(lDataLen)) == BERERR)
  715. return BERERR;
  716. // encode actual syntax
  717. *(*ppByte)++ = (BYTE)(0xFF & nType);
  718. // encode octet string length
  719. AddLen(ppByte, lLenLen, lDataLen);
  720. // usless copy avoided
  721. if (*ppByte != pOctets->stream)
  722. {
  723. // encode actual octets
  724. for (i = 0; i < pOctets->length; i++)
  725. *(*ppByte)++ = pOctets->stream[i];
  726. }
  727. else
  728. {
  729. (*ppByte) += pOctets->length;
  730. }
  731. return (0);
  732. }
  733. LONG
  734. AddOid(
  735. LPBYTE * ppByte,
  736. INT nType,
  737. AsnObjectIdentifier * pOid
  738. )
  739. /*
  740. Routine Description:
  741. Adds object identifier to current stream.
  742. Arguments:
  743. ppByte - pointer to pointer to current stream.
  744. nType - exact syntax of object identifier.
  745. pOid - pointer to object identifier.
  746. Return Values:
  747. Returns BERERR if unsuccessful.
  748. */
  749. {
  750. UINT i;
  751. LONG lLenLen = 0;
  752. LONG lDataLen;
  753. // determine oid length
  754. if ((lDataLen = FindLenOid(pOid)) == BERERR)
  755. return BERERR;
  756. // calculate number of bytes required for length
  757. if ((lLenLen = DoLenLen(lDataLen)) == BERERR)
  758. return BERERR;
  759. // add syntax to stream
  760. *(*ppByte)++ = (BYTE)(0xFF & nType);
  761. // add object identifier length
  762. AddLen(ppByte, lLenLen, lDataLen);
  763. // add first subid
  764. if (pOid->idLength < 2)
  765. *(*ppByte)++ = (BYTE)(pOid->ids[0] * 40);
  766. else
  767. *(*ppByte)++ = (BYTE)((pOid->ids[0] * 40) + pOid->ids[1]);
  768. // walk remaining subidentifiers
  769. for (i = 2; i < pOid->idLength; i++) {
  770. if (pOid->ids[i] < 0x80) {
  771. // 0 - 0x7f
  772. *(*ppByte)++ = (BYTE)pOid->ids[i];
  773. } else if (pOid->ids[i] < 0x4000) {
  774. // 0x80 - 0x3fff
  775. *(*ppByte)++ = (BYTE)
  776. (((pOid->ids[i]) >> 7) | 0x80); // set high bit
  777. *(*ppByte)++ = (BYTE)(pOid->ids[i] & 0x7f);
  778. } else if (pOid->ids[i] < 0x200000) {
  779. // 0x4000 - 0x1FFFFF
  780. *(*ppByte)++ = (BYTE)
  781. (((pOid->ids[i]) >> 14) | 0x80); // set high bit
  782. *(*ppByte)++ = (BYTE)
  783. (((pOid->ids[i]) >> 7) | 0x80); // set high bit
  784. *(*ppByte)++ = (BYTE)(pOid->ids[i] & 0x7f);
  785. } else if (pOid->ids[i] < 0x10000000) {
  786. // 0x200000 - 0xFFfffff
  787. *(*ppByte)++ = (BYTE)
  788. (((pOid->ids[i]) >> 21) | 0x80); // set high bit
  789. *(*ppByte)++ = (BYTE)
  790. (((pOid->ids[i]) >> 14) | 0x80); // set high bit
  791. *(*ppByte)++ = (BYTE)
  792. (((pOid->ids[i]) >> 7) | 0x80); // set high bit
  793. *(*ppByte)++ = (BYTE)(pOid->ids[i] & 0x7f);
  794. } else {
  795. *(*ppByte)++ = (BYTE)
  796. (((pOid->ids[i]) >> 28) | 0x80); // set high bit
  797. *(*ppByte)++ = (BYTE)
  798. (((pOid->ids[i]) >> 21) | 0x80); // set high bit
  799. *(*ppByte)++ = (BYTE)
  800. (((pOid->ids[i]) >> 14) | 0x80); // set high bit
  801. *(*ppByte)++ = (BYTE)
  802. (((pOid->ids[i]) >> 7) | 0x80); // set high bit
  803. *(*ppByte)++ = (BYTE)(pOid->ids[i] & 0x7f);
  804. }
  805. }
  806. return (0);
  807. }
  808. LONG
  809. AddAsnAny(
  810. LPBYTE * ppByte,
  811. AsnAny * pAny
  812. )
  813. /*
  814. Routine Description:
  815. Adds variable binding value to current stream.
  816. Arguments:
  817. ppByte - pointer to pointer to current stream.
  818. pAny - variable binding value.
  819. Return Values:
  820. Returns BERERR if unsuccessful.
  821. */
  822. {
  823. // determine syntax
  824. switch (pAny->asnType) {
  825. case ASN_COUNTER32:
  826. case ASN_GAUGE32:
  827. case ASN_TIMETICKS:
  828. case ASN_UNSIGNED32:
  829. return AddUInt(
  830. ppByte,
  831. (INT)pAny->asnType,
  832. pAny->asnValue.unsigned32
  833. );
  834. case ASN_INTEGER32:
  835. return AddInt(
  836. ppByte,
  837. (INT)pAny->asnType,
  838. pAny->asnValue.number
  839. );
  840. case ASN_OBJECTIDENTIFIER:
  841. return AddOid(
  842. ppByte,
  843. (INT)pAny->asnType,
  844. &pAny->asnValue.object
  845. );
  846. case ASN_COUNTER64:
  847. return AddCntr64(
  848. ppByte,
  849. (INT)pAny->asnType,
  850. &pAny->asnValue.counter64
  851. );
  852. case ASN_OCTETSTRING:
  853. case ASN_IPADDRESS:
  854. case ASN_OPAQUE:
  855. return AddOctets(
  856. ppByte,
  857. (INT)pAny->asnType,
  858. &pAny->asnValue.string
  859. );
  860. case ASN_NULL:
  861. case SNMP_EXCEPTION_NOSUCHOBJECT:
  862. case SNMP_EXCEPTION_NOSUCHINSTANCE:
  863. case SNMP_EXCEPTION_ENDOFMIBVIEW:
  864. AddNull(ppByte, (INT)pAny->asnType);
  865. return (0);
  866. }
  867. return BERERR;
  868. }
  869. LONG
  870. AddVarBind(
  871. LPBYTE * ppByte,
  872. SnmpVarBind * pVb
  873. )
  874. /*
  875. Routine Description:
  876. Adds variable binding to current stream.
  877. Arguments:
  878. ppByte - pointer to pointer to current stream.
  879. pVb - pointer to variable binding.
  880. Return Values:
  881. Returns BERERR if unsuccessful.
  882. */
  883. {
  884. LONG lLenLen;
  885. LONG lDataLen;
  886. // determine actual length of varbind data
  887. if ((lDataLen = FindLenVarBind(pVb)) == BERERR)
  888. return BERERR;
  889. // determine length of varbind data length
  890. if ((lLenLen = DoLenLen(lDataLen)) == BERERR)
  891. return BERERR;
  892. // encode as sequence
  893. *(*ppByte)++ = ASN_SEQUENCE;
  894. // encode data length
  895. AddLen(ppByte, lLenLen, lDataLen);
  896. // encode variable binding name
  897. if (AddOid(ppByte, ASN_OBJECTIDENTIFIER, &pVb->name) == BERERR)
  898. return BERERR;
  899. // encode variable binding value
  900. if (AddAsnAny(ppByte, &pVb->value) == BERERR)
  901. return BERERR;
  902. return (0);
  903. }
  904. LONG
  905. AddVarBindList(
  906. LPBYTE * ppByte,
  907. SnmpVarBindList * pVbl
  908. )
  909. /*
  910. Routine Description:
  911. Adds variable binding list to current stream.
  912. Arguments:
  913. ppByte - pointer to pointer to current stream.
  914. pVbl - pointer to variable binding list.
  915. Return Values:
  916. Returns BERERR if unsuccessful.
  917. */
  918. {
  919. UINT i;
  920. // add each variable binding
  921. for (i = 0; i < pVbl->len; i++) {
  922. if (AddVarBind(ppByte, &pVbl->list[i]) == BERERR)
  923. return BERERR;
  924. }
  925. return (0);
  926. }
  927. LONG
  928. ParseLength(
  929. LPBYTE * ppByte,
  930. LPBYTE pLastByte
  931. )
  932. /*
  933. Routine Description:
  934. Parse length from current stream.
  935. Arguments:
  936. ppByte - pointer to pointer to current stream.
  937. pLastByte - pointer to end of current stream.
  938. Return Values:
  939. Returns BERERR if unsuccessful.
  940. */
  941. {
  942. LONG i;
  943. LONG lLenLen;
  944. LONG lDataLen;
  945. lDataLen = (LONG)*(*ppByte)++;
  946. if (lDataLen < 0x80)
  947. return (lDataLen);
  948. // check for long form
  949. lLenLen = lDataLen & 0x7f;
  950. // validate long form
  951. if ((lLenLen > 4) || (lLenLen < 1))
  952. return BERERR;
  953. lDataLen = 0L;
  954. for (i = 0; i < lLenLen; i++) {
  955. lDataLen = (lDataLen << 8) + *(*ppByte)++;
  956. }
  957. if (*ppByte > pLastByte)
  958. return BERERR;
  959. return (lDataLen);
  960. }
  961. LONG
  962. ParseType(
  963. LPBYTE * ppByte,
  964. LPBYTE pLastByte
  965. )
  966. /*
  967. Routine Description:
  968. Parse type from current stream.
  969. Arguments:
  970. ppByte - pointer to pointer to current stream.
  971. pLastByte - pointer to end of current stream.
  972. Return Values:
  973. Returns BERERR if unsuccessful.
  974. */
  975. {
  976. SHORT nType = *(*ppByte)++;
  977. if (*ppByte > pLastByte)
  978. return BERERR;
  979. switch (nType) {
  980. case ASN_INTEGER32:
  981. case ASN_OCTETSTRING:
  982. case ASN_OBJECTIDENTIFIER:
  983. case ASN_SEQUENCE:
  984. case ASN_IPADDRESS:
  985. case ASN_COUNTER32:
  986. case ASN_GAUGE32:
  987. case ASN_TIMETICKS:
  988. case ASN_OPAQUE:
  989. case ASN_UNSIGNED32:
  990. case ASN_COUNTER64:
  991. case ASN_NULL:
  992. case SNMP_EXCEPTION_NOSUCHOBJECT:
  993. case SNMP_EXCEPTION_NOSUCHINSTANCE:
  994. case SNMP_EXCEPTION_ENDOFMIBVIEW:
  995. case SNMP_PDU_GET:
  996. case SNMP_PDU_GETNEXT:
  997. case SNMP_PDU_RESPONSE:
  998. case SNMP_PDU_SET:
  999. case SNMP_PDU_V1TRAP:
  1000. case SNMP_PDU_GETBULK:
  1001. case SNMP_PDU_INFORM:
  1002. case SNMP_PDU_TRAP:
  1003. break;
  1004. default:
  1005. nType = BERERR;
  1006. break;
  1007. }
  1008. return (LONG)(SHORT)(nType);
  1009. }
  1010. BOOL
  1011. ParseNull(
  1012. LPBYTE * ppByte,
  1013. LPBYTE pLastByte
  1014. )
  1015. /*
  1016. Routine Description:
  1017. Parse null from current stream.
  1018. Arguments:
  1019. ppByte - pointer to pointer to current stream.
  1020. pLastByte - pointer to end of current stream.
  1021. Return Values:
  1022. Returns FALSE if unsuccessful.
  1023. */
  1024. {
  1025. LONG lDataLen;
  1026. if (!(ParseType(ppByte, pLastByte)))
  1027. return (FALSE);
  1028. if ((lDataLen = ParseLength(ppByte, pLastByte)) == BERERR)
  1029. return (FALSE);
  1030. if (lDataLen != 0)
  1031. return (FALSE);
  1032. if (*ppByte > pLastByte)
  1033. return (FALSE);
  1034. return (TRUE);
  1035. }
  1036. BOOL
  1037. ParseSequence(
  1038. LPBYTE * ppByte,
  1039. LPBYTE pLastByte,
  1040. LONG * plDataLen
  1041. )
  1042. /*
  1043. Routine Description:
  1044. Parse sequence from current stream.
  1045. Arguments:
  1046. ppByte - pointer to pointer to current stream.
  1047. pLastByte - pointer to end of current stream.
  1048. plDataLen - pointer to receive sequence length.
  1049. Return Values:
  1050. Returns FALSE if unsuccessful.
  1051. */
  1052. {
  1053. LONG lDataLen;
  1054. if ((ParseType(ppByte, pLastByte)) != ASN_SEQUENCE)
  1055. return (FALSE);
  1056. if ((lDataLen = ParseLength(ppByte, pLastByte)) == BERERR)
  1057. return (FALSE);
  1058. if (*ppByte > pLastByte)
  1059. return (FALSE);
  1060. if (plDataLen)
  1061. *plDataLen = lDataLen;
  1062. return (TRUE);
  1063. }
  1064. BOOL
  1065. ParseInt(
  1066. LPBYTE * ppByte,
  1067. LPBYTE pLastByte,
  1068. AsnInteger32 * pInteger32
  1069. )
  1070. /*
  1071. Routine Description:
  1072. Parse integer from current stream.
  1073. Arguments:
  1074. ppByte - pointer to pointer to current stream.
  1075. pLastByte - pointer to end of current stream.
  1076. pInteger32 - pointer to receive integer.
  1077. Return Values:
  1078. Returns FALSE if unsuccessful.
  1079. */
  1080. {
  1081. LONG i;
  1082. LONG lSign;
  1083. LONG lDataLen;
  1084. if (ParseType(ppByte, pLastByte) == BERERR)
  1085. return (FALSE);
  1086. if ((lDataLen = ParseLength(ppByte, pLastByte)) == BERERR)
  1087. return (FALSE);
  1088. if (lDataLen > 4)
  1089. return (FALSE);
  1090. lSign = ((*(*ppByte) & 0x80) == 0x00) ? 0x00 : 0xFF;
  1091. *pInteger32 = 0;
  1092. for (i = 0; i < lDataLen; i++)
  1093. *pInteger32 = (*pInteger32 << 8) + (UINT)*(*ppByte)++;
  1094. // sign-extend upper bits
  1095. for (i = lDataLen; i < 4; i++)
  1096. *pInteger32 = *pInteger32 + (lSign << i * 8);
  1097. if (*ppByte > pLastByte)
  1098. return (FALSE);
  1099. return (TRUE);
  1100. }
  1101. BOOL
  1102. ParseUInt(
  1103. LPBYTE * ppByte,
  1104. LPBYTE pLastByte,
  1105. AsnUnsigned32 * pUnsigned32
  1106. )
  1107. /*
  1108. Routine Description:
  1109. Parse unsigned integer from current stream.
  1110. Arguments:
  1111. ppByte - pointer to pointer to current stream.
  1112. pLastByte - pointer to end of current stream.
  1113. pUnsigned32 - pointer to receive integer.
  1114. Return Values:
  1115. Returns FALSE if unsuccessful.
  1116. */
  1117. {
  1118. LONG i;
  1119. LONG lDataLen;
  1120. if (ParseType(ppByte, pLastByte) == BERERR)
  1121. return (FALSE);
  1122. if ((lDataLen = ParseLength(ppByte, pLastByte)) == BERERR)
  1123. return (FALSE);
  1124. if ((lDataLen > 5) || ((lDataLen > 4) && (*(*ppByte) != 0x00)))
  1125. return (FALSE);
  1126. // leading null octet?
  1127. if (*(*ppByte) == 0x00) {
  1128. (*ppByte)++; // if so, skip it
  1129. lDataLen--; // and don't count it
  1130. }
  1131. *pUnsigned32 = 0;
  1132. for (i = 0; i < lDataLen; i++)
  1133. *pUnsigned32 = (*pUnsigned32 << 8) + (UINT)*(*ppByte)++;
  1134. if (*ppByte > pLastByte)
  1135. return (FALSE);
  1136. return (TRUE);
  1137. }
  1138. BOOL
  1139. ParseCntr64(
  1140. LPBYTE * ppByte,
  1141. LPBYTE pLastByte,
  1142. AsnCounter64 * pCntr64
  1143. )
  1144. /*
  1145. Routine Description:
  1146. Parse 64-bit counter from current stream.
  1147. Arguments:
  1148. ppByte - pointer to pointer to current stream.
  1149. pLastByte - pointer to end of current stream.
  1150. pCntr64 - pointer to receive counter.
  1151. Return Values:
  1152. Returns FALSE if unsuccessful.
  1153. */
  1154. {
  1155. LONG i;
  1156. LONG lDataLen;
  1157. LONG nType;
  1158. // initialize
  1159. pCntr64->HighPart = 0L;
  1160. pCntr64->LowPart = 0L;
  1161. if ((nType = ParseType(ppByte, pLastByte)) == BERERR)
  1162. return (FALSE);
  1163. if (nType != ASN_COUNTER64)
  1164. return (FALSE);
  1165. if ((lDataLen = ParseLength(ppByte, pLastByte)) == BERERR)
  1166. return (FALSE);
  1167. if ((lDataLen > 9) || ((lDataLen > 8) && (*(*ppByte) != 0x00)))
  1168. return (FALSE);
  1169. // leading null octet?
  1170. if (*(*ppByte) == 0x00) {
  1171. (*ppByte)++; // if so, skip it
  1172. lDataLen--; // and don't count it
  1173. }
  1174. for (i = 0; i < lDataLen; i++) {
  1175. pCntr64->HighPart = (pCntr64->HighPart << 8) +
  1176. (pCntr64->LowPart >> 24);
  1177. pCntr64->LowPart = (pCntr64->LowPart << 8) +
  1178. (unsigned long) *(*ppByte)++;
  1179. }
  1180. if (*ppByte > pLastByte)
  1181. return (FALSE);
  1182. return TRUE;
  1183. }
  1184. BOOL
  1185. ParseOctets(
  1186. LPBYTE * ppByte,
  1187. LPBYTE pLastByte,
  1188. AsnOctetString * pOctets
  1189. )
  1190. /*
  1191. Routine Description:
  1192. Parse octet string from current stream.
  1193. Arguments:
  1194. ppByte - pointer to pointer to current stream.
  1195. pLastByte - pointer to end of current stream.
  1196. pOctets - pointer to receive string.
  1197. Return Values:
  1198. Returns FALSE if unsuccessful.
  1199. */
  1200. {
  1201. LONG errCode;
  1202. // initialize
  1203. pOctets->length = 0;
  1204. pOctets->stream = NULL;
  1205. pOctets->dynamic = FALSE;
  1206. if (ParseType(ppByte, pLastByte) == BERERR)
  1207. return (FALSE);
  1208. // make sure no conversion to UINT is done before testing
  1209. // (pOctets->length is UINT)
  1210. if ((errCode = ParseLength(ppByte, pLastByte)) == BERERR)
  1211. return (FALSE);
  1212. pOctets->length = (UINT)errCode;
  1213. // avoid wrapping around on machines with 4-byte pointers
  1214. if ((((*ppByte) + pOctets->length) < *ppByte) ||
  1215. ((*ppByte) + pOctets->length) > pLastByte)
  1216. return (FALSE);
  1217. // validate length
  1218. if (pOctets->length) {
  1219. // point into buffer
  1220. pOctets->stream = *ppByte; // WARNING! WARNING!
  1221. }
  1222. *ppByte += pOctets->length;
  1223. return (TRUE);
  1224. }
  1225. BOOL
  1226. ParseOid(
  1227. LPBYTE * ppByte,
  1228. LPBYTE pLastByte,
  1229. AsnObjectIdentifier * pOid
  1230. )
  1231. /*
  1232. Routine Description:
  1233. Parse object identifier from current stream.
  1234. Arguments:
  1235. ppByte - pointer to pointer to current stream.
  1236. pLastByte - pointer to end of current stream.
  1237. pOid - pointer to receive oid.
  1238. Return Values:
  1239. Returns FALSE if unsuccessful.
  1240. */
  1241. {
  1242. LONG i;
  1243. LONG lDataLen;
  1244. LONG nType;
  1245. // initialize
  1246. pOid->idLength = 0;
  1247. pOid->ids = NULL;
  1248. if ((nType = ParseType(ppByte, pLastByte)) == BERERR)
  1249. return (FALSE);
  1250. if (nType != ASN_OBJECTIDENTIFIER)
  1251. return (FALSE);
  1252. if ((lDataLen = ParseLength(ppByte, pLastByte)) == BERERR)
  1253. return (FALSE);
  1254. if (lDataLen <= 0) //--ft 03/02/98 removed trailing "|| lDataLen > SNMP_MAX_OID_LEN)"
  1255. { // check is done in the while loop below
  1256. SNMPDBG((
  1257. SNMP_LOG_ERROR,
  1258. "SNMP: SVC: ParseOid: lDataLen <= 0, lDataLen=%d.\n",
  1259. lDataLen
  1260. ));
  1261. return (FALSE);
  1262. }
  1263. // BUG# 486089
  1264. // the ((lDataLen + 2) * sizeof(UINT)) expression might cause overflow in
  1265. // SnmpUtilMemAlloc below. adding one more check to limit its max. value.
  1266. if ( lDataLen > (pLastByte - (*ppByte)) )
  1267. {
  1268. SNMPDBG((
  1269. SNMP_LOG_ERROR,
  1270. "SNMP: SVC: ParseOid: invalid lDataLen=%d, pLastByte=%p, *ppByte=%p.\n",
  1271. lDataLen, pLastByte, *ppByte
  1272. ));
  1273. return (FALSE);
  1274. }
  1275. pOid->ids = SnmpUtilMemAlloc((DWORD)((lDataLen + 2) * sizeof(UINT)));
  1276. if (pOid->ids == NULL)
  1277. return (FALSE);
  1278. // pOid->ids array space is pre-zero'd via SnmpUtilMemAlloc()
  1279. while (lDataLen && (pOid->idLength < SNMP_MAX_OID_LEN))
  1280. {
  1281. pOid->ids[pOid->idLength] =
  1282. (pOid->ids[pOid->idLength] << 7) | (*(*ppByte) & 0x7F);
  1283. if ((*(*ppByte)++ & 0x80) == 0)
  1284. { // on the last octet of this sub-id
  1285. if (pOid->idLength == 0) // check for first sub-id
  1286. { // ASN.1/BER packs two into it
  1287. pOid->ids[1] = pOid->ids[0];
  1288. pOid->ids[0] /= 40;
  1289. if (pOid->ids[0] > 2)
  1290. pOid->ids[0] = 2;
  1291. pOid->ids[1] -= (pOid->ids[0] * 40);
  1292. pOid->idLength++; // extra bump
  1293. }
  1294. pOid->idLength++; // increment the count on sub-id
  1295. }
  1296. lDataLen--; // note: *ppByte is incremented in the if statement above
  1297. } // end_while (lDataLen)
  1298. // BUG 506192
  1299. // Invalid OID BER of the form like "06 07 FF FF FF FF FF FF FF"
  1300. // causes pOid->idLength becomes 0. Each subidentifier should be
  1301. // encoded as a non-negative integer using as few 7-bit blocks as possible.
  1302. // The blocks are packed in octets with the first bit of each octet equal
  1303. // to 1 except for the last octet of each subidentifier. The example above
  1304. // does not have the last octet. Added the (0 == pOid->idLength) test below.
  1305. if (lDataLen || (0 == pOid->idLength))
  1306. {
  1307. // the above while loop is terminated without finishing the parsing of the stream
  1308. SnmpUtilMemFree(pOid->ids);
  1309. pOid->ids = NULL;
  1310. pOid->idLength = 0;
  1311. return (FALSE);
  1312. }
  1313. return (TRUE);
  1314. }
  1315. BOOL
  1316. ParseAsnAny(
  1317. LPBYTE * ppByte,
  1318. LPBYTE pLastByte,
  1319. AsnAny * pAny
  1320. )
  1321. /*
  1322. Routine Description:
  1323. Parse variable binding value from current stream.
  1324. Arguments:
  1325. ppByte - pointer to pointer to current stream.
  1326. pLastByte - pointer to end of current stream.
  1327. pAny - pointer to variable binding value.
  1328. Return Values:
  1329. Returns FALSE if unsuccessful.
  1330. */
  1331. {
  1332. // determine asn type
  1333. switch (pAny->asnType) {
  1334. case ASN_COUNTER32:
  1335. case ASN_GAUGE32:
  1336. case ASN_TIMETICKS:
  1337. case ASN_UNSIGNED32:
  1338. return ParseUInt(
  1339. ppByte,
  1340. pLastByte,
  1341. &pAny->asnValue.unsigned32
  1342. );
  1343. case ASN_INTEGER32:
  1344. return ParseInt(
  1345. ppByte,
  1346. pLastByte,
  1347. &pAny->asnValue.number
  1348. );
  1349. case ASN_OBJECTIDENTIFIER:
  1350. return ParseOid(
  1351. ppByte,
  1352. pLastByte,
  1353. &pAny->asnValue.object
  1354. );
  1355. case ASN_COUNTER64:
  1356. return ParseCntr64(
  1357. ppByte,
  1358. pLastByte,
  1359. &pAny->asnValue.counter64
  1360. );
  1361. case ASN_OCTETSTRING:
  1362. case ASN_IPADDRESS:
  1363. case ASN_OPAQUE:
  1364. return ParseOctets(
  1365. ppByte,
  1366. pLastByte,
  1367. &pAny->asnValue.string
  1368. );
  1369. case ASN_NULL:
  1370. case SNMP_EXCEPTION_NOSUCHOBJECT:
  1371. case SNMP_EXCEPTION_NOSUCHINSTANCE:
  1372. case SNMP_EXCEPTION_ENDOFMIBVIEW:
  1373. return ParseNull(ppByte, pLastByte);
  1374. }
  1375. return (FALSE);
  1376. }
  1377. BOOL
  1378. ParseVarBind(
  1379. LPBYTE * ppByte,
  1380. LPBYTE pLastByte,
  1381. SnmpVarBind * pVb
  1382. )
  1383. /*
  1384. Routine Description:
  1385. Parse variable binding from current stream.
  1386. Arguments:
  1387. ppByte - pointer to pointer to current stream.
  1388. pLastByte - pointer to end of current stream.
  1389. pVb - pointer to variable binding.
  1390. Return Values:
  1391. Returns FALSE if unsuccessful.
  1392. */
  1393. {
  1394. if (!(ParseSequence(ppByte, pLastByte, NULL)))
  1395. return (FALSE);
  1396. if (!(ParseOid(ppByte, pLastByte, &pVb->name)))
  1397. return (FALSE);
  1398. pVb->value.asnType = (UINT)*(*ppByte);
  1399. if (!(ParseAsnAny(ppByte, pLastByte, &pVb->value)))
  1400. {
  1401. // free memory allocated by ParseOid
  1402. SnmpUtilOidFree(&pVb->name);
  1403. return (FALSE);
  1404. }
  1405. return TRUE;
  1406. }
  1407. BOOL
  1408. ParseVarBindList(
  1409. LPBYTE * ppByte,
  1410. LPBYTE pLastByte,
  1411. SnmpVarBindList * pVbl
  1412. )
  1413. /*
  1414. Routine Description:
  1415. Parse variable binding from current stream.
  1416. Arguments:
  1417. ppByte - pointer to pointer to current stream.
  1418. pLastByte - pointer to end of current stream.
  1419. pVbl - pointer to variable binding list.
  1420. Return Values:
  1421. Returns FALSE if unsuccessful.
  1422. */
  1423. {
  1424. SnmpVarBind Vb;
  1425. SnmpVarBind * pVb = NULL;
  1426. // initialize
  1427. pVbl->list = NULL;
  1428. pVbl->len = 0;
  1429. // loop while data is left
  1430. while (*ppByte < pLastByte) {
  1431. if (!(ParseVarBind(ppByte, pLastByte, &Vb)))
  1432. return (FALSE);
  1433. // copy pointer
  1434. pVb = pVbl->list;
  1435. // attempt to allocate new variable binding
  1436. pVb = SnmpUtilMemReAlloc(pVb, (pVbl->len + 1) * sizeof(SnmpVarBind));
  1437. // validate
  1438. if (pVb == NULL)
  1439. {
  1440. SnmpUtilVarBindFree(&Vb);
  1441. return FALSE;
  1442. }
  1443. // update varbind
  1444. pVb[pVbl->len] = Vb;
  1445. // update list
  1446. pVbl->list = pVb;
  1447. pVbl->len++;
  1448. }
  1449. return TRUE;
  1450. }
  1451. ///////////////////////////////////////////////////////////////////////////////
  1452. // //
  1453. // Public procedures (based on snmp\manager\winsnmp\dll\wsnmp_bn.c) //
  1454. // //
  1455. ///////////////////////////////////////////////////////////////////////////////
  1456. typedef UNALIGNED LONG* PUALONG;
  1457. BOOL
  1458. BuildMessage(
  1459. AsnInteger32 nVersion,
  1460. AsnOctetString * pCommunity,
  1461. PSNMP_PDU pPdu,
  1462. PBYTE pMessage,
  1463. PDWORD pMessageSize
  1464. )
  1465. /*
  1466. Routine Description:
  1467. Builds outgoing SNMP PDU based on structure.
  1468. Arguments:
  1469. nVersion - SNMP version.
  1470. pCommunity - pointer to community string.
  1471. pPdu - pointer to PDU data structure.
  1472. pMessage - pointer to buffer in which to build message.
  1473. pMessageSize - pointer to receive size of message.
  1474. Return Values:
  1475. Returns true if successful.
  1476. */
  1477. {
  1478. LONG nVbDataLength;
  1479. LONG nVbLenLength;
  1480. LONG nVbTotalLength;
  1481. LONG nPduDataLength;
  1482. LONG nPduLenLength;
  1483. LONG nPduTotalLength;
  1484. LONG nMsgDataLength;
  1485. LONG nMsgLenLength;
  1486. LONG nMsgTotalLength;
  1487. LONG nMsgAvailLength;
  1488. LONG nTmpDataLength;
  1489. LPBYTE tmpPtr = pMessage;
  1490. // determine bytes available
  1491. nMsgAvailLength = *pMessageSize;
  1492. // find length of variable bindings list
  1493. if ((nVbDataLength = FindLenVarBindList(&pPdu->Vbl)) == BERERR)
  1494. return FALSE;
  1495. // find length of length of variable bindings
  1496. if ((nVbLenLength = DoLenLen(nVbDataLength)) == BERERR)
  1497. return FALSE;
  1498. // calculate total bytes required to encode varbinds
  1499. nVbTotalLength = 1 + nVbLenLength + nVbDataLength;
  1500. // determine pdu nType
  1501. switch (pPdu->nType) {
  1502. case SNMP_PDU_GET:
  1503. case SNMP_PDU_GETNEXT:
  1504. case SNMP_PDU_RESPONSE:
  1505. case SNMP_PDU_SET:
  1506. case SNMP_PDU_GETBULK:
  1507. case SNMP_PDU_INFORM:
  1508. case SNMP_PDU_TRAP:
  1509. // calculate bytes required to encode pdu entries
  1510. nPduDataLength = FindLenIntEx(pPdu->Pdu.NormPdu.nRequestId)
  1511. + FindLenIntEx(pPdu->Pdu.NormPdu.nErrorStatus)
  1512. + FindLenIntEx(pPdu->Pdu.NormPdu.nErrorIndex)
  1513. + nVbTotalLength;
  1514. break;
  1515. case SNMP_PDU_V1TRAP:
  1516. // calculate bytes required to encode pdu entries
  1517. nPduDataLength = FindLenIntEx(pPdu->Pdu.TrapPdu.nGenericTrap)
  1518. + FindLenIntEx(pPdu->Pdu.TrapPdu.nSpecificTrap)
  1519. + FindLenUIntEx(pPdu->Pdu.TrapPdu.nTimeticks)
  1520. + nVbTotalLength;
  1521. // find oid length
  1522. if ((nTmpDataLength =
  1523. FindLenOidEx(&pPdu->Pdu.TrapPdu.EnterpriseOid)) == BERERR)
  1524. return FALSE;
  1525. // add EnterpriseOid oid length
  1526. nPduDataLength += nTmpDataLength;
  1527. // find address length
  1528. if ((nTmpDataLength =
  1529. FindLenOctetsEx(&pPdu->Pdu.TrapPdu.AgentAddr)) == BERERR)
  1530. return FALSE;
  1531. // add agent address length
  1532. nPduDataLength += nTmpDataLength;
  1533. break;
  1534. default:
  1535. return FALSE;
  1536. }
  1537. // find length of pdu length
  1538. if ((nPduLenLength = DoLenLen(nPduDataLength)) == BERERR)
  1539. return FALSE;
  1540. // calculate total bytes required to encode pdu
  1541. nPduTotalLength = 1 + nPduLenLength + nPduDataLength;
  1542. // find length of message data
  1543. nMsgDataLength = FindLenUIntEx(nVersion)
  1544. + FindLenOctetsEx(pCommunity)
  1545. + nPduTotalLength;
  1546. // find length of message data length
  1547. nMsgLenLength = DoLenLen(nMsgDataLength);
  1548. // calculate total bytes required to encode message
  1549. nMsgTotalLength = 1 + nMsgLenLength + nMsgDataLength;
  1550. // record bytes required
  1551. *pMessageSize = nMsgTotalLength;
  1552. // make sure message fits in buffer
  1553. if (nMsgTotalLength <= nMsgAvailLength) {
  1554. LONG oldLength; // the length of the request PDU
  1555. LONG delta; // difference between the request PDU length and the responce PDU length
  1556. BYTE *newStream;// new location for the community stream inside the response PDU.
  1557. // encode message as asn sequence
  1558. *tmpPtr++ = ASN_SEQUENCE;
  1559. // the pointer to the community string points either directly in the incoming buffer
  1560. // (for req PDUs) or in the TRAP_DESTINATION_LIST_ENTRY for the outgoing traps.
  1561. // In the first case, when building the outgoing message on the same buffer as the
  1562. // incoming message, we need to take care to no overwrite the community name (in case
  1563. // the length field is larger than for the initial message). Hence, in this case only
  1564. // we shift the community name with a few octets, as many as the difference between the
  1565. // encodings of the two lengths (the length of the outgoing response - the length of the
  1566. // incoming request).
  1567. if (pPdu->nType != SNMP_PDU_V1TRAP)
  1568. {
  1569. // here tmpPtr points exactly to the length of the request pdu
  1570. oldLength = *(PUALONG)tmpPtr; // bug# 176433
  1571. // compute the offset the community stream should be shifted with
  1572. delta = nMsgLenLength - ((oldLength & 0x80) ? (oldLength & 0x7f) + 1 : 1);
  1573. newStream = pCommunity->stream + delta;
  1574. // pCommunity->stream is shifted regardles memory regions overlapp
  1575. memmove(newStream, pCommunity->stream, pCommunity->length);
  1576. // make old community to point to the new location
  1577. pCommunity->stream = newStream;
  1578. }
  1579. // encode global message information
  1580. AddLen(&tmpPtr, nMsgLenLength, nMsgDataLength);
  1581. AddUInt(&tmpPtr, ASN_INTEGER32, nVersion);
  1582. AddOctets(&tmpPtr, ASN_OCTETSTRING, pCommunity);
  1583. // encode pdu header information
  1584. *tmpPtr++ = (BYTE)pPdu->nType;
  1585. AddLen(&tmpPtr, nPduLenLength, nPduDataLength);
  1586. // determine pdu nType
  1587. switch (pPdu->nType) {
  1588. case SNMP_PDU_RESPONSE:
  1589. case SNMP_PDU_TRAP:
  1590. AddInt(&tmpPtr, ASN_INTEGER32, pPdu->Pdu.NormPdu.nRequestId);
  1591. AddInt(&tmpPtr, ASN_INTEGER32, pPdu->Pdu.NormPdu.nErrorStatus);
  1592. AddInt(&tmpPtr, ASN_INTEGER32, pPdu->Pdu.NormPdu.nErrorIndex);
  1593. break;
  1594. case SNMP_PDU_V1TRAP:
  1595. if (AddOid(
  1596. &tmpPtr,
  1597. ASN_OBJECTIDENTIFIER,
  1598. &pPdu->Pdu.TrapPdu.EnterpriseOid)== BERERR)
  1599. return FALSE;
  1600. if (AddOctets(
  1601. &tmpPtr,
  1602. ASN_IPADDRESS,
  1603. &pPdu->Pdu.TrapPdu.AgentAddr) == BERERR)
  1604. return FALSE;
  1605. AddInt(&tmpPtr, ASN_INTEGER32, pPdu->Pdu.TrapPdu.nGenericTrap);
  1606. AddInt(&tmpPtr, ASN_INTEGER32, pPdu->Pdu.TrapPdu.nSpecificTrap);
  1607. AddUInt(&tmpPtr, ASN_TIMETICKS, pPdu->Pdu.TrapPdu.nTimeticks);
  1608. break;
  1609. case SNMP_PDU_GET:
  1610. case SNMP_PDU_GETNEXT:
  1611. case SNMP_PDU_SET:
  1612. case SNMP_PDU_INFORM:
  1613. case SNMP_PDU_GETBULK:
  1614. default:
  1615. return FALSE;
  1616. }
  1617. // encode variable bindings
  1618. *tmpPtr++ = ASN_SEQUENCE;
  1619. AddLen(&tmpPtr, nVbLenLength, nVbDataLength);
  1620. if (AddVarBindList(&tmpPtr, &pPdu->Vbl) == BERERR)
  1621. return FALSE;
  1622. // success
  1623. return TRUE;
  1624. }
  1625. // failure
  1626. return FALSE;
  1627. }
  1628. BOOL
  1629. ParseMessage(
  1630. AsnInteger32 * pVersion,
  1631. AsnOctetString * pCommunity,
  1632. PSNMP_PDU pPdu,
  1633. PBYTE pMessage,
  1634. DWORD dwMessageSize
  1635. )
  1636. /*
  1637. Routine Description:
  1638. Parses incoming SNMP PDU into structure.
  1639. Arguments:
  1640. pVersion - pointer to receive SNMP version.
  1641. pCommunity - pointer to receive community string.
  1642. pPdu - pointer to receive remaining PDU data.
  1643. pMessage - pointer to message to parse.
  1644. dwMessageSize - number of bytes in message.
  1645. Return Values:
  1646. Returns true if successful.
  1647. */
  1648. {
  1649. LONG lLength;
  1650. LPBYTE pByte;
  1651. LPBYTE pLastByte;
  1652. // initialize community
  1653. pCommunity->stream = NULL;
  1654. pCommunity->length = 0;
  1655. // initialize vbl
  1656. pPdu->Vbl.len = 0;
  1657. pPdu->Vbl.list = NULL;
  1658. // validate pointer
  1659. if (!(pByte = pMessage))
  1660. goto cleanup;
  1661. // set limit based on packet size
  1662. pLastByte = pByte + dwMessageSize;
  1663. // decode asn sequence message wrapper
  1664. if (!(ParseSequence(&pByte, pLastByte, &lLength)))
  1665. goto cleanup;
  1666. // check for packet fragments
  1667. if (pLastByte < (pByte + lLength))
  1668. goto cleanup;
  1669. // re-adjust based on data
  1670. pLastByte = pByte + lLength;
  1671. // decode snmp version
  1672. if (!(ParseUInt(&pByte, pLastByte, pVersion)))
  1673. goto cleanup;
  1674. // validate snmp version
  1675. if ((*pVersion != SNMP_VERSION_1) &&
  1676. (*pVersion != SNMP_VERSION_2C))
  1677. {
  1678. // register version mismatch into the management structure
  1679. mgmtCTick(CsnmpInBadVersions);
  1680. goto cleanup;
  1681. }
  1682. // decode community string
  1683. if (!(ParseOctets(&pByte, pLastByte, pCommunity)))
  1684. goto cleanup;
  1685. // decode nType of incoming pdu
  1686. if ((pPdu->nType = ParseType(&pByte, pLastByte)) == BERERR)
  1687. goto cleanup;
  1688. // decode length of incoming pdu
  1689. if ((lLength = ParseLength(&pByte, pLastByte)) == BERERR)
  1690. goto cleanup;
  1691. // validate length
  1692. if (pByte + lLength > pLastByte)
  1693. goto cleanup;
  1694. // determine pdu nType
  1695. switch (pPdu->nType) {
  1696. case SNMP_PDU_GET:
  1697. case SNMP_PDU_GETNEXT:
  1698. case SNMP_PDU_SET:
  1699. // decode the pdu header information
  1700. if (!(ParseInt(&pByte, pLastByte, &pPdu->Pdu.NormPdu.nRequestId)))
  1701. goto cleanup;
  1702. if (!(ParseInt(&pByte, pLastByte, &pPdu->Pdu.NormPdu.nErrorStatus)))
  1703. goto cleanup;
  1704. if (!(ParseInt(&pByte, pLastByte, &pPdu->Pdu.NormPdu.nErrorIndex)))
  1705. goto cleanup;
  1706. // update the management counters for the incoming errorStatus coding
  1707. mgmtUtilUpdateErrStatus(IN_errStatus, pPdu->Pdu.NormPdu.nErrorStatus);
  1708. // no reason here to have any ErrorStatus and ErrorIndex.
  1709. // initialize error status variables to NOERROR
  1710. pPdu->Pdu.NormPdu.nErrorStatus = SNMP_ERRORSTATUS_NOERROR;
  1711. pPdu->Pdu.NormPdu.nErrorIndex = 0;
  1712. break;
  1713. case SNMP_PDU_GETBULK:
  1714. // decode the getbulk pdu header information
  1715. if (!(ParseInt(&pByte, pLastByte, &pPdu->Pdu.BulkPdu.nRequestId)))
  1716. goto cleanup;
  1717. if (!(ParseInt(&pByte, pLastByte, &pPdu->Pdu.BulkPdu.nNonRepeaters)))
  1718. goto cleanup;
  1719. if (!(ParseInt(&pByte, pLastByte, &pPdu->Pdu.BulkPdu.nMaxRepetitions)))
  1720. goto cleanup;
  1721. // see if value needs to be adjusted
  1722. if (pPdu->Pdu.BulkPdu.nNonRepeaters < 0) {
  1723. // adjust non-repeaters to zero
  1724. pPdu->Pdu.BulkPdu.nNonRepeaters = 0;
  1725. }
  1726. // see if value needs to be adjusted
  1727. if (pPdu->Pdu.BulkPdu.nMaxRepetitions < 0) {
  1728. // adjust max-repetitions to zero
  1729. pPdu->Pdu.BulkPdu.nMaxRepetitions = 0;
  1730. }
  1731. // initialize status information
  1732. pPdu->Pdu.BulkPdu.nErrorStatus = SNMP_ERRORSTATUS_NOERROR;
  1733. pPdu->Pdu.BulkPdu.nErrorIndex = 0;
  1734. break;
  1735. case SNMP_PDU_INFORM:
  1736. case SNMP_PDU_RESPONSE:
  1737. case SNMP_PDU_TRAP:
  1738. case SNMP_PDU_V1TRAP:
  1739. default:
  1740. goto cleanup;
  1741. }
  1742. // parse over sequence
  1743. if (!(ParseSequence(&pByte, pLastByte, NULL)))
  1744. goto cleanup;
  1745. // parse variable binding list
  1746. if (!(ParseVarBindList(&pByte, pLastByte, &pPdu->Vbl)))
  1747. goto cleanup;
  1748. // success
  1749. return TRUE;
  1750. cleanup:
  1751. // cleanup community string
  1752. SnmpUtilOctetsFree(pCommunity);
  1753. // cleanup any allocated varbinds
  1754. SnmpUtilVarBindListFree(&pPdu->Vbl);
  1755. // failure
  1756. return FALSE;
  1757. }