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