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