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.

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