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