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