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