3 * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
6 * Author: Harti Brandt <harti@freebsd.org>
8 * Redistribution of this software and documentation and use in source and
9 * binary forms, with or without modification, are permitted provided that
10 * the following conditions are met:
12 * 1. Redistributions of source code or documentation must retain the above
13 * copyright notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY FRAUNHOFER FOKUS
22 * AND ITS CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
23 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
24 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
25 * FRAUNHOFER FOKUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
28 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
31 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 * $Begemot: bsnmp/snmpd/trans_lsock.c,v 1.3 2003/12/09 12:28:53 hbb Exp $
35 * Local domain socket transport
37 #include <sys/types.h>
50 #include "trans_lsock.h"
54 static const struct asn_oid
55 oid_begemotSnmpdLocalPortTable = OIDX_begemotSnmpdLocalPortTable;
57 static int lsock_start(void);
58 static int lsock_stop(int);
59 static void lsock_close_port(struct tport *);
60 static int lsock_init_port(struct tport *);
61 static ssize_t lsock_send(struct tport *, const u_char *, size_t,
62 const struct sockaddr *, size_t);
65 const struct transport_def lsock_trans = {
67 OIDX_begemotSnmpdTransLsock,
74 static struct transport *my_trans;
77 lsock_remove(struct tport *tp, intptr_t arg __unused)
79 struct lsock_port *port = (struct lsock_port *)tp;
81 (void)remove(port->name);
90 if (my_trans != NULL) {
91 if (!force && trans_first_port(my_trans) != NULL)
92 return (SNMP_ERR_GENERR);
93 trans_iter_port(my_trans, lsock_remove, NULL);
94 return (trans_unregister(my_trans));
96 return (SNMP_ERR_NOERROR);
102 return (trans_register(&lsock_trans, &my_trans));
106 * Open a local port. If this is a datagram socket create also the
110 lsock_open_port(u_char *name, size_t namelen, struct lsock_port **pp,
113 struct lsock_port *port;
114 struct lsock_peer *peer = NULL;
115 int is_stream, need_cred;
118 struct sockaddr_un sa;
120 if (namelen == 0 || namelen + 1 > sizeof(sa.sun_path)) {
122 return (SNMP_ERR_BADVALUE);
125 case LOCP_DGRAM_UNPRIV:
130 case LOCP_DGRAM_PRIV:
135 case LOCP_STREAM_UNPRIV:
140 case LOCP_STREAM_PRIV:
147 return (SNMP_ERR_BADVALUE);
150 if ((port = malloc(sizeof(*port))) == NULL) {
152 return (SNMP_ERR_GENERR);
154 memset(port, 0, sizeof(*port));
156 if ((peer = malloc(sizeof(*peer))) == NULL) {
159 return (SNMP_ERR_GENERR);
161 memset(peer, 0, sizeof(*peer));
163 if ((port->name = malloc(namelen + 1)) == NULL) {
168 return (SNMP_ERR_GENERR);
170 strncpy(port->name, name, namelen);
171 port->name[namelen] = '\0';
175 LIST_INIT(&port->peers);
177 port->tport.index.len = namelen + 1;
178 port->tport.index.subs[0] = namelen;
179 for (u = 0; u < namelen; u++)
180 port->tport.index.subs[u + 1] = name[u];
183 LIST_INSERT_HEAD(&port->peers, peer, link);
188 peer->input.id = NULL;
189 peer->input.stream = is_stream;
190 peer->input.cred = need_cred;
191 peer->input.peer = (struct sockaddr *)&peer->peer;
194 trans_insert_port(my_trans, &port->tport);
196 if (community != COMM_INITIALIZE &&
197 (err = lsock_init_port(&port->tport)) != SNMP_ERR_NOERROR) {
198 lsock_close_port(&port->tport);
204 return (SNMP_ERR_NOERROR);
208 * Close a local domain peer
211 lsock_peer_close(struct lsock_peer *peer)
214 LIST_REMOVE(peer, link);
215 snmpd_input_close(&peer->input);
223 lsock_close_port(struct tport *tp)
225 struct lsock_port *port = (struct lsock_port *)tp;
226 struct lsock_peer *peer;
228 if (port->str_id != NULL)
229 fd_deselect(port->str_id);
230 if (port->str_sock >= 0)
231 (void)close(port->str_sock);
232 (void)remove(port->name);
234 trans_remove_port(tp);
236 while ((peer = LIST_FIRST(&port->peers)) != NULL)
237 lsock_peer_close(peer);
244 * Input on a local socket (either datagram or stream)
247 lsock_input(int fd __unused, void *udata)
249 struct lsock_peer *peer = udata;
250 struct lsock_port *p = peer->port;
252 peer->input.peerlen = sizeof(peer->peer);
253 if (snmpd_input(&peer->input, &p->tport) == -1 && peer->input.stream)
254 /* framing or other input error */
255 lsock_peer_close(peer);
259 * A UNIX domain listening socket is ready. This means we have a peer
260 * that we need to accept
263 lsock_listen_input(int fd, void *udata)
265 struct lsock_port *p = udata;
266 struct lsock_peer *peer;
268 if ((peer = malloc(sizeof(*peer))) == NULL) {
269 syslog(LOG_WARNING, "%s: peer malloc failed", p->name);
270 (void)close(accept(fd, NULL, NULL));
273 memset(peer, 0, sizeof(*peer));
277 peer->input.stream = 1;
278 peer->input.cred = (p->type == LOCP_DGRAM_PRIV ||
279 p->type == LOCP_STREAM_PRIV);
280 peer->input.peerlen = sizeof(peer->peer);
281 peer->input.peer = (struct sockaddr *)&peer->peer;
283 peer->input.fd = accept(fd, peer->input.peer, &peer->input.peerlen);
284 if (peer->input.fd == -1) {
285 syslog(LOG_WARNING, "%s: accept failed: %m", p->name);
290 if ((peer->input.id = fd_select(peer->input.fd, lsock_input,
291 peer, NULL)) == NULL) {
292 close(peer->input.fd);
297 LIST_INSERT_HEAD(&p->peers, peer, link);
301 * Create a local socket
304 lsock_init_port(struct tport *tp)
306 struct lsock_port *p = (struct lsock_port *)tp;
307 struct sockaddr_un sa;
309 if (p->type == LOCP_STREAM_PRIV || p->type == LOCP_STREAM_UNPRIV) {
310 if ((p->str_sock = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) {
311 syslog(LOG_ERR, "creating local socket: %m");
312 return (SNMP_ERR_RES_UNAVAIL);
315 strcpy(sa.sun_path, p->name);
316 sa.sun_family = AF_LOCAL;
317 sa.sun_len = strlen(p->name) +
318 offsetof(struct sockaddr_un, sun_path);
320 (void)remove(p->name);
322 if (bind(p->str_sock, (struct sockaddr *)&sa, sizeof(sa))) {
323 if (errno == EADDRNOTAVAIL) {
326 return (SNMP_ERR_INCONS_NAME);
328 syslog(LOG_ERR, "bind: %s %m", p->name);
331 return (SNMP_ERR_GENERR);
333 if (chmod(p->name, 0666) == -1)
334 syslog(LOG_WARNING, "chmod(%s,0666): %m", p->name);
336 if (listen(p->str_sock, 10) == -1) {
337 syslog(LOG_ERR, "listen: %s %m", p->name);
338 (void)remove(p->name);
341 return (SNMP_ERR_GENERR);
344 p->str_id = fd_select(p->str_sock, lsock_listen_input, p, NULL);
345 if (p->str_id == NULL) {
346 (void)remove(p->name);
349 return (SNMP_ERR_GENERR);
352 struct lsock_peer *peer;
354 peer = LIST_FIRST(&p->peers);
356 if ((peer->input.fd = socket(PF_LOCAL, SOCK_DGRAM, 0)) < 0) {
357 syslog(LOG_ERR, "creating local socket: %m");
358 return (SNMP_ERR_RES_UNAVAIL);
361 strcpy(sa.sun_path, p->name);
362 sa.sun_family = AF_LOCAL;
363 sa.sun_len = strlen(p->name) +
364 offsetof(struct sockaddr_un, sun_path);
366 (void)remove(p->name);
368 if (bind(peer->input.fd, (struct sockaddr *)&sa, sizeof(sa))) {
369 if (errno == EADDRNOTAVAIL) {
370 close(peer->input.fd);
372 return (SNMP_ERR_INCONS_NAME);
374 syslog(LOG_ERR, "bind: %s %m", p->name);
375 close(peer->input.fd);
377 return (SNMP_ERR_GENERR);
379 if (chmod(p->name, 0666) == -1)
380 syslog(LOG_WARNING, "chmod(%s,0666): %m", p->name);
382 peer->input.id = fd_select(peer->input.fd, lsock_input,
384 if (peer->input.id == NULL) {
385 (void)remove(p->name);
386 close(peer->input.fd);
388 return (SNMP_ERR_GENERR);
391 return (SNMP_ERR_NOERROR);
398 lsock_send(struct tport *tp, const u_char *buf, size_t len,
399 const struct sockaddr *addr, size_t addrlen)
401 struct lsock_port *p = (struct lsock_port *)tp;
402 struct lsock_peer *peer;
404 if (p->type == LOCP_DGRAM_PRIV || p->type == LOCP_DGRAM_UNPRIV) {
405 peer = LIST_FIRST(&p->peers);
408 /* search for the peer */
409 LIST_FOREACH(peer, &p->peers, link)
410 if (peer->input.peerlen == addrlen &&
411 memcmp(peer->input.peer, addr, addrlen) == 0)
419 return (sendto(peer->input.fd, buf, len, 0, addr, addrlen));
423 * Dependency to create a lsock port
426 struct snmp_dependency dep;
428 /* index (path name) */
433 struct lsock_port *port;
435 /* which of the fields are set */
438 /* type of the port */
445 #define LD_STATUS 0x02
446 #define LD_CREATE 0x04 /* rollback create */
449 * Finish handler for deleting a port - this cannot fail :-)
452 lsock_del(struct snmp_context *ctx __unused, int fail, void *arg)
454 struct lsock_dep *ld = (struct lsock_dep *)(void *)arg;
457 lsock_close_port(&ld->port->tport);
461 * dependency handler for lsock ports
464 lsock_func(struct snmp_context *ctx, struct snmp_dependency *dep,
467 struct lsock_dep *ld = (struct lsock_dep *)(void *)dep;
468 int err = SNMP_ERR_NOERROR;
472 case SNMP_DEPOP_COMMIT:
473 if (!(ld->set & LD_STATUS))
474 err = SNMP_ERR_BADVALUE;
475 else if (ld->port == NULL) {
477 err = SNMP_ERR_BADVALUE;
481 err = lsock_open_port(ld->path, ld->pathlen,
482 &ld->port, ld->type);
483 if (err == SNMP_ERR_NOERROR)
484 ld->set |= LD_CREATE;
486 } else if (!ld->status) {
487 /* delete - hard to roll back so defer to
489 if (snmp_set_atfinish(ctx, lsock_del, ld->port))
490 err = SNMP_ERR_RES_UNAVAIL;
492 /* modify - read-only */
493 err = SNMP_ERR_READONLY;
499 case SNMP_DEPOP_ROLLBACK:
500 if (ld->set & LD_CREATE) {
502 lsock_close_port(&ld->port->tport);
504 return (SNMP_ERR_NOERROR);
513 op_lsock_port(struct snmp_context *ctx, struct snmp_value *value,
514 u_int sub, u_int iidx, enum snmp_op op)
516 asn_subid_t which = value->var.subs[sub-1];
517 struct lsock_port *p;
520 struct lsock_dep *ld;
525 case SNMP_OP_GETNEXT:
526 if ((p = (struct lsock_port *)trans_next_port(my_trans,
527 &value->var, sub)) == NULL)
528 return (SNMP_ERR_NOSUCHNAME);
529 index_append(&value->var, sub, &p->tport.index);
533 if ((p = (struct lsock_port *)trans_find_port(my_trans,
534 &value->var, sub)) == NULL)
535 return (SNMP_ERR_NOSUCHNAME);
539 p = (struct lsock_port *)trans_find_port(my_trans,
542 if (index_decode(&value->var, sub, iidx, &name, &namelen))
543 return (SNMP_ERR_NO_CREATION);
545 asn_slice_oid(&didx, &value->var, sub, value->var.len);
546 if ((ld = (struct lsock_dep *)(void *)snmp_dep_lookup(ctx,
547 &oid_begemotSnmpdLocalPortTable, &didx, sizeof(*ld),
548 lsock_func)) == NULL) {
550 return (SNMP_ERR_GENERR);
553 if (ld->path == NULL) {
555 ld->pathlen = namelen;
563 case LEAF_begemotSnmpdLocalPortStatus:
564 if (ld->set & LD_STATUS)
565 return (SNMP_ERR_INCONS_VALUE);
566 if (!TRUTH_OK(value->v.integer))
567 return (SNMP_ERR_WRONG_VALUE);
569 ld->status = TRUTH_GET(value->v.integer);
570 ld->set |= LD_STATUS;
573 case LEAF_begemotSnmpdLocalPortType:
574 if (ld->set & LD_TYPE)
575 return (SNMP_ERR_INCONS_VALUE);
576 if (value->v.integer < 1 || value->v.integer > 4)
577 return (SNMP_ERR_WRONG_VALUE);
579 ld->type = value->v.integer;
583 return (SNMP_ERR_NOERROR);
585 case SNMP_OP_ROLLBACK:
587 return (SNMP_ERR_NOERROR);
594 * Come here to fetch the value
598 case LEAF_begemotSnmpdLocalPortStatus:
599 value->v.integer = 1;
602 case LEAF_begemotSnmpdLocalPortType:
603 value->v.integer = p->type;
610 return (SNMP_ERR_NOERROR);