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 */
25
26 /*
27 * Main door handler functions used by ipmgmtd to process the different door
28 * call requests, issued by the library libipadm.so.
29 */
30
31 #include <alloca.h>
32 #include <pwd.h>
33 #include <auth_attr.h>
34 #include <secdb.h>
35 #include <stdlib.h>
36 #include <stdio.h>
37 #include <string.h>
38 #include <strings.h>
39 #include <errno.h>
40 #include <assert.h>
41 #include <libnvpair.h>
42 #include "ipmgmt_impl.h"
43
208
209 cb.dbw_nvl = nvl;
210 cb.dbw_flags = pargp->ia_flags;
211 err = ipmgmt_db_walk(ipmgmt_db_update, &cb, IPADM_DB_WRITE);
212 fail:
213 nvlist_free(nvl);
214 rval.ir_err = err;
215 (void) door_return((char *)&rval, sizeof (rval), NULL, 0);
216 }
217
218 /*
219 * Helper function for ipmgmt_setaddr_handler().
220 * It converts the nvlist_t, `nvl', to aobjmap node `nodep'.
221 */
222 static int
223 i_ipmgmt_nvl2aobjnode(nvlist_t *nvl, ipmgmt_aobjmap_t *nodep)
224 {
225 char *aobjname = NULL, *ifname = NULL;
226 int32_t lnum;
227 nvlist_t *nvladdr;
228 struct sockaddr_storage addr;
229 uint_t n;
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_exists(nvl, IPADM_NVP_DHCP)) {
248 af = AF_INET;
249 addrtype = IPADM_ADDR_DHCP;
250 } else if (nvlist_exists(nvl, IPADM_NVP_IPV6ADDR)) {
251 af = AF_INET6;
252 addrtype = IPADM_ADDR_STATIC;
253 } else if (nvlist_lookup_nvlist(nvl, IPADM_NVP_INTFID, &nvladdr) == 0) {
254 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&addr;
255 uint8_t *addr6;
256 uint32_t plen;
257
258 af = AF_INET6;
259 addrtype = IPADM_ADDR_IPV6_ADDRCONF;
260 if (nvlist_lookup_uint32(nvladdr, IPADM_NVP_PREFIXLEN,
261 &plen) != 0)
262 return (EINVAL);
263 if (plen != 0) {
264 if (nvlist_lookup_uint8_array(nvladdr,
265 IPADM_NVP_IPNUMADDR, &addr6, &n) != 0)
266 return (EINVAL);
267 bcopy(addr6, &sin6->sin6_addr, n);
268 } else {
269 bzero(&sin6->sin6_addr, sizeof (sin6->sin6_addr));
270 }
271 }
272
273 /*
274 * populate the `*nodep' with retrieved values.
275 */
276 (void) strlcpy(nodep->am_ifname, ifname, sizeof (nodep->am_ifname));
277 (void) strlcpy(nodep->am_aobjname, aobjname,
278 sizeof (nodep->am_aobjname));
279 nodep->am_lnum = lnum;
280 nodep->am_family = af;
281 nodep->am_atype = addrtype;
282 if (addrtype == IPADM_ADDR_IPV6_ADDRCONF) {
283 nodep->am_linklocal = B_TRUE;
284 nodep->am_ifid = addr;
285 }
286 nodep->am_next = NULL;
287
288 /*
289 * Do not store logical interface number in persistent store as it
290 * takes different value on reboot. So remove it from `nvl'.
291 */
292 if (nvlist_exists(nvl, IPADM_NVP_LIFNUM))
293 (void) nvlist_remove(nvl, IPADM_NVP_LIFNUM, DATA_TYPE_INT32);
294
295 return (0);
296 }
297
298 /*
299 * Handles the door command IPMGMT_CMD_SETADDR. It adds a new address object
300 * node to the list `aobjmap' and then persists the address information in the
301 * DB.
302 */
303 static void
304 ipmgmt_setaddr_handler(void *argp)
305 {
306 ipmgmt_setaddr_arg_t *sargp = argp;
307 ipmgmt_retval_t rval;
308 ipmgmt_aobjmap_t node;
309 nvlist_t *nvl = NULL;
310 char *nvlbuf;
311 size_t nvlsize = sargp->ia_nvlsize;
312 uint32_t flags = sargp->ia_flags;
313 int err = 0;
314
315 nvlbuf = (char *)argp + sizeof (ipmgmt_setaddr_arg_t);
316 if ((err = nvlist_unpack(nvlbuf, nvlsize, &nvl, NV_ENCODE_NATIVE)) != 0)
317 goto ret;
318 if (flags & (IPMGMT_ACTIVE|IPMGMT_INIT)) {
319 if ((err = i_ipmgmt_nvl2aobjnode(nvl, &node)) != 0)
320 goto ret;
321 if (flags & IPMGMT_INIT)
322 node.am_flags = (IPMGMT_ACTIVE|IPMGMT_PERSIST);
323 else
324 node.am_flags = flags;
325 if ((err = ipmgmt_aobjmap_op(&node, ADDROBJ_ADD)) != 0)
326 goto ret;
327 }
328 if (flags & IPMGMT_PERSIST) {
329 ipadm_dbwrite_cbarg_t cb;
330
331 cb.dbw_nvl = nvl;
332 cb.dbw_flags = 0;
333 err = ipmgmt_db_walk(ipmgmt_db_add, &cb, IPADM_DB_WRITE);
334 }
335 ret:
336 nvlist_free(nvl);
337 rval.ir_err = err;
338 (void) door_return((char *)&rval, sizeof (rval), NULL, 0);
339 }
340
341 /*
342 * Handles the door commands that modify the `aobjmap' structure.
343 *
344 * IPMGMT_CMD_ADDROBJ_LOOKUPADD - places a stub address object in `aobjmap'
345 * after ensuring that the namespace is not taken. If required, also
346 * generates an `aobjname' for address object for the library to use.
347 * IPMGMT_CMD_ADDROBJ_ADD - add/update address object in `aobjmap'
348 * IPMGMT_CMD_LIF2ADDROBJ - given a logical interface, return address object
349 * associated with that logical interface.
350 * IPMGMT_CMD_AOBJNAME2ADDROBJ - given an address object name return logical
351 * interface associated with that address object.
352 */
353 static void
354 ipmgmt_aobjop_handler(void *argp)
355 {
356 ipmgmt_aobjop_arg_t *largp = argp;
357 ipmgmt_retval_t rval;
358 ipmgmt_aobjop_rval_t aobjrval;
359 void *rvalp;
360 size_t rsize;
361 ipmgmt_aobjmap_t node;
362 int err = 0;
424 rsize = sizeof (ipmgmt_aobjop_rval_t);
425 rvalp = &aobjrval;
426 bzero(&aobjrval, sizeof (aobjrval));
427 if (aobjname[0] == '\0') {
428 err = EINVAL;
429 break;
430 }
431 (void) pthread_rwlock_rdlock(&aobjmap.aobjmap_rwlock);
432 head = aobjmap.aobjmap_head;
433 for (; head; head = head->am_next) {
434 if (strcmp(head->am_aobjname, aobjname) != 0)
435 continue;
436 /*
437 * For an auto-configured interface, return
438 * the lifnum that has the link-local on it.
439 * Other logical interfaces were created for
440 * prefixes and dhcpv6 addresses and do not
441 * have am_ifid set.
442 */
443 if (head->am_atype != IPADM_ADDR_IPV6_ADDRCONF ||
444 head->am_linklocal) {
445 break;
446 }
447 }
448 if (head == NULL) {
449 err = ENOENT;
450 (void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
451 break;
452 }
453 (void) strlcpy(aobjrval.ir_ifname, head->am_ifname,
454 sizeof (aobjrval.ir_ifname));
455 aobjrval.ir_lnum = head->am_lnum;
456 aobjrval.ir_family = head->am_family;
457 aobjrval.ir_flags = head->am_flags;
458 aobjrval.ir_atype = head->am_atype;
459 if (head->am_atype == IPADM_ADDR_IPV6_ADDRCONF &&
460 head->am_linklocal)
461 aobjrval.ir_ifid = head->am_ifid;
462 (void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
463 break;
464 case IPMGMT_CMD_LIF2ADDROBJ:
465 rsize = sizeof (ipmgmt_aobjop_rval_t);
466 rvalp = &aobjrval;
467 bzero(&aobjrval, sizeof (aobjrval));
468 if (ifname[0] == '\0') {
469 err = EINVAL;
470 break;
471 }
472 (void) pthread_rwlock_rdlock(&aobjmap.aobjmap_rwlock);
473 head = aobjmap.aobjmap_head;
474 for (; head; head = head->am_next) {
475 if (strcmp(head->am_ifname, ifname) == 0 &&
476 head->am_lnum == lnum &&
477 head->am_family == af) {
478 break;
479 }
480 }
481 if (head == NULL) {
482 err = ENOENT;
483 (void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
484 break;
485 }
486 (void) strlcpy(aobjrval.ir_aobjname, head->am_aobjname,
487 sizeof (aobjrval.ir_aobjname));
488 aobjrval.ir_atype = head->am_atype;
489 aobjrval.ir_flags = head->am_flags;
490 (void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
491 break;
492 default:
493 rsize = sizeof (ipmgmt_retval_t);
494 rvalp = &rval;
495 err = EINVAL;
496 }
497 ((ipmgmt_retval_t *)rvalp)->ir_err = err;
498 (void) door_return((char *)rvalp, rsize, NULL, 0);
499 }
500
501 /*
502 * Given an interface name and family, deletes all the address objects
503 * associated with it.
504 */
505 void
506 i_ipmgmt_delif_aobjs(char *ifname, sa_family_t af, uint32_t flags)
507 {
508 ipmgmt_aobjmap_t *head, *next, *prev;
509 ipadm_db_op_t db_op;
|
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, 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
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 boolean_t primary;
249
250 af = AF_INET;
251 addrtype = IPADM_ADDR_DHCP;
252
253 if (nvlist_lookup_boolean_value(nvladdr, IPADM_NVP_PRIMARY,
254 &primary) != 0)
255 return (EINVAL);
256 nodep->ipmgmt_am_primary = primary;
257
258 /*
259 * ipmgmt_am_reqhost comes through in `nvl' for purposes of updating
260 * the cached representation, but it is persisted as a stand-alone
261 * 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, DATA_TYPE_STRING);
273 }
274 } else if (nvlist_exists(nvl, IPADM_NVP_IPV6ADDR)) {
275 af = AF_INET6;
276 addrtype = IPADM_ADDR_STATIC;
277 } else if (nvlist_lookup_nvlist(nvl, IPADM_NVP_INTFID, &nvladdr) == 0) {
278 struct sockaddr_in6 sin6 = {0};
279 uint8_t *addr6;
280 uint32_t plen;
281 uint_t n;
282
283 af = AF_INET6;
284 addrtype = IPADM_ADDR_IPV6_ADDRCONF;
285 if (nvlist_lookup_uint32(nvladdr, IPADM_NVP_PREFIXLEN,
286 &plen) != 0)
287 return (EINVAL);
288 if (plen != 0) {
289 if (nvlist_lookup_uint8_array(nvladdr,
290 IPADM_NVP_IPNUMADDR, &addr6, &n) != 0)
291 return (EINVAL);
292 bcopy(addr6, &sin6.sin6_addr, n);
293 }
294
295 nodep->ipmgmt_am_linklocal = B_TRUE;
296 nodep->ipmgmt_am_ifid = sin6;
297 }
298
299 /*
300 * populate the non-addrtype-specific `*nodep' with retrieved values.
301 */
302 (void) strlcpy(nodep->am_ifname, ifname, sizeof (nodep->am_ifname));
303 (void) strlcpy(nodep->am_aobjname, aobjname,
304 sizeof (nodep->am_aobjname));
305 nodep->am_lnum = lnum;
306 nodep->am_family = af;
307 nodep->am_atype = addrtype;
308 nodep->am_next = NULL;
309
310 /*
311 * Do not store logical interface number in persistent store as it
312 * takes different value on reboot. So remove it from `nvl'.
313 */
314 if (nvlist_exists(nvl, IPADM_NVP_LIFNUM))
315 (void) nvlist_remove(nvl, IPADM_NVP_LIFNUM, DATA_TYPE_INT32);
316
317 return (0);
318 }
319
320 /*
321 * Handles the door command IPMGMT_CMD_SETADDR. It adds a new address object
322 * node to the list `aobjmap' and optionally persists the address
323 * information in the DB.
324 */
325 static void
326 ipmgmt_setaddr_handler(void *argp)
327 {
328 ipmgmt_setaddr_arg_t *sargp = argp;
329 ipmgmt_retval_t rval;
330 ipmgmt_aobjmap_t node = {0};
331 nvlist_t *nvl = NULL;
332 char *nvlbuf;
333 size_t nvlsize = sargp->ia_nvlsize;
334 uint32_t flags = sargp->ia_flags;
335 int err = 0;
336
337 nvlbuf = (char *)argp + sizeof (ipmgmt_setaddr_arg_t);
338 if ((err = nvlist_unpack(nvlbuf, nvlsize, &nvl, NV_ENCODE_NATIVE)) != 0)
339 goto ret;
340 if (flags & (IPMGMT_ACTIVE|IPMGMT_INIT)) {
341 if ((err = i_ipmgmt_nvl2aobjnode(nvl, &node)) != 0)
342 goto ret;
343 if (flags & IPMGMT_INIT)
344 node.am_flags = (IPMGMT_ACTIVE|IPMGMT_PERSIST);
345 else
346 node.am_flags = flags & ~IPMGMT_PROPS_ONLY;
347 if ((err = ipmgmt_aobjmap_op(&node, ADDROBJ_ADD)) != 0)
348 goto ret;
349 }
350 if ((flags & IPMGMT_PERSIST) && !(flags & IPMGMT_PROPS_ONLY)) {
351 ipadm_dbwrite_cbarg_t cb;
352
353 cb.dbw_nvl = nvl;
354 cb.dbw_flags = 0;
355 err = ipmgmt_db_walk(ipmgmt_db_add, &cb, IPADM_DB_WRITE);
356 }
357 ret:
358 nvlist_free(nvl);
359 rval.ir_err = err;
360 (void) door_return((char *)&rval, sizeof (rval), NULL, 0);
361 }
362
363 /*
364 * Handles the door commands that read or modify the `aobjmap' structure.
365 *
366 * IPMGMT_CMD_ADDROBJ_LOOKUPADD - places a stub address object in `aobjmap'
367 * after ensuring that the namespace is not taken. If required, also
368 * generates an `aobjname' for address object for the library to use.
369 * IPMGMT_CMD_ADDROBJ_ADD - add/update address object in `aobjmap'
370 * IPMGMT_CMD_LIF2ADDROBJ - given a logical interface, return address object
371 * associated with that logical interface.
372 * IPMGMT_CMD_AOBJNAME2ADDROBJ - given an address object name return logical
373 * interface associated with that address object.
374 */
375 static void
376 ipmgmt_aobjop_handler(void *argp)
377 {
378 ipmgmt_aobjop_arg_t *largp = argp;
379 ipmgmt_retval_t rval;
380 ipmgmt_aobjop_rval_t aobjrval;
381 void *rvalp;
382 size_t rsize;
383 ipmgmt_aobjmap_t node;
384 int err = 0;
446 rsize = sizeof (ipmgmt_aobjop_rval_t);
447 rvalp = &aobjrval;
448 bzero(&aobjrval, sizeof (aobjrval));
449 if (aobjname[0] == '\0') {
450 err = EINVAL;
451 break;
452 }
453 (void) pthread_rwlock_rdlock(&aobjmap.aobjmap_rwlock);
454 head = aobjmap.aobjmap_head;
455 for (; head; head = head->am_next) {
456 if (strcmp(head->am_aobjname, aobjname) != 0)
457 continue;
458 /*
459 * For an auto-configured interface, return
460 * the lifnum that has the link-local on it.
461 * Other logical interfaces were created for
462 * prefixes and dhcpv6 addresses and do not
463 * have am_ifid set.
464 */
465 if (head->am_atype != IPADM_ADDR_IPV6_ADDRCONF ||
466 head->ipmgmt_am_linklocal) {
467 break;
468 }
469 }
470 if (head == NULL) {
471 err = ENOENT;
472 (void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
473 break;
474 }
475 (void) strlcpy(aobjrval.ir_ifname, head->am_ifname,
476 sizeof (aobjrval.ir_ifname));
477 aobjrval.ir_lnum = head->am_lnum;
478 aobjrval.ir_family = head->am_family;
479 aobjrval.ir_flags = head->am_flags;
480 aobjrval.ir_atype = head->am_atype;
481 (void) memcpy(&aobjrval.ir_atype_cache, &head->am_atype_cache,
482 sizeof (aobjrval.ir_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 (void) memcpy(&aobjrval.ir_atype_cache, &head->am_atype_cache,
512 sizeof (aobjrval.ir_atype_cache));
513 (void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
514 break;
515 default:
516 rsize = sizeof (ipmgmt_retval_t);
517 rvalp = &rval;
518 err = EINVAL;
519 }
520 ((ipmgmt_retval_t *)rvalp)->ir_err = err;
521 (void) door_return((char *)rvalp, rsize, NULL, 0);
522 }
523
524 /*
525 * Given an interface name and family, deletes all the address objects
526 * associated with it.
527 */
528 void
529 i_ipmgmt_delif_aobjs(char *ifname, sa_family_t af, uint32_t flags)
530 {
531 ipmgmt_aobjmap_t *head, *next, *prev;
532 ipadm_db_op_t db_op;
|