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