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) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26 /*
27 * Main door handler functions used by dlmgmtd to process the different door
28 * call requests. Door call requests can come from the user-land applications,
29 * or from the kernel.
30 *
31 * Note on zones handling:
32 *
33 * There are two zoneid's associated with a link. One is the zoneid of the
34 * zone in which the link was created (ll_zoneid in the dlmgmt_link_t), and
35 * the other is the zoneid of the zone where the link is currently assigned
36 * (the "zone" link property). The two can be different if a datalink is
37 * created in the global zone and subsequently assigned to a non-global zone
38 * via zonecfg or via explicitly setting the "zone" link property.
39 *
40 * Door clients can see links that were created in their zone, and links that
41 * are currently assigned to their zone. Door clients in a zone can only
42 * modify links that were created in their zone.
43 *
44 * The datalink ID space is global, while each zone has its own datalink name
45 * space. This allows each zone to have complete freedom over the names that
46 * they assign to links created within the zone.
47 */
48
49 #include <assert.h>
50 #include <alloca.h>
51 #include <errno.h>
52 #include <priv_utils.h>
53 #include <stdlib.h>
54 #include <strings.h>
55 #include <syslog.h>
56 #include <sys/sysevent/eventdefs.h>
57 #include <zone.h>
58 #include <libsysevent.h>
59 #include <libdlmgmt.h>
60 #include <librcm.h>
61 #include "dlmgmt_impl.h"
62
63 typedef void dlmgmt_door_handler_t(void *, void *, size_t *, zoneid_t,
64 ucred_t *);
65
66 typedef struct dlmgmt_door_info_s {
67 uint_t di_cmd;
68 size_t di_reqsz;
69 size_t di_acksz;
70 dlmgmt_door_handler_t *di_handler;
71 } dlmgmt_door_info_t;
72
73 /*
74 * Check if the caller has the required privileges to operate on a link of the
75 * given class.
76 */
77 static int
78 dlmgmt_checkprivs(datalink_class_t class, ucred_t *cred)
79 {
80 const priv_set_t *eset;
362 datalink_id_t linkid = destroy->ld_linkid;
363 dlmgmt_link_t *linkp = NULL;
364 uint32_t flags, dflags = 0;
365 int err = 0;
366
367 flags = DLMGMT_ACTIVE | (destroy->ld_persist ? DLMGMT_PERSIST : 0);
368
369 /*
370 * Hold the writer lock to update the link table.
371 */
372 dlmgmt_table_lock(B_TRUE);
373
374 if ((linkp = link_by_id(linkid, zoneid)) == NULL) {
375 err = ENOENT;
376 goto done;
377 }
378
379 if ((err = dlmgmt_checkprivs(linkp->ll_class, cred)) != 0)
380 goto done;
381
382 if (((linkp->ll_flags & flags) & DLMGMT_ACTIVE) != 0) {
383 if ((err = dlmgmt_delete_db_entry(linkp, DLMGMT_ACTIVE)) != 0)
384 goto done;
385 dflags |= DLMGMT_ACTIVE;
386 }
387
388 if (((linkp->ll_flags & flags) & DLMGMT_PERSIST) != 0) {
389 if ((err = dlmgmt_delete_db_entry(linkp, DLMGMT_PERSIST)) != 0)
390 goto done;
391 dflags |= DLMGMT_PERSIST;
392 }
393
394 err = dlmgmt_destroy_common(linkp, flags);
395 done:
396 if (err != 0 && dflags != 0)
397 (void) dlmgmt_write_db_entry(linkp->ll_link, linkp, dflags);
398
399 dlmgmt_table_unlock();
400 retvalp->lr_err = err;
401 }
422 } else {
423 retvalp->lr_flags = linkp->ll_flags;
424 retvalp->lr_class = linkp->ll_class;
425 retvalp->lr_media = linkp->ll_media;
426 }
427
428 dlmgmt_table_unlock();
429 retvalp->lr_err = err;
430 }
431
432 /* ARGSUSED */
433 static void
434 dlmgmt_getlinkid(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
435 ucred_t *cred)
436 {
437 dlmgmt_door_getlinkid_t *getlinkid = argp;
438 dlmgmt_getlinkid_retval_t *retvalp = retp;
439 dlmgmt_link_t *linkp;
440 int err = 0;
441
442 /*
443 * Hold the reader lock to access the link
444 */
445 dlmgmt_table_lock(B_FALSE);
446
447 if ((linkp = link_by_name(getlinkid->ld_link, zoneid)) == NULL) {
448 /*
449 * The link does not exist in this zone.
450 */
451 err = ENOENT;
452 goto done;
453 }
454
455 retvalp->lr_linkid = linkp->ll_linkid;
456 retvalp->lr_flags = linkp->ll_flags;
457 retvalp->lr_class = linkp->ll_class;
458 retvalp->lr_media = linkp->ll_media;
459
460 done:
461 dlmgmt_table_unlock();
631 boolean_t renamed = B_FALSE;
632 int err = 0;
633
634 if (!dladm_valid_linkname(remapid->ld_link)) {
635 retvalp->lr_err = EINVAL;
636 return;
637 }
638
639 /*
640 * Hold the writer lock to update the link table.
641 */
642 dlmgmt_table_lock(B_TRUE);
643 if ((linkp = link_by_id(remapid->ld_linkid, zoneid)) == NULL) {
644 err = ENOENT;
645 goto done;
646 }
647
648 if ((err = dlmgmt_checkprivs(linkp->ll_class, cred)) != 0)
649 goto done;
650
651 if (link_by_name(remapid->ld_link, linkp->ll_zoneid) != NULL) {
652 err = EEXIST;
653 goto done;
654 }
655
656 (void) strlcpy(oldname, linkp->ll_link, MAXLINKNAMELEN);
657 avl_remove(&dlmgmt_name_avl, linkp);
658 (void) strlcpy(linkp->ll_link, remapid->ld_link, MAXLINKNAMELEN);
659 avl_add(&dlmgmt_name_avl, linkp);
660 renamed = B_TRUE;
661
662 if (linkp->ll_flags & DLMGMT_ACTIVE) {
663 err = dlmgmt_write_db_entry(oldname, linkp, DLMGMT_ACTIVE);
664 if (err != 0)
665 goto done;
666 }
667 if (linkp->ll_flags & DLMGMT_PERSIST) {
668 err = dlmgmt_write_db_entry(oldname, linkp, DLMGMT_PERSIST);
669 if (err != 0) {
670 if (linkp->ll_flags & DLMGMT_ACTIVE) {
692 dlmgmt_upid(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
693 ucred_t *cred)
694 {
695 dlmgmt_door_upid_t *upid = argp;
696 dlmgmt_upid_retval_t *retvalp = retp;
697 dlmgmt_link_t *linkp;
698 int err = 0;
699
700 /*
701 * Hold the writer lock to update the link table.
702 */
703 dlmgmt_table_lock(B_TRUE);
704 if ((linkp = link_by_id(upid->ld_linkid, zoneid)) == NULL) {
705 err = ENOENT;
706 goto done;
707 }
708
709 if ((err = dlmgmt_checkprivs(linkp->ll_class, cred)) != 0)
710 goto done;
711
712 if (linkp->ll_flags & DLMGMT_ACTIVE) {
713 err = EINVAL;
714 goto done;
715 }
716
717 if ((err = link_activate(linkp)) == 0) {
718 (void) dlmgmt_write_db_entry(linkp->ll_link, linkp,
719 DLMGMT_ACTIVE);
720 }
721 done:
722 dlmgmt_table_unlock();
723 retvalp->lr_err = err;
724 }
725
726 /* ARGSUSED */
727 static void
728 dlmgmt_createconf(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
729 ucred_t *cred)
730 {
731 dlmgmt_door_createconf_t *createconf = argp;
1199 datalink_id_t linkid = setzoneid->ld_linkid;
1200 zoneid_t oldzoneid, newzoneid;
1201 int err = 0;
1202
1203 dlmgmt_table_lock(B_TRUE);
1204
1205 /* We currently only allow changing zoneid's from the global zone. */
1206 if (zoneid != GLOBAL_ZONEID) {
1207 err = EACCES;
1208 goto done;
1209 }
1210
1211 if ((linkp = link_by_id(linkid, zoneid)) == NULL) {
1212 err = ENOENT;
1213 goto done;
1214 }
1215
1216 if ((err = dlmgmt_checkprivs(linkp->ll_class, cred)) != 0)
1217 goto done;
1218
1219 /* We can only assign an active link to a zone. */
1220 if (!(linkp->ll_flags & DLMGMT_ACTIVE)) {
1221 err = EINVAL;
1222 goto done;
1223 }
1224
1225 oldzoneid = linkp->ll_zoneid;
1226 newzoneid = setzoneid->ld_zoneid;
1227
1228 if (oldzoneid == newzoneid)
1229 goto done;
1230
1231 /*
1232 * Before we remove the link from its current zone, make sure that
1233 * there isn't a link with the same name in the destination zone.
1234 */
1235 if (zoneid != GLOBAL_ZONEID &&
1236 link_by_name(linkp->ll_link, newzoneid) != NULL) {
1237 err = EEXIST;
1238 goto done;
1239 }
1240
1241 if (oldzoneid != GLOBAL_ZONEID) {
1242 if (zone_remove_datalink(oldzoneid, linkid) != 0) {
1243 err = errno;
1244 dlmgmt_log(LOG_WARNING, "unable to remove link %d from "
1245 "zone %d: %s", linkid, oldzoneid, strerror(err));
1246 goto done;
1247 }
1248 avl_remove(&dlmgmt_loan_avl, linkp);
1249 linkp->ll_onloan = B_FALSE;
1250 }
1251 if (newzoneid != GLOBAL_ZONEID) {
1252 if (zone_add_datalink(newzoneid, linkid) != 0) {
1253 err = errno;
1254 dlmgmt_log(LOG_WARNING, "unable to add link %d to zone "
1255 "%d: %s", linkid, newzoneid, strerror(err));
1256 (void) zone_add_datalink(oldzoneid, linkid);
1257 goto done;
1258 }
1259 avl_add(&dlmgmt_loan_avl, linkp);
1260 linkp->ll_onloan = B_TRUE;
1261 }
1262
1263 avl_remove(&dlmgmt_name_avl, linkp);
1264 linkp->ll_zoneid = newzoneid;
1265 avl_add(&dlmgmt_name_avl, linkp);
1266
1267 done:
1268 dlmgmt_table_unlock();
1269 retvalp->lr_err = err;
1270 }
1271
1272 /* ARGSUSED */
1273 static void
1274 dlmgmt_zoneboot(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
1275 ucred_t *cred)
1276 {
1277 int err;
1278 dlmgmt_door_zoneboot_t *zoneboot = argp;
1279 dlmgmt_zoneboot_retval_t *retvalp = retp;
1292 goto done;
1293 }
1294
1295 if ((err = dlmgmt_elevate_privileges()) == 0) {
1296 err = dlmgmt_zone_init(zoneboot->ld_zoneid);
1297 (void) dlmgmt_drop_privileges();
1298 }
1299 done:
1300 dlmgmt_table_unlock();
1301 retvalp->lr_err = err;
1302 }
1303
1304 /* ARGSUSED */
1305 static void
1306 dlmgmt_zonehalt(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
1307 ucred_t *cred)
1308 {
1309 int err = 0;
1310 dlmgmt_door_zonehalt_t *zonehalt = argp;
1311 dlmgmt_zonehalt_retval_t *retvalp = retp;
1312
1313 if ((err = dlmgmt_checkprivs(0, cred)) == 0) {
1314 if (zoneid != GLOBAL_ZONEID) {
1315 err = EACCES;
1316 } else if (zonehalt->ld_zoneid == GLOBAL_ZONEID) {
1317 err = EINVAL;
1318 } else {
1319 dlmgmt_table_lock(B_TRUE);
1320 dlmgmt_db_fini(zonehalt->ld_zoneid);
1321 dlmgmt_table_unlock();
1322 }
1323 }
1324 retvalp->lr_err = err;
1325 }
1326
1327 static dlmgmt_door_info_t i_dlmgmt_door_info_tbl[] = {
1328 { DLMGMT_CMD_DLS_CREATE, sizeof (dlmgmt_upcall_arg_create_t),
1329 sizeof (dlmgmt_create_retval_t), dlmgmt_upcall_create },
1330 { DLMGMT_CMD_DLS_GETATTR, sizeof (dlmgmt_upcall_arg_getattr_t),
1331 sizeof (dlmgmt_getattr_retval_t), dlmgmt_upcall_getattr },
1332 { DLMGMT_CMD_DLS_DESTROY, sizeof (dlmgmt_upcall_arg_destroy_t),
1333 sizeof (dlmgmt_destroy_retval_t), dlmgmt_upcall_destroy },
1334 { DLMGMT_CMD_GETNAME, sizeof (dlmgmt_door_getname_t),
1335 sizeof (dlmgmt_getname_retval_t), dlmgmt_getname },
1336 { DLMGMT_CMD_GETLINKID, sizeof (dlmgmt_door_getlinkid_t),
1337 sizeof (dlmgmt_getlinkid_retval_t), dlmgmt_getlinkid },
1338 { DLMGMT_CMD_GETNEXT, sizeof (dlmgmt_door_getnext_t),
1339 sizeof (dlmgmt_getnext_retval_t), dlmgmt_getnext },
1340 { DLMGMT_CMD_DLS_UPDATE, sizeof (dlmgmt_upcall_arg_update_t),
1341 sizeof (dlmgmt_update_retval_t), dlmgmt_upcall_update },
|
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) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright (c) 2011, Joyent Inc. All rights reserved.
25 */
26
27 /*
28 * Main door handler functions used by dlmgmtd to process the different door
29 * call requests. Door call requests can come from the user-land applications,
30 * or from the kernel.
31 *
32 * Note on zones handling:
33 *
34 * There are two zoneid's associated with a link. One is the zoneid of the
35 * zone in which the link was created (ll_zoneid in the dlmgmt_link_t), and
36 * the other is the zoneid of the zone where the link is currently assigned
37 * (the "zone" link property). The two can be different if a datalink is
38 * created in the global zone and subsequently assigned to a non-global zone
39 * via zonecfg or via explicitly setting the "zone" link property.
40 *
41 * Door clients can see links that were created in their zone, and links that
42 * are currently assigned to their zone. Door clients in a zone can only
43 * modify links that were created in their zone.
44 *
45 * The datalink ID space is global, while each zone has its own datalink name
46 * space. This allows each zone to have complete freedom over the names that
47 * they assign to links created within the zone.
48 */
49
50 #include <assert.h>
51 #include <alloca.h>
52 #include <errno.h>
53 #include <priv_utils.h>
54 #include <stdlib.h>
55 #include <strings.h>
56 #include <syslog.h>
57 #include <sys/sysevent/eventdefs.h>
58 #include <zone.h>
59 #include <libsysevent.h>
60 #include <libdlmgmt.h>
61 #include <librcm.h>
62 #include <sys/types.h>
63 #include <sys/stat.h>
64 #include <fcntl.h>
65 #include <unistd.h>
66 #include "dlmgmt_impl.h"
67
68 typedef void dlmgmt_door_handler_t(void *, void *, size_t *, zoneid_t,
69 ucred_t *);
70
71 typedef struct dlmgmt_door_info_s {
72 uint_t di_cmd;
73 size_t di_reqsz;
74 size_t di_acksz;
75 dlmgmt_door_handler_t *di_handler;
76 } dlmgmt_door_info_t;
77
78 /*
79 * Check if the caller has the required privileges to operate on a link of the
80 * given class.
81 */
82 static int
83 dlmgmt_checkprivs(datalink_class_t class, ucred_t *cred)
84 {
85 const priv_set_t *eset;
367 datalink_id_t linkid = destroy->ld_linkid;
368 dlmgmt_link_t *linkp = NULL;
369 uint32_t flags, dflags = 0;
370 int err = 0;
371
372 flags = DLMGMT_ACTIVE | (destroy->ld_persist ? DLMGMT_PERSIST : 0);
373
374 /*
375 * Hold the writer lock to update the link table.
376 */
377 dlmgmt_table_lock(B_TRUE);
378
379 if ((linkp = link_by_id(linkid, zoneid)) == NULL) {
380 err = ENOENT;
381 goto done;
382 }
383
384 if ((err = dlmgmt_checkprivs(linkp->ll_class, cred)) != 0)
385 goto done;
386
387 if (linkp->ll_tomb == B_TRUE) {
388 err = EINPROGRESS;
389 goto done;
390 }
391
392 if (((linkp->ll_flags & flags) & DLMGMT_ACTIVE) != 0) {
393 if ((err = dlmgmt_delete_db_entry(linkp, DLMGMT_ACTIVE)) != 0)
394 goto done;
395 dflags |= DLMGMT_ACTIVE;
396 }
397
398 if (((linkp->ll_flags & flags) & DLMGMT_PERSIST) != 0) {
399 if ((err = dlmgmt_delete_db_entry(linkp, DLMGMT_PERSIST)) != 0)
400 goto done;
401 dflags |= DLMGMT_PERSIST;
402 }
403
404 err = dlmgmt_destroy_common(linkp, flags);
405 done:
406 if (err != 0 && dflags != 0)
407 (void) dlmgmt_write_db_entry(linkp->ll_link, linkp, dflags);
408
409 dlmgmt_table_unlock();
410 retvalp->lr_err = err;
411 }
432 } else {
433 retvalp->lr_flags = linkp->ll_flags;
434 retvalp->lr_class = linkp->ll_class;
435 retvalp->lr_media = linkp->ll_media;
436 }
437
438 dlmgmt_table_unlock();
439 retvalp->lr_err = err;
440 }
441
442 /* ARGSUSED */
443 static void
444 dlmgmt_getlinkid(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
445 ucred_t *cred)
446 {
447 dlmgmt_door_getlinkid_t *getlinkid = argp;
448 dlmgmt_getlinkid_retval_t *retvalp = retp;
449 dlmgmt_link_t *linkp;
450 int err = 0;
451
452 /* Enable the global zone to lookup links it has given away. */
453 if (zoneid == GLOBAL_ZONEID && getlinkid->ld_zoneid != -1)
454 zoneid = getlinkid->ld_zoneid;
455
456 /*
457 * Hold the reader lock to access the link
458 */
459 dlmgmt_table_lock(B_FALSE);
460
461 if ((linkp = link_by_name(getlinkid->ld_link, zoneid)) == NULL) {
462 /*
463 * The link does not exist in this zone.
464 */
465 err = ENOENT;
466 goto done;
467 }
468
469 retvalp->lr_linkid = linkp->ll_linkid;
470 retvalp->lr_flags = linkp->ll_flags;
471 retvalp->lr_class = linkp->ll_class;
472 retvalp->lr_media = linkp->ll_media;
473
474 done:
475 dlmgmt_table_unlock();
645 boolean_t renamed = B_FALSE;
646 int err = 0;
647
648 if (!dladm_valid_linkname(remapid->ld_link)) {
649 retvalp->lr_err = EINVAL;
650 return;
651 }
652
653 /*
654 * Hold the writer lock to update the link table.
655 */
656 dlmgmt_table_lock(B_TRUE);
657 if ((linkp = link_by_id(remapid->ld_linkid, zoneid)) == NULL) {
658 err = ENOENT;
659 goto done;
660 }
661
662 if ((err = dlmgmt_checkprivs(linkp->ll_class, cred)) != 0)
663 goto done;
664
665 if (linkp->ll_tomb == B_TRUE) {
666 err = EBUSY;
667 goto done;
668 }
669
670
671 if (link_by_name(remapid->ld_link, linkp->ll_zoneid) != NULL) {
672 err = EEXIST;
673 goto done;
674 }
675
676 (void) strlcpy(oldname, linkp->ll_link, MAXLINKNAMELEN);
677 avl_remove(&dlmgmt_name_avl, linkp);
678 (void) strlcpy(linkp->ll_link, remapid->ld_link, MAXLINKNAMELEN);
679 avl_add(&dlmgmt_name_avl, linkp);
680 renamed = B_TRUE;
681
682 if (linkp->ll_flags & DLMGMT_ACTIVE) {
683 err = dlmgmt_write_db_entry(oldname, linkp, DLMGMT_ACTIVE);
684 if (err != 0)
685 goto done;
686 }
687 if (linkp->ll_flags & DLMGMT_PERSIST) {
688 err = dlmgmt_write_db_entry(oldname, linkp, DLMGMT_PERSIST);
689 if (err != 0) {
690 if (linkp->ll_flags & DLMGMT_ACTIVE) {
712 dlmgmt_upid(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
713 ucred_t *cred)
714 {
715 dlmgmt_door_upid_t *upid = argp;
716 dlmgmt_upid_retval_t *retvalp = retp;
717 dlmgmt_link_t *linkp;
718 int err = 0;
719
720 /*
721 * Hold the writer lock to update the link table.
722 */
723 dlmgmt_table_lock(B_TRUE);
724 if ((linkp = link_by_id(upid->ld_linkid, zoneid)) == NULL) {
725 err = ENOENT;
726 goto done;
727 }
728
729 if ((err = dlmgmt_checkprivs(linkp->ll_class, cred)) != 0)
730 goto done;
731
732 if (linkp->ll_tomb == B_TRUE) {
733 err = EBUSY;
734 goto done;
735 }
736
737 if (linkp->ll_flags & DLMGMT_ACTIVE) {
738 err = EINVAL;
739 goto done;
740 }
741
742 if ((err = link_activate(linkp)) == 0) {
743 (void) dlmgmt_write_db_entry(linkp->ll_link, linkp,
744 DLMGMT_ACTIVE);
745 }
746 done:
747 dlmgmt_table_unlock();
748 retvalp->lr_err = err;
749 }
750
751 /* ARGSUSED */
752 static void
753 dlmgmt_createconf(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
754 ucred_t *cred)
755 {
756 dlmgmt_door_createconf_t *createconf = argp;
1224 datalink_id_t linkid = setzoneid->ld_linkid;
1225 zoneid_t oldzoneid, newzoneid;
1226 int err = 0;
1227
1228 dlmgmt_table_lock(B_TRUE);
1229
1230 /* We currently only allow changing zoneid's from the global zone. */
1231 if (zoneid != GLOBAL_ZONEID) {
1232 err = EACCES;
1233 goto done;
1234 }
1235
1236 if ((linkp = link_by_id(linkid, zoneid)) == NULL) {
1237 err = ENOENT;
1238 goto done;
1239 }
1240
1241 if ((err = dlmgmt_checkprivs(linkp->ll_class, cred)) != 0)
1242 goto done;
1243
1244 if (linkp->ll_tomb == B_TRUE) {
1245 err = EBUSY;
1246 goto done;
1247 }
1248
1249 /* We can only assign an active link to a zone. */
1250 if (!(linkp->ll_flags & DLMGMT_ACTIVE)) {
1251 err = EINVAL;
1252 goto done;
1253 }
1254
1255 oldzoneid = linkp->ll_zoneid;
1256 newzoneid = setzoneid->ld_zoneid;
1257
1258 if (oldzoneid == newzoneid)
1259 goto done;
1260
1261 /*
1262 * Before we remove the link from its current zone, make sure that
1263 * there isn't a link with the same name in the destination zone.
1264 */
1265 if (zoneid != GLOBAL_ZONEID &&
1266 link_by_name(linkp->ll_link, newzoneid) != NULL) {
1267 err = EEXIST;
1268 goto done;
1269 }
1270
1271 if (oldzoneid != GLOBAL_ZONEID) {
1272 if (zone_remove_datalink(oldzoneid, linkid) != 0) {
1273 err = errno;
1274 dlmgmt_log(LOG_WARNING, "unable to remove link %d from "
1275 "zone %d: %s", linkid, oldzoneid, strerror(err));
1276 goto done;
1277 }
1278
1279 if (newzoneid == GLOBAL_ZONEID && linkp->ll_onloan) {
1280 /*
1281 * We can only reassign a loaned VNIC back to the
1282 * global zone when the zone is shutting down, since
1283 * otherwise the VNIC is in use by the zone and will be
1284 * busy. Leave the VNIC assigned to the zone so we can
1285 * still see it and delete it when dlmgmt_zonehalt()
1286 * runs.
1287 */
1288 goto done;
1289 }
1290
1291 linkp->ll_onloan = B_FALSE;
1292 }
1293 if (newzoneid != GLOBAL_ZONEID) {
1294 if (zone_add_datalink(newzoneid, linkid) != 0) {
1295 err = errno;
1296 dlmgmt_log(LOG_WARNING, "unable to add link %d to zone "
1297 "%d: %s", linkid, newzoneid, strerror(err));
1298 (void) zone_add_datalink(oldzoneid, linkid);
1299 goto done;
1300 }
1301 linkp->ll_onloan = B_TRUE;
1302 }
1303
1304 avl_remove(&dlmgmt_name_avl, linkp);
1305 linkp->ll_zoneid = newzoneid;
1306 avl_add(&dlmgmt_name_avl, linkp);
1307
1308 done:
1309 dlmgmt_table_unlock();
1310 retvalp->lr_err = err;
1311 }
1312
1313 /* ARGSUSED */
1314 static void
1315 dlmgmt_zoneboot(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
1316 ucred_t *cred)
1317 {
1318 int err;
1319 dlmgmt_door_zoneboot_t *zoneboot = argp;
1320 dlmgmt_zoneboot_retval_t *retvalp = retp;
1333 goto done;
1334 }
1335
1336 if ((err = dlmgmt_elevate_privileges()) == 0) {
1337 err = dlmgmt_zone_init(zoneboot->ld_zoneid);
1338 (void) dlmgmt_drop_privileges();
1339 }
1340 done:
1341 dlmgmt_table_unlock();
1342 retvalp->lr_err = err;
1343 }
1344
1345 /* ARGSUSED */
1346 static void
1347 dlmgmt_zonehalt(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
1348 ucred_t *cred)
1349 {
1350 int err = 0;
1351 dlmgmt_door_zonehalt_t *zonehalt = argp;
1352 dlmgmt_zonehalt_retval_t *retvalp = retp;
1353 static char my_pid[10];
1354
1355 if (my_pid[0] == NULL)
1356 (void) snprintf(my_pid, sizeof (my_pid), "%d\n", getpid());
1357
1358 if ((err = dlmgmt_checkprivs(0, cred)) == 0) {
1359 if (zoneid != GLOBAL_ZONEID) {
1360 err = EACCES;
1361 } else if (zonehalt->ld_zoneid == GLOBAL_ZONEID) {
1362 err = EINVAL;
1363 } else {
1364 /*
1365 * dls and mac don't honor the locking rules defined in
1366 * mac. In order to try and make that case less likely
1367 * to happen, we try to serialize some of the zone
1368 * activity here between dlmgmtd and the brands on
1369 * /etc/dladm/zone.lck
1370 */
1371 int fd;
1372
1373 while ((fd = open(ZONE_LOCK, O_WRONLY |
1374 O_CREAT | O_EXCL, S_IRUSR | S_IWUSR)) < 0)
1375 (void) sleep(1);
1376 (void) write(fd, my_pid, sizeof (my_pid));
1377 (void) close(fd);
1378
1379 dlmgmt_table_lock(B_TRUE);
1380 dlmgmt_db_fini(zonehalt->ld_zoneid);
1381 dlmgmt_table_unlock();
1382
1383 (void) unlink(ZONE_LOCK);
1384 }
1385 }
1386 retvalp->lr_err = err;
1387 }
1388
1389 static dlmgmt_door_info_t i_dlmgmt_door_info_tbl[] = {
1390 { DLMGMT_CMD_DLS_CREATE, sizeof (dlmgmt_upcall_arg_create_t),
1391 sizeof (dlmgmt_create_retval_t), dlmgmt_upcall_create },
1392 { DLMGMT_CMD_DLS_GETATTR, sizeof (dlmgmt_upcall_arg_getattr_t),
1393 sizeof (dlmgmt_getattr_retval_t), dlmgmt_upcall_getattr },
1394 { DLMGMT_CMD_DLS_DESTROY, sizeof (dlmgmt_upcall_arg_destroy_t),
1395 sizeof (dlmgmt_destroy_retval_t), dlmgmt_upcall_destroy },
1396 { DLMGMT_CMD_GETNAME, sizeof (dlmgmt_door_getname_t),
1397 sizeof (dlmgmt_getname_retval_t), dlmgmt_getname },
1398 { DLMGMT_CMD_GETLINKID, sizeof (dlmgmt_door_getlinkid_t),
1399 sizeof (dlmgmt_getlinkid_retval_t), dlmgmt_getlinkid },
1400 { DLMGMT_CMD_GETNEXT, sizeof (dlmgmt_door_getnext_t),
1401 sizeof (dlmgmt_getnext_retval_t), dlmgmt_getnext },
1402 { DLMGMT_CMD_DLS_UPDATE, sizeof (dlmgmt_upcall_arg_update_t),
1403 sizeof (dlmgmt_update_retval_t), dlmgmt_upcall_update },
|