/contrib/bsnmp/lib/snmp.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 1453 lines · 1146 code · 223 blank · 84 comment · 394 complexity · 84cc7c07a3f1e42cb84f51467d0d25c2 MD5 · raw file

  1. /*
  2. * Copyright (c) 2001-2003
  3. * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
  4. * All rights reserved.
  5. *
  6. * Author: Harti Brandt <harti@freebsd.org>
  7. *
  8. * Copyright (c) 2010 The FreeBSD Foundation
  9. * All rights reserved.
  10. *
  11. * Portions of this software were developed by Shteryana Sotirova Shopova
  12. * under sponsorship from the FreeBSD Foundation.
  13. *
  14. * Redistribution and use in source and binary forms, with or without
  15. * modification, are permitted provided that the following conditions
  16. * are met:
  17. * 1. Redistributions of source code must retain the above copyright
  18. * notice, this list of conditions and the following disclaimer.
  19. * 2. Redistributions in binary form must reproduce the above copyright
  20. * notice, this list of conditions and the following disclaimer in the
  21. * documentation and/or other materials provided with the distribution.
  22. *
  23. * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  24. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  25. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  26. * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
  27. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  28. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  29. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  30. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  31. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  32. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  33. * SUCH DAMAGE.
  34. *
  35. * $Begemot: bsnmp/lib/snmp.c,v 1.40 2005/10/04 14:32:42 brandt_h Exp $
  36. *
  37. * SNMP
  38. */
  39. #include <sys/types.h>
  40. #include <sys/socket.h>
  41. #include <stdio.h>
  42. #include <stdlib.h>
  43. #include <stddef.h>
  44. #include <stdarg.h>
  45. #ifdef HAVE_STDINT_H
  46. #include <stdint.h>
  47. #elif defined(HAVE_INTTYPES_H)
  48. #include <inttypes.h>
  49. #endif
  50. #include <string.h>
  51. #include <ctype.h>
  52. #include <netdb.h>
  53. #include <errno.h>
  54. #include "asn1.h"
  55. #include "snmp.h"
  56. #include "snmppriv.h"
  57. static void snmp_error_func(const char *, ...);
  58. static void snmp_printf_func(const char *, ...);
  59. void (*snmp_error)(const char *, ...) = snmp_error_func;
  60. void (*snmp_printf)(const char *, ...) = snmp_printf_func;
  61. /*
  62. * Get the next variable binding from the list.
  63. * ASN errors on the sequence or the OID are always fatal.
  64. */
  65. static enum asn_err
  66. get_var_binding(struct asn_buf *b, struct snmp_value *binding)
  67. {
  68. u_char type;
  69. asn_len_t len, trailer;
  70. enum asn_err err;
  71. if (asn_get_sequence(b, &len) != ASN_ERR_OK) {
  72. snmp_error("cannot parse varbind header");
  73. return (ASN_ERR_FAILED);
  74. }
  75. /* temporary truncate the length so that the parser does not
  76. * eat up bytes behind the sequence in the case the encoding is
  77. * wrong of inner elements. */
  78. trailer = b->asn_len - len;
  79. b->asn_len = len;
  80. if (asn_get_objid(b, &binding->var) != ASN_ERR_OK) {
  81. snmp_error("cannot parse binding objid");
  82. return (ASN_ERR_FAILED);
  83. }
  84. if (asn_get_header(b, &type, &len) != ASN_ERR_OK) {
  85. snmp_error("cannot parse binding value header");
  86. return (ASN_ERR_FAILED);
  87. }
  88. switch (type) {
  89. case ASN_TYPE_NULL:
  90. binding->syntax = SNMP_SYNTAX_NULL;
  91. err = asn_get_null_raw(b, len);
  92. break;
  93. case ASN_TYPE_INTEGER:
  94. binding->syntax = SNMP_SYNTAX_INTEGER;
  95. err = asn_get_integer_raw(b, len, &binding->v.integer);
  96. break;
  97. case ASN_TYPE_OCTETSTRING:
  98. binding->syntax = SNMP_SYNTAX_OCTETSTRING;
  99. binding->v.octetstring.octets = malloc(len);
  100. if (binding->v.octetstring.octets == NULL) {
  101. snmp_error("%s", strerror(errno));
  102. return (ASN_ERR_FAILED);
  103. }
  104. binding->v.octetstring.len = len;
  105. err = asn_get_octetstring_raw(b, len,
  106. binding->v.octetstring.octets,
  107. &binding->v.octetstring.len);
  108. if (ASN_ERR_STOPPED(err)) {
  109. free(binding->v.octetstring.octets);
  110. binding->v.octetstring.octets = NULL;
  111. }
  112. break;
  113. case ASN_TYPE_OBJID:
  114. binding->syntax = SNMP_SYNTAX_OID;
  115. err = asn_get_objid_raw(b, len, &binding->v.oid);
  116. break;
  117. case ASN_CLASS_APPLICATION|ASN_APP_IPADDRESS:
  118. binding->syntax = SNMP_SYNTAX_IPADDRESS;
  119. err = asn_get_ipaddress_raw(b, len, binding->v.ipaddress);
  120. break;
  121. case ASN_CLASS_APPLICATION|ASN_APP_TIMETICKS:
  122. binding->syntax = SNMP_SYNTAX_TIMETICKS;
  123. err = asn_get_uint32_raw(b, len, &binding->v.uint32);
  124. break;
  125. case ASN_CLASS_APPLICATION|ASN_APP_COUNTER:
  126. binding->syntax = SNMP_SYNTAX_COUNTER;
  127. err = asn_get_uint32_raw(b, len, &binding->v.uint32);
  128. break;
  129. case ASN_CLASS_APPLICATION|ASN_APP_GAUGE:
  130. binding->syntax = SNMP_SYNTAX_GAUGE;
  131. err = asn_get_uint32_raw(b, len, &binding->v.uint32);
  132. break;
  133. case ASN_CLASS_APPLICATION|ASN_APP_COUNTER64:
  134. binding->syntax = SNMP_SYNTAX_COUNTER64;
  135. err = asn_get_counter64_raw(b, len, &binding->v.counter64);
  136. break;
  137. case ASN_CLASS_CONTEXT | ASN_EXCEPT_NOSUCHOBJECT:
  138. binding->syntax = SNMP_SYNTAX_NOSUCHOBJECT;
  139. err = asn_get_null_raw(b, len);
  140. break;
  141. case ASN_CLASS_CONTEXT | ASN_EXCEPT_NOSUCHINSTANCE:
  142. binding->syntax = SNMP_SYNTAX_NOSUCHINSTANCE;
  143. err = asn_get_null_raw(b, len);
  144. break;
  145. case ASN_CLASS_CONTEXT | ASN_EXCEPT_ENDOFMIBVIEW:
  146. binding->syntax = SNMP_SYNTAX_ENDOFMIBVIEW;
  147. err = asn_get_null_raw(b, len);
  148. break;
  149. default:
  150. if ((err = asn_skip(b, len)) == ASN_ERR_OK)
  151. err = ASN_ERR_TAG;
  152. snmp_error("bad binding value type 0x%x", type);
  153. break;
  154. }
  155. if (ASN_ERR_STOPPED(err)) {
  156. snmp_error("cannot parse binding value");
  157. return (err);
  158. }
  159. if (b->asn_len != 0)
  160. snmp_error("ignoring junk at end of binding");
  161. b->asn_len = trailer;
  162. return (err);
  163. }
  164. /*
  165. * Parse the different PDUs contents. Any ASN error in the outer components
  166. * are fatal. Only errors in variable values may be tolerated. If all
  167. * components can be parsed it returns either ASN_ERR_OK or the first
  168. * error that was found.
  169. */
  170. enum asn_err
  171. snmp_parse_pdus_hdr(struct asn_buf *b, struct snmp_pdu *pdu, asn_len_t *lenp)
  172. {
  173. if (pdu->type == SNMP_PDU_TRAP) {
  174. if (asn_get_objid(b, &pdu->enterprise) != ASN_ERR_OK) {
  175. snmp_error("cannot parse trap enterprise");
  176. return (ASN_ERR_FAILED);
  177. }
  178. if (asn_get_ipaddress(b, pdu->agent_addr) != ASN_ERR_OK) {
  179. snmp_error("cannot parse trap agent address");
  180. return (ASN_ERR_FAILED);
  181. }
  182. if (asn_get_integer(b, &pdu->generic_trap) != ASN_ERR_OK) {
  183. snmp_error("cannot parse 'generic-trap'");
  184. return (ASN_ERR_FAILED);
  185. }
  186. if (asn_get_integer(b, &pdu->specific_trap) != ASN_ERR_OK) {
  187. snmp_error("cannot parse 'specific-trap'");
  188. return (ASN_ERR_FAILED);
  189. }
  190. if (asn_get_timeticks(b, &pdu->time_stamp) != ASN_ERR_OK) {
  191. snmp_error("cannot parse trap 'time-stamp'");
  192. return (ASN_ERR_FAILED);
  193. }
  194. } else {
  195. if (asn_get_integer(b, &pdu->request_id) != ASN_ERR_OK) {
  196. snmp_error("cannot parse 'request-id'");
  197. return (ASN_ERR_FAILED);
  198. }
  199. if (asn_get_integer(b, &pdu->error_status) != ASN_ERR_OK) {
  200. snmp_error("cannot parse 'error_status'");
  201. return (ASN_ERR_FAILED);
  202. }
  203. if (asn_get_integer(b, &pdu->error_index) != ASN_ERR_OK) {
  204. snmp_error("cannot parse 'error_index'");
  205. return (ASN_ERR_FAILED);
  206. }
  207. }
  208. if (asn_get_sequence(b, lenp) != ASN_ERR_OK) {
  209. snmp_error("cannot get varlist header");
  210. return (ASN_ERR_FAILED);
  211. }
  212. return (ASN_ERR_OK);
  213. }
  214. static enum asn_err
  215. parse_pdus(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip)
  216. {
  217. asn_len_t len, trailer;
  218. struct snmp_value *v;
  219. enum asn_err err, err1;
  220. err = snmp_parse_pdus_hdr(b, pdu, &len);
  221. if (ASN_ERR_STOPPED(err))
  222. return (err);
  223. trailer = b->asn_len - len;
  224. v = pdu->bindings;
  225. err = ASN_ERR_OK;
  226. while (b->asn_len != 0) {
  227. if (pdu->nbindings == SNMP_MAX_BINDINGS) {
  228. snmp_error("too many bindings (> %u) in PDU",
  229. SNMP_MAX_BINDINGS);
  230. return (ASN_ERR_FAILED);
  231. }
  232. err1 = get_var_binding(b, v);
  233. if (ASN_ERR_STOPPED(err1))
  234. return (ASN_ERR_FAILED);
  235. if (err1 != ASN_ERR_OK && err == ASN_ERR_OK) {
  236. err = err1;
  237. *ip = pdu->nbindings + 1;
  238. }
  239. pdu->nbindings++;
  240. v++;
  241. }
  242. b->asn_len = trailer;
  243. return (err);
  244. }
  245. static enum asn_err
  246. parse_secparams(struct asn_buf *b, struct snmp_pdu *pdu)
  247. {
  248. asn_len_t octs_len;
  249. u_char buf[256]; /* XXX: calc max possible size here */
  250. struct asn_buf tb;
  251. memset(buf, 0, 256);
  252. tb.asn_ptr = buf;
  253. tb.asn_len = 256;
  254. if (asn_get_octetstring(b, buf, &tb.asn_len) != ASN_ERR_OK) {
  255. snmp_error("cannot parse usm header");
  256. return (ASN_ERR_FAILED);
  257. }
  258. if (asn_get_sequence(&tb, &octs_len) != ASN_ERR_OK) {
  259. snmp_error("cannot decode usm header");
  260. return (ASN_ERR_FAILED);
  261. }
  262. octs_len = SNMP_ENGINE_ID_SIZ;
  263. if (asn_get_octetstring(&tb, (u_char *)&pdu->engine.engine_id,
  264. &octs_len) != ASN_ERR_OK) {
  265. snmp_error("cannot decode msg engine id");
  266. return (ASN_ERR_FAILED);
  267. }
  268. pdu->engine.engine_len = octs_len;
  269. if (asn_get_integer(&tb, &pdu->engine.engine_boots) != ASN_ERR_OK) {
  270. snmp_error("cannot decode msg engine boots");
  271. return (ASN_ERR_FAILED);
  272. }
  273. if (asn_get_integer(&tb, &pdu->engine.engine_time) != ASN_ERR_OK) {
  274. snmp_error("cannot decode msg engine time");
  275. return (ASN_ERR_FAILED);
  276. }
  277. octs_len = SNMP_ADM_STR32_SIZ - 1;
  278. if (asn_get_octetstring(&tb, (u_char *)&pdu->user.sec_name, &octs_len)
  279. != ASN_ERR_OK) {
  280. snmp_error("cannot decode msg user name");
  281. return (ASN_ERR_FAILED);
  282. }
  283. pdu->user.sec_name[octs_len] = '\0';
  284. octs_len = sizeof(pdu->msg_digest);
  285. if (asn_get_octetstring(&tb, (u_char *)&pdu->msg_digest, &octs_len) !=
  286. ASN_ERR_OK || ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0 &&
  287. octs_len != sizeof(pdu->msg_digest))) {
  288. snmp_error("cannot decode msg authentication param");
  289. return (ASN_ERR_FAILED);
  290. }
  291. octs_len = sizeof(pdu->msg_salt);
  292. if (asn_get_octetstring(&tb, (u_char *)&pdu->msg_salt, &octs_len) !=
  293. ASN_ERR_OK ||((pdu->flags & SNMP_MSG_PRIV_FLAG) != 0 &&
  294. octs_len != sizeof(pdu->msg_salt))) {
  295. snmp_error("cannot decode msg authentication param");
  296. return (ASN_ERR_FAILED);
  297. }
  298. if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0) {
  299. pdu->digest_ptr = b->asn_ptr - SNMP_USM_AUTH_SIZE;
  300. pdu->digest_ptr -= octs_len + ASN_MAXLENLEN;
  301. }
  302. return (ASN_ERR_OK);
  303. }
  304. static enum snmp_code
  305. pdu_encode_secparams(struct asn_buf *b, struct snmp_pdu *pdu)
  306. {
  307. u_char buf[256], *sptr;
  308. struct asn_buf tb;
  309. size_t auth_off, moved = 0;
  310. auth_off = 0;
  311. memset(buf, 0, 256);
  312. tb.asn_ptr = buf;
  313. tb.asn_len = 256;
  314. if (asn_put_temp_header(&tb, (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED),
  315. &sptr) != ASN_ERR_OK)
  316. return (SNMP_CODE_FAILED);
  317. if (asn_put_octetstring(&tb, (u_char *)pdu->engine.engine_id,
  318. pdu->engine.engine_len) != ASN_ERR_OK)
  319. return (SNMP_CODE_FAILED);
  320. if (asn_put_integer(&tb, pdu->engine.engine_boots) != ASN_ERR_OK)
  321. return (SNMP_CODE_FAILED);
  322. if (asn_put_integer(&tb, pdu->engine.engine_time) != ASN_ERR_OK)
  323. return (SNMP_CODE_FAILED);
  324. if (asn_put_octetstring(&tb, (u_char *)pdu->user.sec_name,
  325. strlen(pdu->user.sec_name)) != ASN_ERR_OK)
  326. return (SNMP_CODE_FAILED);
  327. if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0) {
  328. auth_off = sizeof(buf) - tb.asn_len + ASN_MAXLENLEN;
  329. if (asn_put_octetstring(&tb, (u_char *)pdu->msg_digest,
  330. sizeof(pdu->msg_digest)) != ASN_ERR_OK)
  331. return (SNMP_CODE_FAILED);
  332. } else {
  333. if (asn_put_octetstring(&tb, (u_char *)pdu->msg_digest, 0)
  334. != ASN_ERR_OK)
  335. return (SNMP_CODE_FAILED);
  336. }
  337. if ((pdu->flags & SNMP_MSG_PRIV_FLAG) != 0) {
  338. if (asn_put_octetstring(&tb, (u_char *)pdu->msg_salt,
  339. sizeof(pdu->msg_salt)) != ASN_ERR_OK)
  340. return (SNMP_CODE_FAILED);
  341. } else {
  342. if (asn_put_octetstring(&tb, (u_char *)pdu->msg_salt, 0)
  343. != ASN_ERR_OK)
  344. return (SNMP_CODE_FAILED);
  345. }
  346. if (asn_commit_header(&tb, sptr, &moved) != ASN_ERR_OK)
  347. return (SNMP_CODE_FAILED);
  348. if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0)
  349. pdu->digest_ptr = b->asn_ptr + auth_off - moved;
  350. if (asn_put_octetstring(b, buf, sizeof(buf) - tb.asn_len) != ASN_ERR_OK)
  351. return (SNMP_CODE_FAILED);
  352. pdu->digest_ptr += ASN_MAXLENLEN;
  353. if ((pdu->flags & SNMP_MSG_PRIV_FLAG) != 0 && asn_put_temp_header(b,
  354. ASN_TYPE_OCTETSTRING, &pdu->encrypted_ptr) != ASN_ERR_OK)
  355. return (SNMP_CODE_FAILED);
  356. return (SNMP_CODE_OK);
  357. }
  358. /*
  359. * Decode the PDU except for the variable bindings itself.
  360. * If decoding fails because of a bad binding, but the rest can be
  361. * decoded, ip points to the index of the failed variable (errors
  362. * OORANGE, BADLEN or BADVERS).
  363. */
  364. enum snmp_code
  365. snmp_pdu_decode(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip)
  366. {
  367. enum snmp_code code;
  368. if ((code = snmp_pdu_decode_header(b, pdu)) != SNMP_CODE_OK)
  369. return (code);
  370. if (pdu->version == SNMP_V3) {
  371. if (pdu->security_model != SNMP_SECMODEL_USM)
  372. return (SNMP_CODE_FAILED);
  373. if ((code = snmp_pdu_decode_secmode(b, pdu)) != SNMP_CODE_OK)
  374. return (code);
  375. }
  376. code = snmp_pdu_decode_scoped(b, pdu, ip);
  377. switch (code) {
  378. case SNMP_CODE_FAILED:
  379. snmp_pdu_free(pdu);
  380. break;
  381. case SNMP_CODE_BADENC:
  382. if (pdu->version == SNMP_Verr)
  383. return (SNMP_CODE_BADVERS);
  384. default:
  385. break;
  386. }
  387. return (code);
  388. }
  389. enum snmp_code
  390. snmp_pdu_decode_header(struct asn_buf *b, struct snmp_pdu *pdu)
  391. {
  392. int32_t version;
  393. u_int octs_len;
  394. asn_len_t len;
  395. pdu->outer_ptr = b->asn_ptr;
  396. pdu->outer_len = b->asn_len;
  397. if (asn_get_sequence(b, &len) != ASN_ERR_OK) {
  398. snmp_error("cannot decode pdu header");
  399. return (SNMP_CODE_FAILED);
  400. }
  401. if (b->asn_len < len) {
  402. snmp_error("outer sequence value too short");
  403. return (SNMP_CODE_FAILED);
  404. }
  405. if (b->asn_len != len) {
  406. snmp_error("ignoring trailing junk in message");
  407. b->asn_len = len;
  408. }
  409. if (asn_get_integer(b, &version) != ASN_ERR_OK) {
  410. snmp_error("cannot decode version");
  411. return (SNMP_CODE_FAILED);
  412. }
  413. if (version == 0)
  414. pdu->version = SNMP_V1;
  415. else if (version == 1)
  416. pdu->version = SNMP_V2c;
  417. else if (version == 3)
  418. pdu->version = SNMP_V3;
  419. else {
  420. pdu->version = SNMP_Verr;
  421. snmp_error("unsupported SNMP version");
  422. return (SNMP_CODE_BADENC);
  423. }
  424. if (pdu->version == SNMP_V3) {
  425. if (asn_get_sequence(b, &len) != ASN_ERR_OK) {
  426. snmp_error("cannot decode pdu global data header");
  427. return (SNMP_CODE_FAILED);
  428. }
  429. if (asn_get_integer(b, &pdu->identifier) != ASN_ERR_OK) {
  430. snmp_error("cannot decode msg indetifier");
  431. return (SNMP_CODE_FAILED);
  432. }
  433. if (asn_get_integer(b, &pdu->engine.max_msg_size)
  434. != ASN_ERR_OK) {
  435. snmp_error("cannot decode msg size");
  436. return (SNMP_CODE_FAILED);
  437. }
  438. octs_len = 1;
  439. if (asn_get_octetstring(b, (u_char *)&pdu->flags,
  440. &octs_len) != ASN_ERR_OK) {
  441. snmp_error("cannot decode msg flags");
  442. return (SNMP_CODE_FAILED);
  443. }
  444. if (asn_get_integer(b, &pdu->security_model) != ASN_ERR_OK) {
  445. snmp_error("cannot decode msg size");
  446. return (SNMP_CODE_FAILED);
  447. }
  448. if (pdu->security_model != SNMP_SECMODEL_USM)
  449. return (SNMP_CODE_FAILED);
  450. if (parse_secparams(b, pdu) != ASN_ERR_OK)
  451. return (SNMP_CODE_FAILED);
  452. } else {
  453. octs_len = SNMP_COMMUNITY_MAXLEN;
  454. if (asn_get_octetstring(b, (u_char *)pdu->community,
  455. &octs_len) != ASN_ERR_OK) {
  456. snmp_error("cannot decode community");
  457. return (SNMP_CODE_FAILED);
  458. }
  459. pdu->community[octs_len] = '\0';
  460. }
  461. return (SNMP_CODE_OK);
  462. }
  463. enum snmp_code
  464. snmp_pdu_decode_scoped(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip)
  465. {
  466. u_char type;
  467. asn_len_t len, trailer;
  468. enum asn_err err;
  469. if (pdu->version == SNMP_V3) {
  470. if (asn_get_sequence(b, &len) != ASN_ERR_OK) {
  471. snmp_error("cannot decode scoped pdu header");
  472. return (SNMP_CODE_FAILED);
  473. }
  474. len = SNMP_ENGINE_ID_SIZ;
  475. if (asn_get_octetstring(b, (u_char *)&pdu->context_engine,
  476. &len) != ASN_ERR_OK) {
  477. snmp_error("cannot decode msg context engine");
  478. return (SNMP_CODE_FAILED);
  479. }
  480. pdu->context_engine_len = len;
  481. len = SNMP_CONTEXT_NAME_SIZ;
  482. if (asn_get_octetstring(b, (u_char *)&pdu->context_name,
  483. &len) != ASN_ERR_OK) {
  484. snmp_error("cannot decode msg context name");
  485. return (SNMP_CODE_FAILED);
  486. }
  487. pdu->context_name[len] = '\0';
  488. }
  489. if (asn_get_header(b, &type, &len) != ASN_ERR_OK) {
  490. snmp_error("cannot get pdu header");
  491. return (SNMP_CODE_FAILED);
  492. }
  493. if ((type & ~ASN_TYPE_MASK) !=
  494. (ASN_TYPE_CONSTRUCTED | ASN_CLASS_CONTEXT)) {
  495. snmp_error("bad pdu header tag");
  496. return (SNMP_CODE_FAILED);
  497. }
  498. pdu->type = type & ASN_TYPE_MASK;
  499. switch (pdu->type) {
  500. case SNMP_PDU_GET:
  501. case SNMP_PDU_GETNEXT:
  502. case SNMP_PDU_RESPONSE:
  503. case SNMP_PDU_SET:
  504. break;
  505. case SNMP_PDU_TRAP:
  506. if (pdu->version != SNMP_V1) {
  507. snmp_error("bad pdu type %u", pdu->type);
  508. return (SNMP_CODE_FAILED);
  509. }
  510. break;
  511. case SNMP_PDU_GETBULK:
  512. case SNMP_PDU_INFORM:
  513. case SNMP_PDU_TRAP2:
  514. case SNMP_PDU_REPORT:
  515. if (pdu->version == SNMP_V1) {
  516. snmp_error("bad pdu type %u", pdu->type);
  517. return (SNMP_CODE_FAILED);
  518. }
  519. break;
  520. default:
  521. snmp_error("bad pdu type %u", pdu->type);
  522. return (SNMP_CODE_FAILED);
  523. }
  524. trailer = b->asn_len - len;
  525. b->asn_len = len;
  526. err = parse_pdus(b, pdu, ip);
  527. if (ASN_ERR_STOPPED(err))
  528. return (SNMP_CODE_FAILED);
  529. if (b->asn_len != 0)
  530. snmp_error("ignoring trailing junk after pdu");
  531. b->asn_len = trailer;
  532. return (SNMP_CODE_OK);
  533. }
  534. enum snmp_code
  535. snmp_pdu_decode_secmode(struct asn_buf *b, struct snmp_pdu *pdu)
  536. {
  537. u_char type;
  538. enum snmp_code code;
  539. uint8_t digest[SNMP_USM_AUTH_SIZE];
  540. if (pdu->user.auth_proto != SNMP_AUTH_NOAUTH &&
  541. (pdu->flags & SNMP_MSG_AUTH_FLAG) == 0)
  542. return (SNMP_CODE_BADSECLEVEL);
  543. if ((code = snmp_pdu_calc_digest(pdu, digest)) !=
  544. SNMP_CODE_OK)
  545. return (SNMP_CODE_FAILED);
  546. if (pdu->user.auth_proto != SNMP_AUTH_NOAUTH &&
  547. memcmp(digest, pdu->msg_digest, sizeof(pdu->msg_digest)) != 0)
  548. return (SNMP_CODE_BADDIGEST);
  549. if (pdu->user.priv_proto != SNMP_PRIV_NOPRIV && (asn_get_header(b, &type,
  550. &pdu->scoped_len) != ASN_ERR_OK || type != ASN_TYPE_OCTETSTRING)) {
  551. snmp_error("cannot decode encrypted pdu");
  552. return (SNMP_CODE_FAILED);
  553. }
  554. pdu->scoped_ptr = b->asn_ptr;
  555. if (pdu->user.priv_proto != SNMP_PRIV_NOPRIV &&
  556. (pdu->flags & SNMP_MSG_PRIV_FLAG) == 0)
  557. return (SNMP_CODE_BADSECLEVEL);
  558. if ((code = snmp_pdu_decrypt(pdu)) != SNMP_CODE_OK)
  559. return (SNMP_CODE_FAILED);
  560. return (code);
  561. }
  562. /*
  563. * Check whether what we have is the complete PDU by snooping at the
  564. * enclosing structure header. This returns:
  565. * -1 if there are ASN.1 errors
  566. * 0 if we need more data
  567. * > 0 the length of this PDU
  568. */
  569. int
  570. snmp_pdu_snoop(const struct asn_buf *b0)
  571. {
  572. u_int length;
  573. asn_len_t len;
  574. struct asn_buf b = *b0;
  575. /* <0x10|0x20> <len> <data...> */
  576. if (b.asn_len == 0)
  577. return (0);
  578. if (b.asn_cptr[0] != (ASN_TYPE_SEQUENCE | ASN_TYPE_CONSTRUCTED)) {
  579. asn_error(&b, "bad sequence type %u", b.asn_cptr[0]);
  580. return (-1);
  581. }
  582. b.asn_len--;
  583. b.asn_cptr++;
  584. if (b.asn_len == 0)
  585. return (0);
  586. if (*b.asn_cptr & 0x80) {
  587. /* long length */
  588. length = *b.asn_cptr++ & 0x7f;
  589. b.asn_len--;
  590. if (length == 0) {
  591. asn_error(&b, "indefinite length not supported");
  592. return (-1);
  593. }
  594. if (length > ASN_MAXLENLEN) {
  595. asn_error(&b, "long length too long (%u)", length);
  596. return (-1);
  597. }
  598. if (length > b.asn_len)
  599. return (0);
  600. len = 0;
  601. while (length--) {
  602. len = (len << 8) | *b.asn_cptr++;
  603. b.asn_len--;
  604. }
  605. } else {
  606. len = *b.asn_cptr++;
  607. b.asn_len--;
  608. }
  609. if (len > b.asn_len)
  610. return (0);
  611. return (len + b.asn_cptr - b0->asn_cptr);
  612. }
  613. /*
  614. * Encode the SNMP PDU without the variable bindings field.
  615. * We do this the rather uneffective way by
  616. * moving things around and assuming that the length field will never
  617. * use more than 2 bytes.
  618. * We need a number of pointers to apply the fixes afterwards.
  619. */
  620. enum snmp_code
  621. snmp_pdu_encode_header(struct asn_buf *b, struct snmp_pdu *pdu)
  622. {
  623. enum asn_err err;
  624. u_char *v3_hdr_ptr;
  625. if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED),
  626. &pdu->outer_ptr) != ASN_ERR_OK)
  627. return (SNMP_CODE_FAILED);
  628. if (pdu->version == SNMP_V1)
  629. err = asn_put_integer(b, 0);
  630. else if (pdu->version == SNMP_V2c)
  631. err = asn_put_integer(b, 1);
  632. else if (pdu->version == SNMP_V3)
  633. err = asn_put_integer(b, 3);
  634. else
  635. return (SNMP_CODE_BADVERS);
  636. if (err != ASN_ERR_OK)
  637. return (SNMP_CODE_FAILED);
  638. if (pdu->version == SNMP_V3) {
  639. if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE |
  640. ASN_TYPE_CONSTRUCTED), &v3_hdr_ptr) != ASN_ERR_OK)
  641. return (SNMP_CODE_FAILED);
  642. if (asn_put_integer(b, pdu->identifier) != ASN_ERR_OK)
  643. return (SNMP_CODE_FAILED);
  644. if (asn_put_integer(b, pdu->engine.max_msg_size) != ASN_ERR_OK)
  645. return (SNMP_CODE_FAILED);
  646. if (pdu->type != SNMP_PDU_RESPONSE &&
  647. pdu->type != SNMP_PDU_TRAP &&
  648. pdu->type != SNMP_PDU_TRAP2 &&
  649. pdu->type != SNMP_PDU_REPORT)
  650. pdu->flags |= SNMP_MSG_REPORT_FLAG;
  651. if (asn_put_octetstring(b, (u_char *)&pdu->flags, 1)
  652. != ASN_ERR_OK)
  653. return (SNMP_CODE_FAILED);
  654. if (asn_put_integer(b, pdu->security_model) != ASN_ERR_OK)
  655. return (SNMP_CODE_FAILED);
  656. if (asn_commit_header(b, v3_hdr_ptr, NULL) != ASN_ERR_OK)
  657. return (SNMP_CODE_FAILED);
  658. if (pdu->security_model != SNMP_SECMODEL_USM)
  659. return (SNMP_CODE_FAILED);
  660. if (pdu_encode_secparams(b, pdu) != SNMP_CODE_OK)
  661. return (SNMP_CODE_FAILED);
  662. /* View-based Access Conntrol information */
  663. if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE |
  664. ASN_TYPE_CONSTRUCTED), &pdu->scoped_ptr) != ASN_ERR_OK)
  665. return (SNMP_CODE_FAILED);
  666. if (asn_put_octetstring(b, (u_char *)pdu->context_engine,
  667. pdu->context_engine_len) != ASN_ERR_OK)
  668. return (SNMP_CODE_FAILED);
  669. if (asn_put_octetstring(b, (u_char *)pdu->context_name,
  670. strlen(pdu->context_name)) != ASN_ERR_OK)
  671. return (SNMP_CODE_FAILED);
  672. } else {
  673. if (asn_put_octetstring(b, (u_char *)pdu->community,
  674. strlen(pdu->community)) != ASN_ERR_OK)
  675. return (SNMP_CODE_FAILED);
  676. }
  677. if (asn_put_temp_header(b, (ASN_TYPE_CONSTRUCTED | ASN_CLASS_CONTEXT |
  678. pdu->type), &pdu->pdu_ptr) != ASN_ERR_OK)
  679. return (SNMP_CODE_FAILED);
  680. if (pdu->type == SNMP_PDU_TRAP) {
  681. if (pdu->version != SNMP_V1 ||
  682. asn_put_objid(b, &pdu->enterprise) != ASN_ERR_OK ||
  683. asn_put_ipaddress(b, pdu->agent_addr) != ASN_ERR_OK ||
  684. asn_put_integer(b, pdu->generic_trap) != ASN_ERR_OK ||
  685. asn_put_integer(b, pdu->specific_trap) != ASN_ERR_OK ||
  686. asn_put_timeticks(b, pdu->time_stamp) != ASN_ERR_OK)
  687. return (SNMP_CODE_FAILED);
  688. } else {
  689. if (pdu->version == SNMP_V1 && (pdu->type == SNMP_PDU_GETBULK ||
  690. pdu->type == SNMP_PDU_INFORM ||
  691. pdu->type == SNMP_PDU_TRAP2 ||
  692. pdu->type == SNMP_PDU_REPORT))
  693. return (SNMP_CODE_FAILED);
  694. if (asn_put_integer(b, pdu->request_id) != ASN_ERR_OK ||
  695. asn_put_integer(b, pdu->error_status) != ASN_ERR_OK ||
  696. asn_put_integer(b, pdu->error_index) != ASN_ERR_OK)
  697. return (SNMP_CODE_FAILED);
  698. }
  699. if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED),
  700. &pdu->vars_ptr) != ASN_ERR_OK)
  701. return (SNMP_CODE_FAILED);
  702. return (SNMP_CODE_OK);
  703. }
  704. static enum asn_err
  705. snmp_pdu_fix_padd(struct asn_buf *b, struct snmp_pdu *pdu)
  706. {
  707. asn_len_t padlen;
  708. if (pdu->user.priv_proto == SNMP_PRIV_DES && pdu->scoped_len % 8 != 0) {
  709. padlen = 8 - (pdu->scoped_len % 8);
  710. if (asn_pad(b, padlen) != ASN_ERR_OK)
  711. return (ASN_ERR_FAILED);
  712. pdu->scoped_len += padlen;
  713. }
  714. return (ASN_ERR_OK);
  715. }
  716. enum snmp_code
  717. snmp_fix_encoding(struct asn_buf *b, struct snmp_pdu *pdu)
  718. {
  719. size_t moved = 0;
  720. enum snmp_code code;
  721. if (asn_commit_header(b, pdu->vars_ptr, NULL) != ASN_ERR_OK ||
  722. asn_commit_header(b, pdu->pdu_ptr, NULL) != ASN_ERR_OK)
  723. return (SNMP_CODE_FAILED);
  724. if (pdu->version == SNMP_V3) {
  725. if (asn_commit_header(b, pdu->scoped_ptr, NULL) != ASN_ERR_OK)
  726. return (SNMP_CODE_FAILED);
  727. pdu->scoped_len = b->asn_ptr - pdu->scoped_ptr;
  728. if ((code = snmp_pdu_fix_padd(b, pdu))!= ASN_ERR_OK)
  729. return (SNMP_CODE_FAILED);
  730. if (pdu->security_model != SNMP_SECMODEL_USM)
  731. return (SNMP_CODE_FAILED);
  732. if (snmp_pdu_encrypt(pdu) != SNMP_CODE_OK)
  733. return (SNMP_CODE_FAILED);
  734. if (pdu->user.priv_proto != SNMP_PRIV_NOPRIV &&
  735. asn_commit_header(b, pdu->encrypted_ptr, NULL) != ASN_ERR_OK)
  736. return (SNMP_CODE_FAILED);
  737. }
  738. if (asn_commit_header(b, pdu->outer_ptr, &moved) != ASN_ERR_OK)
  739. return (SNMP_CODE_FAILED);
  740. pdu->outer_len = b->asn_ptr - pdu->outer_ptr;
  741. pdu->digest_ptr -= moved;
  742. if (pdu->version == SNMP_V3) {
  743. if ((code = snmp_pdu_calc_digest(pdu, pdu->msg_digest)) !=
  744. SNMP_CODE_OK)
  745. return (SNMP_CODE_FAILED);
  746. if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0)
  747. memcpy(pdu->digest_ptr, pdu->msg_digest,
  748. sizeof(pdu->msg_digest));
  749. }
  750. return (SNMP_CODE_OK);
  751. }
  752. /*
  753. * Encode a binding. Caller must ensure, that the syntax is ok for that version.
  754. * Be sure not to cobber b, when something fails.
  755. */
  756. enum asn_err
  757. snmp_binding_encode(struct asn_buf *b, const struct snmp_value *binding)
  758. {
  759. u_char *ptr;
  760. enum asn_err err;
  761. struct asn_buf save = *b;
  762. if ((err = asn_put_temp_header(b, (ASN_TYPE_SEQUENCE |
  763. ASN_TYPE_CONSTRUCTED), &ptr)) != ASN_ERR_OK) {
  764. *b = save;
  765. return (err);
  766. }
  767. if ((err = asn_put_objid(b, &binding->var)) != ASN_ERR_OK) {
  768. *b = save;
  769. return (err);
  770. }
  771. switch (binding->syntax) {
  772. case SNMP_SYNTAX_NULL:
  773. err = asn_put_null(b);
  774. break;
  775. case SNMP_SYNTAX_INTEGER:
  776. err = asn_put_integer(b, binding->v.integer);
  777. break;
  778. case SNMP_SYNTAX_OCTETSTRING:
  779. err = asn_put_octetstring(b, binding->v.octetstring.octets,
  780. binding->v.octetstring.len);
  781. break;
  782. case SNMP_SYNTAX_OID:
  783. err = asn_put_objid(b, &binding->v.oid);
  784. break;
  785. case SNMP_SYNTAX_IPADDRESS:
  786. err = asn_put_ipaddress(b, binding->v.ipaddress);
  787. break;
  788. case SNMP_SYNTAX_TIMETICKS:
  789. err = asn_put_uint32(b, ASN_APP_TIMETICKS, binding->v.uint32);
  790. break;
  791. case SNMP_SYNTAX_COUNTER:
  792. err = asn_put_uint32(b, ASN_APP_COUNTER, binding->v.uint32);
  793. break;
  794. case SNMP_SYNTAX_GAUGE:
  795. err = asn_put_uint32(b, ASN_APP_GAUGE, binding->v.uint32);
  796. break;
  797. case SNMP_SYNTAX_COUNTER64:
  798. err = asn_put_counter64(b, binding->v.counter64);
  799. break;
  800. case SNMP_SYNTAX_NOSUCHOBJECT:
  801. err = asn_put_exception(b, ASN_EXCEPT_NOSUCHOBJECT);
  802. break;
  803. case SNMP_SYNTAX_NOSUCHINSTANCE:
  804. err = asn_put_exception(b, ASN_EXCEPT_NOSUCHINSTANCE);
  805. break;
  806. case SNMP_SYNTAX_ENDOFMIBVIEW:
  807. err = asn_put_exception(b, ASN_EXCEPT_ENDOFMIBVIEW);
  808. break;
  809. }
  810. if (err != ASN_ERR_OK) {
  811. *b = save;
  812. return (err);
  813. }
  814. err = asn_commit_header(b, ptr, NULL);
  815. if (err != ASN_ERR_OK) {
  816. *b = save;
  817. return (err);
  818. }
  819. return (ASN_ERR_OK);
  820. }
  821. /*
  822. * Encode an PDU.
  823. */
  824. enum snmp_code
  825. snmp_pdu_encode(struct snmp_pdu *pdu, struct asn_buf *resp_b)
  826. {
  827. u_int idx;
  828. enum snmp_code err;
  829. if ((err = snmp_pdu_encode_header(resp_b, pdu)) != SNMP_CODE_OK)
  830. return (err);
  831. for (idx = 0; idx < pdu->nbindings; idx++)
  832. if ((err = snmp_binding_encode(resp_b, &pdu->bindings[idx]))
  833. != ASN_ERR_OK)
  834. return (SNMP_CODE_FAILED);
  835. return (snmp_fix_encoding(resp_b, pdu));
  836. }
  837. static void
  838. dump_binding(const struct snmp_value *b)
  839. {
  840. u_int i;
  841. char buf[ASN_OIDSTRLEN];
  842. snmp_printf("%s=", asn_oid2str_r(&b->var, buf));
  843. switch (b->syntax) {
  844. case SNMP_SYNTAX_NULL:
  845. snmp_printf("NULL");
  846. break;
  847. case SNMP_SYNTAX_INTEGER:
  848. snmp_printf("INTEGER %d", b->v.integer);
  849. break;
  850. case SNMP_SYNTAX_OCTETSTRING:
  851. snmp_printf("OCTET STRING %lu:", b->v.octetstring.len);
  852. for (i = 0; i < b->v.octetstring.len; i++)
  853. snmp_printf(" %02x", b->v.octetstring.octets[i]);
  854. break;
  855. case SNMP_SYNTAX_OID:
  856. snmp_printf("OID %s", asn_oid2str_r(&b->v.oid, buf));
  857. break;
  858. case SNMP_SYNTAX_IPADDRESS:
  859. snmp_printf("IPADDRESS %u.%u.%u.%u", b->v.ipaddress[0],
  860. b->v.ipaddress[1], b->v.ipaddress[2], b->v.ipaddress[3]);
  861. break;
  862. case SNMP_SYNTAX_COUNTER:
  863. snmp_printf("COUNTER %u", b->v.uint32);
  864. break;
  865. case SNMP_SYNTAX_GAUGE:
  866. snmp_printf("GAUGE %u", b->v.uint32);
  867. break;
  868. case SNMP_SYNTAX_TIMETICKS:
  869. snmp_printf("TIMETICKS %u", b->v.uint32);
  870. break;
  871. case SNMP_SYNTAX_COUNTER64:
  872. snmp_printf("COUNTER64 %lld", b->v.counter64);
  873. break;
  874. case SNMP_SYNTAX_NOSUCHOBJECT:
  875. snmp_printf("NoSuchObject");
  876. break;
  877. case SNMP_SYNTAX_NOSUCHINSTANCE:
  878. snmp_printf("NoSuchInstance");
  879. break;
  880. case SNMP_SYNTAX_ENDOFMIBVIEW:
  881. snmp_printf("EndOfMibView");
  882. break;
  883. default:
  884. snmp_printf("UNKNOWN SYNTAX %u", b->syntax);
  885. break;
  886. }
  887. }
  888. static __inline void
  889. dump_bindings(const struct snmp_pdu *pdu)
  890. {
  891. u_int i;
  892. for (i = 0; i < pdu->nbindings; i++) {
  893. snmp_printf(" [%u]: ", i);
  894. dump_binding(&pdu->bindings[i]);
  895. snmp_printf("\n");
  896. }
  897. }
  898. static __inline void
  899. dump_notrap(const struct snmp_pdu *pdu)
  900. {
  901. snmp_printf(" request_id=%d", pdu->request_id);
  902. snmp_printf(" error_status=%d", pdu->error_status);
  903. snmp_printf(" error_index=%d\n", pdu->error_index);
  904. dump_bindings(pdu);
  905. }
  906. void
  907. snmp_pdu_dump(const struct snmp_pdu *pdu)
  908. {
  909. char buf[ASN_OIDSTRLEN];
  910. const char *vers;
  911. static const char *types[] = {
  912. [SNMP_PDU_GET] = "GET",
  913. [SNMP_PDU_GETNEXT] = "GETNEXT",
  914. [SNMP_PDU_RESPONSE] = "RESPONSE",
  915. [SNMP_PDU_SET] = "SET",
  916. [SNMP_PDU_TRAP] = "TRAPv1",
  917. [SNMP_PDU_GETBULK] = "GETBULK",
  918. [SNMP_PDU_INFORM] = "INFORM",
  919. [SNMP_PDU_TRAP2] = "TRAPv2",
  920. [SNMP_PDU_REPORT] = "REPORT",
  921. };
  922. if (pdu->version == SNMP_V1)
  923. vers = "SNMPv1";
  924. else if (pdu->version == SNMP_V2c)
  925. vers = "SNMPv2c";
  926. else if (pdu->version == SNMP_V3)
  927. vers = "SNMPv3";
  928. else
  929. vers = "v?";
  930. switch (pdu->type) {
  931. case SNMP_PDU_TRAP:
  932. snmp_printf("%s %s '%s'", types[pdu->type], vers, pdu->community);
  933. snmp_printf(" enterprise=%s", asn_oid2str_r(&pdu->enterprise, buf));
  934. snmp_printf(" agent_addr=%u.%u.%u.%u", pdu->agent_addr[0],
  935. pdu->agent_addr[1], pdu->agent_addr[2], pdu->agent_addr[3]);
  936. snmp_printf(" generic_trap=%d", pdu->generic_trap);
  937. snmp_printf(" specific_trap=%d", pdu->specific_trap);
  938. snmp_printf(" time-stamp=%u\n", pdu->time_stamp);
  939. dump_bindings(pdu);
  940. break;
  941. case SNMP_PDU_GET:
  942. case SNMP_PDU_GETNEXT:
  943. case SNMP_PDU_RESPONSE:
  944. case SNMP_PDU_SET:
  945. case SNMP_PDU_GETBULK:
  946. case SNMP_PDU_INFORM:
  947. case SNMP_PDU_TRAP2:
  948. case SNMP_PDU_REPORT:
  949. snmp_printf("%s %s '%s'", types[pdu->type], vers, pdu->community);
  950. dump_notrap(pdu);
  951. break;
  952. default:
  953. snmp_printf("bad pdu type %u\n", pdu->type);
  954. break;
  955. }
  956. }
  957. void
  958. snmp_value_free(struct snmp_value *value)
  959. {
  960. if (value->syntax == SNMP_SYNTAX_OCTETSTRING)
  961. free(value->v.octetstring.octets);
  962. value->syntax = SNMP_SYNTAX_NULL;
  963. }
  964. int
  965. snmp_value_copy(struct snmp_value *to, const struct snmp_value *from)
  966. {
  967. to->var = from->var;
  968. to->syntax = from->syntax;
  969. if (from->syntax == SNMP_SYNTAX_OCTETSTRING) {
  970. if ((to->v.octetstring.len = from->v.octetstring.len) == 0)
  971. to->v.octetstring.octets = NULL;
  972. else {
  973. to->v.octetstring.octets = malloc(to->v.octetstring.len);
  974. if (to->v.octetstring.octets == NULL)
  975. return (-1);
  976. (void)memcpy(to->v.octetstring.octets,
  977. from->v.octetstring.octets, to->v.octetstring.len);
  978. }
  979. } else
  980. to->v = from->v;
  981. return (0);
  982. }
  983. void
  984. snmp_pdu_init_secparams(struct snmp_pdu *pdu)
  985. {
  986. int32_t rval;
  987. if (pdu->user.auth_proto != SNMP_AUTH_NOAUTH)
  988. pdu->flags |= SNMP_MSG_AUTH_FLAG;
  989. switch (pdu->user.priv_proto) {
  990. case SNMP_PRIV_DES:
  991. memcpy(pdu->msg_salt, &pdu->engine.engine_boots,
  992. sizeof(pdu->engine.engine_boots));
  993. rval = random();
  994. memcpy(pdu->msg_salt + sizeof(pdu->engine.engine_boots), &rval,
  995. sizeof(int32_t));
  996. pdu->flags |= SNMP_MSG_PRIV_FLAG;
  997. break;
  998. case SNMP_PRIV_AES:
  999. rval = random();
  1000. memcpy(pdu->msg_salt, &rval, sizeof(int32_t));
  1001. rval = random();
  1002. memcpy(pdu->msg_salt + sizeof(int32_t), &rval, sizeof(int32_t));
  1003. pdu->flags |= SNMP_MSG_PRIV_FLAG;
  1004. break;
  1005. default:
  1006. break;
  1007. }
  1008. }
  1009. void
  1010. snmp_pdu_free(struct snmp_pdu *pdu)
  1011. {
  1012. u_int i;
  1013. for (i = 0; i < pdu->nbindings; i++)
  1014. snmp_value_free(&pdu->bindings[i]);
  1015. }
  1016. /*
  1017. * Parse an ASCII SNMP value into the binary form
  1018. */
  1019. int
  1020. snmp_value_parse(const char *str, enum snmp_syntax syntax, union snmp_values *v)
  1021. {
  1022. char *end;
  1023. switch (syntax) {
  1024. case SNMP_SYNTAX_NULL:
  1025. case SNMP_SYNTAX_NOSUCHOBJECT:
  1026. case SNMP_SYNTAX_NOSUCHINSTANCE:
  1027. case SNMP_SYNTAX_ENDOFMIBVIEW:
  1028. if (*str != '\0')
  1029. return (-1);
  1030. return (0);
  1031. case SNMP_SYNTAX_INTEGER:
  1032. v->integer = strtoll(str, &end, 0);
  1033. if (*end != '\0')
  1034. return (-1);
  1035. return (0);
  1036. case SNMP_SYNTAX_OCTETSTRING:
  1037. {
  1038. u_long len; /* actual length of string */
  1039. u_long alloc; /* allocate length of string */
  1040. u_char *octs; /* actual octets */
  1041. u_long oct; /* actual octet */
  1042. u_char *nocts; /* to avoid memory leak */
  1043. u_char c; /* actual character */
  1044. # define STUFFC(C) \
  1045. if (alloc == len) { \
  1046. alloc += 100; \
  1047. if ((nocts = realloc(octs, alloc)) == NULL) { \
  1048. free(octs); \
  1049. return (-1); \
  1050. } \
  1051. octs = nocts; \
  1052. } \
  1053. octs[len++] = (C);
  1054. len = alloc = 0;
  1055. octs = NULL;
  1056. if (*str == '"') {
  1057. str++;
  1058. while((c = *str++) != '\0') {
  1059. if (c == '"') {
  1060. if (*str != '\0') {
  1061. free(octs);
  1062. return (-1);
  1063. }
  1064. break;
  1065. }
  1066. if (c == '\\') {
  1067. switch (c = *str++) {
  1068. case '\\':
  1069. break;
  1070. case 'a':
  1071. c = '\a';
  1072. break;
  1073. case 'b':
  1074. c = '\b';
  1075. break;
  1076. case 'f':
  1077. c = '\f';
  1078. break;
  1079. case 'n':
  1080. c = '\n';
  1081. break;
  1082. case 'r':
  1083. c = '\r';
  1084. break;
  1085. case 't':
  1086. c = '\t';
  1087. break;
  1088. case 'v':
  1089. c = '\v';
  1090. break;
  1091. case 'x':
  1092. c = 0;
  1093. if (!isxdigit(*str))
  1094. break;
  1095. if (isdigit(*str))
  1096. c = *str++ - '0';
  1097. else if (isupper(*str))
  1098. c = *str++ - 'A' + 10;
  1099. else
  1100. c = *str++ - 'a' + 10;
  1101. if (!isxdigit(*str))
  1102. break;
  1103. if (isdigit(*str))
  1104. c += *str++ - '0';
  1105. else if (isupper(*str))
  1106. c += *str++ - 'A' + 10;
  1107. else
  1108. c += *str++ - 'a' + 10;
  1109. break;
  1110. case '0': case '1': case '2':
  1111. case '3': case '4': case '5':
  1112. case '6': case '7':
  1113. c = *str++ - '0';
  1114. if (*str < '0' || *str > '7')
  1115. break;
  1116. c = *str++ - '0';
  1117. if (*str < '0' || *str > '7')
  1118. break;
  1119. c = *str++ - '0';
  1120. break;
  1121. default:
  1122. break;
  1123. }
  1124. }
  1125. STUFFC(c);
  1126. }
  1127. } else {
  1128. while (*str != '\0') {
  1129. oct = strtoul(str, &end, 16);
  1130. str = end;
  1131. if (oct > 0xff) {
  1132. free(octs);
  1133. return (-1);
  1134. }
  1135. STUFFC(oct);
  1136. if (*str == ':')
  1137. str++;
  1138. else if(*str != '\0') {
  1139. free(octs);
  1140. return (-1);
  1141. }
  1142. }
  1143. }
  1144. v->octetstring.octets = octs;
  1145. v->octetstring.len = len;
  1146. return (0);
  1147. # undef STUFFC
  1148. }
  1149. case SNMP_SYNTAX_OID:
  1150. {
  1151. u_long subid;
  1152. v->oid.len = 0;
  1153. for (;;) {
  1154. if (v->oid.len == ASN_MAXOIDLEN)
  1155. return (-1);
  1156. subid = strtoul(str, &end, 10);
  1157. str = end;
  1158. if (subid > ASN_MAXID)
  1159. return (-1);
  1160. v->oid.subs[v->oid.len++] = (asn_subid_t)subid;
  1161. if (*str == '\0')
  1162. break;
  1163. if (*str != '.')
  1164. return (-1);
  1165. str++;
  1166. }
  1167. return (0);
  1168. }
  1169. case SNMP_SYNTAX_IPADDRESS:
  1170. {
  1171. struct hostent *he;
  1172. u_long ip[4];
  1173. int n;
  1174. if (sscanf(str, "%lu.%lu.%lu.%lu%n", &ip[0], &ip[1], &ip[2],
  1175. &ip[3], &n) == 4 && (size_t)n == strlen(str) &&
  1176. ip[0] <= 0xff && ip[1] <= 0xff &&
  1177. ip[2] <= 0xff && ip[3] <= 0xff) {
  1178. v->ipaddress[0] = (u_char)ip[0];
  1179. v->ipaddress[1] = (u_char)ip[1];
  1180. v->ipaddress[2] = (u_char)ip[2];
  1181. v->ipaddress[3] = (u_char)ip[3];
  1182. return (0);
  1183. }
  1184. if ((he = gethostbyname(str)) == NULL)
  1185. return (-1);
  1186. if (he->h_addrtype != AF_INET)
  1187. return (-1);
  1188. v->ipaddress[0] = he->h_addr[0];
  1189. v->ipaddress[1] = he->h_addr[1];
  1190. v->ipaddress[2] = he->h_addr[2];
  1191. v->ipaddress[3] = he->h_addr[3];
  1192. return (0);
  1193. }
  1194. case SNMP_SYNTAX_COUNTER:
  1195. case SNMP_SYNTAX_GAUGE:
  1196. case SNMP_SYNTAX_TIMETICKS:
  1197. {
  1198. uint64_t sub;
  1199. sub = strtoull(str, &end, 0);
  1200. if (*end != '\0' || sub > 0xffffffff)
  1201. return (-1);
  1202. v->uint32 = (uint32_t)sub;
  1203. return (0);
  1204. }
  1205. case SNMP_SYNTAX_COUNTER64:
  1206. v->counter64 = strtoull(str, &end, 0);
  1207. if (*end != '\0')
  1208. return (-1);
  1209. return (0);
  1210. }
  1211. abort();
  1212. }
  1213. static void
  1214. snmp_error_func(const char *fmt, ...)
  1215. {
  1216. va_list ap;
  1217. va_start(ap, fmt);
  1218. fprintf(stderr, "SNMP: ");
  1219. vfprintf(stderr, fmt, ap);
  1220. fprintf(stderr, "\n");
  1221. va_end(ap);
  1222. }
  1223. static void
  1224. snmp_printf_func(const char *fmt, ...)
  1225. {
  1226. va_list ap;
  1227. va_start(ap, fmt);
  1228. vfprintf(stderr, fmt, ap);
  1229. va_end(ap);
  1230. }