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