PageRenderTime 61ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/contrib/bsnmp/snmpd/main.c

https://bitbucket.org/freebsd/freebsd-head/
C | 3277 lines | 2434 code | 513 blank | 330 comment | 652 complexity | 0688c8abe78f8fe7c0eac9a3c53b4665 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, BSD-3-Clause, LGPL-2.0, LGPL-2.1, BSD-2-Clause, 0BSD, JSON, AGPL-1.0, GPL-2.0
  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/snmpd/main.c,v 1.100 2006/02/14 09:04:20 brandt_h Exp $
  36. *
  37. * SNMPd main stuff.
  38. */
  39. #include <sys/queue.h>
  40. #include <sys/param.h>
  41. #include <sys/un.h>
  42. #include <sys/ucred.h>
  43. #include <sys/uio.h>
  44. #include <stdio.h>
  45. #include <stdlib.h>
  46. #include <stddef.h>
  47. #include <string.h>
  48. #include <stdarg.h>
  49. #include <ctype.h>
  50. #include <errno.h>
  51. #include <syslog.h>
  52. #include <unistd.h>
  53. #include <signal.h>
  54. #include <dlfcn.h>
  55. #include <inttypes.h>
  56. #ifdef USE_TCPWRAPPERS
  57. #include <arpa/inet.h>
  58. #include <tcpd.h>
  59. #endif
  60. #include "support.h"
  61. #include "snmpmod.h"
  62. #include "snmpd.h"
  63. #include "tree.h"
  64. #include "oid.h"
  65. #define PATH_PID "/var/run/%s.pid"
  66. #define PATH_CONFIG "/etc/%s.config"
  67. #define PATH_ENGINE "/var/%s.engine"
  68. uint64_t this_tick; /* start of processing of current packet (absolute) */
  69. uint64_t start_tick; /* start of processing */
  70. struct systemg systemg = {
  71. NULL,
  72. { 8, { 1, 3, 6, 1, 4, 1, 1115, 7352 }},
  73. NULL, NULL, NULL,
  74. 64 + 8 + 4,
  75. 0
  76. };
  77. struct debug debug = {
  78. 0, /* dump_pdus */
  79. LOG_DEBUG, /* log_pri */
  80. 0, /* evdebug */
  81. };
  82. struct snmpd snmpd = {
  83. 2048, /* txbuf */
  84. 2048, /* rxbuf */
  85. 0, /* comm_dis */
  86. 0, /* auth_traps */
  87. {0, 0, 0, 0}, /* trap1addr */
  88. VERS_ENABLE_ALL,/* version_enable */
  89. };
  90. struct snmpd_stats snmpd_stats;
  91. struct snmpd_usmstat snmpd_usmstats;
  92. /* snmpEngine */
  93. struct snmp_engine snmpd_engine;
  94. /* snmpSerialNo */
  95. int32_t snmp_serial_no;
  96. struct snmpd_target_stats snmpd_target_stats;
  97. /* search path for config files */
  98. const char *syspath = PATH_SYSCONFIG;
  99. /* list of all loaded modules */
  100. struct lmodules lmodules = TAILQ_HEAD_INITIALIZER(lmodules);
  101. /* list of loaded modules during start-up in the order they were loaded */
  102. static struct lmodules modules_start = TAILQ_HEAD_INITIALIZER(modules_start);
  103. /* list of all known communities */
  104. struct community_list community_list = TAILQ_HEAD_INITIALIZER(community_list);
  105. /* list of all known USM users */
  106. struct usm_userlist usm_userlist = SLIST_HEAD_INITIALIZER(usm_userlist);
  107. /* A list of all VACM users configured, including v1, v2c and v3 */
  108. struct vacm_userlist vacm_userlist = SLIST_HEAD_INITIALIZER(vacm_userlist);
  109. /* A list of all VACM groups */
  110. struct vacm_grouplist vacm_grouplist = SLIST_HEAD_INITIALIZER(vacm_grouplist);
  111. static struct vacm_group vacm_default_group = {
  112. .groupname = "",
  113. };
  114. /* The list of configured access entries */
  115. struct vacm_accesslist vacm_accesslist = TAILQ_HEAD_INITIALIZER(vacm_accesslist);
  116. /* The list of configured views */
  117. struct vacm_viewlist vacm_viewlist = SLIST_HEAD_INITIALIZER(vacm_viewlist);
  118. /* The list of configured contexts */
  119. struct vacm_contextlist vacm_contextlist =
  120. SLIST_HEAD_INITIALIZER(vacm_contextlist);
  121. /* list of all installed object resources */
  122. struct objres_list objres_list = TAILQ_HEAD_INITIALIZER(objres_list);
  123. /* community value generator */
  124. static u_int next_community_index = 1;
  125. /* list of all known ranges */
  126. struct idrange_list idrange_list = TAILQ_HEAD_INITIALIZER(idrange_list);
  127. /* identifier generator */
  128. u_int next_idrange = 1;
  129. /* list of all current timers */
  130. struct timer_list timer_list = LIST_HEAD_INITIALIZER(timer_list);
  131. /* list of file descriptors */
  132. struct fdesc_list fdesc_list = LIST_HEAD_INITIALIZER(fdesc_list);
  133. /* program arguments */
  134. static char **progargs;
  135. static int nprogargs;
  136. /* current community */
  137. u_int community;
  138. static struct community *comm;
  139. /* current USM user */
  140. struct usm_user *usm_user;
  141. /* file names */
  142. static char config_file[MAXPATHLEN + 1];
  143. static char pid_file[MAXPATHLEN + 1];
  144. char engine_file[MAXPATHLEN + 1];
  145. #ifndef USE_LIBBEGEMOT
  146. /* event context */
  147. static evContext evctx;
  148. #endif
  149. /* signal mask */
  150. static sigset_t blocked_sigs;
  151. /* signal handling */
  152. static int work;
  153. #define WORK_DOINFO 0x0001
  154. #define WORK_RECONFIG 0x0002
  155. /* oids */
  156. static const struct asn_oid
  157. oid_snmpMIB = OIDX_snmpMIB,
  158. oid_begemotSnmpd = OIDX_begemotSnmpd,
  159. oid_coldStart = OIDX_coldStart,
  160. oid_authenticationFailure = OIDX_authenticationFailure;
  161. const struct asn_oid oid_zeroDotZero = { 2, { 0, 0 }};
  162. const struct asn_oid oid_usmUnknownEngineIDs =
  163. { 11, { 1, 3, 6, 1, 6, 3, 15, 1, 1, 4, 0}};
  164. const struct asn_oid oid_usmNotInTimeWindows =
  165. { 11, { 1, 3, 6, 1, 6, 3, 15, 1, 1, 2, 0}};
  166. /* request id generator for traps */
  167. u_int trap_reqid;
  168. /* help text */
  169. static const char usgtxt[] = "\
  170. Begemot simple SNMP daemon. Copyright (c) 2001-2002 Fraunhofer Institute for\n\
  171. Open Communication Systems (FhG Fokus). All rights reserved.\n\
  172. Copyright (c) 2010 The FreeBSD Foundation. All rights reserved.\n\
  173. usage: snmpd [-dh] [-c file] [-D options] [-e file] [-I path]\n\
  174. [-l prefix] [-m variable=value] [-p file]\n\
  175. options:\n\
  176. -d don't daemonize\n\
  177. -h print this info\n\
  178. -c file specify configuration file\n\
  179. -D options debugging options\n\
  180. -e file specify engine id file\n\
  181. -I path system include path\n\
  182. -l prefix default basename for pid and config file\n\
  183. -m var=val define variable\n\
  184. -p file specify pid file\n\
  185. ";
  186. /* hosts_access(3) request */
  187. #ifdef USE_TCPWRAPPERS
  188. static struct request_info req;
  189. #endif
  190. /* transports */
  191. extern const struct transport_def udp_trans;
  192. extern const struct transport_def lsock_trans;
  193. struct transport_list transport_list = TAILQ_HEAD_INITIALIZER(transport_list);
  194. /* forward declarations */
  195. static void snmp_printf_func(const char *fmt, ...);
  196. static void snmp_error_func(const char *err, ...);
  197. static void snmp_debug_func(const char *err, ...);
  198. static void asn_error_func(const struct asn_buf *b, const char *err, ...);
  199. /*
  200. * Allocate rx/tx buffer. We allocate one byte more for rx.
  201. */
  202. void *
  203. buf_alloc(int tx)
  204. {
  205. void *buf;
  206. if ((buf = malloc(tx ? snmpd.txbuf : snmpd.rxbuf)) == NULL) {
  207. syslog(LOG_CRIT, "cannot allocate buffer");
  208. if (tx)
  209. snmpd_stats.noTxbuf++;
  210. else
  211. snmpd_stats.noRxbuf++;
  212. return (NULL);
  213. }
  214. return (buf);
  215. }
  216. /*
  217. * Return the buffer size.
  218. */
  219. size_t
  220. buf_size(int tx)
  221. {
  222. return (tx ? snmpd.txbuf : snmpd.rxbuf);
  223. }
  224. /*
  225. * Prepare a PDU for output
  226. */
  227. void
  228. snmp_output(struct snmp_pdu *pdu, u_char *sndbuf, size_t *sndlen,
  229. const char *dest)
  230. {
  231. struct asn_buf resp_b;
  232. resp_b.asn_ptr = sndbuf;
  233. resp_b.asn_len = snmpd.txbuf;
  234. if (snmp_pdu_encode(pdu, &resp_b) != 0) {
  235. syslog(LOG_ERR, "cannot encode message");
  236. abort();
  237. }
  238. if (debug.dump_pdus) {
  239. snmp_printf("%s <- ", dest);
  240. snmp_pdu_dump(pdu);
  241. }
  242. *sndlen = (size_t)(resp_b.asn_ptr - sndbuf);
  243. }
  244. /*
  245. * Check USM PDU header credentials against local SNMP Engine & users.
  246. */
  247. static enum snmp_code
  248. snmp_pdu_auth_user(struct snmp_pdu *pdu)
  249. {
  250. uint64_t etime;
  251. usm_user = NULL;
  252. /* un-authenticated snmpEngineId discovery */
  253. if (pdu->engine.engine_len == 0 && strlen(pdu->user.sec_name) == 0) {
  254. pdu->engine.engine_len = snmpd_engine.engine_len;
  255. memcpy(pdu->engine.engine_id, snmpd_engine.engine_id,
  256. snmpd_engine.engine_len);
  257. pdu->engine.engine_boots = snmpd_engine.engine_boots;
  258. pdu->engine.engine_time = snmpd_engine.engine_time;
  259. pdu->flags |= SNMP_MSG_AUTODISCOVER;
  260. return (SNMP_CODE_OK);
  261. }
  262. if ((usm_user = usm_find_user(pdu->engine.engine_id,
  263. pdu->engine.engine_len, pdu->user.sec_name)) == NULL ||
  264. usm_user->status != 1 /* active */)
  265. return (SNMP_CODE_BADUSER);
  266. if (usm_user->user_engine_len != snmpd_engine.engine_len ||
  267. memcmp(usm_user->user_engine_id, snmpd_engine.engine_id,
  268. snmpd_engine.engine_len) != 0)
  269. return (SNMP_CODE_BADENGINE);
  270. pdu->user.priv_proto = usm_user->suser.priv_proto;
  271. memcpy(pdu->user.priv_key, usm_user->suser.priv_key,
  272. sizeof(pdu->user.priv_key));
  273. /* authenticated snmpEngineId discovery */
  274. if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0) {
  275. etime = (get_ticks() - start_tick) / 100ULL;
  276. if (etime < INT32_MAX)
  277. snmpd_engine.engine_time = etime;
  278. else {
  279. start_tick = get_ticks();
  280. set_snmpd_engine();
  281. snmpd_engine.engine_time = start_tick;
  282. }
  283. pdu->user.auth_proto = usm_user->suser.auth_proto;
  284. memcpy(pdu->user.auth_key, usm_user->suser.auth_key,
  285. sizeof(pdu->user.auth_key));
  286. if (pdu->engine.engine_boots == 0 &&
  287. pdu->engine.engine_time == 0) {
  288. pdu->flags |= SNMP_MSG_AUTODISCOVER;
  289. return (SNMP_CODE_OK);
  290. }
  291. if (pdu->engine.engine_boots != snmpd_engine.engine_boots ||
  292. abs(pdu->engine.engine_time - snmpd_engine.engine_time) >
  293. SNMP_TIME_WINDOW)
  294. return (SNMP_CODE_NOTINTIME);
  295. }
  296. if (((pdu->flags & SNMP_MSG_PRIV_FLAG) != 0 &&
  297. (pdu->flags & SNMP_MSG_AUTH_FLAG) == 0) ||
  298. ((pdu->flags & SNMP_MSG_AUTH_FLAG) == 0 &&
  299. usm_user->suser.auth_proto != SNMP_AUTH_NOAUTH) ||
  300. ((pdu->flags & SNMP_MSG_PRIV_FLAG) == 0 &&
  301. usm_user->suser.priv_proto != SNMP_PRIV_NOPRIV))
  302. return (SNMP_CODE_BADSECLEVEL);
  303. return (SNMP_CODE_OK);
  304. }
  305. /*
  306. * Check whether access to each of var bindings in the PDU is allowed based
  307. * on the user credentials against the configured User groups & VACM views.
  308. */
  309. enum snmp_code
  310. snmp_pdu_auth_access(struct snmp_pdu *pdu, int32_t *ip)
  311. {
  312. const char *uname;
  313. int32_t suboid, smodel;
  314. uint32_t i;
  315. struct vacm_user *vuser;
  316. struct vacm_access *acl;
  317. struct vacm_context *vacmctx;
  318. struct vacm_view *view;
  319. /*
  320. * At least a default context exists if the snmpd_vacm(3) module is
  321. * running.
  322. */
  323. if (SLIST_EMPTY(&vacm_contextlist) ||
  324. (pdu->flags & SNMP_MSG_AUTODISCOVER) != 0)
  325. return (SNMP_CODE_OK);
  326. switch (pdu->version) {
  327. case SNMP_V1:
  328. if ((uname = comm_string(community)) == NULL)
  329. return (SNMP_CODE_FAILED);
  330. smodel = SNMP_SECMODEL_SNMPv1;
  331. break;
  332. case SNMP_V2c:
  333. if ((uname = comm_string(community)) == NULL)
  334. return (SNMP_CODE_FAILED);
  335. smodel = SNMP_SECMODEL_SNMPv2c;
  336. break;
  337. case SNMP_V3:
  338. uname = pdu->user.sec_name;
  339. if ((smodel = pdu->security_model) != SNMP_SECMODEL_USM)
  340. return (SNMP_CODE_FAILED);
  341. /* Compare the PDU context engine id against the agent's */
  342. if (pdu->context_engine_len != snmpd_engine.engine_len ||
  343. memcmp(pdu->context_engine, snmpd_engine.engine_id,
  344. snmpd_engine.engine_len) != 0)
  345. return (SNMP_CODE_FAILED);
  346. break;
  347. default:
  348. abort();
  349. }
  350. SLIST_FOREACH(vuser, &vacm_userlist, vvu)
  351. if (strcmp(uname, vuser->secname) == 0 &&
  352. vuser->sec_model == smodel)
  353. break;
  354. if (vuser == NULL || vuser->group == NULL)
  355. return (SNMP_CODE_FAILED);
  356. /* XXX: shteryana - recheck */
  357. TAILQ_FOREACH_REVERSE(acl, &vacm_accesslist, vacm_accesslist, vva) {
  358. if (acl->group != vuser->group)
  359. continue;
  360. SLIST_FOREACH(vacmctx, &vacm_contextlist, vcl)
  361. if (memcmp(vacmctx->ctxname, acl->ctx_prefix,
  362. acl->ctx_match) == 0)
  363. goto match;
  364. }
  365. return (SNMP_CODE_FAILED);
  366. match:
  367. switch (pdu->type) {
  368. case SNMP_PDU_GET:
  369. case SNMP_PDU_GETNEXT:
  370. case SNMP_PDU_GETBULK:
  371. if ((view = acl->read_view) == NULL)
  372. return (SNMP_CODE_FAILED);
  373. break;
  374. case SNMP_PDU_SET:
  375. if ((view = acl->write_view) == NULL)
  376. return (SNMP_CODE_FAILED);
  377. break;
  378. case SNMP_PDU_TRAP:
  379. case SNMP_PDU_INFORM:
  380. case SNMP_PDU_TRAP2:
  381. case SNMP_PDU_REPORT:
  382. if ((view = acl->notify_view) == NULL)
  383. return (SNMP_CODE_FAILED);
  384. break;
  385. case SNMP_PDU_RESPONSE:
  386. /* NOTREACHED */
  387. return (SNMP_CODE_FAILED);
  388. default:
  389. abort();
  390. }
  391. for (i = 0; i < pdu->nbindings; i++) {
  392. /* XXX - view->mask*/
  393. suboid = asn_is_suboid(&view->subtree, &pdu->bindings[i].var);
  394. if ((!suboid && !view->exclude) || (suboid && view->exclude)) {
  395. *ip = i + 1;
  396. return (SNMP_CODE_FAILED);
  397. }
  398. }
  399. return (SNMP_CODE_OK);
  400. }
  401. /*
  402. * SNMP input. Start: decode the PDU, find the user or community.
  403. */
  404. enum snmpd_input_err
  405. snmp_input_start(const u_char *buf, size_t len, const char *source,
  406. struct snmp_pdu *pdu, int32_t *ip, size_t *pdulen)
  407. {
  408. struct asn_buf b;
  409. enum snmp_code code;
  410. enum snmpd_input_err ret;
  411. int sret;
  412. /* update uptime */
  413. this_tick = get_ticks();
  414. b.asn_cptr = buf;
  415. b.asn_len = len;
  416. /* look whether we have enough bytes for the entire PDU. */
  417. switch (sret = snmp_pdu_snoop(&b)) {
  418. case 0:
  419. return (SNMPD_INPUT_TRUNC);
  420. case -1:
  421. snmpd_stats.inASNParseErrs++;
  422. return (SNMPD_INPUT_FAILED);
  423. }
  424. b.asn_len = *pdulen = (size_t)sret;
  425. memset(pdu, 0, sizeof(*pdu));
  426. if ((code = snmp_pdu_decode_header(&b, pdu)) != SNMP_CODE_OK)
  427. goto decoded;
  428. if (pdu->version == SNMP_V3) {
  429. if (pdu->security_model != SNMP_SECMODEL_USM) {
  430. code = SNMP_CODE_FAILED;
  431. goto decoded;
  432. }
  433. if ((code = snmp_pdu_auth_user(pdu)) != SNMP_CODE_OK)
  434. goto decoded;
  435. if ((code = snmp_pdu_decode_secmode(&b, pdu)) != SNMP_CODE_OK)
  436. goto decoded;
  437. }
  438. code = snmp_pdu_decode_scoped(&b, pdu, ip);
  439. ret = SNMPD_INPUT_OK;
  440. decoded:
  441. snmpd_stats.inPkts++;
  442. switch (code) {
  443. case SNMP_CODE_FAILED:
  444. snmpd_stats.inASNParseErrs++;
  445. return (SNMPD_INPUT_FAILED);
  446. case SNMP_CODE_BADVERS:
  447. bad_vers:
  448. snmpd_stats.inBadVersions++;
  449. return (SNMPD_INPUT_FAILED);
  450. case SNMP_CODE_BADLEN:
  451. if (pdu->type == SNMP_OP_SET)
  452. ret = SNMPD_INPUT_VALBADLEN;
  453. break;
  454. case SNMP_CODE_OORANGE:
  455. if (pdu->type == SNMP_OP_SET)
  456. ret = SNMPD_INPUT_VALRANGE;
  457. break;
  458. case SNMP_CODE_BADENC:
  459. if (pdu->type == SNMP_OP_SET)
  460. ret = SNMPD_INPUT_VALBADENC;
  461. break;
  462. case SNMP_CODE_BADSECLEVEL:
  463. snmpd_usmstats.unsupported_seclevels++;
  464. return (SNMPD_INPUT_FAILED);
  465. case SNMP_CODE_NOTINTIME:
  466. snmpd_usmstats.not_in_time_windows++;
  467. return (SNMPD_INPUT_FAILED);
  468. case SNMP_CODE_BADUSER:
  469. snmpd_usmstats.unknown_users++;
  470. return (SNMPD_INPUT_FAILED);
  471. case SNMP_CODE_BADENGINE:
  472. snmpd_usmstats.unknown_engine_ids++;
  473. return (SNMPD_INPUT_FAILED);
  474. case SNMP_CODE_BADDIGEST:
  475. snmpd_usmstats.wrong_digests++;
  476. return (SNMPD_INPUT_FAILED);
  477. case SNMP_CODE_EDECRYPT:
  478. snmpd_usmstats.decrypt_errors++;
  479. return (SNMPD_INPUT_FAILED);
  480. case SNMP_CODE_OK:
  481. switch (pdu->version) {
  482. case SNMP_V1:
  483. if (!(snmpd.version_enable & VERS_ENABLE_V1))
  484. goto bad_vers;
  485. break;
  486. case SNMP_V2c:
  487. if (!(snmpd.version_enable & VERS_ENABLE_V2C))
  488. goto bad_vers;
  489. break;
  490. case SNMP_V3:
  491. if (!(snmpd.version_enable & VERS_ENABLE_V3))
  492. goto bad_vers;
  493. break;
  494. case SNMP_Verr:
  495. goto bad_vers;
  496. }
  497. break;
  498. }
  499. if (debug.dump_pdus) {
  500. snmp_printf("%s -> ", source);
  501. snmp_pdu_dump(pdu);
  502. }
  503. /*
  504. * Look, whether we know the community or user
  505. */
  506. if (pdu->version != SNMP_V3) {
  507. TAILQ_FOREACH(comm, &community_list, link)
  508. if (comm->string != NULL &&
  509. strcmp(comm->string, pdu->community) == 0)
  510. break;
  511. if (comm == NULL) {
  512. snmpd_stats.inBadCommunityNames++;
  513. snmp_pdu_free(pdu);
  514. if (snmpd.auth_traps)
  515. snmp_send_trap(&oid_authenticationFailure,
  516. (struct snmp_value *)NULL);
  517. ret = SNMPD_INPUT_BAD_COMM;
  518. } else
  519. community = comm->value;
  520. } else if (pdu->nbindings == 0) {
  521. /* RFC 3414 - snmpEngineID Discovery */
  522. if (strlen(pdu->user.sec_name) == 0) {
  523. asn_append_oid(&(pdu->bindings[pdu->nbindings++].var),
  524. &oid_usmUnknownEngineIDs);
  525. pdu->context_engine_len = snmpd_engine.engine_len;
  526. memcpy(pdu->context_engine, snmpd_engine.engine_id,
  527. snmpd_engine.engine_len);
  528. } else if (pdu->engine.engine_boots == 0 &&
  529. pdu->engine.engine_time == 0) {
  530. asn_append_oid(&(pdu->bindings[pdu->nbindings++].var),
  531. &oid_usmNotInTimeWindows);
  532. pdu->engine.engine_boots = snmpd_engine.engine_boots;
  533. pdu->engine.engine_time = snmpd_engine.engine_time;
  534. }
  535. } else if (usm_user->suser.auth_proto != SNMP_AUTH_NOAUTH &&
  536. (pdu->engine.engine_boots == 0 || pdu->engine.engine_time == 0)) {
  537. snmpd_usmstats.not_in_time_windows++;
  538. ret = SNMP_CODE_FAILED;
  539. }
  540. if ((code = snmp_pdu_auth_access(pdu, ip)) != SNMP_CODE_OK)
  541. ret = SNMP_CODE_FAILED;
  542. return (ret);
  543. }
  544. /*
  545. * Will return only _OK or _FAILED
  546. */
  547. enum snmpd_input_err
  548. snmp_input_finish(struct snmp_pdu *pdu, const u_char *rcvbuf, size_t rcvlen,
  549. u_char *sndbuf, size_t *sndlen, const char *source,
  550. enum snmpd_input_err ierr, int32_t ivar, void *data)
  551. {
  552. struct snmp_pdu resp;
  553. struct asn_buf resp_b, pdu_b;
  554. enum snmp_ret ret;
  555. resp_b.asn_ptr = sndbuf;
  556. resp_b.asn_len = snmpd.txbuf;
  557. pdu_b.asn_cptr = rcvbuf;
  558. pdu_b.asn_len = rcvlen;
  559. if (ierr != SNMPD_INPUT_OK) {
  560. /* error decoding the input of a SET */
  561. if (pdu->version == SNMP_V1)
  562. pdu->error_status = SNMP_ERR_BADVALUE;
  563. else if (ierr == SNMPD_INPUT_VALBADLEN)
  564. pdu->error_status = SNMP_ERR_WRONG_LENGTH;
  565. else if (ierr == SNMPD_INPUT_VALRANGE)
  566. pdu->error_status = SNMP_ERR_WRONG_VALUE;
  567. else
  568. pdu->error_status = SNMP_ERR_WRONG_ENCODING;
  569. pdu->error_index = ivar;
  570. if (snmp_make_errresp(pdu, &pdu_b, &resp_b) == SNMP_RET_IGN) {
  571. syslog(LOG_WARNING, "could not encode error response");
  572. snmpd_stats.silentDrops++;
  573. return (SNMPD_INPUT_FAILED);
  574. }
  575. if (debug.dump_pdus) {
  576. snmp_printf("%s <- ", source);
  577. snmp_pdu_dump(pdu);
  578. }
  579. *sndlen = (size_t)(resp_b.asn_ptr - sndbuf);
  580. return (SNMPD_INPUT_OK);
  581. }
  582. switch (pdu->type) {
  583. case SNMP_PDU_GET:
  584. ret = snmp_get(pdu, &resp_b, &resp, data);
  585. break;
  586. case SNMP_PDU_GETNEXT:
  587. ret = snmp_getnext(pdu, &resp_b, &resp, data);
  588. break;
  589. case SNMP_PDU_SET:
  590. ret = snmp_set(pdu, &resp_b, &resp, data);
  591. break;
  592. case SNMP_PDU_GETBULK:
  593. ret = snmp_getbulk(pdu, &resp_b, &resp, data);
  594. break;
  595. default:
  596. ret = SNMP_RET_IGN;
  597. break;
  598. }
  599. switch (ret) {
  600. case SNMP_RET_OK:
  601. /* normal return - send a response */
  602. if (debug.dump_pdus) {
  603. snmp_printf("%s <- ", source);
  604. snmp_pdu_dump(&resp);
  605. }
  606. *sndlen = (size_t)(resp_b.asn_ptr - sndbuf);
  607. snmp_pdu_free(&resp);
  608. return (SNMPD_INPUT_OK);
  609. case SNMP_RET_IGN:
  610. /* error - send nothing */
  611. snmpd_stats.silentDrops++;
  612. return (SNMPD_INPUT_FAILED);
  613. case SNMP_RET_ERR:
  614. /* error - send error response. The snmp routine has
  615. * changed the error fields in the original message. */
  616. resp_b.asn_ptr = sndbuf;
  617. resp_b.asn_len = snmpd.txbuf;
  618. if (snmp_make_errresp(pdu, &pdu_b, &resp_b) == SNMP_RET_IGN) {
  619. syslog(LOG_WARNING, "could not encode error response");
  620. snmpd_stats.silentDrops++;
  621. return (SNMPD_INPUT_FAILED);
  622. } else {
  623. if (debug.dump_pdus) {
  624. snmp_printf("%s <- ", source);
  625. snmp_pdu_dump(pdu);
  626. }
  627. *sndlen = (size_t)(resp_b.asn_ptr - sndbuf);
  628. return (SNMPD_INPUT_OK);
  629. }
  630. }
  631. abort();
  632. }
  633. /*
  634. * Insert a port into the right place in the transport's table of ports
  635. */
  636. void
  637. trans_insert_port(struct transport *t, struct tport *port)
  638. {
  639. struct tport *p;
  640. TAILQ_FOREACH(p, &t->table, link) {
  641. if (asn_compare_oid(&p->index, &port->index) > 0) {
  642. TAILQ_INSERT_BEFORE(p, port, link);
  643. return;
  644. }
  645. }
  646. port->transport = t;
  647. TAILQ_INSERT_TAIL(&t->table, port, link);
  648. }
  649. /*
  650. * Remove a port from a transport's list
  651. */
  652. void
  653. trans_remove_port(struct tport *port)
  654. {
  655. TAILQ_REMOVE(&port->transport->table, port, link);
  656. }
  657. /*
  658. * Find a port on a transport's list
  659. */
  660. struct tport *
  661. trans_find_port(struct transport *t, const struct asn_oid *idx, u_int sub)
  662. {
  663. return (FIND_OBJECT_OID(&t->table, idx, sub));
  664. }
  665. /*
  666. * Find next port on a transport's list
  667. */
  668. struct tport *
  669. trans_next_port(struct transport *t, const struct asn_oid *idx, u_int sub)
  670. {
  671. return (NEXT_OBJECT_OID(&t->table, idx, sub));
  672. }
  673. /*
  674. * Return first port
  675. */
  676. struct tport *
  677. trans_first_port(struct transport *t)
  678. {
  679. return (TAILQ_FIRST(&t->table));
  680. }
  681. /*
  682. * Iterate through all ports until a function returns a 0.
  683. */
  684. struct tport *
  685. trans_iter_port(struct transport *t, int (*func)(struct tport *, intptr_t),
  686. intptr_t arg)
  687. {
  688. struct tport *p;
  689. TAILQ_FOREACH(p, &t->table, link)
  690. if (func(p, arg) == 0)
  691. return (p);
  692. return (NULL);
  693. }
  694. /*
  695. * Register a transport
  696. */
  697. int
  698. trans_register(const struct transport_def *def, struct transport **pp)
  699. {
  700. u_int i;
  701. char or_descr[256];
  702. if ((*pp = malloc(sizeof(**pp))) == NULL)
  703. return (SNMP_ERR_GENERR);
  704. /* construct index */
  705. (*pp)->index.len = strlen(def->name) + 1;
  706. (*pp)->index.subs[0] = strlen(def->name);
  707. for (i = 0; i < (*pp)->index.subs[0]; i++)
  708. (*pp)->index.subs[i + 1] = def->name[i];
  709. (*pp)->vtab = def;
  710. if (FIND_OBJECT_OID(&transport_list, &(*pp)->index, 0) != NULL) {
  711. free(*pp);
  712. return (SNMP_ERR_INCONS_VALUE);
  713. }
  714. /* register module */
  715. snprintf(or_descr, sizeof(or_descr), "%s transport mapping", def->name);
  716. if (((*pp)->or_index = or_register(&def->id, or_descr, NULL)) == 0) {
  717. free(*pp);
  718. return (SNMP_ERR_GENERR);
  719. }
  720. INSERT_OBJECT_OID((*pp), &transport_list);
  721. TAILQ_INIT(&(*pp)->table);
  722. return (SNMP_ERR_NOERROR);
  723. }
  724. /*
  725. * Unregister transport
  726. */
  727. int
  728. trans_unregister(struct transport *t)
  729. {
  730. if (!TAILQ_EMPTY(&t->table))
  731. return (SNMP_ERR_INCONS_VALUE);
  732. or_unregister(t->or_index);
  733. TAILQ_REMOVE(&transport_list, t, link);
  734. return (SNMP_ERR_NOERROR);
  735. }
  736. /*
  737. * File descriptor support
  738. */
  739. #ifdef USE_LIBBEGEMOT
  740. static void
  741. input(int fd, int mask __unused, void *uap)
  742. #else
  743. static void
  744. input(evContext ctx __unused, void *uap, int fd, int mask __unused)
  745. #endif
  746. {
  747. struct fdesc *f = uap;
  748. (*f->func)(fd, f->udata);
  749. }
  750. void
  751. fd_suspend(void *p)
  752. {
  753. struct fdesc *f = p;
  754. #ifdef USE_LIBBEGEMOT
  755. if (f->id >= 0) {
  756. poll_unregister(f->id);
  757. f->id = -1;
  758. }
  759. #else
  760. if (evTestID(f->id)) {
  761. (void)evDeselectFD(evctx, f->id);
  762. evInitID(&f->id);
  763. }
  764. #endif
  765. }
  766. int
  767. fd_resume(void *p)
  768. {
  769. struct fdesc *f = p;
  770. int err;
  771. #ifdef USE_LIBBEGEMOT
  772. if (f->id >= 0)
  773. return (0);
  774. if ((f->id = poll_register(f->fd, input, f, POLL_IN)) < 0) {
  775. err = errno;
  776. syslog(LOG_ERR, "select fd %d: %m", f->fd);
  777. errno = err;
  778. return (-1);
  779. }
  780. #else
  781. if (evTestID(f->id))
  782. return (0);
  783. if (evSelectFD(evctx, f->fd, EV_READ, input, f, &f->id)) {
  784. err = errno;
  785. syslog(LOG_ERR, "select fd %d: %m", f->fd);
  786. errno = err;
  787. return (-1);
  788. }
  789. #endif
  790. return (0);
  791. }
  792. void *
  793. fd_select(int fd, void (*func)(int, void *), void *udata, struct lmodule *mod)
  794. {
  795. struct fdesc *f;
  796. int err;
  797. if ((f = malloc(sizeof(struct fdesc))) == NULL) {
  798. err = errno;
  799. syslog(LOG_ERR, "fd_select: %m");
  800. errno = err;
  801. return (NULL);
  802. }
  803. f->fd = fd;
  804. f->func = func;
  805. f->udata = udata;
  806. f->owner = mod;
  807. #ifdef USE_LIBBEGEMOT
  808. f->id = -1;
  809. #else
  810. evInitID(&f->id);
  811. #endif
  812. if (fd_resume(f)) {
  813. err = errno;
  814. free(f);
  815. errno = err;
  816. return (NULL);
  817. }
  818. LIST_INSERT_HEAD(&fdesc_list, f, link);
  819. return (f);
  820. }
  821. void
  822. fd_deselect(void *p)
  823. {
  824. struct fdesc *f = p;
  825. LIST_REMOVE(f, link);
  826. fd_suspend(f);
  827. free(f);
  828. }
  829. static void
  830. fd_flush(struct lmodule *mod)
  831. {
  832. struct fdesc *t, *t1;
  833. t = LIST_FIRST(&fdesc_list);
  834. while (t != NULL) {
  835. t1 = LIST_NEXT(t, link);
  836. if (t->owner == mod)
  837. fd_deselect(t);
  838. t = t1;
  839. }
  840. }
  841. /*
  842. * Consume a message from the input buffer
  843. */
  844. static void
  845. snmp_input_consume(struct port_input *pi)
  846. {
  847. if (!pi->stream) {
  848. /* always consume everything */
  849. pi->length = 0;
  850. return;
  851. }
  852. if (pi->consumed >= pi->length) {
  853. /* all bytes consumed */
  854. pi->length = 0;
  855. return;
  856. }
  857. memmove(pi->buf, pi->buf + pi->consumed, pi->length - pi->consumed);
  858. pi->length -= pi->consumed;
  859. }
  860. static void
  861. check_priv_dgram(struct port_input *pi, struct sockcred *cred)
  862. {
  863. /* process explicitly sends credentials */
  864. if (cred)
  865. pi->priv = (cred->sc_euid == 0);
  866. else
  867. pi->priv = 0;
  868. }
  869. static void
  870. check_priv_stream(struct port_input *pi)
  871. {
  872. struct xucred ucred;
  873. socklen_t ucredlen;
  874. /* obtain the accept time credentials */
  875. ucredlen = sizeof(ucred);
  876. if (getsockopt(pi->fd, 0, LOCAL_PEERCRED, &ucred, &ucredlen) == 0 &&
  877. ucredlen >= sizeof(ucred) && ucred.cr_version == XUCRED_VERSION)
  878. pi->priv = (ucred.cr_uid == 0);
  879. else
  880. pi->priv = 0;
  881. }
  882. /*
  883. * Input from a stream socket.
  884. */
  885. static int
  886. recv_stream(struct port_input *pi)
  887. {
  888. struct msghdr msg;
  889. struct iovec iov[1];
  890. ssize_t len;
  891. if (pi->buf == NULL) {
  892. /* no buffer yet - allocate one */
  893. if ((pi->buf = buf_alloc(0)) == NULL) {
  894. /* ups - could not get buffer. Return an error
  895. * the caller must close the transport. */
  896. return (-1);
  897. }
  898. pi->buflen = buf_size(0);
  899. pi->consumed = 0;
  900. pi->length = 0;
  901. }
  902. /* try to get a message */
  903. msg.msg_name = pi->peer;
  904. msg.msg_namelen = pi->peerlen;
  905. msg.msg_iov = iov;
  906. msg.msg_iovlen = 1;
  907. msg.msg_control = NULL;
  908. msg.msg_controllen = 0;
  909. msg.msg_flags = 0;
  910. iov[0].iov_base = pi->buf + pi->length;
  911. iov[0].iov_len = pi->buflen - pi->length;
  912. len = recvmsg(pi->fd, &msg, 0);
  913. if (len == -1 || len == 0)
  914. /* receive error */
  915. return (-1);
  916. pi->length += len;
  917. if (pi->cred)
  918. check_priv_stream(pi);
  919. return (0);
  920. }
  921. /*
  922. * Input from a datagram socket.
  923. * Each receive should return one datagram.
  924. */
  925. static int
  926. recv_dgram(struct port_input *pi, struct in_addr *laddr)
  927. {
  928. u_char embuf[1000];
  929. char cbuf[CMSG_SPACE(SOCKCREDSIZE(CMGROUP_MAX)) +
  930. CMSG_SPACE(sizeof(struct in_addr))];
  931. struct msghdr msg;
  932. struct iovec iov[1];
  933. ssize_t len;
  934. struct cmsghdr *cmsg;
  935. struct sockcred *cred = NULL;
  936. if (pi->buf == NULL) {
  937. /* no buffer yet - allocate one */
  938. if ((pi->buf = buf_alloc(0)) == NULL) {
  939. /* ups - could not get buffer. Read away input
  940. * and drop it */
  941. (void)recvfrom(pi->fd, embuf, sizeof(embuf),
  942. 0, NULL, NULL);
  943. /* return error */
  944. return (-1);
  945. }
  946. pi->buflen = buf_size(0);
  947. }
  948. /* try to get a message */
  949. msg.msg_name = pi->peer;
  950. msg.msg_namelen = pi->peerlen;
  951. msg.msg_iov = iov;
  952. msg.msg_iovlen = 1;
  953. memset(cbuf, 0, sizeof(cbuf));
  954. msg.msg_control = cbuf;
  955. msg.msg_controllen = sizeof(cbuf);
  956. msg.msg_flags = 0;
  957. iov[0].iov_base = pi->buf;
  958. iov[0].iov_len = pi->buflen;
  959. len = recvmsg(pi->fd, &msg, 0);
  960. if (len == -1 || len == 0)
  961. /* receive error */
  962. return (-1);
  963. if (msg.msg_flags & MSG_TRUNC) {
  964. /* truncated - drop */
  965. snmpd_stats.silentDrops++;
  966. snmpd_stats.inTooLong++;
  967. return (-1);
  968. }
  969. pi->length = (size_t)len;
  970. for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
  971. cmsg = CMSG_NXTHDR(&msg, cmsg)) {
  972. if (cmsg->cmsg_level == IPPROTO_IP &&
  973. cmsg->cmsg_type == IP_RECVDSTADDR)
  974. memcpy(laddr, CMSG_DATA(cmsg), sizeof(struct in_addr));
  975. if (cmsg->cmsg_level == SOL_SOCKET &&
  976. cmsg->cmsg_type == SCM_CREDS)
  977. cred = (struct sockcred *)CMSG_DATA(cmsg);
  978. }
  979. if (pi->cred)
  980. check_priv_dgram(pi, cred);
  981. return (0);
  982. }
  983. /*
  984. * Input from a socket
  985. */
  986. int
  987. snmpd_input(struct port_input *pi, struct tport *tport)
  988. {
  989. u_char *sndbuf;
  990. size_t sndlen;
  991. struct snmp_pdu pdu;
  992. enum snmpd_input_err ierr, ferr;
  993. enum snmpd_proxy_err perr;
  994. int32_t vi;
  995. int ret;
  996. ssize_t slen;
  997. #ifdef USE_TCPWRAPPERS
  998. char client[16];
  999. #endif
  1000. struct msghdr msg;
  1001. struct iovec iov[1];
  1002. char cbuf[CMSG_SPACE(sizeof(struct in_addr))];
  1003. struct cmsghdr *cmsgp;
  1004. /* get input depending on the transport */
  1005. if (pi->stream) {
  1006. msg.msg_control = NULL;
  1007. msg.msg_controllen = 0;
  1008. ret = recv_stream(pi);
  1009. } else {
  1010. struct in_addr *laddr;
  1011. memset(cbuf, 0, CMSG_SPACE(sizeof(struct in_addr)));
  1012. msg.msg_control = cbuf;
  1013. msg.msg_controllen = CMSG_SPACE(sizeof(struct in_addr));
  1014. cmsgp = CMSG_FIRSTHDR(&msg);
  1015. cmsgp->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
  1016. cmsgp->cmsg_level = IPPROTO_IP;
  1017. cmsgp->cmsg_type = IP_SENDSRCADDR;
  1018. laddr = (struct in_addr *)CMSG_DATA(cmsgp);
  1019. ret = recv_dgram(pi, laddr);
  1020. if (laddr->s_addr == 0) {
  1021. msg.msg_control = NULL;
  1022. msg.msg_controllen = 0;
  1023. }
  1024. }
  1025. if (ret == -1)
  1026. return (-1);
  1027. #ifdef USE_TCPWRAPPERS
  1028. /*
  1029. * In case of AF_INET{6} peer, do hosts_access(5) check.
  1030. */
  1031. if (pi->peer->sa_family != AF_LOCAL &&
  1032. inet_ntop(pi->peer->sa_family,
  1033. &((const struct sockaddr_in *)(const void *)pi->peer)->sin_addr,
  1034. client, sizeof(client)) != NULL) {
  1035. request_set(&req, RQ_CLIENT_ADDR, client, 0);
  1036. if (hosts_access(&req) == 0) {
  1037. syslog(LOG_ERR, "refused connection from %.500s",
  1038. eval_client(&req));
  1039. return (-1);
  1040. }
  1041. } else if (pi->peer->sa_family != AF_LOCAL)
  1042. syslog(LOG_ERR, "inet_ntop(): %m");
  1043. #endif
  1044. /*
  1045. * Handle input
  1046. */
  1047. ierr = snmp_input_start(pi->buf, pi->length, "SNMP", &pdu, &vi,
  1048. &pi->consumed);
  1049. if (ierr == SNMPD_INPUT_TRUNC) {
  1050. /* need more bytes. This is ok only for streaming transports.
  1051. * but only if we have not reached bufsiz yet. */
  1052. if (pi->stream) {
  1053. if (pi->length == buf_size(0)) {
  1054. snmpd_stats.silentDrops++;
  1055. return (-1);
  1056. }
  1057. return (0);
  1058. }
  1059. snmpd_stats.silentDrops++;
  1060. return (-1);
  1061. }
  1062. /* can't check for bad SET pdus here, because a proxy may have to
  1063. * check the access first. We don't want to return an error response
  1064. * to a proxy PDU with a wrong community */
  1065. if (ierr == SNMPD_INPUT_FAILED) {
  1066. /* for streaming transports this is fatal */
  1067. if (pi->stream)
  1068. return (-1);
  1069. snmp_input_consume(pi);
  1070. return (0);
  1071. }
  1072. if (ierr == SNMPD_INPUT_BAD_COMM) {
  1073. snmp_input_consume(pi);
  1074. return (0);
  1075. }
  1076. /*
  1077. * If that is a module community and the module has a proxy function,
  1078. * the hand it over to the module.
  1079. */
  1080. if (comm != NULL && comm->owner != NULL &&
  1081. comm->owner->config->proxy != NULL) {
  1082. perr = (*comm->owner->config->proxy)(&pdu, tport->transport,
  1083. &tport->index, pi->peer, pi->peerlen, ierr, vi,
  1084. !pi->cred || pi->priv);
  1085. switch (perr) {
  1086. case SNMPD_PROXY_OK:
  1087. snmp_input_consume(pi);
  1088. return (0);
  1089. case SNMPD_PROXY_REJ:
  1090. break;
  1091. case SNMPD_PROXY_DROP:
  1092. snmp_input_consume(pi);
  1093. snmp_pdu_free(&pdu);
  1094. snmpd_stats.proxyDrops++;
  1095. return (0);
  1096. case SNMPD_PROXY_BADCOMM:
  1097. snmp_input_consume(pi);
  1098. snmp_pdu_free(&pdu);
  1099. snmpd_stats.inBadCommunityNames++;
  1100. if (snmpd.auth_traps)
  1101. snmp_send_trap(&oid_authenticationFailure,
  1102. (struct snmp_value *)NULL);
  1103. return (0);
  1104. case SNMPD_PROXY_BADCOMMUSE:
  1105. snmp_input_consume(pi);
  1106. snmp_pdu_free(&pdu);
  1107. snmpd_stats.inBadCommunityUses++;
  1108. if (snmpd.auth_traps)
  1109. snmp_send_trap(&oid_authenticationFailure,
  1110. (struct snmp_value *)NULL);
  1111. return (0);
  1112. }
  1113. }
  1114. /*
  1115. * Check type
  1116. */
  1117. if (pdu.type == SNMP_PDU_RESPONSE ||
  1118. pdu.type == SNMP_PDU_TRAP ||
  1119. pdu.type == SNMP_PDU_TRAP2) {
  1120. snmpd_stats.silentDrops++;
  1121. snmpd_stats.inBadPduTypes++;
  1122. snmp_pdu_free(&pdu);
  1123. snmp_input_consume(pi);
  1124. return (0);
  1125. }
  1126. /*
  1127. * Check community
  1128. */
  1129. if (pdu.version < SNMP_V3 &&
  1130. ((pi->cred && !pi->priv && pdu.type == SNMP_PDU_SET) ||
  1131. (community != COMM_WRITE &&
  1132. (pdu.type == SNMP_PDU_SET || community != COMM_READ)))) {
  1133. snmpd_stats.inBadCommunityUses++;
  1134. snmp_pdu_free(&pdu);
  1135. snmp_input_consume(pi);
  1136. if (snmpd.auth_traps)
  1137. snmp_send_trap(&oid_authenticationFailure,
  1138. (struct snmp_value *)NULL);
  1139. return (0);
  1140. }
  1141. /*
  1142. * Execute it.
  1143. */
  1144. if ((sndbuf = buf_alloc(1)) == NULL) {
  1145. snmpd_stats.silentDrops++;
  1146. snmp_pdu_free(&pdu);
  1147. snmp_input_consume(pi);
  1148. return (0);
  1149. }
  1150. ferr = snmp_input_finish(&pdu, pi->buf, pi->length,
  1151. sndbuf, &sndlen, "SNMP", ierr, vi, NULL);
  1152. if (ferr == SNMPD_INPUT_OK) {
  1153. msg.msg_name = pi->peer;
  1154. msg.msg_namelen = pi->peerlen;
  1155. msg.msg_iov = iov;
  1156. msg.msg_iovlen = 1;
  1157. msg.msg_flags = 0;
  1158. iov[0].iov_base = sndbuf;
  1159. iov[0].iov_len = sndlen;
  1160. slen = sendmsg(pi->fd, &msg, 0);
  1161. if (slen == -1)
  1162. syslog(LOG_ERR, "sendmsg: %m");
  1163. else if ((size_t)slen != sndlen)
  1164. syslog(LOG_ERR, "sendmsg: short write %zu/%zu",
  1165. sndlen, (size_t)slen);
  1166. }
  1167. snmp_pdu_free(&pdu);
  1168. free(sndbuf);
  1169. snmp_input_consume(pi);
  1170. return (0);
  1171. }
  1172. /*
  1173. * Send a PDU to a given port
  1174. */
  1175. void
  1176. snmp_send_port(void *targ, const struct asn_oid *port, struct snmp_pdu *pdu,
  1177. const struct sockaddr *addr, socklen_t addrlen)
  1178. {
  1179. struct transport *trans = targ;
  1180. struct tport *tp;
  1181. u_char *sndbuf;
  1182. size_t sndlen;
  1183. ssize_t len;
  1184. TAILQ_FOREACH(tp, &trans->table, link)
  1185. if (asn_compare_oid(port, &tp->index) == 0)
  1186. break;
  1187. if (tp == 0)
  1188. return;
  1189. if ((sndbuf = buf_alloc(1)) == NULL)
  1190. return;
  1191. snmp_output(pdu, sndbuf, &sndlen, "SNMP PROXY");
  1192. len = trans->vtab->send(tp, sndbuf, sndlen, addr, addrlen);
  1193. if (len == -1)
  1194. syslog(LOG_ERR, "sendto: %m");
  1195. else if ((size_t)len != sndlen)
  1196. syslog(LOG_ERR, "sendto: short write %zu/%zu",
  1197. sndlen, (size_t)len);
  1198. free(sndbuf);
  1199. }
  1200. /*
  1201. * Close an input source
  1202. */
  1203. void
  1204. snmpd_input_close(struct port_input *pi)
  1205. {
  1206. if (pi->id != NULL)
  1207. fd_deselect(pi->id);
  1208. if (pi->fd >= 0)
  1209. (void)close(pi->fd);
  1210. if (pi->buf != NULL)
  1211. free(pi->buf);
  1212. }
  1213. /*
  1214. * Dump internal state.
  1215. */
  1216. #ifdef USE_LIBBEGEMOT
  1217. static void
  1218. info_func(void)
  1219. #else
  1220. static void
  1221. info_func(evContext ctx __unused, void *uap __unused, const void *tag __unused)
  1222. #endif
  1223. {
  1224. struct lmodule *m;
  1225. u_int i;
  1226. char buf[10000];
  1227. syslog(LOG_DEBUG, "Dump of SNMPd %lu\n", (u_long)getpid());
  1228. for (i = 0; i < tree_size; i++) {
  1229. switch (tree[i].type) {
  1230. case SNMP_NODE_LEAF:
  1231. sprintf(buf, "LEAF: %s %s", tree[i].name,
  1232. asn_oid2str(&tree[i].oid));
  1233. break;
  1234. case SNMP_NODE_COLUMN:
  1235. sprintf(buf, "COL: %s %s", tree[i].name,
  1236. asn_oid2str(&tree[i].oid));
  1237. break;
  1238. }
  1239. syslog(LOG_DEBUG, "%s", buf);
  1240. }
  1241. TAILQ_FOREACH(m, &lmodules, link)
  1242. if (m->config->dump)
  1243. (*m->config->dump)();
  1244. }
  1245. /*
  1246. * Re-read configuration
  1247. */
  1248. #ifdef USE_LIBBEGEMOT
  1249. static void
  1250. config_func(void)
  1251. #else
  1252. static void
  1253. config_func(evContext ctx __unused, void *uap __unused,
  1254. const void *tag __unused)
  1255. #endif
  1256. {
  1257. struct lmodule *m;
  1258. if (read_config(config_file, NULL)) {
  1259. syslog(LOG_ERR, "error reading config file '%s'", config_file);
  1260. return;
  1261. }
  1262. TAILQ_FOREACH(m, &lmodules, link)
  1263. if (m->config->config)
  1264. (*m->config->config)();
  1265. }
  1266. /*
  1267. * On USR1 dump actual configuration.
  1268. */
  1269. static void
  1270. onusr1(int s __unused)
  1271. {
  1272. work |= WORK_DOINFO;
  1273. }
  1274. static void
  1275. onhup(int s __unused)
  1276. {
  1277. work |= WORK_RECONFIG;
  1278. }
  1279. static void
  1280. onterm(int s __unused)
  1281. {
  1282. /* allow clean-up */
  1283. exit(0);
  1284. }
  1285. static void
  1286. init_sigs(void)
  1287. {
  1288. struct sigaction sa;
  1289. sa.sa_handler = onusr1;
  1290. sa.sa_flags = SA_RESTART;
  1291. sigemptyset(&sa.sa_mask);
  1292. if (sigaction(SIGUSR1, &sa, NULL)) {
  1293. syslog(LOG_ERR, "sigaction: %m");
  1294. exit(1);
  1295. }
  1296. sa.sa_handler = onhup;
  1297. if (sigaction(SIGHUP, &sa, NULL)) {
  1298. syslog(LOG_ERR, "sigaction: %m");
  1299. exit(1);
  1300. }
  1301. sa.sa_handler = onterm;
  1302. sa.sa_flags = 0;
  1303. sigemptyset(&sa.sa_mask);
  1304. if (sigaction(SIGTERM, &sa, NULL)) {
  1305. syslog(LOG_ERR, "sigaction: %m");
  1306. exit(1);
  1307. }
  1308. if (sigaction(SIGINT, &sa, NULL)) {
  1309. syslog(LOG_ERR, "sigaction: %m");
  1310. exit(1);
  1311. }
  1312. }
  1313. static void
  1314. block_sigs(void)
  1315. {
  1316. sigset_t set;
  1317. sigfillset(&set);
  1318. if (sigprocmask(SIG_BLOCK, &set, &blocked_sigs) == -1) {
  1319. syslog(LOG_ERR, "SIG_BLOCK: %m");
  1320. exit(1);
  1321. }
  1322. }
  1323. static void
  1324. unblock_sigs(void)
  1325. {
  1326. if (sigprocmask(SIG_SETMASK, &blocked_sigs, NULL) == -1) {
  1327. syslog(LOG_ERR, "SIG_SETMASK: %m");
  1328. exit(1);
  1329. }
  1330. }
  1331. /*
  1332. * Shut down
  1333. */
  1334. static void
  1335. term(void)
  1336. {
  1337. (void)unlink(pid_file);
  1338. }
  1339. static void
  1340. trans_stop(void)
  1341. {
  1342. struct transport *t;
  1343. TAILQ_FOREACH(t, &transport_list, link)
  1344. (void)t->vtab->stop(1);
  1345. }
  1346. /*
  1347. * Define a macro from the command line
  1348. */
  1349. static void
  1350. do_macro(char *arg)
  1351. {
  1352. char *eq;
  1353. int err;
  1354. if ((eq = strchr(arg, '=')) == NULL)
  1355. err = define_macro(arg, "");
  1356. else {
  1357. *eq++ = '\0';
  1358. err = define_macro(arg, eq);
  1359. }
  1360. if (err == -1) {
  1361. syslog(LOG_ERR, "cannot save macro: %m");
  1362. exit(1);
  1363. }
  1364. }
  1365. /*
  1366. * Re-implement getsubopt from scratch, because the second argument is broken
  1367. * and will not compile with WARNS=5.
  1368. */
  1369. static int
  1370. getsubopt1(char **arg, const char *const *options, char **valp, char **optp)
  1371. {
  1372. static const char *const delim = ",\t ";
  1373. u_int i;
  1374. char *ptr;
  1375. *optp = NULL;
  1376. /* skip leading junk */
  1377. for (ptr = *arg; *ptr != '\0'; ptr++)
  1378. if (strchr(delim, *ptr) == NULL)
  1379. break;
  1380. if (*ptr == '\0') {
  1381. *arg = ptr;
  1382. return (-1);
  1383. }
  1384. *optp = ptr;
  1385. /* find the end of the option */
  1386. while (*++ptr != '\0')
  1387. if (strchr(delim, *ptr) != NULL || *ptr == '=')
  1388. break;
  1389. if (*ptr != '\0') {
  1390. if (*ptr == '=') {
  1391. *ptr++ = '\0';
  1392. *valp = ptr;
  1393. while (*ptr != '\0' && strchr(delim, *ptr) == NULL)
  1394. ptr++;
  1395. if (*ptr != '\0')
  1396. *ptr++ = '\0';
  1397. } else
  1398. *ptr++ = '\0';
  1399. }
  1400. *arg = ptr;
  1401. for (i = 0; *options != NULL; options++, i++)
  1402. if (strcmp(*optp, *options) == 0)
  1403. return (i);
  1404. return (-1);
  1405. }
  1406. int
  1407. main(int argc, char *argv[])
  1408. {
  1409. int opt;
  1410. FILE *fp;
  1411. int background = 1;
  1412. struct tport *p;
  1413. const char *prefix = "snmpd";
  1414. struct lmodule *m;
  1415. char *value = NULL, *option; /* XXX */
  1416. struct transport *t;
  1417. #define DBG_DUMP 0
  1418. #define DBG_EVENTS 1
  1419. #define DBG_TRACE 2
  1420. static const char *const debug_opts[] = {
  1421. "dump",
  1422. "events",
  1423. "trace",
  1424. NULL
  1425. };
  1426. snmp_printf = snmp_printf_func;
  1427. snmp_error = snmp_error_func;
  1428. snmp_debug = snmp_debug_func;
  1429. asn_error = asn_error_func;
  1430. while ((opt = getopt(argc, argv, "c:dD:e:hI:l:m:p:")) != EOF)
  1431. switch (opt) {
  1432. case 'c':
  1433. strlcpy(config_file, optarg, sizeof(config_file));
  1434. break;
  1435. case 'd':
  1436. background = 0;
  1437. break;
  1438. case 'D':
  1439. while (*optarg) {
  1440. switch (getsubopt1(&optarg, debug_opts,
  1441. &value, &option)) {
  1442. case DBG_DUMP:
  1443. debug.dump_pdus = 1;
  1444. break;
  1445. case DBG_EVENTS:
  1446. debug.evdebug++;
  1447. break;
  1448. case DBG_TRACE:
  1449. if (value == NULL)
  1450. syslog(LOG_ERR,
  1451. "no value for 'trace'");
  1452. else
  1453. snmp_trace = strtoul(value,
  1454. NULL, 0);
  1455. break;
  1456. case -1:
  1457. if (suboptarg)
  1458. syslog(LOG_ERR,
  1459. "unknown debug flag '%s'",
  1460. option);
  1461. else
  1462. syslog(LOG_ERR,
  1463. "missing debug flag");
  1464. break;
  1465. }
  1466. }
  1467. break;
  1468. case 'e':
  1469. strlcpy(engine_file, optarg, sizeof(engine_file));
  1470. break;
  1471. case 'h':
  1472. fprintf(stderr, "%s", usgtxt);
  1473. exit(0);
  1474. case 'I':
  1475. syspath = optarg;
  1476. break;
  1477. case 'l':
  1478. prefix = optarg;
  1479. break;
  1480. case 'm':
  1481. do_macro(optarg);
  1482. break;
  1483. case 'p':
  1484. strlcpy(pid_file, optarg, sizeof(pid_file));
  1485. break;
  1486. }
  1487. openlog(prefix, LOG_PID | (background ? 0 : LOG_PERROR), LOG_USER);
  1488. setlogmask(LOG_UPTO(debug.logpri - 1));
  1489. if (background && daemon(0, 0) < 0) {
  1490. syslog(LOG_ERR, "daemon: %m");
  1491. exit(1);
  1492. }
  1493. argc -= optind;
  1494. argv += optind;
  1495. progargs = argv;
  1496. nprogargs = argc;
  1497. srandomdev();
  1498. snmp_serial_no = random();
  1499. #ifdef USE_TCPWRAPPERS
  1500. /*
  1501. * Initialize hosts_access(3) handler.
  1502. */
  1503. request_init(&req, RQ_DAEMON, "snmpd", 0);
  1504. sock_methods(&req);
  1505. #endif
  1506. /*
  1507. * Initialize the tree.
  1508. */
  1509. if ((tree = malloc(sizeof(struct snmp_node) * CTREE_SIZE)) == NULL) {
  1510. syslog(LOG_ERR, "%m");
  1511. exit(1);
  1512. }
  1513. memcpy(tree, ctree, sizeof(struct snmp_node) * CTREE_SIZE);
  1514. tree_size = CTREE_SIZE;
  1515. /*
  1516. * Get standard communities
  1517. */
  1518. (void)comm_define(1, "SNMP read", NULL, NULL);
  1519. (void)comm_define(2, "SNMP write", NULL, NULL);
  1520. community = COMM_INITIALIZE;
  1521. trap_reqid = reqid_allocate(512, NULL);
  1522. if (config_file[0] == '\0')
  1523. snprintf(config_file, sizeof(config_file), PATH_CONFIG, prefix);
  1524. init_actvals();
  1525. init_snmpd_engine();
  1526. this_tick = get_ticks();
  1527. start_tick = this_tick;
  1528. /* start transports */
  1529. if (atexit(trans_stop) == -1) {
  1530. syslog(LOG_ERR, "atexit failed: %m");
  1531. exit(1);
  1532. }
  1533. if (udp_trans.start() != SNMP_ERR_NOERROR)
  1534. syslog(LOG_WARNING, "cannot start UDP transport");
  1535. if (lsock_trans.start() != SNMP_ERR_NOERROR)
  1536. syslog(LOG_WARNING, "cannot start LSOCK transport");
  1537. #ifdef USE_LIBBEGEMOT
  1538. if (debug.evdebug > 0)
  1539. rpoll_trace = 1;
  1540. #else
  1541. if (evCreate(&evctx)) {
  1542. syslog(LOG_ERR, "evCreate: %m");
  1543. exit(1);
  1544. }
  1545. if (debug.evdebug > 0)
  1546. evSetDebug(evctx, 10, stderr);
  1547. #endif
  1548. if (engine_file[0] == '\0')
  1549. snprintf(engine_file, sizeof(engine_file), PATH_ENGINE, prefix);
  1550. if (read_config(config_file, NULL)) {
  1551. syslog(LOG_ERR, "error in config file");
  1552. exit(1);
  1553. }
  1554. TAILQ_FOREACH(t, &transport_list, link)
  1555. TAILQ_FOREACH(p, &t->table, link)
  1556. t->vtab->init_port(p);
  1557. init_sigs();
  1558. if (pid_file[0] == '\0')
  1559. snprintf(pid_file, sizeof(pid_file), PATH_PID, prefix);
  1560. if ((fp = fopen(pid_file, "w")) != NULL) {
  1561. fprintf(fp, "%u", getpid());
  1562. fclose(fp);
  1563. if (atexit(term) == -1) {
  1564. syslog(LOG_ERR, "atexit failed: %m");
  1565. (void)remove(pid_file);
  1566. exit(0);
  1567. }
  1568. }
  1569. if (or_register(&oid_snmpMIB, "The MIB module for SNMPv2 entities.",
  1570. NULL) == 0) {
  1571. syslog(LOG_ERR, "cannot register SNMPv2 MIB");
  1572. exit(1);
  1573. }
  1574. if (or_register(&oid_begemotSnmpd, "The MIB module for the Begemot SNMPd.",
  1575. NULL) == 0) {
  1576. syslog(LOG_ERR, "cannot register begemotSnmpd MIB");
  1577. exit(1);
  1578. }
  1579. while ((m = TAILQ_FIRST(&modules_start)) != NULL) {
  1580. m->flags &= ~LM_ONSTARTLIST;
  1581. TAILQ_REMOVE(&modules_start, m, start);
  1582. lm_start(m);
  1583. }
  1584. snmp_send_trap(&oid_coldStart, (struct snmp_value *)NULL);
  1585. for (;;) {
  1586. #ifndef USE_LIBBEGEMOT
  1587. evEvent event;
  1588. #endif
  1589. struct lmodule *mod;
  1590. TAILQ_FOREACH(mod, &lmodules, link)
  1591. if (mod->config->idle != NULL)
  1592. (*mod->config->idle)();
  1593. #ifndef USE_LIBBEGEMOT
  1594. if (evGetNext(evctx, &event, EV_WAIT) == 0) {
  1595. if (evDispatch(evctx, event))
  1596. syslog(LOG_ERR, "evDispatch: %m");
  1597. } else if (errno != EINTR) {
  1598. syslog(LOG_ERR, "evGetNext: %m");
  1599. exit(1);
  1600. }
  1601. #else
  1602. poll_dispatch(1);
  1603. #endif
  1604. if (work != 0) {
  1605. block_sigs();
  1606. if (work & WORK_DOINFO) {
  1607. #ifdef USE_LIBBEGEMOT
  1608. info_func();
  1609. #else
  1610. if (evWaitFor(evctx, &work, info_func,
  1611. NULL, NULL) == -1) {
  1612. syslog(LOG_ERR, "evWaitFor: %m");
  1613. exit(1);
  1614. }
  1615. #endif
  1616. }
  1617. if (work & WORK_RECONFIG) {
  1618. #ifdef USE_LIBBEGEMOT
  1619. config_func();
  1620. #else
  1621. if (evWaitFor(evctx, &work, config_func,
  1622. NULL, NULL) == -1) {
  1623. syslog(LOG_ERR, "evWaitFor: %m");
  1624. exit(1);
  1625. }
  1626. #endif
  1627. }
  1628. work = 0;
  1629. unblock_sigs();
  1630. #ifndef USE_LIBBEGEMOT
  1631. if (evDo(evctx, &work) == -1) {
  1632. syslog(LOG_ERR, "evDo: %m");
  1633. exit(1);
  1634. }
  1635. #endif
  1636. }
  1637. }
  1638. return (0);
  1639. }
  1640. uint64_t
  1641. get_ticks(void)
  1642. {
  1643. struct timeval tv;
  1644. uint64_t ret;
  1645. if (gettimeofday(&tv, NULL))
  1646. abort();
  1647. ret = tv.tv_sec * 100ULL + tv.tv_usec / 10000ULL;
  1648. return (ret);
  1649. }
  1650. /*
  1651. * Timer support
  1652. */
  1653. /*
  1654. * Trampoline for the non-repeatable timers.
  1655. */
  1656. #ifdef USE_LIBBEGEMOT
  1657. static void
  1658. tfunc(int tid __unused, void *uap)
  1659. #else
  1660. static void
  1661. tfunc(evContext ctx __unused, void *uap, struct timespec due __unused,
  1662. struct timespec inter __unused)
  1663. #endif
  1664. {
  1665. struct timer *tp = uap;
  1666. LIST_REMOVE(tp, link);
  1667. tp->func(tp->udata);
  1668. free(tp);
  1669. }
  1670. /*
  1671. * Trampoline for the repeatable timers.
  1672. */
  1673. #ifdef USE_LIBBEGEMOT
  1674. static void
  1675. trfunc(int tid __unused, void *uap)
  1676. #else
  1677. static void
  1678. trfunc(evContext ctx __unused, void *uap, struct timespec due __unused,
  1679. struct timespec inter __unused)
  1680. #endif
  1681. {
  1682. struct timer *tp = uap;
  1683. tp->func(tp->udata);
  1684. }
  1685. /*
  1686. * Start a one-shot timer
  1687. */
  1688. void *
  1689. timer_start(u_int ticks, void (*func)(void *), void *udata, struct lmodule *mod)
  1690. {
  1691. struct timer *tp;
  1692. #ifndef USE_LIBBEGEMOT
  1693. struct timespec due;
  1694. #endif
  1695. if ((tp = malloc(sizeof(struct timer))) == NULL) {
  1696. syslog(LOG_CRIT, "out of memory for timer");
  1697. exit(1);
  1698. }
  1699. #ifndef USE_LIBBEGEMOT
  1700. due = evAddTime(evNowTime(),
  1701. evConsTime(ticks / 100, (ticks % 100) * 10000));
  1702. #endif
  1703. tp->udata = udata;
  1704. tp->owner = mod;
  1705. tp->func = func;
  1706. LIST_INSERT_HEAD(&timer_list, tp, link);
  1707. #ifdef USE_LIBBEGEMOT
  1708. if ((tp->id = poll_start_timer(ticks * 10, 0, tfunc, tp)) < 0) {
  1709. syslog(LOG_ERR, "cannot set timer: %m");
  1710. exit(1);
  1711. }
  1712. #else
  1713. if (evSetTimer(evctx, tfunc, tp, due, evConsTime(0, 0), &tp->id)
  1714. == -1) {
  1715. syslog(LOG_ERR, "cannot set timer: %m");
  1716. exit(1);
  1717. }
  1718. #endif
  1719. return (tp);
  1720. }
  1721. /*
  1722. * Start a repeatable timer. When used with USE_LIBBEGEMOT the first argument
  1723. * is currently ignored and the initial number of ticks is set to the
  1724. * repeat number of ticks.
  1725. */
  1726. void *
  1727. timer_start_repeat(u_int ticks __unused, u_int repeat_ticks,
  1728. void (*func)(void *), void *udata, struct lmodule *mod)
  1729. {
  1730. struct timer *tp;
  1731. #ifndef USE_LIBBEGEMOT
  1732. struct timespec due;
  1733. struct timespec inter;
  1734. #endif
  1735. if ((tp = malloc(sizeof(struct timer))) == NULL) {
  1736. syslog(LOG_CRIT, "out of memory for timer");
  1737. exit(1);
  1738. }
  1739. #ifndef USE_LIBBEGEMOT
  1740. due = evAddTime(evNowTime(),
  1741. evConsTime(ticks / 100, (ticks % 100) * 10000));
  1742. inter = evConsTime(repeat_ticks / 100, (repeat_ticks % 100) * 10000);
  1743. #endif
  1744. tp->udata = udata;
  1745. tp->owner = mod;
  1746. tp->func = func;
  1747. LIST_INSERT_HEAD(&timer_list, tp, link);
  1748. #ifdef USE_LIBBEGEMOT
  1749. if ((tp->id = poll_start_timer(repeat_ticks * 10, 1, trfunc, tp)) < 0) {
  1750. syslog(LOG_ERR, "cannot set timer: %m");
  1751. exit(1);
  1752. }
  1753. #else
  1754. if (evSetTimer(evctx, trfunc, tp, due, inter, &tp->id) == -1) {
  1755. syslog(LOG_ERR, "cannot set timer: %m");
  1756. exit(1);
  1757. }
  1758. #endif
  1759. return (tp);
  1760. }
  1761. /*
  1762. * Stop a timer.
  1763. */
  1764. void
  1765. timer_stop(void *p)
  1766. {
  1767. struct timer *tp = p;
  1768. LIST_REMOVE(tp, link);
  1769. #ifdef USE_LIBBEGEMOT
  1770. poll_stop_timer(tp->id);
  1771. #else
  1772. if (evClearTimer(evctx, tp->id) == -1) {
  1773. syslog(LOG_ERR, "cannot stop timer: %m");
  1774. exit(1);
  1775. }
  1776. #endif
  1777. free(p);
  1778. }
  1779. static void
  1780. timer_flush(struct lmodule *mod)
  1781. {
  1782. struct timer *t, *t1;
  1783. t = LIST_FIRST(&timer_list);
  1784. while (t != NULL) {
  1785. t1 = LIST_NEXT(t, link);
  1786. if (t->owner == mod)
  1787. timer_stop(t);
  1788. t = t1;
  1789. }
  1790. }
  1791. static void
  1792. snmp_printf_func(const char *fmt, ...)
  1793. {
  1794. va_list ap;
  1795. static char *pend = NULL;
  1796. char *ret, *new;
  1797. va_start(ap, fmt);
  1798. vasprintf(&ret, fmt, ap);
  1799. va_end(ap);
  1800. if (ret == NULL)
  1801. return;
  1802. if (pend != NULL) {
  1803. if ((new = realloc(pend, strlen(pend) + strlen(ret) + 1))
  1804. == NULL) {
  1805. free(ret);
  1806. return;
  1807. }
  1808. pend = new;
  1809. strcat(pend, ret);
  1810. free(ret);
  1811. } else
  1812. pend = ret;
  1813. while ((ret = strchr(pend, '\n')) != NULL) {
  1814. *ret = '\0';
  1815. syslog(LOG_DEBUG, "%s", pend);
  1816. if (strlen(ret + 1) == 0) {
  1817. free(pend);
  1818. pend = NULL;
  1819. break;
  1820. }
  1821. strcpy(pend, ret + 1);
  1822. }
  1823. }
  1824. static void
  1825. snmp_error_func(const char *err, ...)
  1826. {
  1827. char errbuf[1000];
  1828. va_list ap;
  1829. if (!(snmp_trace & LOG_SNMP_ERRORS))
  1830. return;
  1831. va_start(ap, err);
  1832. snprintf(errbuf, sizeof(errbuf), "SNMP: ");
  1833. vsnprintf(errbuf + strlen(errbuf),
  1834. sizeof(errbuf) - strlen(errbuf), err, ap);
  1835. va_end(ap);
  1836. syslog(LOG_ERR, "%s", errbuf);
  1837. }
  1838. static void
  1839. snmp_debug_func(const char *err, ...)
  1840. {
  1841. char errbuf[1000];
  1842. va_list ap;
  1843. va_start(ap, err);
  1844. snprintf(errbuf, sizeof(errbuf), "SNMP: ");
  1845. vsnprintf(errbuf+strlen(errbuf), sizeof(errbuf)-strlen(errbuf),
  1846. err, ap);
  1847. va_end(ap);
  1848. syslog(LOG_DEBUG, "%s", errbuf);
  1849. }
  1850. static void
  1851. asn_error_func(const struct asn_buf *b, const char *err, ...)
  1852. {
  1853. char errbuf[1000];
  1854. va_list ap;
  1855. u_int i;
  1856. if (!(snmp_trace & LOG_ASN1_ERRORS))
  1857. return;
  1858. va_start(ap, err);
  1859. snprintf(errbuf, sizeof(errbuf), "ASN.1: ");
  1860. vsnprintf(errbuf + strlen(errbuf),
  1861. sizeof(errbuf) - strlen(errbuf), err, ap);
  1862. va_end(ap);
  1863. if (b != NULL) {
  1864. snprintf(errbuf + strlen(errbuf),
  1865. sizeof(errbuf) - strlen(errbuf), " at");
  1866. for (i = 0; b->asn_len > i; i++)
  1867. snprintf(errbuf + strlen(errbuf),
  1868. sizeof(errbuf) - strlen(errbuf),
  1869. " %02x", b->asn_cptr[i]);
  1870. }
  1871. syslog(LOG_ERR, "%s", errbuf);
  1872. }
  1873. /*
  1874. * Create a new community
  1875. */
  1876. u_int
  1877. comm_define(u_int priv, const char *descr, struct lmodule *owner,
  1878. const char *str)
  1879. {
  1880. struct community *c, *p;
  1881. u_int ncomm;
  1882. /* generate an identifier */
  1883. do {
  1884. if ((ncomm = next_community_index++) == UINT_MAX)
  1885. next_community_index = 1;
  1886. TAILQ_FOREACH(c, &community_list, link)
  1887. if (c->value == ncomm)
  1888. break;
  1889. } while (c != NULL);
  1890. if ((c = malloc(sizeof(struct community))) == NULL) {
  1891. syslog(LOG_ERR, "comm_define: %m");
  1892. return (0);
  1893. }
  1894. c->owner = owner;
  1895. c->value = ncomm;
  1896. c->descr = descr;
  1897. c->string = NULL;
  1898. c->private = priv;
  1899. if (str != NULL) {
  1900. if((c->string = malloc(strlen(str)+1)) == NULL) {
  1901. free(c);
  1902. return (0);
  1903. }
  1904. strcpy(c->string, str);
  1905. }
  1906. /* make index */
  1907. if (c->owner == NULL) {
  1908. c->index.len = 1;
  1909. c->index.subs[0] = 0;
  1910. } else {
  1911. c->index = c->owner->index;
  1912. }
  1913. c->index.subs[c->index.len++] = c->private;
  1914. /*
  1915. * Insert ordered
  1916. */
  1917. TAILQ_FOREACH(p, &community_list, link) {
  1918. if (asn_compare_oid(&p->index, &c->index) > 0) {
  1919. TAILQ_INSERT_BEFORE(p, c, link);
  1920. break;
  1921. }
  1922. }
  1923. if (p == NULL)
  1924. TAILQ_INSERT_TAIL(&community_list, c, link);
  1925. return (c->value);
  1926. }
  1927. const char *
  1928. comm_string(u_int ncomm)
  1929. {
  1930. struct community *p;
  1931. TAILQ_FOREACH(p, &community_list, link)
  1932. if (p->value == ncomm)
  1933. return (p->string);
  1934. return (NULL);
  1935. }
  1936. /*
  1937. * Delete all communities allocated by a module
  1938. */
  1939. static void
  1940. comm_flush(struct lmodule *mod)
  1941. {
  1942. struct community *p, *p1;
  1943. p = TAILQ_FIRST(&community_list);
  1944. while (p != NULL) {
  1945. p1 = TAILQ_NEXT(p, link);
  1946. if (p->owner == mod) {
  1947. free(p->string);
  1948. TAILQ_REMOVE(&community_list, p, link);
  1949. free(p);
  1950. }
  1951. p = p1;
  1952. }
  1953. }
  1954. /*
  1955. * Request ID handling.
  1956. *
  1957. * Allocate a new range of request ids. Use a first fit algorithm.
  1958. */
  1959. u_int
  1960. reqid_allocate(int size, struct lmodule *mod)
  1961. {
  1962. u_int type;
  1963. struct idrange *r, *r1;
  1964. if (size <= 0 || size > INT32_MAX) {
  1965. syslog(LOG_CRIT, "%s: size out of range: %d", __func__, size);
  1966. return (0);
  1967. }
  1968. /* allocate a type id */
  1969. do {
  1970. if ((type = next_idrange++) == UINT_MAX)
  1971. next_idrange = 1;
  1972. TAILQ_FOREACH(r, &idrange_list, link)
  1973. if (r->type == type)
  1974. break;
  1975. } while(r != NULL);
  1976. /* find a range */
  1977. if (TAILQ_EMPTY(&idrange_list))
  1978. r = NULL;
  1979. else {
  1980. r = TAILQ_FIRST(&idrange_list);
  1981. if (r->base < size) {
  1982. while((r1 = TAILQ_NEXT(r, link)) != NULL) {
  1983. if (r1->base - (r->base + r->size) >= size)
  1984. break;
  1985. r = r1;
  1986. }
  1987. r = r1;
  1988. }
  1989. if (r == NULL) {
  1990. r1 = TAILQ_LAST(&idrange_list, idrange_list);
  1991. if (INT32_MAX - size + 1 < r1->base + r1->size) {
  1992. syslog(LOG_ERR, "out of id ranges (%u)", size);
  1993. return (0);
  1994. }
  1995. }
  1996. }
  1997. /* allocate structure */
  1998. if ((r1 = malloc(sizeof(struct idrange))) == NULL) {
  1999. syslog(LOG_ERR, "%s: %m", __FUNCTION__);
  2000. return (0);
  2001. }
  2002. r1->type = type;
  2003. r1->size = size;
  2004. r1->owner = mod;
  2005. if (TAILQ_EMPTY(&idrange_list) || r == TAILQ_FIRST(&idrange_list)) {
  2006. r1->base = 0;
  2007. TAILQ_INSERT_HEAD(&idrange_list, r1, link);
  2008. } else if (r == NULL) {
  2009. r = TAILQ_LAST(&idrange_list, idrange_list);
  2010. r1->base = r->base + r->size;
  2011. TAILQ_INSERT_TAIL(&idrange_list, r1, link);
  2012. } else {
  2013. r = TAILQ_PREV(r, idrange_list, link);
  2014. r1->base = r->base + r->size;
  2015. TAILQ_INSERT_AFTER(&idrange_list, r, r1, link);
  2016. }
  2017. r1->next = r1->base;
  2018. return (type);
  2019. }
  2020. int32_t
  2021. reqid_next(u_int type)
  2022. {
  2023. struct idrange *r;
  2024. int32_t id;
  2025. TAILQ_FOREACH(r, &idrange_list, link)
  2026. if (r->type == type)
  2027. break;
  2028. if (r == NULL) {
  2029. syslog(LOG_CRIT, "wrong idrange type");
  2030. abort();
  2031. }
  2032. if ((id = r->next++) == r->base + (r->size - 1))
  2033. r->next = r->base;
  2034. return (id);
  2035. }
  2036. int32_t
  2037. reqid_base(u_int type)
  2038. {
  2039. struct idrange *r;
  2040. TAILQ_FOREACH(r, &idrange_list, link)
  2041. if (r->type == type)
  2042. return (r->base);
  2043. syslog(LOG_CRIT, "wrong idrange type");
  2044. abort();
  2045. }
  2046. u_int
  2047. reqid_type(int32_t reqid)
  2048. {
  2049. struct idrange *r;
  2050. TAILQ_FOREACH(r, &idrange_list, link)
  2051. if (reqid >= r->base && reqid <= r->base + (r->size - 1))
  2052. return (r->type);
  2053. return (0);
  2054. }
  2055. int
  2056. reqid_istype(int32_t reqid, u_int type)
  2057. {
  2058. return (reqid_type(reqid) == type);
  2059. }
  2060. /*
  2061. * Delete all communities allocated by a module
  2062. */
  2063. static void
  2064. reqid_flush(struct lmodule *mod)
  2065. {
  2066. struct idrange *p, *p1;
  2067. p = TAILQ_FIRST(&idrange_list);
  2068. while (p != NULL) {
  2069. p1 = TAILQ_NEXT(p, link);
  2070. if (p->owner == mod) {
  2071. TAILQ_REMOVE(&idrange_list, p, link);
  2072. free(p);
  2073. }
  2074. p = p1;
  2075. }
  2076. }
  2077. /*
  2078. * Merge the given tree for the given module into the main tree.
  2079. */
  2080. static int
  2081. compare_node(const void *v1, const void *v2)
  2082. {
  2083. const struct snmp_node *n1 = v1;
  2084. const struct snmp_node *n2 = v2;
  2085. return (asn_compare_oid(&n1->oid, &n2->oid));
  2086. }
  2087. static int
  2088. tree_merge(const struct snmp_node *ntree, u_int nsize, struct lmodule *mod)
  2089. {
  2090. struct snmp_node *xtree;
  2091. u_int i;
  2092. xtree = realloc(tree, sizeof(*tree) * (tree_size + nsize));
  2093. if (xtree == NULL) {
  2094. syslog(LOG_ERR, "tree_merge: %m");
  2095. return (-1);
  2096. }
  2097. tree = xtree;
  2098. memcpy(&tree[tree_size], ntree, sizeof(*tree) * nsize);
  2099. for (i = 0; i < nsize; i++)
  2100. tree[tree_size + i].tree_data = mod;
  2101. tree_size += nsize;
  2102. qsort(tree, tree_size, sizeof(tree[0]), compare_node);
  2103. return (0);
  2104. }
  2105. /*
  2106. * Remove all nodes belonging to the loadable module
  2107. */
  2108. static void
  2109. tree_unmerge(struct lmodule *mod)
  2110. {
  2111. u_int s, d;
  2112. for(s = d = 0; s < tree_size; s++)
  2113. if (tree[s].tree_data != mod) {
  2114. if (s != d)
  2115. tree[d] = tree[s];
  2116. d++;
  2117. }
  2118. tree_size = d;
  2119. }
  2120. /*
  2121. * Loadable modules
  2122. */
  2123. struct lmodule *
  2124. lm_load(const char *path, const char *section)
  2125. {
  2126. struct lmodule *m;
  2127. int err;
  2128. int i;
  2129. char *av[MAX_MOD_ARGS + 1];
  2130. int ac;
  2131. u_int u;
  2132. if ((m = malloc(sizeof(*m))) == NULL) {
  2133. syslog(LOG_ERR, "lm_load: %m");
  2134. return (NULL);
  2135. }
  2136. m->handle = NULL;
  2137. m->flags = 0;
  2138. strcpy(m->section, section);
  2139. if ((m->path = malloc(strlen(path) + 1)) == NULL) {
  2140. syslog(LOG_ERR, "lm_load: %m");
  2141. goto err;
  2142. }
  2143. strcpy(m->path, path);
  2144. /*
  2145. * Make index
  2146. */
  2147. m->index.subs[0] = strlen(section);
  2148. m->index.len = m->index.subs[0] + 1;
  2149. for (u = 0; u < m->index.subs[0]; u++)
  2150. m->index.subs[u + 1] = section[u];
  2151. /*
  2152. * Load the object file and locate the config structure
  2153. */
  2154. if ((m->handle = dlopen(m->path, RTLD_NOW|RTLD_GLOBAL)) == NULL) {
  2155. syslog(LOG_ERR, "lm_load: open %s", dlerror());
  2156. goto err;
  2157. }
  2158. if ((m->config = dlsym(m->handle, "config")) == NULL) {
  2159. syslog(LOG_ERR, "lm_load: no 'config' symbol %s", dlerror());
  2160. goto err;
  2161. }
  2162. /*
  2163. * Insert it into the right place
  2164. */
  2165. INSERT_OBJECT_OID(m, &lmodules);
  2166. /* preserve order */
  2167. if (community == COMM_INITIALIZE) {
  2168. m->flags |= LM_ONSTARTLIST;
  2169. TAILQ_INSERT_TAIL(&modules_start, m, start);
  2170. }
  2171. /*
  2172. * make the argument vector.
  2173. */
  2174. ac = 0;
  2175. for (i = 0; i < nprogargs; i++) {
  2176. if (strlen(progargs[i]) >= strlen(section) + 1 &&
  2177. strncmp(progargs[i], section, strlen(section)) == 0 &&
  2178. progargs[i][strlen(section)] == ':') {
  2179. if (ac == MAX_MOD_ARGS) {
  2180. syslog(LOG_WARNING, "too many arguments for "
  2181. "module '%s", section);
  2182. break;
  2183. }
  2184. av[ac++] = &progargs[i][strlen(section)+1];
  2185. }
  2186. }
  2187. av[ac] = NULL;
  2188. /*
  2189. * Run the initialization function
  2190. */
  2191. if ((err = (*m->config->init)(m, ac, av)) != 0) {
  2192. syslog(LOG_ERR, "lm_load: init failed: %d", err);
  2193. TAILQ_REMOVE(&lmodules, m, link);
  2194. goto err;
  2195. }
  2196. return (m);
  2197. err:
  2198. if ((m->flags & LM_ONSTARTLIST) != 0)
  2199. TAILQ_REMOVE(&modules_start, m, start);
  2200. if (m->handle)
  2201. dlclose(m->handle);
  2202. free(m->path);
  2203. free(m);
  2204. return (NULL);
  2205. }
  2206. /*
  2207. * Start a module
  2208. */
  2209. void
  2210. lm_start(struct lmodule *mod)
  2211. {
  2212. const struct lmodule *m;
  2213. /*
  2214. * Merge tree. If this fails, unload the module.
  2215. */
  2216. if (tree_merge(mod->config->tree, mod->config->tree_size, mod)) {
  2217. lm_unload(mod);
  2218. return;
  2219. }
  2220. /*
  2221. * Read configuration
  2222. */
  2223. if (read_config(config_file, mod)) {
  2224. syslog(LOG_ERR, "error in config file");
  2225. lm_unload(mod);
  2226. return;
  2227. }
  2228. if (mod->config->start)
  2229. (*mod->config->start)();
  2230. mod->flags |= LM_STARTED;
  2231. /*
  2232. * Inform other modules
  2233. */
  2234. TAILQ_FOREACH(m, &lmodules, link)
  2235. if (m->config->loading)
  2236. (*m->config->loading)(mod, 1);
  2237. }
  2238. /*
  2239. * Unload a module.
  2240. */
  2241. void
  2242. lm_unload(struct lmodule *m)
  2243. {
  2244. int err;
  2245. const struct lmodule *mod;
  2246. TAILQ_REMOVE(&lmodules, m, link);
  2247. if (m->flags & LM_ONSTARTLIST)
  2248. TAILQ_REMOVE(&modules_start, m, start);
  2249. tree_unmerge(m);
  2250. if ((m->flags & LM_STARTED) && m->config->fini &&
  2251. (err = (*m->config->fini)()) != 0)
  2252. syslog(LOG_WARNING, "lm_unload(%s): fini %d", m->section, err);
  2253. comm_flush(m);
  2254. reqid_flush(m);
  2255. timer_flush(m);
  2256. fd_flush(m);
  2257. dlclose(m->handle);
  2258. free(m->path);
  2259. /*
  2260. * Inform other modules
  2261. */
  2262. TAILQ_FOREACH(mod, &lmodules, link)
  2263. if (mod->config->loading)
  2264. (*mod->config->loading)(m, 0);
  2265. free(m);
  2266. }
  2267. /*
  2268. * Register an object resource and return the index (or 0 on failures)
  2269. */
  2270. u_int
  2271. or_register(const struct asn_oid *or, const char *descr, struct lmodule *mod)
  2272. {
  2273. struct objres *objres, *or1;
  2274. u_int idx;
  2275. /* find a free index */
  2276. idx = 1;
  2277. for (objres = TAILQ_FIRST(&objres_list);
  2278. objres != NULL;
  2279. objres = TAILQ_NEXT(objres, link)) {
  2280. if ((or1 = TAILQ_NEXT(objres, link)) == NULL ||
  2281. or1->index > objres->index + 1) {
  2282. idx = objres->index + 1;
  2283. break;
  2284. }
  2285. }
  2286. if ((objres = malloc(sizeof(*objres))) == NULL)
  2287. return (0);
  2288. objres->index = idx;
  2289. objres->oid = *or;
  2290. strlcpy(objres->descr, descr, sizeof(objres->descr));
  2291. objres->uptime = (uint32_t)(get_ticks() - start_tick);
  2292. objres->module = mod;
  2293. INSERT_OBJECT_INT(objres, &objres_list);
  2294. systemg.or_last_change = objres->uptime;
  2295. return (idx);
  2296. }
  2297. void
  2298. or_unregister(u_int idx)
  2299. {
  2300. struct objres *objres;
  2301. TAILQ_FOREACH(objres, &objres_list, link)
  2302. if (objres->index == idx) {
  2303. TAILQ_REMOVE(&objres_list, objres, link);
  2304. free(objres);
  2305. return;
  2306. }
  2307. }
  2308. /*
  2309. * RFC 3414 User-based Security Model support
  2310. */
  2311. struct snmpd_usmstat *
  2312. bsnmpd_get_usm_stats(void)
  2313. {
  2314. return (&snmpd_usmstats);
  2315. }
  2316. void
  2317. bsnmpd_reset_usm_stats(void)
  2318. {
  2319. memset(&snmpd_usmstats, 0, sizeof(snmpd_usmstats));
  2320. }
  2321. struct usm_user *
  2322. usm_first_user(void)
  2323. {
  2324. return (SLIST_FIRST(&usm_userlist));
  2325. }
  2326. struct usm_user *
  2327. usm_next_user(struct usm_user *uuser)
  2328. {
  2329. if (uuser == NULL)
  2330. return (NULL);
  2331. return (SLIST_NEXT(uuser, up));
  2332. }
  2333. struct usm_user *
  2334. usm_find_user(uint8_t *engine, uint32_t elen, char *uname)
  2335. {
  2336. struct usm_user *uuser;
  2337. SLIST_FOREACH(uuser, &usm_userlist, up)
  2338. if (uuser->user_engine_len == elen &&
  2339. memcmp(uuser->user_engine_id, engine, elen) == 0 &&
  2340. strlen(uuser->suser.sec_name) == strlen(uname) &&
  2341. strcmp(uuser->suser.sec_name, uname) == 0)
  2342. break;
  2343. return (uuser);
  2344. }
  2345. static int
  2346. usm_compare_user(struct usm_user *u1, struct usm_user *u2)
  2347. {
  2348. uint32_t i;
  2349. if (u1->user_engine_len < u2->user_engine_len)
  2350. return (-1);
  2351. if (u1->user_engine_len > u2->user_engine_len)
  2352. return (1);
  2353. for (i = 0; i < u1->user_engine_len; i++) {
  2354. if (u1->user_engine_id[i] < u2->user_engine_id[i])
  2355. return (-1);
  2356. if (u1->user_engine_id[i] > u2->user_engine_id[i])
  2357. return (1);
  2358. }
  2359. if (strlen(u1->suser.sec_name) < strlen(u2->suser.sec_name))
  2360. return (-1);
  2361. if (strlen(u1->suser.sec_name) > strlen(u2->suser.sec_name))
  2362. return (1);
  2363. for (i = 0; i < strlen(u1->suser.sec_name); i++) {
  2364. if (u1->suser.sec_name[i] < u2->suser.sec_name[i])
  2365. return (-1);
  2366. if (u1->suser.sec_name[i] > u2->suser.sec_name[i])
  2367. return (1);
  2368. }
  2369. return (0);
  2370. }
  2371. struct usm_user *
  2372. usm_new_user(uint8_t *eid, uint32_t elen, char *uname)
  2373. {
  2374. int cmp;
  2375. struct usm_user *uuser, *temp, *prev;
  2376. for (uuser = usm_first_user(); uuser != NULL;
  2377. (uuser = usm_next_user(uuser))) {
  2378. if (uuser->user_engine_len == elen &&
  2379. strlen(uname) == strlen(uuser->suser.sec_name) &&
  2380. strcmp(uname, uuser->suser.sec_name) == 0 &&
  2381. memcmp(eid, uuser->user_engine_id, elen) == 0)
  2382. return (NULL);
  2383. }
  2384. if ((uuser = (struct usm_user *)malloc(sizeof(*uuser))) == NULL)
  2385. return (NULL);
  2386. memset(uuser, 0, sizeof(struct usm_user));
  2387. strlcpy(uuser->suser.sec_name, uname, SNMP_ADM_STR32_SIZ);
  2388. memcpy(uuser->user_engine_id, eid, elen);
  2389. uuser->user_engine_len = elen;
  2390. if ((prev = SLIST_FIRST(&usm_userlist)) == NULL ||
  2391. usm_compare_user(uuser, prev) < 0) {
  2392. SLIST_INSERT_HEAD(&usm_userlist, uuser, up);
  2393. return (uuser);
  2394. }
  2395. SLIST_FOREACH(temp, &usm_userlist, up) {
  2396. if ((cmp = usm_compare_user(uuser, temp)) <= 0)
  2397. break;
  2398. prev = temp;
  2399. }
  2400. if (temp == NULL || cmp < 0)
  2401. SLIST_INSERT_AFTER(prev, uuser, up);
  2402. else if (cmp > 0)
  2403. SLIST_INSERT_AFTER(temp, uuser, up);
  2404. else {
  2405. syslog(LOG_ERR, "User %s exists", uuser->suser.sec_name);
  2406. free(uuser);
  2407. return (NULL);
  2408. }
  2409. return (uuser);
  2410. }
  2411. void
  2412. usm_delete_user(struct usm_user *uuser)
  2413. {
  2414. SLIST_REMOVE(&usm_userlist, uuser, usm_user, up);
  2415. free(uuser);
  2416. }
  2417. void
  2418. usm_flush_users(void)
  2419. {
  2420. struct usm_user *uuser;
  2421. while ((uuser = SLIST_FIRST(&usm_userlist)) != NULL) {
  2422. SLIST_REMOVE_HEAD(&usm_userlist, up);
  2423. free(uuser);
  2424. }
  2425. SLIST_INIT(&usm_userlist);
  2426. }
  2427. /*
  2428. * RFC 3415 View-based Access Control Model support
  2429. */
  2430. struct vacm_user *
  2431. vacm_first_user(void)
  2432. {
  2433. return (SLIST_FIRST(&vacm_userlist));
  2434. }
  2435. struct vacm_user *
  2436. vacm_next_user(struct vacm_user *vuser)
  2437. {
  2438. if (vuser == NULL)
  2439. return (NULL);
  2440. return (SLIST_NEXT(vuser, vvu));
  2441. }
  2442. static int
  2443. vacm_compare_user(struct vacm_user *v1, struct vacm_user *v2)
  2444. {
  2445. uint32_t i;
  2446. if (v1->sec_model < v2->sec_model)
  2447. return (-1);
  2448. if (v1->sec_model > v2->sec_model)
  2449. return (1);
  2450. if (strlen(v1->secname) < strlen(v2->secname))
  2451. return (-1);
  2452. if (strlen(v1->secname) > strlen(v2->secname))
  2453. return (1);
  2454. for (i = 0; i < strlen(v1->secname); i++) {
  2455. if (v1->secname[i] < v2->secname[i])
  2456. return (-1);
  2457. if (v1->secname[i] > v2->secname[i])
  2458. return (1);
  2459. }
  2460. return (0);
  2461. }
  2462. struct vacm_user *
  2463. vacm_new_user(int32_t smodel, char *uname)
  2464. {
  2465. int cmp;
  2466. struct vacm_user *user, *temp, *prev;
  2467. SLIST_FOREACH(user, &vacm_userlist, vvu)
  2468. if (strcmp(uname, user->secname) == 0 &&
  2469. smodel == user->sec_model)
  2470. return (NULL);
  2471. if ((user = (struct vacm_user *)malloc(sizeof(*user))) == NULL)
  2472. return (NULL);
  2473. memset(user, 0, sizeof(*user));
  2474. user->group = &vacm_default_group;
  2475. SLIST_INSERT_HEAD(&vacm_default_group.group_users, user, vvg);
  2476. user->sec_model = smodel;
  2477. strlcpy(user->secname, uname, sizeof(user->secname));
  2478. if ((prev = SLIST_FIRST(&vacm_userlist)) == NULL ||
  2479. vacm_compare_user(user, prev) < 0) {
  2480. SLIST_INSERT_HEAD(&vacm_userlist, user, vvu);
  2481. return (user);
  2482. }
  2483. SLIST_FOREACH(temp, &vacm_userlist, vvu) {
  2484. if ((cmp = vacm_compare_user(user, temp)) <= 0)
  2485. break;
  2486. prev = temp;
  2487. }
  2488. if (temp == NULL || cmp < 0)
  2489. SLIST_INSERT_AFTER(prev, user, vvu);
  2490. else if (cmp > 0)
  2491. SLIST_INSERT_AFTER(temp, user, vvu);
  2492. else {
  2493. syslog(LOG_ERR, "User %s exists", user->secname);
  2494. free(user);
  2495. return (NULL);
  2496. }
  2497. return (user);
  2498. }
  2499. int
  2500. vacm_delete_user(struct vacm_user *user)
  2501. {
  2502. if (user->group != NULL && user->group != &vacm_default_group) {
  2503. SLIST_REMOVE(&user->group->group_users, user, vacm_user, vvg);
  2504. if (SLIST_EMPTY(&user->group->group_users)) {
  2505. SLIST_REMOVE(&vacm_grouplist, user->group,
  2506. vacm_group, vge);
  2507. free(user->group);
  2508. }
  2509. }
  2510. SLIST_REMOVE(&vacm_userlist, user, vacm_user, vvu);
  2511. free(user);
  2512. return (0);
  2513. }
  2514. int
  2515. vacm_user_set_group(struct vacm_user *user, u_char *octets, u_int len)
  2516. {
  2517. struct vacm_group *group;
  2518. if (len >= SNMP_ADM_STR32_SIZ)
  2519. return (-1);
  2520. SLIST_FOREACH(group, &vacm_grouplist, vge)
  2521. if (strlen(group->groupname) == len &&
  2522. memcmp(octets, group->groupname, len) == 0)
  2523. break;
  2524. if (group == NULL) {
  2525. if ((group = (struct vacm_group *)malloc(sizeof(*group))) == NULL)
  2526. return (-1);
  2527. memset(group, 0, sizeof(*group));
  2528. memcpy(group->groupname, octets, len);
  2529. group->groupname[len] = '\0';
  2530. SLIST_INSERT_HEAD(&vacm_grouplist, group, vge);
  2531. }
  2532. SLIST_REMOVE(&user->group->group_users, user, vacm_user, vvg);
  2533. SLIST_INSERT_HEAD(&group->group_users, user, vvg);
  2534. user->group = group;
  2535. return (0);
  2536. }
  2537. void
  2538. vacm_groups_init(void)
  2539. {
  2540. SLIST_INSERT_HEAD(&vacm_grouplist, &vacm_default_group, vge);
  2541. }
  2542. struct vacm_access *
  2543. vacm_first_access_rule(void)
  2544. {
  2545. return (TAILQ_FIRST(&vacm_accesslist));
  2546. }
  2547. struct vacm_access *
  2548. vacm_next_access_rule(struct vacm_access *acl)
  2549. {
  2550. if (acl == NULL)
  2551. return (NULL);
  2552. return (TAILQ_NEXT(acl, vva));
  2553. }
  2554. static int
  2555. vacm_compare_access_rule(struct vacm_access *v1, struct vacm_access *v2)
  2556. {
  2557. uint32_t i;
  2558. if (strlen(v1->group->groupname) < strlen(v2->group->groupname))
  2559. return (-1);
  2560. if (strlen(v1->group->groupname) > strlen(v2->group->groupname))
  2561. return (1);
  2562. for (i = 0; i < strlen(v1->group->groupname); i++) {
  2563. if (v1->group->groupname[i] < v2->group->groupname[i])
  2564. return (-1);
  2565. if (v1->group->groupname[i] > v2->group->groupname[i])
  2566. return (1);
  2567. }
  2568. if (strlen(v1->ctx_prefix) < strlen(v2->ctx_prefix))
  2569. return (-1);
  2570. if (strlen(v1->ctx_prefix) > strlen(v2->ctx_prefix))
  2571. return (1);
  2572. for (i = 0; i < strlen(v1->ctx_prefix); i++) {
  2573. if (v1->ctx_prefix[i] < v2->ctx_prefix[i])
  2574. return (-1);
  2575. if (v1->ctx_prefix[i] > v2->ctx_prefix[i])
  2576. return (1);
  2577. }
  2578. if (v1->sec_model < v2->sec_model)
  2579. return (-1);
  2580. if (v1->sec_model > v2->sec_model)
  2581. return (1);
  2582. if (v1->sec_level < v2->sec_level)
  2583. return (-1);
  2584. if (v1->sec_level > v2->sec_level)
  2585. return (1);
  2586. return (0);
  2587. }
  2588. struct vacm_access *
  2589. vacm_new_access_rule(char *gname, char *cprefix, int32_t smodel, int32_t slevel)
  2590. {
  2591. struct vacm_group *group;
  2592. struct vacm_access *acl, *temp;
  2593. TAILQ_FOREACH(acl, &vacm_accesslist, vva) {
  2594. if (acl->group == NULL)
  2595. continue;
  2596. if (strcmp(gname, acl->group->groupname) == 0 &&
  2597. strcmp(cprefix, acl->ctx_prefix) == 0 &&
  2598. acl->sec_model == smodel && acl->sec_level == slevel)
  2599. return (NULL);
  2600. }
  2601. /* Make sure the group exists */
  2602. SLIST_FOREACH(group, &vacm_grouplist, vge)
  2603. if (strcmp(gname, group->groupname) == 0)
  2604. break;
  2605. if (group == NULL)
  2606. return (NULL);
  2607. if ((acl = (struct vacm_access *)malloc(sizeof(*acl))) == NULL)
  2608. return (NULL);
  2609. memset(acl, 0, sizeof(*acl));
  2610. acl->group = group;
  2611. strlcpy(acl->ctx_prefix, cprefix, sizeof(acl->ctx_prefix));
  2612. acl->sec_model = smodel;
  2613. acl->sec_level = slevel;
  2614. if ((temp = TAILQ_FIRST(&vacm_accesslist)) == NULL ||
  2615. vacm_compare_access_rule(acl, temp) < 0) {
  2616. TAILQ_INSERT_HEAD(&vacm_accesslist, acl, vva);
  2617. return (acl);
  2618. }
  2619. TAILQ_FOREACH(temp, &vacm_accesslist, vva)
  2620. if (vacm_compare_access_rule(acl, temp) < 0) {
  2621. TAILQ_INSERT_BEFORE(temp, acl, vva);
  2622. return (acl);
  2623. }
  2624. TAILQ_INSERT_TAIL(&vacm_accesslist, acl, vva);
  2625. return (acl);
  2626. }
  2627. int
  2628. vacm_delete_access_rule(struct vacm_access *acl)
  2629. {
  2630. TAILQ_REMOVE(&vacm_accesslist, acl, vva);
  2631. free(acl);
  2632. return (0);
  2633. }
  2634. struct vacm_view *
  2635. vacm_first_view(void)
  2636. {
  2637. return (SLIST_FIRST(&vacm_viewlist));
  2638. }
  2639. struct vacm_view *
  2640. vacm_next_view(struct vacm_view *view)
  2641. {
  2642. if (view == NULL)
  2643. return (NULL);
  2644. return (SLIST_NEXT(view, vvl));
  2645. }
  2646. static int
  2647. vacm_compare_view(struct vacm_view *v1, struct vacm_view *v2)
  2648. {
  2649. uint32_t i;
  2650. if (strlen(v1->viewname) < strlen(v2->viewname))
  2651. return (-1);
  2652. if (strlen(v1->viewname) > strlen(v2->viewname))
  2653. return (1);
  2654. for (i = 0; i < strlen(v1->viewname); i++) {
  2655. if (v1->viewname[i] < v2->viewname[i])
  2656. return (-1);
  2657. if (v1->viewname[i] > v2->viewname[i])
  2658. return (1);
  2659. }
  2660. return (asn_compare_oid(&v1->subtree, &v2->subtree));
  2661. }
  2662. struct vacm_view *
  2663. vacm_new_view(char *vname, struct asn_oid *oid)
  2664. {
  2665. int cmp;
  2666. struct vacm_view *view, *temp, *prev;
  2667. SLIST_FOREACH(view, &vacm_viewlist, vvl)
  2668. if (strcmp(vname, view->viewname) == 0)
  2669. return (NULL);
  2670. if ((view = (struct vacm_view *)malloc(sizeof(*view))) == NULL)
  2671. return (NULL);
  2672. memset(view, 0, sizeof(*view));
  2673. strlcpy(view->viewname, vname, sizeof(view->viewname));
  2674. asn_append_oid(&view->subtree, oid);
  2675. if ((prev = SLIST_FIRST(&vacm_viewlist)) == NULL ||
  2676. vacm_compare_view(view, prev) < 0) {
  2677. SLIST_INSERT_HEAD(&vacm_viewlist, view, vvl);
  2678. return (view);
  2679. }
  2680. SLIST_FOREACH(temp, &vacm_viewlist, vvl) {
  2681. if ((cmp = vacm_compare_view(view, temp)) <= 0)
  2682. break;
  2683. prev = temp;
  2684. }
  2685. if (temp == NULL || cmp < 0)
  2686. SLIST_INSERT_AFTER(prev, view, vvl);
  2687. else if (cmp > 0)
  2688. SLIST_INSERT_AFTER(temp, view, vvl);
  2689. else {
  2690. syslog(LOG_ERR, "View %s exists", view->viewname);
  2691. free(view);
  2692. return (NULL);
  2693. }
  2694. return (view);
  2695. }
  2696. int
  2697. vacm_delete_view(struct vacm_view *view)
  2698. {
  2699. SLIST_REMOVE(&vacm_viewlist, view, vacm_view, vvl);
  2700. free(view);
  2701. return (0);
  2702. }
  2703. struct vacm_context *
  2704. vacm_first_context(void)
  2705. {
  2706. return (SLIST_FIRST(&vacm_contextlist));
  2707. }
  2708. struct vacm_context *
  2709. vacm_next_context(struct vacm_context *vacmctx)
  2710. {
  2711. if (vacmctx == NULL)
  2712. return (NULL);
  2713. return (SLIST_NEXT(vacmctx, vcl));
  2714. }
  2715. struct vacm_context *
  2716. vacm_add_context(char *ctxname, int regid)
  2717. {
  2718. int cmp;
  2719. struct vacm_context *ctx, *temp, *prev;
  2720. SLIST_FOREACH(ctx, &vacm_contextlist, vcl)
  2721. if (strcmp(ctxname, ctx->ctxname) == 0) {
  2722. syslog(LOG_ERR, "Context %s exists", ctx->ctxname);
  2723. return (NULL);
  2724. }
  2725. if ((ctx = (struct vacm_context *)malloc(sizeof(*ctx))) == NULL)
  2726. return (NULL);
  2727. memset(ctx, 0, sizeof(*ctx));
  2728. strlcpy(ctx->ctxname, ctxname, sizeof(ctx->ctxname));
  2729. ctx->regid = regid;
  2730. if ((prev = SLIST_FIRST(&vacm_contextlist)) == NULL ||
  2731. strlen(ctx->ctxname) < strlen(prev->ctxname) ||
  2732. strcmp(ctx->ctxname, prev->ctxname) < 0) {
  2733. SLIST_INSERT_HEAD(&vacm_contextlist, ctx, vcl);
  2734. return (ctx);
  2735. }
  2736. SLIST_FOREACH(temp, &vacm_contextlist, vcl) {
  2737. if (strlen(ctx->ctxname) < strlen(temp->ctxname) ||
  2738. strcmp(ctx->ctxname, temp->ctxname) < 0) {
  2739. cmp = -1;
  2740. break;
  2741. }
  2742. prev = temp;
  2743. }
  2744. if (temp == NULL || cmp < 0)
  2745. SLIST_INSERT_AFTER(prev, ctx, vcl);
  2746. else if (cmp > 0)
  2747. SLIST_INSERT_AFTER(temp, ctx, vcl);
  2748. else {
  2749. syslog(LOG_ERR, "Context %s exists", ctx->ctxname);
  2750. free(ctx);
  2751. return (NULL);
  2752. }
  2753. return (ctx);
  2754. }
  2755. void
  2756. vacm_flush_contexts(int regid)
  2757. {
  2758. struct vacm_context *ctx, *temp;
  2759. SLIST_FOREACH_SAFE(ctx, &vacm_contextlist, vcl, temp)
  2760. if (ctx->regid == regid) {
  2761. SLIST_REMOVE(&vacm_contextlist, ctx, vacm_context, vcl);
  2762. free(ctx);
  2763. }
  2764. }