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