1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 24 * Copyright (c) 2016-2017, Chris Fraire <cfraire@me.com>. 25 */ 26 27 /* 28 * Main door handler functions used by ipmgmtd to process the different door 29 * call requests, issued by the library libipadm.so. 30 */ 31 32 #include <alloca.h> 33 #include <pwd.h> 34 #include <auth_attr.h> 35 #include <secdb.h> 36 #include <stdlib.h> 37 #include <stdio.h> 38 #include <string.h> 39 #include <strings.h> 40 #include <errno.h> 41 #include <assert.h> 42 #include <libnvpair.h> 43 #include "ipmgmt_impl.h" 44 45 /* Handler declaration for each door command */ 46 typedef void ipmgmt_door_handler_t(void *argp); 47 48 static ipmgmt_door_handler_t ipmgmt_getaddr_handler, 49 ipmgmt_getprop_handler, 50 ipmgmt_getif_handler, 51 ipmgmt_initif_handler, 52 ipmgmt_aobjop_handler, 53 ipmgmt_resetaddr_handler, 54 ipmgmt_setif_handler, 55 ipmgmt_resetif_handler, 56 ipmgmt_resetprop_handler, 57 ipmgmt_setaddr_handler, 58 ipmgmt_setprop_handler; 59 60 typedef struct ipmgmt_door_info_s { 61 uint_t idi_cmd; 62 boolean_t idi_set; 63 ipmgmt_door_handler_t *idi_handler; 64 } ipmgmt_door_info_t; 65 66 /* maps door commands to door handler functions */ 67 static ipmgmt_door_info_t i_ipmgmt_door_info_tbl[] = { 68 { IPMGMT_CMD_SETPROP, B_TRUE, ipmgmt_setprop_handler }, 69 { IPMGMT_CMD_SETIF, B_TRUE, ipmgmt_setif_handler }, 70 { IPMGMT_CMD_SETADDR, B_TRUE, ipmgmt_setaddr_handler }, 71 { IPMGMT_CMD_GETPROP, B_FALSE, ipmgmt_getprop_handler }, 72 { IPMGMT_CMD_GETIF, B_FALSE, ipmgmt_getif_handler }, 73 { IPMGMT_CMD_GETADDR, B_FALSE, ipmgmt_getaddr_handler }, 74 { IPMGMT_CMD_RESETIF, B_TRUE, ipmgmt_resetif_handler }, 75 { IPMGMT_CMD_RESETADDR, B_TRUE, ipmgmt_resetaddr_handler }, 76 { IPMGMT_CMD_RESETPROP, B_TRUE, ipmgmt_resetprop_handler }, 77 { IPMGMT_CMD_INITIF, B_TRUE, ipmgmt_initif_handler }, 78 { IPMGMT_CMD_ADDROBJ_LOOKUPADD, B_TRUE, ipmgmt_aobjop_handler }, 79 { IPMGMT_CMD_ADDROBJ_SETLIFNUM, B_TRUE, ipmgmt_aobjop_handler }, 80 { IPMGMT_CMD_ADDROBJ_ADD, B_TRUE, ipmgmt_aobjop_handler }, 81 { IPMGMT_CMD_AOBJNAME2ADDROBJ, B_FALSE, ipmgmt_aobjop_handler }, 82 { IPMGMT_CMD_LIF2ADDROBJ, B_FALSE, ipmgmt_aobjop_handler }, 83 { 0, 0, NULL }, 84 }; 85 86 /* 87 * The main server procedure function that gets invoked for any of the incoming 88 * door commands. Inside this function we identify the incoming command and 89 * invoke the right door handler function. 90 */ 91 /* ARGSUSED */ 92 void 93 ipmgmt_handler(void *cookie, char *argp, size_t argsz, door_desc_t *dp, 94 uint_t n_desc) 95 { 96 ipmgmt_door_info_t *infop = NULL; 97 ipmgmt_retval_t retval; 98 int i; 99 uint_t err; 100 ucred_t *cred = NULL; 101 102 for (i = 0; i_ipmgmt_door_info_tbl[i].idi_cmd != 0; i++) { 103 if (i_ipmgmt_door_info_tbl[i].idi_cmd == 104 ((ipmgmt_arg_t *)(void *)argp)->ia_cmd) { 105 infop = &i_ipmgmt_door_info_tbl[i]; 106 break; 107 } 108 } 109 110 if (infop == NULL) { 111 ipmgmt_log(LOG_ERR, "Invalid door command specified"); 112 err = EINVAL; 113 goto fail; 114 } 115 116 /* check for solaris.network.interface.config authorization */ 117 if (infop->idi_set) { 118 uid_t uid; 119 struct passwd pwd; 120 char buf[1024]; 121 122 if (door_ucred(&cred) != 0) { 123 err = errno; 124 ipmgmt_log(LOG_ERR, "Could not get user credentials."); 125 goto fail; 126 } 127 uid = ucred_getruid(cred); 128 if ((int)uid < 0) { 129 err = errno; 130 ipmgmt_log(LOG_ERR, "Could not get user id."); 131 goto fail; 132 } 133 if (getpwuid_r(uid, &pwd, buf, sizeof (buf)) == 134 NULL) { 135 err = errno; 136 ipmgmt_log(LOG_ERR, "Could not get password entry."); 137 goto fail; 138 } 139 if (chkauthattr(NETWORK_INTERFACE_CONFIG_AUTH, 140 pwd.pw_name) != 1) { 141 err = EPERM; 142 ipmgmt_log(LOG_ERR, "Not authorized for operation."); 143 goto fail; 144 } 145 ucred_free(cred); 146 } 147 148 /* individual handlers take care of calling door_return */ 149 infop->idi_handler((void *)argp); 150 return; 151 fail: 152 ucred_free(cred); 153 retval.ir_err = err; 154 (void) door_return((char *)&retval, sizeof (retval), NULL, 0); 155 } 156 157 /* 158 * Handles the door command IPMGMT_CMD_GETPROP. It retrieves the persisted 159 * property value for the given property. 160 */ 161 static void 162 ipmgmt_getprop_handler(void *argp) 163 { 164 ipmgmt_prop_arg_t *pargp = argp; 165 ipmgmt_getprop_rval_t rval, *rvalp = &rval; 166 167 assert(pargp->ia_cmd == IPMGMT_CMD_GETPROP); 168 169 rvalp->ir_err = ipmgmt_db_walk(ipmgmt_db_getprop, pargp, IPADM_DB_READ); 170 if (rvalp->ir_err == 0) 171 (void) strlcpy(rvalp->ir_pval, pargp->ia_pval, 172 sizeof (rvalp->ir_pval)); 173 (void) door_return((char *)rvalp, sizeof (*rvalp), NULL, 0); 174 } 175 176 /* 177 * Handles the door command IPMGMT_CMD_SETPROP. It persists the property value 178 * for the given property in the DB. 179 */ 180 static void 181 ipmgmt_setprop_handler(void *argp) 182 { 183 ipmgmt_prop_arg_t *pargp = argp; 184 ipmgmt_retval_t rval; 185 ipadm_dbwrite_cbarg_t cb; 186 nvlist_t *nvl = NULL; 187 int err; 188 189 assert(pargp->ia_cmd == IPMGMT_CMD_SETPROP); 190 191 if ((err = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0)) != 0) 192 goto fail; 193 if (pargp->ia_module[0] != '\0' && 194 (err = nvlist_add_string(nvl, IPADM_NVP_PROTONAME, 195 pargp->ia_module)) != 0) { 196 goto fail; 197 } 198 if (pargp->ia_ifname[0] != '\0' && 199 (err = nvlist_add_string(nvl, IPADM_NVP_IFNAME, 200 pargp->ia_ifname)) != 0) 201 goto fail; 202 if (pargp->ia_aobjname[0] != '\0' && 203 (err = nvlist_add_string(nvl, IPADM_NVP_AOBJNAME, 204 pargp->ia_aobjname)) != 0) 205 goto fail; 206 if ((err = nvlist_add_string(nvl, pargp->ia_pname, 207 pargp->ia_pval)) != 0) 208 goto fail; 209 210 cb.dbw_nvl = nvl; 211 cb.dbw_flags = pargp->ia_flags; 212 err = ipmgmt_db_walk(ipmgmt_db_update, &cb, IPADM_DB_WRITE); 213 fail: 214 nvlist_free(nvl); 215 rval.ir_err = err; 216 (void) door_return((char *)&rval, sizeof (rval), NULL, 0); 217 } 218 219 /* 220 * Helper function for ipmgmt_setaddr_handler(). 221 * It converts the nvlist_t, `nvl', to aobjmap node `nodep'. 222 */ 223 static int 224 i_ipmgmt_nvl2aobjnode(nvlist_t *nvl, ipmgmt_aobjmap_t *nodep) 225 { 226 char *aobjname = NULL, *ifname = NULL; 227 int32_t lnum; 228 nvlist_t *nvladdr; 229 sa_family_t af = AF_UNSPEC; 230 ipadm_addr_type_t addrtype = IPADM_ADDR_NONE; 231 int err = 0; 232 233 /* 234 * Retrieve all the information needed to build '*nodep' from 235 * nvlist_t nvl. 236 */ 237 if ((err = nvlist_lookup_string(nvl, IPADM_NVP_AOBJNAME, 238 &aobjname)) != 0 || 239 (err = nvlist_lookup_string(nvl, IPADM_NVP_IFNAME, &ifname)) != 0 || 240 (err = nvlist_lookup_int32(nvl, IPADM_NVP_LIFNUM, &lnum)) != 0) { 241 return (err); 242 } 243 if (nvlist_exists(nvl, IPADM_NVP_IPV4ADDR)) { 244 af = AF_INET; 245 addrtype = IPADM_ADDR_STATIC; 246 } else if (nvlist_lookup_nvlist(nvl, IPADM_NVP_DHCP, &nvladdr) == 0) { 247 char *reqhost; 248 249 af = AF_INET; 250 addrtype = IPADM_ADDR_DHCP; 251 252 /* 253 * ipmgmt_am_reqhost comes through in `nvl' for purposes of 254 * updating the cached representation, but it is persisted as 255 * a stand-alone DB line; so remove it after copying it. 256 */ 257 if (!nvlist_exists(nvl, IPADM_NVP_REQHOST)) { 258 *nodep->ipmgmt_am_reqhost = '\0'; 259 } else { 260 if ((err = nvlist_lookup_string(nvl, IPADM_NVP_REQHOST, 261 &reqhost)) != 0) 262 return (err); 263 264 (void) strlcpy(nodep->ipmgmt_am_reqhost, reqhost, 265 sizeof (nodep->ipmgmt_am_reqhost)); 266 (void) nvlist_remove(nvl, IPADM_NVP_REQHOST, 267 DATA_TYPE_STRING); 268 } 269 } else if (nvlist_exists(nvl, IPADM_NVP_IPV6ADDR)) { 270 af = AF_INET6; 271 addrtype = IPADM_ADDR_STATIC; 272 } else if (nvlist_lookup_nvlist(nvl, IPADM_NVP_INTFID, &nvladdr) == 0) { 273 struct sockaddr_in6 sin6 = {0}; 274 uint8_t *addr6; 275 uint32_t plen; 276 uint_t n; 277 278 af = AF_INET6; 279 addrtype = IPADM_ADDR_IPV6_ADDRCONF; 280 if (nvlist_lookup_uint32(nvladdr, IPADM_NVP_PREFIXLEN, 281 &plen) != 0) 282 return (EINVAL); 283 if (plen != 0) { 284 if (nvlist_lookup_uint8_array(nvladdr, 285 IPADM_NVP_IPNUMADDR, &addr6, &n) != 0) 286 return (EINVAL); 287 bcopy(addr6, &sin6.sin6_addr, n); 288 } 289 290 nodep->ipmgmt_am_linklocal = B_TRUE; 291 nodep->ipmgmt_am_ifid = sin6; 292 } 293 294 /* 295 * populate the non-addrtype-specific `*nodep' with retrieved values. 296 */ 297 (void) strlcpy(nodep->am_ifname, ifname, sizeof (nodep->am_ifname)); 298 (void) strlcpy(nodep->am_aobjname, aobjname, 299 sizeof (nodep->am_aobjname)); 300 nodep->am_lnum = lnum; 301 nodep->am_family = af; 302 nodep->am_atype = addrtype; 303 nodep->am_next = NULL; 304 305 /* 306 * Do not store logical interface number in persistent store as it 307 * takes different value on reboot. So remove it from `nvl'. 308 */ 309 if (nvlist_exists(nvl, IPADM_NVP_LIFNUM)) 310 (void) nvlist_remove(nvl, IPADM_NVP_LIFNUM, DATA_TYPE_INT32); 311 312 return (0); 313 } 314 315 /* 316 * Handles the door command IPMGMT_CMD_SETADDR. It adds a new address object 317 * node to the list `aobjmap' and optionally persists the address 318 * information in the DB. 319 */ 320 static void 321 ipmgmt_setaddr_handler(void *argp) 322 { 323 ipmgmt_setaddr_arg_t *sargp = argp; 324 ipmgmt_retval_t rval; 325 ipmgmt_aobjmap_t node = {0}; 326 nvlist_t *nvl = NULL; 327 char *nvlbuf; 328 size_t nvlsize = sargp->ia_nvlsize; 329 uint32_t flags = sargp->ia_flags; 330 int err = 0; 331 332 nvlbuf = (char *)argp + sizeof (ipmgmt_setaddr_arg_t); 333 if ((err = nvlist_unpack(nvlbuf, nvlsize, &nvl, 0)) != 0) 334 goto ret; 335 if (flags & (IPMGMT_ACTIVE|IPMGMT_INIT)) { 336 if ((err = i_ipmgmt_nvl2aobjnode(nvl, &node)) != 0) 337 goto ret; 338 if (flags & IPMGMT_INIT) 339 node.am_flags = (IPMGMT_ACTIVE|IPMGMT_PERSIST); 340 else 341 node.am_flags = flags & ~IPMGMT_PROPS_ONLY; 342 if ((err = ipmgmt_aobjmap_op(&node, ADDROBJ_ADD)) != 0) 343 goto ret; 344 } 345 if ((flags & IPMGMT_PERSIST) && !(flags & IPMGMT_PROPS_ONLY)) { 346 ipadm_dbwrite_cbarg_t cb; 347 348 cb.dbw_nvl = nvl; 349 cb.dbw_flags = 0; 350 err = ipmgmt_db_walk(ipmgmt_db_add, &cb, IPADM_DB_WRITE); 351 } 352 ret: 353 nvlist_free(nvl); 354 rval.ir_err = err; 355 (void) door_return((char *)&rval, sizeof (rval), NULL, 0); 356 } 357 358 /* 359 * Handles the door commands that read or modify the `aobjmap' structure. 360 * 361 * IPMGMT_CMD_ADDROBJ_LOOKUPADD - places a stub address object in `aobjmap' 362 * after ensuring that the namespace is not taken. If required, also 363 * generates an `aobjname' for address object for the library to use. 364 * IPMGMT_CMD_ADDROBJ_ADD - add/update address object in `aobjmap' 365 * IPMGMT_CMD_LIF2ADDROBJ - given a logical interface, return address object 366 * associated with that logical interface. 367 * IPMGMT_CMD_AOBJNAME2ADDROBJ - given an address object name return logical 368 * interface associated with that address object. 369 */ 370 static void 371 ipmgmt_aobjop_handler(void *argp) 372 { 373 ipmgmt_aobjop_arg_t *largp = argp; 374 ipmgmt_retval_t rval; 375 ipmgmt_aobjop_rval_t aobjrval; 376 void *rvalp; 377 size_t rsize; 378 ipmgmt_aobjmap_t node; 379 int err = 0; 380 char *ifname = largp->ia_ifname; 381 char *aobjname = largp->ia_aobjname; 382 int32_t lnum = largp->ia_lnum; 383 sa_family_t af = largp->ia_family; 384 ipadm_addr_type_t atype = largp->ia_atype; 385 ipmgmt_aobjmap_t *head; 386 387 switch (largp->ia_cmd) { 388 case IPMGMT_CMD_ADDROBJ_LOOKUPADD: 389 rsize = sizeof (ipmgmt_aobjop_rval_t); 390 rvalp = &aobjrval; 391 bzero(&node, sizeof (node)); 392 (void) strlcpy(node.am_aobjname, aobjname, 393 sizeof (node.am_aobjname)); 394 (void) strlcpy(node.am_ifname, ifname, 395 sizeof (node.am_ifname)); 396 node.am_family = af; 397 node.am_atype = atype; 398 /* no logical number is associated with this addrobj yet */ 399 node.am_lnum = -1; 400 /* The address object is not persisted yet. */ 401 node.am_flags = IPMGMT_ACTIVE; 402 err = ipmgmt_aobjmap_op(&node, ADDROBJ_LOOKUPADD); 403 if (err == 0) { 404 (void) strlcpy(aobjrval.ir_aobjname, node.am_aobjname, 405 sizeof (aobjrval.ir_aobjname)); 406 } 407 break; 408 case IPMGMT_CMD_ADDROBJ_SETLIFNUM: 409 rsize = sizeof (ipmgmt_retval_t); 410 rvalp = &rval; 411 bzero(&node, sizeof (node)); 412 (void) strlcpy(node.am_aobjname, aobjname, 413 sizeof (node.am_aobjname)); 414 (void) strlcpy(node.am_ifname, ifname, 415 sizeof (node.am_ifname)); 416 node.am_family = af; 417 node.am_lnum = lnum; 418 err = ipmgmt_aobjmap_op(&node, ADDROBJ_SETLIFNUM); 419 break; 420 case IPMGMT_CMD_ADDROBJ_ADD: 421 rsize = sizeof (ipmgmt_retval_t); 422 rvalp = &rval; 423 if (aobjname[0] == '\0' || ifname[0] == '\0' || lnum == -1 || 424 af == AF_UNSPEC) { 425 err = EINVAL; 426 break; 427 } 428 bzero(&node, sizeof (node)); 429 (void) strlcpy(node.am_aobjname, aobjname, 430 sizeof (node.am_aobjname)); 431 (void) strlcpy(node.am_ifname, ifname, 432 sizeof (node.am_ifname)); 433 node.am_atype = atype; 434 node.am_lnum = lnum; 435 node.am_family = af; 436 /* The address object is not persisted. */ 437 node.am_flags = IPMGMT_ACTIVE; 438 err = ipmgmt_aobjmap_op(&node, ADDROBJ_ADD); 439 break; 440 case IPMGMT_CMD_AOBJNAME2ADDROBJ: 441 rsize = sizeof (ipmgmt_aobjop_rval_t); 442 rvalp = &aobjrval; 443 bzero(&aobjrval, sizeof (aobjrval)); 444 if (aobjname[0] == '\0') { 445 err = EINVAL; 446 break; 447 } 448 (void) pthread_rwlock_rdlock(&aobjmap.aobjmap_rwlock); 449 head = aobjmap.aobjmap_head; 450 for (; head; head = head->am_next) { 451 if (strcmp(head->am_aobjname, aobjname) != 0) 452 continue; 453 /* 454 * For an auto-configured interface, return 455 * the lifnum that has the link-local on it. 456 * Other logical interfaces were created for 457 * prefixes and dhcpv6 addresses and do not 458 * have am_ifid set. 459 */ 460 if (head->am_atype != IPADM_ADDR_IPV6_ADDRCONF || 461 head->ipmgmt_am_linklocal) { 462 break; 463 } 464 } 465 if (head == NULL) { 466 err = ENOENT; 467 (void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock); 468 break; 469 } 470 (void) strlcpy(aobjrval.ir_ifname, head->am_ifname, 471 sizeof (aobjrval.ir_ifname)); 472 aobjrval.ir_lnum = head->am_lnum; 473 aobjrval.ir_family = head->am_family; 474 aobjrval.ir_flags = head->am_flags; 475 aobjrval.ir_atype = head->am_atype; 476 aobjrval.ir_atype_cache = head->am_atype_cache; 477 (void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock); 478 break; 479 case IPMGMT_CMD_LIF2ADDROBJ: 480 rsize = sizeof (ipmgmt_aobjop_rval_t); 481 rvalp = &aobjrval; 482 bzero(&aobjrval, sizeof (aobjrval)); 483 if (ifname[0] == '\0') { 484 err = EINVAL; 485 break; 486 } 487 (void) pthread_rwlock_rdlock(&aobjmap.aobjmap_rwlock); 488 head = aobjmap.aobjmap_head; 489 for (; head; head = head->am_next) { 490 if (strcmp(head->am_ifname, ifname) == 0 && 491 head->am_lnum == lnum && 492 head->am_family == af) { 493 break; 494 } 495 } 496 if (head == NULL) { 497 err = ENOENT; 498 (void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock); 499 break; 500 } 501 (void) strlcpy(aobjrval.ir_aobjname, head->am_aobjname, 502 sizeof (aobjrval.ir_aobjname)); 503 aobjrval.ir_atype = head->am_atype; 504 aobjrval.ir_flags = head->am_flags; 505 aobjrval.ir_atype_cache = head->am_atype_cache; 506 (void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock); 507 break; 508 default: 509 rsize = sizeof (ipmgmt_retval_t); 510 rvalp = &rval; 511 err = EINVAL; 512 } 513 ((ipmgmt_retval_t *)rvalp)->ir_err = err; 514 (void) door_return((char *)rvalp, rsize, NULL, 0); 515 } 516 517 /* 518 * Given an interface name and family, deletes all the address objects 519 * associated with it. 520 */ 521 void 522 i_ipmgmt_delif_aobjs(char *ifname, sa_family_t af, uint32_t flags) 523 { 524 ipmgmt_aobjmap_t *head, *next, *prev; 525 ipadm_db_op_t db_op; 526 527 prev = NULL; 528 529 (void) pthread_rwlock_wrlock(&aobjmap.aobjmap_rwlock); 530 head = aobjmap.aobjmap_head; 531 for (; head; head = next) { 532 next = head->am_next; 533 if (strcmp(head->am_ifname, ifname) != 0 || 534 head->am_family != af) { 535 prev = head; 536 continue; 537 } 538 539 if (head->am_flags == (IPMGMT_ACTIVE|IPMGMT_PERSIST) && 540 flags == IPMGMT_ACTIVE) { 541 /* 542 * If the addres is present in both active and 543 * persistent store, and if we are performing 544 * a temporary delete, we update the node to 545 * indicate that the address is only present in 546 * persistent store and we proceed. Otherwise 547 * we always delete the node from aobjmap. 548 */ 549 head->am_flags &= ~IPMGMT_ACTIVE; 550 head->am_lnum = -1; 551 db_op = IPADM_DB_WRITE; 552 } else { 553 db_op = IPADM_DB_DELETE; 554 if (prev == NULL) 555 aobjmap.aobjmap_head = next; 556 else 557 prev->am_next = next; 558 } 559 (void) ipmgmt_persist_aobjmap(head, db_op); 560 if (db_op == IPADM_DB_DELETE) 561 free(head); 562 } 563 (void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock); 564 } 565 566 /* 567 * Handles the door command IPMGMT_CMD_SETIF. It persists the interface 568 * information in the DB. 569 */ 570 static void 571 ipmgmt_setif_handler(void *argp) 572 { 573 ipmgmt_retval_t rval; 574 575 rval.ir_err = ipmgmt_persist_if(argp); 576 (void) door_return((char *)&rval, sizeof (rval), NULL, 0); 577 } 578 579 /* 580 * Handles the door command IPMGMT_CMD_RESETIF. For the given interface, 581 * deletes all the persisted interface configuration. It also deletes, from 582 * `aobjmap', all the address objects configured on the given interface. 583 */ 584 static void 585 ipmgmt_resetif_handler(void *argp) 586 { 587 ipmgmt_if_arg_t *rargp = argp; 588 ipmgmt_retval_t rval; 589 ipmgmt_if_cbarg_t cbarg; 590 uint32_t flags = rargp->ia_flags; 591 int err = 0; 592 593 cbarg.cb_family = rargp->ia_family; 594 cbarg.cb_ifname = rargp->ia_ifname; 595 if (flags & IPMGMT_PERSIST) 596 err = ipmgmt_db_walk(ipmgmt_db_resetif, &cbarg, 597 IPADM_DB_DELETE); 598 599 if (flags & IPMGMT_ACTIVE) 600 i_ipmgmt_delif_aobjs(rargp->ia_ifname, rargp->ia_family, 601 flags); 602 603 rval.ir_err = err; 604 (void) door_return((char *)&rval, sizeof (rval), NULL, 0); 605 } 606 607 /* 608 * Handles the door command IPMGMT_CMD_RESETADDR. For the given addrobj 609 * deletes all the persisted addrobj configuration. It also deletes the 610 * corresponding node, from `aobjmap'. 611 */ 612 static void 613 ipmgmt_resetaddr_handler(void *argp) 614 { 615 ipmgmt_addr_arg_t *rargp = argp; 616 ipmgmt_retval_t rval; 617 ipmgmt_aobjmap_t node; 618 uint32_t flags = rargp->ia_flags; 619 int err = 0; 620 ipmgmt_resetaddr_cbarg_t cbarg; 621 622 cbarg.cb_aobjname = rargp->ia_aobjname; 623 624 if (flags & IPMGMT_PERSIST) 625 err = ipmgmt_db_walk(ipmgmt_db_resetaddr, &cbarg, 626 IPADM_DB_DELETE); 627 628 if (flags & IPMGMT_ACTIVE) { 629 bzero(&node, sizeof (node)); 630 (void) strlcpy(node.am_aobjname, rargp->ia_aobjname, 631 sizeof (node.am_aobjname)); 632 633 /* 634 * am_lnum is used only for IPv6 autoconf case, since there 635 * can be multiple nodes with the same aobjname. 636 */ 637 node.am_lnum = rargp->ia_lnum; 638 node.am_flags = flags; 639 (void) ipmgmt_aobjmap_op(&node, ADDROBJ_DELETE); 640 } 641 642 rval.ir_err = err; 643 (void) door_return((char *)&rval, sizeof (rval), NULL, 0); 644 } 645 646 /* 647 * Handles the door command IPMGMT_CMD_GETADDR. It retrieves the persisted 648 * address for a given `gargp->ia_aobjname'. If it is not defined then it 649 * retrieves all the addresses configured on `gargp->ia_ifname'. The 650 * "ipadm show-addr addrobj" or "ipadm show-addr <ifname>/\*" will call this 651 * handler through library. 652 */ 653 static void 654 ipmgmt_getaddr_handler(void *argp) 655 { 656 size_t buflen, onvlsize; 657 char *buf, *onvlbuf; 658 ipmgmt_getaddr_arg_t *gargp = argp; 659 ipmgmt_getaddr_cbarg_t cbarg; 660 ipmgmt_get_rval_t rval, *rvalp = &rval; 661 int err = 0; 662 663 cbarg.cb_ifname = gargp->ia_ifname; 664 cbarg.cb_aobjname = gargp->ia_aobjname; 665 cbarg.cb_ocnt = 0; 666 if (nvlist_alloc(&cbarg.cb_onvl, NV_UNIQUE_NAME, 0) != 0) 667 goto fail; 668 err = ipmgmt_db_walk(ipmgmt_db_getaddr, &cbarg, IPADM_DB_READ); 669 if (err == ENOENT && cbarg.cb_ocnt > 0) { 670 /* 671 * If there is atleast one entry in the nvlist, 672 * do not return error. 673 */ 674 err = 0; 675 } 676 if (err != 0) 677 goto fail; 678 679 if ((err = nvlist_size(cbarg.cb_onvl, &onvlsize, 680 NV_ENCODE_NATIVE)) != 0) { 681 goto fail; 682 } 683 buflen = onvlsize + sizeof (ipmgmt_get_rval_t); 684 /* 685 * We cannot use malloc() here because door_return never returns, and 686 * memory allocated by malloc() would get leaked. Use alloca() instead. 687 */ 688 buf = alloca(buflen); 689 onvlbuf = buf + sizeof (ipmgmt_get_rval_t); 690 if ((err = nvlist_pack(cbarg.cb_onvl, &onvlbuf, &onvlsize, 691 NV_ENCODE_NATIVE, 0)) != 0) { 692 goto fail; 693 } 694 nvlist_free(cbarg.cb_onvl); 695 rvalp = (ipmgmt_get_rval_t *)(void *)buf; 696 rvalp->ir_err = 0; 697 rvalp->ir_nvlsize = onvlsize; 698 699 (void) door_return(buf, buflen, NULL, 0); 700 return; 701 fail: 702 nvlist_free(cbarg.cb_onvl); 703 rvalp->ir_err = err; 704 (void) door_return((char *)rvalp, sizeof (*rvalp), NULL, 0); 705 } 706 707 /* 708 * Handles the door command IPMGMT_CMD_RESETPROP. It deletes the property line 709 * from the DB. 710 */ 711 static void 712 ipmgmt_resetprop_handler(void *argp) 713 { 714 ipmgmt_prop_arg_t *pargp = argp; 715 ipmgmt_retval_t rval; 716 717 assert(pargp->ia_cmd == IPMGMT_CMD_RESETPROP); 718 719 rval.ir_err = ipmgmt_db_walk(ipmgmt_db_resetprop, pargp, 720 IPADM_DB_DELETE); 721 (void) door_return((char *)&rval, sizeof (rval), NULL, 0); 722 } 723 724 /* 725 * Handles the door command IPMGMT_CMD_GETIF. It retrieves the name of all the 726 * persisted interfaces and the IP protocols (IPv4 or IPv6) they support. 727 */ 728 static void 729 ipmgmt_getif_handler(void *argp) 730 { 731 ipmgmt_getif_arg_t *getif = argp; 732 ipmgmt_getif_rval_t *rvalp; 733 ipmgmt_retval_t rval; 734 ipmgmt_getif_cbarg_t cbarg; 735 ipadm_if_info_t *ifp, *rifp, *curifp; 736 int i, err = 0, count = 0; 737 size_t rbufsize; 738 739 assert(getif->ia_cmd == IPMGMT_CMD_GETIF); 740 741 bzero(&cbarg, sizeof (cbarg)); 742 cbarg.cb_ifname = getif->ia_ifname; 743 err = ipmgmt_db_walk(ipmgmt_db_getif, &cbarg, IPADM_DB_READ); 744 if (err == ENOENT && cbarg.cb_ifinfo) { 745 /* 746 * If there is atleast one entry in the nvlist, 747 * do not return error. 748 */ 749 err = 0; 750 } 751 if (err != 0) { 752 rval.ir_err = err; 753 (void) door_return((char *)&rval, sizeof (rval), NULL, 0); 754 return; 755 } 756 757 /* allocate sufficient buffer to return the interface info */ 758 for (ifp = cbarg.cb_ifinfo; ifp != NULL; ifp = ifp->ifi_next) 759 ++count; 760 rbufsize = sizeof (*rvalp) + count * sizeof (*ifp); 761 rvalp = alloca(rbufsize); 762 bzero(rvalp, rbufsize); 763 764 rvalp->ir_ifcnt = count; 765 rifp = rvalp->ir_ifinfo; 766 ifp = cbarg.cb_ifinfo; 767 768 /* 769 * copy the interface info to buffer allocated on stack. The reason 770 * we do this is to avoid memory leak, as door_return() would never 771 * return 772 */ 773 for (i = 0; i < count; i++) { 774 rifp = rvalp->ir_ifinfo + i; 775 (void) bcopy(ifp, rifp, sizeof (*rifp)); 776 rifp->ifi_next = NULL; 777 curifp = ifp->ifi_next; 778 free(ifp); 779 ifp = curifp; 780 } 781 rvalp->ir_err = err; 782 (void) door_return((char *)rvalp, rbufsize, NULL, 0); 783 } 784 785 /* 786 * Handles the door command IPMGMT_CMD_INITIF. It retrieves all the persisted 787 * interface configuration (interface properties and addresses), for all those 788 * interfaces that need to be initialized. 789 */ 790 static void 791 ipmgmt_initif_handler(void *argp) 792 { 793 ipmgmt_initif_arg_t *initif = argp; 794 size_t buflen, nvlsize; 795 char *buf = NULL, *onvlbuf, *invlbuf; 796 ipmgmt_get_rval_t rval, *rvalp = &rval; 797 ipmgmt_initif_cbarg_t cbarg; 798 int err; 799 800 assert(initif->ia_cmd == IPMGMT_CMD_INITIF); 801 802 bzero(&cbarg, sizeof (cbarg)); 803 invlbuf = (char *)argp + sizeof (ipmgmt_initif_arg_t); 804 nvlsize = initif->ia_nvlsize; 805 err = nvlist_unpack(invlbuf, nvlsize, &cbarg.cb_invl, 0); 806 if (err != 0) 807 goto fail; 808 809 cbarg.cb_family = initif->ia_family; 810 if (nvlist_alloc(&cbarg.cb_onvl, NV_UNIQUE_NAME, 0) != 0) 811 goto fail; 812 813 err = ipmgmt_db_walk(ipmgmt_db_initif, &cbarg, IPADM_DB_READ); 814 if (err == ENOENT && cbarg.cb_ocnt > 0) { 815 /* 816 * If there is atleast one entry in the nvlist, 817 * do not return error. 818 */ 819 err = 0; 820 } 821 if (err != 0) 822 goto fail; 823 824 if ((err = nvlist_size(cbarg.cb_onvl, &nvlsize, NV_ENCODE_NATIVE)) != 0) 825 goto fail; 826 buflen = nvlsize + sizeof (ipmgmt_get_rval_t); 827 /* 828 * We cannot use malloc() here because door_return never returns, and 829 * memory allocated by malloc() would get leaked. Use alloca() instead. 830 */ 831 buf = alloca(buflen); 832 onvlbuf = buf + sizeof (ipmgmt_get_rval_t); 833 if ((err = nvlist_pack(cbarg.cb_onvl, &onvlbuf, &nvlsize, 834 NV_ENCODE_NATIVE, 0)) != 0) { 835 goto fail; 836 } 837 nvlist_free(cbarg.cb_invl); 838 nvlist_free(cbarg.cb_onvl); 839 rvalp = (ipmgmt_get_rval_t *)(void *)buf; 840 rvalp->ir_err = 0; 841 rvalp->ir_nvlsize = nvlsize; 842 843 (void) door_return(buf, buflen, NULL, 0); 844 return; 845 fail: 846 nvlist_free(cbarg.cb_invl); 847 nvlist_free(cbarg.cb_onvl); 848 rvalp->ir_err = err; 849 (void) door_return((char *)rvalp, sizeof (*rvalp), NULL, 0); 850 } 851 852 int 853 ipmgmt_persist_if(ipmgmt_if_arg_t *sargp) 854 { 855 ipadm_dbwrite_cbarg_t cb; 856 uint32_t flags = sargp->ia_flags; 857 nvlist_t *nvl = NULL; 858 int err = 0; 859 char strval[IPMGMT_STRSIZE]; 860 861 if (!(flags & IPMGMT_PERSIST) || sargp->ia_family == AF_UNSPEC || 862 sargp->ia_ifname[0] == '\0') { 863 err = EINVAL; 864 goto ret; 865 } 866 if ((err = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0)) != 0) 867 goto ret; 868 if ((err = nvlist_add_string(nvl, IPADM_NVP_IFNAME, 869 sargp->ia_ifname)) != 0) 870 goto ret; 871 (void) snprintf(strval, IPMGMT_STRSIZE, "%d", sargp->ia_family); 872 if ((err = nvlist_add_string(nvl, IPADM_NVP_FAMILY, strval)) != 0) 873 goto ret; 874 cb.dbw_nvl = nvl; 875 cb.dbw_flags = 0; 876 err = ipmgmt_db_walk(ipmgmt_db_add, &cb, IPADM_DB_WRITE); 877 ret: 878 nvlist_free(nvl); 879 return (err); 880 } 881