/contrib/bsnmp/snmpd/trans_lsock.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 604 lines · 429 code · 96 blank · 79 comment · 107 complexity · 9ff3238223177f66028ae6bfc5b10609 MD5 · raw file

  1. /*
  2. * Copyright (c) 2003
  3. * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
  4. * All rights reserved.
  5. *
  6. * Author: Harti Brandt <harti@freebsd.org>
  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 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 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. * $Begemot: bsnmp/snmpd/trans_lsock.c,v 1.6 2005/02/25 11:50:25 brandt_h Exp $
  30. *
  31. * Local domain socket transport
  32. */
  33. #include <sys/types.h>
  34. #include <sys/queue.h>
  35. #include <sys/un.h>
  36. #include <sys/stat.h>
  37. #include <stdio.h>
  38. #include <stdlib.h>
  39. #include <stddef.h>
  40. #include <syslog.h>
  41. #include <string.h>
  42. #include <errno.h>
  43. #include <unistd.h>
  44. #include "snmpmod.h"
  45. #include "snmpd.h"
  46. #include "trans_lsock.h"
  47. #include "tree.h"
  48. #include "oid.h"
  49. static const struct asn_oid
  50. oid_begemotSnmpdLocalPortTable = OIDX_begemotSnmpdLocalPortTable;
  51. static int lsock_start(void);
  52. static int lsock_stop(int);
  53. static void lsock_close_port(struct tport *);
  54. static int lsock_init_port(struct tport *);
  55. static ssize_t lsock_send(struct tport *, const u_char *, size_t,
  56. const struct sockaddr *, size_t);
  57. /* exported */
  58. const struct transport_def lsock_trans = {
  59. "lsock",
  60. OIDX_begemotSnmpdTransLsock,
  61. lsock_start,
  62. lsock_stop,
  63. lsock_close_port,
  64. lsock_init_port,
  65. lsock_send
  66. };
  67. static struct transport *my_trans;
  68. static int
  69. lsock_remove(struct tport *tp, intptr_t arg __unused)
  70. {
  71. struct lsock_port *port = (struct lsock_port *)tp;
  72. (void)remove(port->name);
  73. return (-1);
  74. }
  75. static int
  76. lsock_stop(int force)
  77. {
  78. if (my_trans != NULL) {
  79. if (!force && trans_first_port(my_trans) != NULL)
  80. return (SNMP_ERR_GENERR);
  81. trans_iter_port(my_trans, lsock_remove, 0);
  82. return (trans_unregister(my_trans));
  83. }
  84. return (SNMP_ERR_NOERROR);
  85. }
  86. static int
  87. lsock_start(void)
  88. {
  89. return (trans_register(&lsock_trans, &my_trans));
  90. }
  91. /*
  92. * Open a local port. If this is a datagram socket create also the
  93. * one and only peer.
  94. */
  95. static int
  96. lsock_open_port(u_char *name, size_t namelen, struct lsock_port **pp,
  97. int type)
  98. {
  99. struct lsock_port *port;
  100. struct lsock_peer *peer = NULL;
  101. int is_stream, need_cred;
  102. size_t u;
  103. int err;
  104. struct sockaddr_un sa;
  105. if (namelen == 0 || namelen + 1 > sizeof(sa.sun_path))
  106. return (SNMP_ERR_BADVALUE);
  107. switch (type) {
  108. case LOCP_DGRAM_UNPRIV:
  109. is_stream = 0;
  110. need_cred = 0;
  111. break;
  112. case LOCP_DGRAM_PRIV:
  113. is_stream = 0;
  114. need_cred = 1;
  115. break;
  116. case LOCP_STREAM_UNPRIV:
  117. is_stream = 1;
  118. need_cred = 0;
  119. break;
  120. case LOCP_STREAM_PRIV:
  121. is_stream = 1;
  122. need_cred = 1;
  123. break;
  124. default:
  125. return (SNMP_ERR_BADVALUE);
  126. }
  127. if ((port = malloc(sizeof(*port))) == NULL)
  128. return (SNMP_ERR_GENERR);
  129. memset(port, 0, sizeof(*port));
  130. if (!is_stream) {
  131. if ((peer = malloc(sizeof(*peer))) == NULL) {
  132. free(port);
  133. return (SNMP_ERR_GENERR);
  134. }
  135. memset(peer, 0, sizeof(*peer));
  136. }
  137. if ((port->name = malloc(namelen + 1)) == NULL) {
  138. free(port);
  139. if (!is_stream)
  140. free(peer);
  141. return (SNMP_ERR_GENERR);
  142. }
  143. strncpy(port->name, name, namelen);
  144. port->name[namelen] = '\0';
  145. port->type = type;
  146. port->str_sock = -1;
  147. LIST_INIT(&port->peers);
  148. port->tport.index.len = namelen + 1;
  149. port->tport.index.subs[0] = namelen;
  150. for (u = 0; u < namelen; u++)
  151. port->tport.index.subs[u + 1] = name[u];
  152. if (peer != NULL) {
  153. LIST_INSERT_HEAD(&port->peers, peer, link);
  154. peer->port = port;
  155. peer->input.fd = -1;
  156. peer->input.id = NULL;
  157. peer->input.stream = is_stream;
  158. peer->input.cred = need_cred;
  159. peer->input.peer = (struct sockaddr *)&peer->peer;
  160. }
  161. trans_insert_port(my_trans, &port->tport);
  162. if (community != COMM_INITIALIZE &&
  163. (err = lsock_init_port(&port->tport)) != SNMP_ERR_NOERROR) {
  164. lsock_close_port(&port->tport);
  165. return (err);
  166. }
  167. *pp = port;
  168. return (SNMP_ERR_NOERROR);
  169. }
  170. /*
  171. * Close a local domain peer
  172. */
  173. static void
  174. lsock_peer_close(struct lsock_peer *peer)
  175. {
  176. LIST_REMOVE(peer, link);
  177. snmpd_input_close(&peer->input);
  178. free(peer);
  179. }
  180. /*
  181. * Close a local port
  182. */
  183. static void
  184. lsock_close_port(struct tport *tp)
  185. {
  186. struct lsock_port *port = (struct lsock_port *)tp;
  187. struct lsock_peer *peer;
  188. if (port->str_id != NULL)
  189. fd_deselect(port->str_id);
  190. if (port->str_sock >= 0)
  191. (void)close(port->str_sock);
  192. (void)remove(port->name);
  193. trans_remove_port(tp);
  194. while ((peer = LIST_FIRST(&port->peers)) != NULL)
  195. lsock_peer_close(peer);
  196. free(port->name);
  197. free(port);
  198. }
  199. /*
  200. * Input on a local socket (either datagram or stream)
  201. */
  202. static void
  203. lsock_input(int fd __unused, void *udata)
  204. {
  205. struct lsock_peer *peer = udata;
  206. struct lsock_port *p = peer->port;
  207. peer->input.peerlen = sizeof(peer->peer);
  208. if (snmpd_input(&peer->input, &p->tport) == -1 && peer->input.stream)
  209. /* framing or other input error */
  210. lsock_peer_close(peer);
  211. }
  212. /*
  213. * A UNIX domain listening socket is ready. This means we have a peer
  214. * that we need to accept
  215. */
  216. static void
  217. lsock_listen_input(int fd, void *udata)
  218. {
  219. struct lsock_port *p = udata;
  220. struct lsock_peer *peer;
  221. if ((peer = malloc(sizeof(*peer))) == NULL) {
  222. syslog(LOG_WARNING, "%s: peer malloc failed", p->name);
  223. (void)close(accept(fd, NULL, NULL));
  224. return;
  225. }
  226. memset(peer, 0, sizeof(*peer));
  227. peer->port = p;
  228. peer->input.stream = 1;
  229. peer->input.cred = (p->type == LOCP_DGRAM_PRIV ||
  230. p->type == LOCP_STREAM_PRIV);
  231. peer->input.peerlen = sizeof(peer->peer);
  232. peer->input.peer = (struct sockaddr *)&peer->peer;
  233. peer->input.fd = accept(fd, peer->input.peer, &peer->input.peerlen);
  234. if (peer->input.fd == -1) {
  235. syslog(LOG_WARNING, "%s: accept failed: %m", p->name);
  236. free(peer);
  237. return;
  238. }
  239. if ((peer->input.id = fd_select(peer->input.fd, lsock_input,
  240. peer, NULL)) == NULL) {
  241. close(peer->input.fd);
  242. free(peer);
  243. return;
  244. }
  245. LIST_INSERT_HEAD(&p->peers, peer, link);
  246. }
  247. /*
  248. * Create a local socket
  249. */
  250. static int
  251. lsock_init_port(struct tport *tp)
  252. {
  253. struct lsock_port *p = (struct lsock_port *)tp;
  254. struct sockaddr_un sa;
  255. if (p->type == LOCP_STREAM_PRIV || p->type == LOCP_STREAM_UNPRIV) {
  256. if ((p->str_sock = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) {
  257. syslog(LOG_ERR, "creating local socket: %m");
  258. return (SNMP_ERR_RES_UNAVAIL);
  259. }
  260. strcpy(sa.sun_path, p->name);
  261. sa.sun_family = AF_LOCAL;
  262. sa.sun_len = strlen(p->name) +
  263. offsetof(struct sockaddr_un, sun_path);
  264. (void)remove(p->name);
  265. if (bind(p->str_sock, (struct sockaddr *)&sa, sizeof(sa))) {
  266. if (errno == EADDRNOTAVAIL) {
  267. close(p->str_sock);
  268. p->str_sock = -1;
  269. return (SNMP_ERR_INCONS_NAME);
  270. }
  271. syslog(LOG_ERR, "bind: %s %m", p->name);
  272. close(p->str_sock);
  273. p->str_sock = -1;
  274. return (SNMP_ERR_GENERR);
  275. }
  276. if (chmod(p->name, 0666) == -1)
  277. syslog(LOG_WARNING, "chmod(%s,0666): %m", p->name);
  278. if (listen(p->str_sock, 10) == -1) {
  279. syslog(LOG_ERR, "listen: %s %m", p->name);
  280. (void)remove(p->name);
  281. close(p->str_sock);
  282. p->str_sock = -1;
  283. return (SNMP_ERR_GENERR);
  284. }
  285. p->str_id = fd_select(p->str_sock, lsock_listen_input, p, NULL);
  286. if (p->str_id == NULL) {
  287. (void)remove(p->name);
  288. close(p->str_sock);
  289. p->str_sock = -1;
  290. return (SNMP_ERR_GENERR);
  291. }
  292. } else {
  293. struct lsock_peer *peer;
  294. const int on = 1;
  295. peer = LIST_FIRST(&p->peers);
  296. if ((peer->input.fd = socket(PF_LOCAL, SOCK_DGRAM, 0)) < 0) {
  297. syslog(LOG_ERR, "creating local socket: %m");
  298. return (SNMP_ERR_RES_UNAVAIL);
  299. }
  300. if (setsockopt(peer->input.fd, 0, LOCAL_CREDS, &on,
  301. sizeof(on)) == -1) {
  302. syslog(LOG_ERR, "setsockopt(LOCAL_CREDS): %m");
  303. close(peer->input.fd);
  304. peer->input.fd = -1;
  305. return (SNMP_ERR_GENERR);
  306. }
  307. strcpy(sa.sun_path, p->name);
  308. sa.sun_family = AF_LOCAL;
  309. sa.sun_len = strlen(p->name) +
  310. offsetof(struct sockaddr_un, sun_path);
  311. (void)remove(p->name);
  312. if (bind(peer->input.fd, (struct sockaddr *)&sa, sizeof(sa))) {
  313. if (errno == EADDRNOTAVAIL) {
  314. close(peer->input.fd);
  315. peer->input.fd = -1;
  316. return (SNMP_ERR_INCONS_NAME);
  317. }
  318. syslog(LOG_ERR, "bind: %s %m", p->name);
  319. close(peer->input.fd);
  320. peer->input.fd = -1;
  321. return (SNMP_ERR_GENERR);
  322. }
  323. if (chmod(p->name, 0666) == -1)
  324. syslog(LOG_WARNING, "chmod(%s,0666): %m", p->name);
  325. peer->input.id = fd_select(peer->input.fd, lsock_input,
  326. peer, NULL);
  327. if (peer->input.id == NULL) {
  328. (void)remove(p->name);
  329. close(peer->input.fd);
  330. peer->input.fd = -1;
  331. return (SNMP_ERR_GENERR);
  332. }
  333. }
  334. return (SNMP_ERR_NOERROR);
  335. }
  336. /*
  337. * Send something
  338. */
  339. static ssize_t
  340. lsock_send(struct tport *tp, const u_char *buf, size_t len,
  341. const struct sockaddr *addr, size_t addrlen)
  342. {
  343. struct lsock_port *p = (struct lsock_port *)tp;
  344. struct lsock_peer *peer;
  345. if (p->type == LOCP_DGRAM_PRIV || p->type == LOCP_DGRAM_UNPRIV) {
  346. peer = LIST_FIRST(&p->peers);
  347. } else {
  348. /* search for the peer */
  349. LIST_FOREACH(peer, &p->peers, link)
  350. if (peer->input.peerlen == addrlen &&
  351. memcmp(peer->input.peer, addr, addrlen) == 0)
  352. break;
  353. if (peer == NULL) {
  354. errno = ENOTCONN;
  355. return (-1);
  356. }
  357. }
  358. return (sendto(peer->input.fd, buf, len, 0, addr, addrlen));
  359. }
  360. /*
  361. * Dependency to create a lsock port
  362. */
  363. struct lsock_dep {
  364. struct snmp_dependency dep;
  365. /* index (path name) */
  366. u_char *path;
  367. size_t pathlen;
  368. /* the port */
  369. struct lsock_port *port;
  370. /* which of the fields are set */
  371. u_int set;
  372. /* type of the port */
  373. int type;
  374. /* status */
  375. int status;
  376. };
  377. #define LD_TYPE 0x01
  378. #define LD_STATUS 0x02
  379. #define LD_CREATE 0x04 /* rollback create */
  380. #define LD_DELETE 0x08 /* rollback delete */
  381. /*
  382. * dependency handler for lsock ports
  383. */
  384. static int
  385. lsock_func(struct snmp_context *ctx, struct snmp_dependency *dep,
  386. enum snmp_depop op)
  387. {
  388. struct lsock_dep *ld = (struct lsock_dep *)(void *)dep;
  389. int err = SNMP_ERR_NOERROR;
  390. switch (op) {
  391. case SNMP_DEPOP_COMMIT:
  392. if (!(ld->set & LD_STATUS))
  393. err = SNMP_ERR_BADVALUE;
  394. else if (ld->port == NULL) {
  395. if (!ld->status)
  396. err = SNMP_ERR_BADVALUE;
  397. else {
  398. /* create */
  399. err = lsock_open_port(ld->path, ld->pathlen,
  400. &ld->port, ld->type);
  401. if (err == SNMP_ERR_NOERROR)
  402. ld->set |= LD_CREATE;
  403. }
  404. } else if (!ld->status) {
  405. /* delete - hard to roll back so defer to finalizer */
  406. ld->set |= LD_DELETE;
  407. } else
  408. /* modify - read-only */
  409. err = SNMP_ERR_READONLY;
  410. return (err);
  411. case SNMP_DEPOP_ROLLBACK:
  412. if (ld->set & LD_CREATE) {
  413. /* was create */
  414. lsock_close_port(&ld->port->tport);
  415. }
  416. return (SNMP_ERR_NOERROR);
  417. case SNMP_DEPOP_FINISH:
  418. if ((ld->set & LD_DELETE) && ctx->code == SNMP_RET_OK)
  419. lsock_close_port(&ld->port->tport);
  420. free(ld->path);
  421. return (SNMP_ERR_NOERROR);
  422. }
  423. abort();
  424. }
  425. /*
  426. * Local port table
  427. */
  428. int
  429. op_lsock_port(struct snmp_context *ctx, struct snmp_value *value,
  430. u_int sub, u_int iidx, enum snmp_op op)
  431. {
  432. asn_subid_t which = value->var.subs[sub-1];
  433. struct lsock_port *p;
  434. u_char *name;
  435. size_t namelen;
  436. struct lsock_dep *ld;
  437. struct asn_oid didx;
  438. switch (op) {
  439. case SNMP_OP_GETNEXT:
  440. if ((p = (struct lsock_port *)trans_next_port(my_trans,
  441. &value->var, sub)) == NULL)
  442. return (SNMP_ERR_NOSUCHNAME);
  443. index_append(&value->var, sub, &p->tport.index);
  444. break;
  445. case SNMP_OP_GET:
  446. if ((p = (struct lsock_port *)trans_find_port(my_trans,
  447. &value->var, sub)) == NULL)
  448. return (SNMP_ERR_NOSUCHNAME);
  449. break;
  450. case SNMP_OP_SET:
  451. p = (struct lsock_port *)trans_find_port(my_trans,
  452. &value->var, sub);
  453. if (index_decode(&value->var, sub, iidx, &name, &namelen))
  454. return (SNMP_ERR_NO_CREATION);
  455. asn_slice_oid(&didx, &value->var, sub, value->var.len);
  456. if ((ld = (struct lsock_dep *)(void *)snmp_dep_lookup(ctx,
  457. &oid_begemotSnmpdLocalPortTable, &didx, sizeof(*ld),
  458. lsock_func)) == NULL) {
  459. free(name);
  460. return (SNMP_ERR_GENERR);
  461. }
  462. if (ld->path == NULL) {
  463. ld->path = name;
  464. ld->pathlen = namelen;
  465. } else {
  466. free(name);
  467. }
  468. ld->port = p;
  469. switch (which) {
  470. case LEAF_begemotSnmpdLocalPortStatus:
  471. if (ld->set & LD_STATUS)
  472. return (SNMP_ERR_INCONS_VALUE);
  473. if (!TRUTH_OK(value->v.integer))
  474. return (SNMP_ERR_WRONG_VALUE);
  475. ld->status = TRUTH_GET(value->v.integer);
  476. ld->set |= LD_STATUS;
  477. break;
  478. case LEAF_begemotSnmpdLocalPortType:
  479. if (ld->set & LD_TYPE)
  480. return (SNMP_ERR_INCONS_VALUE);
  481. if (value->v.integer < 1 || value->v.integer > 4)
  482. return (SNMP_ERR_WRONG_VALUE);
  483. ld->type = value->v.integer;
  484. ld->set |= LD_TYPE;
  485. break;
  486. }
  487. return (SNMP_ERR_NOERROR);
  488. case SNMP_OP_ROLLBACK:
  489. case SNMP_OP_COMMIT:
  490. return (SNMP_ERR_NOERROR);
  491. default:
  492. abort();
  493. }
  494. /*
  495. * Come here to fetch the value
  496. */
  497. switch (which) {
  498. case LEAF_begemotSnmpdLocalPortStatus:
  499. value->v.integer = 1;
  500. break;
  501. case LEAF_begemotSnmpdLocalPortType:
  502. value->v.integer = p->type;
  503. break;
  504. default:
  505. abort();
  506. }
  507. return (SNMP_ERR_NOERROR);
  508. }