/contrib/bsnmp/snmp_target/target_snmp.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 837 lines · 692 code · 108 blank · 37 comment · 214 complexity · f76fa680e034dd85e8da7e4953218b19 MD5 · raw file

  1. /*-
  2. * Copyright (c) 2010 The FreeBSD Foundation
  3. * All rights reserved.
  4. *
  5. * This software was developed by Shteryana Sotirova Shopova under
  6. * sponsorship from the FreeBSD Foundation.
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. * 2. Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in the
  15. * documentation and/or other materials provided with the distribution.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  18. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20. * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  21. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  23. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  24. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  26. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  27. * SUCH DAMAGE.
  28. *
  29. * $FreeBSD$
  30. */
  31. #include <sys/queue.h>
  32. #include <sys/types.h>
  33. #include <errno.h>
  34. #include <stdarg.h>
  35. #include <stdlib.h>
  36. #include <stdio.h>
  37. #include <stdint.h>
  38. #include <string.h>
  39. #include <syslog.h>
  40. #include "asn1.h"
  41. #include "snmp.h"
  42. #include "snmpmod.h"
  43. #include "target_tree.h"
  44. #include "target_oid.h"
  45. static struct lmodule *target_module;
  46. /* For the registration. */
  47. static const struct asn_oid oid_target = OIDX_snmpTargetMIB;
  48. static const struct asn_oid oid_notification = OIDX_snmpNotificationMIB;
  49. static uint reg_target;
  50. static uint reg_notification;
  51. static int32_t target_lock;
  52. static const struct asn_oid oid_udp_domain = OIDX_snmpUDPDomain;
  53. /*
  54. * Internal datastructures and forward declarations.
  55. */
  56. static void target_append_index(struct asn_oid *, uint,
  57. const char *);
  58. static int target_decode_index(const struct asn_oid *, uint,
  59. char *);
  60. static struct target_address *target_get_address(const struct asn_oid *,
  61. uint);
  62. static struct target_address *target_get_next_address(const struct asn_oid *,
  63. uint);
  64. static struct target_param *target_get_param(const struct asn_oid *,
  65. uint);
  66. static struct target_param *target_get_next_param(const struct asn_oid *,
  67. uint);
  68. static struct target_notify *target_get_notify(const struct asn_oid *,
  69. uint);
  70. static struct target_notify *target_get_next_notify(const struct asn_oid *,
  71. uint);
  72. int
  73. op_snmp_target(struct snmp_context *ctx __unused, struct snmp_value *val,
  74. uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
  75. {
  76. struct snmpd_target_stats *ctx_stats;
  77. if (val->var.subs[sub - 1] == LEAF_snmpTargetSpinLock) {
  78. switch (op) {
  79. case SNMP_OP_GET:
  80. if (++target_lock == INT32_MAX)
  81. target_lock = 0;
  82. val->v.integer = target_lock;
  83. break;
  84. case SNMP_OP_GETNEXT:
  85. abort();
  86. case SNMP_OP_SET:
  87. if (val->v.integer != target_lock)
  88. return (SNMP_ERR_INCONS_VALUE);
  89. break;
  90. case SNMP_OP_ROLLBACK:
  91. /* FALLTHROUGH */
  92. case SNMP_OP_COMMIT:
  93. break;
  94. }
  95. return (SNMP_ERR_NOERROR);
  96. } else if (op == SNMP_OP_SET)
  97. return (SNMP_ERR_NOT_WRITEABLE);
  98. if ((ctx_stats = bsnmpd_get_target_stats()) == NULL)
  99. return (SNMP_ERR_GENERR);
  100. if (op == SNMP_OP_GET) {
  101. switch (val->var.subs[sub - 1]) {
  102. case LEAF_snmpUnavailableContexts:
  103. val->v.uint32 = ctx_stats->unavail_contexts;
  104. break;
  105. case LEAF_snmpUnknownContexts:
  106. val->v.uint32 = ctx_stats->unknown_contexts;
  107. break;
  108. default:
  109. return (SNMP_ERR_NOSUCHNAME);
  110. }
  111. return (SNMP_ERR_NOERROR);
  112. }
  113. abort();
  114. }
  115. int
  116. op_snmp_target_addrs(struct snmp_context *ctx __unused, struct snmp_value *val,
  117. uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
  118. {
  119. char aname[SNMP_ADM_STR32_SIZ];
  120. struct target_address *addrs;
  121. switch (op) {
  122. case SNMP_OP_GET:
  123. if ((addrs = target_get_address(&val->var, sub)) == NULL)
  124. return (SNMP_ERR_NOSUCHNAME);
  125. break;
  126. case SNMP_OP_GETNEXT:
  127. if ((addrs = target_get_next_address(&val->var, sub)) == NULL)
  128. return (SNMP_ERR_NOSUCHNAME);
  129. target_append_index(&val->var, sub, addrs->name);
  130. break;
  131. case SNMP_OP_SET:
  132. if ((addrs = target_get_address(&val->var, sub)) == NULL &&
  133. (val->var.subs[sub - 1] != LEAF_snmpTargetAddrRowStatus ||
  134. val->v.integer != RowStatus_createAndWait))
  135. return (SNMP_ERR_NOSUCHNAME);
  136. if (addrs != NULL) {
  137. if (community != COMM_INITIALIZE &&
  138. addrs->type == StorageType_readOnly)
  139. return (SNMP_ERR_NOT_WRITEABLE);
  140. if (addrs->status == RowStatus_active &&
  141. val->v.integer != RowStatus_destroy)
  142. return (SNMP_ERR_INCONS_VALUE);
  143. }
  144. switch (val->var.subs[sub - 1]) {
  145. case LEAF_snmpTargetAddrTDomain:
  146. return (SNMP_ERR_INCONS_VALUE);
  147. case LEAF_snmpTargetAddrTAddress:
  148. if (val->v.octetstring.len != SNMP_UDP_ADDR_SIZ)
  149. return (SNMP_ERR_INCONS_VALUE);
  150. ctx->scratch->ptr1 = malloc(SNMP_UDP_ADDR_SIZ);
  151. if (ctx->scratch->ptr1 == NULL)
  152. return (SNMP_ERR_GENERR);
  153. memcpy(ctx->scratch->ptr1, addrs->address,
  154. SNMP_UDP_ADDR_SIZ);
  155. memcpy(addrs->address, val->v.octetstring.octets,
  156. SNMP_UDP_ADDR_SIZ);
  157. break;
  158. case LEAF_snmpTargetAddrTagList:
  159. if (val->v.octetstring.len >= SNMP_TAG_SIZ)
  160. return (SNMP_ERR_INCONS_VALUE);
  161. ctx->scratch->int1 = strlen(addrs->taglist) + 1;
  162. ctx->scratch->ptr1 = malloc(ctx->scratch->int1);
  163. if (ctx->scratch->ptr1 == NULL)
  164. return (SNMP_ERR_GENERR);
  165. strlcpy(ctx->scratch->ptr1, addrs->taglist,
  166. ctx->scratch->int1);
  167. memcpy(addrs->taglist, val->v.octetstring.octets,
  168. val->v.octetstring.len);
  169. addrs->taglist[val->v.octetstring.len] = '\0';
  170. break;
  171. case LEAF_snmpTargetAddrParams:
  172. if (val->v.octetstring.len >= SNMP_ADM_STR32_SIZ)
  173. return (SNMP_ERR_INCONS_VALUE);
  174. ctx->scratch->int1 = strlen(addrs->paramname) + 1;
  175. ctx->scratch->ptr1 = malloc(ctx->scratch->int1);
  176. if (ctx->scratch->ptr1 == NULL)
  177. return (SNMP_ERR_GENERR);
  178. strlcpy(ctx->scratch->ptr1, addrs->paramname,
  179. ctx->scratch->int1);
  180. memcpy(addrs->paramname, val->v.octetstring.octets,
  181. val->v.octetstring.len);
  182. addrs->paramname[val->v.octetstring.len] = '\0';
  183. break;
  184. case LEAF_snmpTargetAddrRetryCount:
  185. ctx->scratch->int1 = addrs->retry;
  186. addrs->retry = val->v.integer;
  187. break;
  188. case LEAF_snmpTargetAddrTimeout:
  189. ctx->scratch->int1 = addrs->timeout;
  190. addrs->timeout = val->v.integer / 10;
  191. break;
  192. case LEAF_snmpTargetAddrStorageType:
  193. return (SNMP_ERR_INCONS_VALUE);
  194. case LEAF_snmpTargetAddrRowStatus:
  195. if (addrs != NULL) {
  196. if (val->v.integer != RowStatus_active &&
  197. val->v.integer != RowStatus_destroy)
  198. return (SNMP_ERR_INCONS_VALUE);
  199. if (val->v.integer == RowStatus_active &&
  200. (addrs->address[0] == 0 ||
  201. strlen(addrs->taglist) == 0 ||
  202. strlen(addrs->paramname) == 0))
  203. return (SNMP_ERR_INCONS_VALUE);
  204. ctx->scratch->int1 = addrs->status;
  205. addrs->status = val->v.integer;
  206. return (SNMP_ERR_NOERROR);
  207. }
  208. if (val->v.integer != RowStatus_createAndWait ||
  209. target_decode_index(&val->var, sub, aname) < 0)
  210. return (SNMP_ERR_INCONS_VALUE);
  211. if ((addrs = target_new_address(aname)) == NULL)
  212. return (SNMP_ERR_GENERR);
  213. addrs->status = RowStatus_destroy;
  214. if (community != COMM_INITIALIZE)
  215. addrs->type = StorageType_volatile;
  216. else
  217. addrs->type = StorageType_readOnly;
  218. break;
  219. }
  220. return (SNMP_ERR_NOERROR);
  221. case SNMP_OP_COMMIT:
  222. switch (val->var.subs[sub - 1]) {
  223. case LEAF_snmpTargetAddrTAddress:
  224. case LEAF_snmpTargetAddrTagList:
  225. case LEAF_snmpTargetAddrParams:
  226. free(ctx->scratch->ptr1);
  227. break;
  228. case LEAF_snmpTargetAddrRowStatus:
  229. if ((addrs = target_get_address(&val->var, sub)) == NULL)
  230. return (SNMP_ERR_GENERR);
  231. if (val->v.integer == RowStatus_destroy)
  232. return (target_delete_address(addrs));
  233. else if (val->v.integer == RowStatus_active)
  234. return (target_activate_address(addrs));
  235. break;
  236. default:
  237. break;
  238. }
  239. return (SNMP_ERR_NOERROR);
  240. case SNMP_OP_ROLLBACK:
  241. if ((addrs = target_get_address(&val->var, sub)) == NULL)
  242. return (SNMP_ERR_GENERR);
  243. switch (val->var.subs[sub - 1]) {
  244. case LEAF_snmpTargetAddrTAddress:
  245. memcpy(addrs->address, ctx->scratch->ptr1,
  246. SNMP_UDP_ADDR_SIZ);
  247. free(ctx->scratch->ptr1);
  248. break;
  249. case LEAF_snmpTargetAddrTagList:
  250. strlcpy(addrs->taglist, ctx->scratch->ptr1,
  251. ctx->scratch->int1);
  252. free(ctx->scratch->ptr1);
  253. break;
  254. case LEAF_snmpTargetAddrParams:
  255. strlcpy(addrs->paramname, ctx->scratch->ptr1,
  256. ctx->scratch->int1);
  257. free(ctx->scratch->ptr1);
  258. break;
  259. case LEAF_snmpTargetAddrRetryCount:
  260. addrs->retry = ctx->scratch->int1;
  261. break;
  262. case LEAF_snmpTargetAddrTimeout:
  263. addrs->timeout = ctx->scratch->int1;
  264. break;
  265. case LEAF_snmpTargetAddrRowStatus:
  266. if (ctx->scratch->int1 == RowStatus_destroy)
  267. return (target_delete_address(addrs));
  268. break;
  269. default:
  270. break;
  271. }
  272. default:
  273. abort();
  274. }
  275. switch (val->var.subs[sub - 1]) {
  276. case LEAF_snmpTargetAddrTDomain:
  277. return (oid_get(val, &oid_udp_domain));
  278. case LEAF_snmpTargetAddrTAddress:
  279. return (string_get(val, addrs->address, SNMP_UDP_ADDR_SIZ));
  280. case LEAF_snmpTargetAddrTimeout:
  281. val->v.integer = addrs->timeout;
  282. break;
  283. case LEAF_snmpTargetAddrRetryCount:
  284. val->v.integer = addrs->retry;
  285. break;
  286. case LEAF_snmpTargetAddrTagList:
  287. return (string_get(val, addrs->taglist, -1));
  288. case LEAF_snmpTargetAddrParams:
  289. return (string_get(val, addrs->paramname, -1));
  290. case LEAF_snmpTargetAddrStorageType:
  291. val->v.integer = addrs->type;
  292. break;
  293. case LEAF_snmpTargetAddrRowStatus:
  294. val->v.integer = addrs->status;
  295. break;
  296. default:
  297. abort();
  298. }
  299. return (SNMP_ERR_NOERROR);
  300. }
  301. int
  302. op_snmp_target_params(struct snmp_context *ctx __unused, struct snmp_value *val,
  303. uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
  304. {
  305. char pname[SNMP_ADM_STR32_SIZ];
  306. struct target_param *param;
  307. switch (op) {
  308. case SNMP_OP_GET:
  309. if ((param = target_get_param(&val->var, sub)) == NULL)
  310. return (SNMP_ERR_NOSUCHNAME);
  311. break;
  312. case SNMP_OP_GETNEXT:
  313. if ((param = target_get_next_param(&val->var, sub)) == NULL)
  314. return (SNMP_ERR_NOSUCHNAME);
  315. target_append_index(&val->var, sub, param->name);
  316. break;
  317. case SNMP_OP_SET:
  318. if ((param = target_get_param(&val->var, sub)) == NULL &&
  319. (val->var.subs[sub - 1] != LEAF_snmpTargetParamsRowStatus ||
  320. val->v.integer != RowStatus_createAndWait))
  321. return (SNMP_ERR_NOSUCHNAME);
  322. if (param != NULL) {
  323. if (community != COMM_INITIALIZE &&
  324. param->type == StorageType_readOnly)
  325. return (SNMP_ERR_NOT_WRITEABLE);
  326. if (param->status == RowStatus_active &&
  327. val->v.integer != RowStatus_destroy)
  328. return (SNMP_ERR_INCONS_VALUE);
  329. }
  330. switch (val->var.subs[sub - 1]) {
  331. case LEAF_snmpTargetParamsMPModel:
  332. if (val->v.integer != SNMP_MPM_SNMP_V1 &&
  333. val->v.integer != SNMP_MPM_SNMP_V2c &&
  334. val->v.integer != SNMP_MPM_SNMP_V3)
  335. return (SNMP_ERR_INCONS_VALUE);
  336. ctx->scratch->int1 = param->mpmodel;
  337. param->mpmodel = val->v.integer;
  338. break;
  339. case LEAF_snmpTargetParamsSecurityModel:
  340. if (val->v.integer != SNMP_SECMODEL_SNMPv1 &&
  341. val->v.integer != SNMP_SECMODEL_SNMPv2c &&
  342. val->v.integer != SNMP_SECMODEL_USM)
  343. return (SNMP_ERR_INCONS_VALUE);
  344. ctx->scratch->int1 = param->sec_model;
  345. param->sec_model = val->v.integer;
  346. break;
  347. case LEAF_snmpTargetParamsSecurityName:
  348. if (val->v.octetstring.len >= SNMP_ADM_STR32_SIZ)
  349. return (SNMP_ERR_INCONS_VALUE);
  350. ctx->scratch->int1 = strlen(param->secname) + 1;
  351. ctx->scratch->ptr1 = malloc(ctx->scratch->int1);
  352. if (ctx->scratch->ptr1 == NULL)
  353. return (SNMP_ERR_GENERR);
  354. strlcpy(ctx->scratch->ptr1, param->secname,
  355. ctx->scratch->int1);
  356. memcpy(param->secname, val->v.octetstring.octets,
  357. val->v.octetstring.len);
  358. param->secname[val->v.octetstring.len] = '\0';
  359. break;
  360. case LEAF_snmpTargetParamsSecurityLevel:
  361. if (val->v.integer != SNMP_noAuthNoPriv &&
  362. val->v.integer != SNMP_authNoPriv &&
  363. val->v.integer != SNMP_authPriv)
  364. return (SNMP_ERR_INCONS_VALUE);
  365. ctx->scratch->int1 = param->sec_level;
  366. param->sec_level = val->v.integer;
  367. break;
  368. case LEAF_snmpTargetParamsStorageType:
  369. return (SNMP_ERR_INCONS_VALUE);
  370. case LEAF_snmpTargetParamsRowStatus:
  371. if (param != NULL) {
  372. if (val->v.integer != RowStatus_active &&
  373. val->v.integer != RowStatus_destroy)
  374. return (SNMP_ERR_INCONS_VALUE);
  375. if (val->v.integer == RowStatus_active &&
  376. (param->sec_model == 0 ||
  377. param->sec_level == 0 ||
  378. strlen(param->secname) == 0))
  379. return (SNMP_ERR_INCONS_VALUE);
  380. ctx->scratch->int1 = param->status;
  381. param->status = val->v.integer;
  382. return (SNMP_ERR_NOERROR);
  383. }
  384. if (val->v.integer != RowStatus_createAndWait ||
  385. target_decode_index(&val->var, sub, pname) < 0)
  386. return (SNMP_ERR_INCONS_VALUE);
  387. if ((param = target_new_param(pname)) == NULL)
  388. return (SNMP_ERR_GENERR);
  389. param->status = RowStatus_destroy;
  390. if (community != COMM_INITIALIZE)
  391. param->type = StorageType_volatile;
  392. else
  393. param->type = StorageType_readOnly;
  394. break;
  395. }
  396. return (SNMP_ERR_NOERROR);
  397. case SNMP_OP_COMMIT:
  398. switch (val->var.subs[sub - 1]) {
  399. case LEAF_snmpTargetParamsSecurityName:
  400. free(ctx->scratch->ptr1);
  401. break;
  402. case LEAF_snmpTargetParamsRowStatus:
  403. if ((param = target_get_param(&val->var, sub)) == NULL)
  404. return (SNMP_ERR_GENERR);
  405. if (val->v.integer == RowStatus_destroy)
  406. return (target_delete_param(param));
  407. break;
  408. default:
  409. break;
  410. }
  411. return (SNMP_ERR_NOERROR);
  412. case SNMP_OP_ROLLBACK:
  413. if ((param = target_get_param(&val->var, sub)) == NULL &&
  414. (val->var.subs[sub - 1] != LEAF_snmpTargetParamsRowStatus ||
  415. val->v.integer != RowStatus_createAndWait))
  416. return (SNMP_ERR_GENERR);
  417. switch (val->var.subs[sub - 1]) {
  418. case LEAF_snmpTargetParamsMPModel:
  419. param->mpmodel = ctx->scratch->int1;
  420. break;
  421. case LEAF_snmpTargetParamsSecurityModel:
  422. param->sec_model = ctx->scratch->int1;
  423. break;
  424. case LEAF_snmpTargetParamsSecurityName:
  425. strlcpy(param->secname, ctx->scratch->ptr1,
  426. sizeof(param->secname));
  427. free(ctx->scratch->ptr1);
  428. break;
  429. case LEAF_snmpTargetParamsSecurityLevel:
  430. param->sec_level = ctx->scratch->int1;
  431. break;
  432. case LEAF_snmpTargetParamsRowStatus:
  433. if (ctx->scratch->int1 == RowStatus_destroy)
  434. return (target_delete_param(param));
  435. break;
  436. default:
  437. break;
  438. }
  439. return (SNMP_ERR_NOERROR);
  440. default:
  441. abort();
  442. }
  443. switch (val->var.subs[sub - 1]) {
  444. case LEAF_snmpTargetParamsMPModel:
  445. val->v.integer = param->mpmodel;
  446. break;
  447. case LEAF_snmpTargetParamsSecurityModel:
  448. val->v.integer = param->sec_model;
  449. break;
  450. case LEAF_snmpTargetParamsSecurityName:
  451. return (string_get(val, param->secname, -1));
  452. case LEAF_snmpTargetParamsSecurityLevel:
  453. val->v.integer = param->sec_level;
  454. break;
  455. case LEAF_snmpTargetParamsStorageType:
  456. val->v.integer = param->type;
  457. break;
  458. case LEAF_snmpTargetParamsRowStatus:
  459. val->v.integer = param->status;
  460. break;
  461. default:
  462. abort();
  463. }
  464. return (SNMP_ERR_NOERROR);
  465. }
  466. int
  467. op_snmp_notify(struct snmp_context *ctx __unused, struct snmp_value *val,
  468. uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
  469. {
  470. char nname[SNMP_ADM_STR32_SIZ];
  471. struct target_notify *notify;
  472. switch (op) {
  473. case SNMP_OP_GET:
  474. if ((notify = target_get_notify(&val->var, sub)) == NULL)
  475. return (SNMP_ERR_NOSUCHNAME);
  476. break;
  477. case SNMP_OP_GETNEXT:
  478. if ((notify = target_get_next_notify(&val->var, sub)) == NULL)
  479. return (SNMP_ERR_NOSUCHNAME);
  480. target_append_index(&val->var, sub, notify->name);
  481. break;
  482. case SNMP_OP_SET:
  483. if ((notify = target_get_notify(&val->var, sub)) == NULL &&
  484. (val->var.subs[sub - 1] != LEAF_snmpNotifyRowStatus ||
  485. val->v.integer != RowStatus_createAndGo))
  486. return (SNMP_ERR_NOSUCHNAME);
  487. if (notify != NULL) {
  488. if (community != COMM_INITIALIZE &&
  489. notify->type == StorageType_readOnly)
  490. return (SNMP_ERR_NOT_WRITEABLE);
  491. }
  492. switch (val->var.subs[sub - 1]) {
  493. case LEAF_snmpNotifyTag:
  494. if (val->v.octetstring.len >= SNMP_TAG_SIZ)
  495. return (SNMP_ERR_INCONS_VALUE);
  496. ctx->scratch->int1 = strlen(notify->taglist) + 1;
  497. ctx->scratch->ptr1 = malloc(ctx->scratch->int1);
  498. if (ctx->scratch->ptr1 == NULL)
  499. return (SNMP_ERR_GENERR);
  500. strlcpy(ctx->scratch->ptr1, notify->taglist,
  501. ctx->scratch->int1);
  502. memcpy(notify->taglist, val->v.octetstring.octets,
  503. val->v.octetstring.len);
  504. notify->taglist[val->v.octetstring.len] = '\0';
  505. break;
  506. case LEAF_snmpNotifyType:
  507. /* FALLTHROUGH */
  508. case LEAF_snmpNotifyStorageType:
  509. return (SNMP_ERR_INCONS_VALUE);
  510. case LEAF_snmpNotifyRowStatus:
  511. if (notify != NULL) {
  512. if (val->v.integer != RowStatus_active &&
  513. val->v.integer != RowStatus_destroy)
  514. return (SNMP_ERR_INCONS_VALUE);
  515. ctx->scratch->int1 = notify->status;
  516. notify->status = val->v.integer;
  517. return (SNMP_ERR_NOERROR);
  518. }
  519. if (val->v.integer != RowStatus_createAndGo ||
  520. target_decode_index(&val->var, sub, nname) < 0)
  521. return (SNMP_ERR_INCONS_VALUE);
  522. if ((notify = target_new_notify(nname)) == NULL)
  523. return (SNMP_ERR_GENERR);
  524. notify->status = RowStatus_destroy;
  525. if (community != COMM_INITIALIZE)
  526. notify->type = StorageType_volatile;
  527. else
  528. notify->type = StorageType_readOnly;
  529. break;
  530. }
  531. return (SNMP_ERR_NOERROR);
  532. case SNMP_OP_COMMIT:
  533. switch (val->var.subs[sub - 1]) {
  534. case LEAF_snmpNotifyTag:
  535. free(ctx->scratch->ptr1);
  536. break;
  537. case LEAF_snmpNotifyRowStatus:
  538. notify = target_get_notify(&val->var, sub);
  539. if (notify == NULL)
  540. return (SNMP_ERR_GENERR);
  541. if (val->v.integer == RowStatus_destroy)
  542. return (target_delete_notify(notify));
  543. else
  544. notify->status = RowStatus_active;
  545. break;
  546. default:
  547. break;
  548. }
  549. return (SNMP_ERR_NOERROR);
  550. case SNMP_OP_ROLLBACK:
  551. if ((notify = target_get_notify(&val->var, sub)) == NULL)
  552. return (SNMP_ERR_GENERR);
  553. switch (val->var.subs[sub - 1]) {
  554. case LEAF_snmpNotifyTag:
  555. strlcpy(notify->taglist, ctx->scratch->ptr1,
  556. ctx->scratch->int1);
  557. free(ctx->scratch->ptr1);
  558. break;
  559. case LEAF_snmpNotifyRowStatus:
  560. if (ctx->scratch->int1 == RowStatus_destroy)
  561. return (target_delete_notify(notify));
  562. break;
  563. default:
  564. break;
  565. }
  566. default:
  567. abort();
  568. }
  569. switch (val->var.subs[sub - 1]) {
  570. case LEAF_snmpNotifyTag:
  571. return (string_get(val, notify->taglist, -1));
  572. case LEAF_snmpNotifyType:
  573. val->v.integer = snmpNotifyType_trap;
  574. break;
  575. case LEAF_snmpNotifyStorageType:
  576. val->v.integer = notify->type;
  577. break;
  578. case LEAF_snmpNotifyRowStatus:
  579. val->v.integer = notify->status;
  580. break;
  581. default:
  582. abort();
  583. }
  584. return (SNMP_ERR_NOERROR);
  585. }
  586. static void
  587. target_append_index(struct asn_oid *oid, uint sub, const char *name)
  588. {
  589. uint32_t i;
  590. oid->len = sub + strlen(name);
  591. for (i = 0; i < strlen(name); i++)
  592. oid->subs[sub + i] = name[i];
  593. }
  594. static int
  595. target_decode_index(const struct asn_oid *oid, uint sub, char *name)
  596. {
  597. uint32_t i, len;
  598. if ((len = oid->len - sub) >= SNMP_ADM_STR32_SIZ)
  599. return (-1);
  600. for (i = 0; i < len; i++)
  601. name[i] = oid->subs[sub + i];
  602. name[i] = '\0';
  603. return (0);
  604. }
  605. static struct target_address *
  606. target_get_address(const struct asn_oid *oid, uint sub)
  607. {
  608. char aname[SNMP_ADM_STR32_SIZ];
  609. struct target_address *addrs;
  610. if (target_decode_index(oid, sub, aname) < 0)
  611. return (NULL);
  612. for (addrs = target_first_address(); addrs != NULL;
  613. addrs = target_next_address(addrs))
  614. if (strcmp(aname, addrs->name) == 0)
  615. return (addrs);
  616. return (NULL);
  617. }
  618. static struct target_address *
  619. target_get_next_address(const struct asn_oid * oid, uint sub)
  620. {
  621. char aname[SNMP_ADM_STR32_SIZ];
  622. struct target_address *addrs;
  623. if (oid->len - sub == 0)
  624. return (target_first_address());
  625. if (target_decode_index(oid, sub, aname) < 0)
  626. return (NULL);
  627. for (addrs = target_first_address(); addrs != NULL;
  628. addrs = target_next_address(addrs))
  629. if (strcmp(aname, addrs->name) == 0)
  630. return (target_next_address(addrs));
  631. return (NULL);
  632. }
  633. static struct target_param *
  634. target_get_param(const struct asn_oid *oid, uint sub)
  635. {
  636. char pname[SNMP_ADM_STR32_SIZ];
  637. struct target_param *param;
  638. if (target_decode_index(oid, sub, pname) < 0)
  639. return (NULL);
  640. for (param = target_first_param(); param != NULL;
  641. param = target_next_param(param))
  642. if (strcmp(pname, param->name) == 0)
  643. return (param);
  644. return (NULL);
  645. }
  646. static struct target_param *
  647. target_get_next_param(const struct asn_oid *oid, uint sub)
  648. {
  649. char pname[SNMP_ADM_STR32_SIZ];
  650. struct target_param *param;
  651. if (oid->len - sub == 0)
  652. return (target_first_param());
  653. if (target_decode_index(oid, sub, pname) < 0)
  654. return (NULL);
  655. for (param = target_first_param(); param != NULL;
  656. param = target_next_param(param))
  657. if (strcmp(pname, param->name) == 0)
  658. return (target_next_param(param));
  659. return (NULL);
  660. }
  661. static struct target_notify *
  662. target_get_notify(const struct asn_oid *oid, uint sub)
  663. {
  664. char nname[SNMP_ADM_STR32_SIZ];
  665. struct target_notify *notify;
  666. if (target_decode_index(oid, sub, nname) < 0)
  667. return (NULL);
  668. for (notify = target_first_notify(); notify != NULL;
  669. notify = target_next_notify(notify))
  670. if (strcmp(nname, notify->name) == 0)
  671. return (notify);
  672. return (NULL);
  673. }
  674. static struct target_notify *
  675. target_get_next_notify(const struct asn_oid *oid, uint sub)
  676. {
  677. char nname[SNMP_ADM_STR32_SIZ];
  678. struct target_notify *notify;
  679. if (oid->len - sub == 0)
  680. return (target_first_notify());
  681. if (target_decode_index(oid, sub, nname) < 0)
  682. return (NULL);
  683. for (notify = target_first_notify(); notify != NULL;
  684. notify = target_next_notify(notify))
  685. if (strcmp(nname, notify->name) == 0)
  686. return (target_next_notify(notify));
  687. return (NULL);
  688. }
  689. static int
  690. target_init(struct lmodule *mod, int argc __unused, char *argv[] __unused)
  691. {
  692. target_module = mod;
  693. target_lock = random();
  694. return (0);
  695. }
  696. static int
  697. target_fini(void)
  698. {
  699. target_flush_all();
  700. or_unregister(reg_target);
  701. or_unregister(reg_notification);
  702. return (0);
  703. }
  704. static void
  705. target_start(void)
  706. {
  707. reg_target = or_register(&oid_target,
  708. "The MIB module for managing SNMP Management Targets.",
  709. target_module);
  710. reg_notification = or_register(&oid_notification,
  711. "The MIB module for configuring generation of SNMP notifications.",
  712. target_module);
  713. }
  714. static void
  715. target_dump(void)
  716. {
  717. /* XXX: dump the module stats & list of mgmt targets */
  718. }
  719. const char target_comment[] = \
  720. "This module implements SNMP Management Target MIB Module defined in RFC 3413.";
  721. const struct snmp_module config = {
  722. .comment = target_comment,
  723. .init = target_init,
  724. .fini = target_fini,
  725. .start = target_start,
  726. .tree = target_ctree,
  727. .dump = target_dump,
  728. .tree_size = target_CTREE_SIZE,
  729. };