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