1d62bc4baSyz147064 /* 2d62bc4baSyz147064 * CDDL HEADER START 3d62bc4baSyz147064 * 4d62bc4baSyz147064 * The contents of this file are subject to the terms of the 5d62bc4baSyz147064 * Common Development and Distribution License (the "License"). 6d62bc4baSyz147064 * You may not use this file except in compliance with the License. 7d62bc4baSyz147064 * 8d62bc4baSyz147064 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9d62bc4baSyz147064 * or http://www.opensolaris.org/os/licensing. 10d62bc4baSyz147064 * See the License for the specific language governing permissions 11d62bc4baSyz147064 * and limitations under the License. 12d62bc4baSyz147064 * 13d62bc4baSyz147064 * When distributing Covered Code, include this CDDL HEADER in each 14d62bc4baSyz147064 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15d62bc4baSyz147064 * If applicable, add the following below this CDDL HEADER, with the 16d62bc4baSyz147064 * fields enclosed by brackets "[]" replaced with your own identifying 17d62bc4baSyz147064 * information: Portions Copyright [yyyy] [name of copyright owner] 18d62bc4baSyz147064 * 19d62bc4baSyz147064 * CDDL HEADER END 20d62bc4baSyz147064 */ 21d62bc4baSyz147064 22d62bc4baSyz147064 /* 23634e26ecSCasper H.S. Dik * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 24d62bc4baSyz147064 * Use is subject to license terms. 25d62bc4baSyz147064 */ 26d62bc4baSyz147064 27d62bc4baSyz147064 /* 28d62bc4baSyz147064 * The dlmgmtd daemon is started by the datalink-management SMF service. 29d62bc4baSyz147064 * This daemon is used to manage <link name, linkid> mapping and the 30d62bc4baSyz147064 * persistent datalink configuration. 31d62bc4baSyz147064 * 32d62bc4baSyz147064 * Today, the <link name, linkid> mapping and the persistent configuration 33d62bc4baSyz147064 * of datalinks is kept in /etc/dladm/datalink.conf, and the daemon keeps 34d62bc4baSyz147064 * a copy of the datalinks in the memory (see dlmgmt_id_avl and 35d62bc4baSyz147064 * dlmgmt_name_avl). The active <link name, linkid> mapping is kept in 36b9e076dcSyz147064 * /etc/svc/volatile/dladm cache file, so that the mapping can be recovered 37b9e076dcSyz147064 * when dlmgmtd exits for some reason (e.g., when dlmgmtd is accidentally 38b9e076dcSyz147064 * killed). 39d62bc4baSyz147064 */ 40d62bc4baSyz147064 41d62bc4baSyz147064 #include <assert.h> 42d62bc4baSyz147064 #include <errno.h> 43d62bc4baSyz147064 #include <fcntl.h> 442b24ab6bSSebastien Roy #include <priv.h> 45d62bc4baSyz147064 #include <signal.h> 46d62bc4baSyz147064 #include <stdlib.h> 47d62bc4baSyz147064 #include <stdio.h> 48d62bc4baSyz147064 #include <strings.h> 49d62bc4baSyz147064 #include <syslog.h> 502b24ab6bSSebastien Roy #include <zone.h> 51d62bc4baSyz147064 #include <sys/dld.h> 5282a2fc47SJames Carlson #include <sys/dld_ioc.h> 53b9e076dcSyz147064 #include <sys/param.h> 54b9e076dcSyz147064 #include <sys/stat.h> 55d62bc4baSyz147064 #include <unistd.h> 564ac67f02SAnurag S. Maskey #include <libdladm_impl.h> 57d62bc4baSyz147064 #include <libdlmgmt.h> 58d62bc4baSyz147064 #include "dlmgmt_impl.h" 59d62bc4baSyz147064 60d62bc4baSyz147064 const char *progname; 61d62bc4baSyz147064 boolean_t debug; 62d62bc4baSyz147064 static int pfds[2]; 634ac67f02SAnurag S. Maskey /* 644ac67f02SAnurag S. Maskey * This file descriptor to DLMGMT_DOOR cannot be in the libdladm 654ac67f02SAnurag S. Maskey * handle because the door isn't created when the handle is created. 664ac67f02SAnurag S. Maskey */ 67d62bc4baSyz147064 static int dlmgmt_door_fd = -1; 684ac67f02SAnurag S. Maskey 694ac67f02SAnurag S. Maskey /* 702b24ab6bSSebastien Roy * This libdladm handle is global so that dlmgmt_upcall_linkprop_init() can 712b24ab6bSSebastien Roy * pass to libdladm. The handle is opened with "ALL" privileges, before 722b24ab6bSSebastien Roy * privileges are dropped in dlmgmt_drop_privileges(). It is not able to open 732b24ab6bSSebastien Roy * DLMGMT_DOOR at that time as it hasn't been created yet. This door in the 742b24ab6bSSebastien Roy * handle is opened in the first call to dladm_door_fd(). 754ac67f02SAnurag S. Maskey */ 764ac67f02SAnurag S. Maskey dladm_handle_t dld_handle = NULL; 77b9e076dcSyz147064 78b9e076dcSyz147064 static void dlmgmtd_exit(int); 79b9e076dcSyz147064 static int dlmgmt_init(); 80b9e076dcSyz147064 static void dlmgmt_fini(); 812b24ab6bSSebastien Roy static int dlmgmt_set_privileges(); 82d62bc4baSyz147064 83d62bc4baSyz147064 static int 84d62bc4baSyz147064 dlmgmt_set_doorfd(boolean_t start) 85d62bc4baSyz147064 { 86d62bc4baSyz147064 dld_ioc_door_t did; 87d62bc4baSyz147064 int err = 0; 88d62bc4baSyz147064 894ac67f02SAnurag S. Maskey assert(dld_handle != NULL); 90d62bc4baSyz147064 91d62bc4baSyz147064 did.did_start_door = start; 92d62bc4baSyz147064 934ac67f02SAnurag S. Maskey if (ioctl(dladm_dld_fd(dld_handle), DLDIOC_DOORSERVER, &did) == -1) 94d62bc4baSyz147064 err = errno; 95d62bc4baSyz147064 96d62bc4baSyz147064 return (err); 97d62bc4baSyz147064 } 98d62bc4baSyz147064 99d62bc4baSyz147064 static int 1002b24ab6bSSebastien Roy dlmgmt_door_init(void) 101d62bc4baSyz147064 { 1022b24ab6bSSebastien Roy int err = 0; 103b9e076dcSyz147064 104d62bc4baSyz147064 if ((dlmgmt_door_fd = door_create(dlmgmt_handler, NULL, 105d62bc4baSyz147064 DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) { 106d62bc4baSyz147064 err = errno; 107b9e076dcSyz147064 dlmgmt_log(LOG_ERR, "door_create() failed: %s", 108d62bc4baSyz147064 strerror(err)); 109d62bc4baSyz147064 return (err); 110d62bc4baSyz147064 } 111d62bc4baSyz147064 return (err); 112d62bc4baSyz147064 } 113d62bc4baSyz147064 114d62bc4baSyz147064 static void 1152b24ab6bSSebastien Roy dlmgmt_door_fini(void) 116d62bc4baSyz147064 { 117b9e076dcSyz147064 if (dlmgmt_door_fd == -1) 118b9e076dcSyz147064 return; 119b9e076dcSyz147064 120b9e076dcSyz147064 if (door_revoke(dlmgmt_door_fd) == -1) { 121d62bc4baSyz147064 dlmgmt_log(LOG_WARNING, "door_revoke(%s) failed: %s", 122b9e076dcSyz147064 DLMGMT_DOOR, strerror(errno)); 123d62bc4baSyz147064 } 124b9e076dcSyz147064 (void) dlmgmt_set_doorfd(B_FALSE); 1252b24ab6bSSebastien Roy dlmgmt_door_fd = -1; 1262b24ab6bSSebastien Roy } 1272b24ab6bSSebastien Roy 1282b24ab6bSSebastien Roy int 1292b24ab6bSSebastien Roy dlmgmt_door_attach(zoneid_t zoneid, char *rootdir) 1302b24ab6bSSebastien Roy { 1312b24ab6bSSebastien Roy int fd; 1322b24ab6bSSebastien Roy int err = 0; 1332b24ab6bSSebastien Roy char doorpath[MAXPATHLEN]; 1342b24ab6bSSebastien Roy 1352b24ab6bSSebastien Roy (void) snprintf(doorpath, sizeof (doorpath), "%s%s", rootdir, 1362b24ab6bSSebastien Roy DLMGMT_DOOR); 1372b24ab6bSSebastien Roy 1382b24ab6bSSebastien Roy /* 1392b24ab6bSSebastien Roy * Create the door file for dlmgmtd. 1402b24ab6bSSebastien Roy */ 1412b24ab6bSSebastien Roy if ((fd = open(doorpath, O_CREAT|O_RDONLY, 0644)) == -1) { 1422b24ab6bSSebastien Roy err = errno; 1432b24ab6bSSebastien Roy dlmgmt_log(LOG_ERR, "open(%s) failed: %s", doorpath, 1442b24ab6bSSebastien Roy strerror(err)); 1452b24ab6bSSebastien Roy return (err); 1462b24ab6bSSebastien Roy } 1472b24ab6bSSebastien Roy (void) close(fd); 148*6ba597c5SAnurag S. Maskey if (chown(doorpath, UID_DLADM, GID_NETADM) == -1) 1492b24ab6bSSebastien Roy return (errno); 1502b24ab6bSSebastien Roy 1512b24ab6bSSebastien Roy /* 1522b24ab6bSSebastien Roy * fdetach first in case a previous daemon instance exited 1532b24ab6bSSebastien Roy * ungracefully. 1542b24ab6bSSebastien Roy */ 1552b24ab6bSSebastien Roy (void) fdetach(doorpath); 1562b24ab6bSSebastien Roy if (fattach(dlmgmt_door_fd, doorpath) != 0) { 1572b24ab6bSSebastien Roy err = errno; 1582b24ab6bSSebastien Roy dlmgmt_log(LOG_ERR, "fattach(%s) failed: %s", doorpath, 1592b24ab6bSSebastien Roy strerror(err)); 1602b24ab6bSSebastien Roy } else if (zoneid == GLOBAL_ZONEID) { 1612b24ab6bSSebastien Roy if ((err = dlmgmt_set_doorfd(B_TRUE)) != 0) { 1622b24ab6bSSebastien Roy dlmgmt_log(LOG_ERR, "cannot set kernel doorfd: %s", 1632b24ab6bSSebastien Roy strerror(err)); 1642b24ab6bSSebastien Roy } 1652b24ab6bSSebastien Roy } 1662b24ab6bSSebastien Roy 1672b24ab6bSSebastien Roy return (err); 1682b24ab6bSSebastien Roy } 1692b24ab6bSSebastien Roy 1702b24ab6bSSebastien Roy /* 1712b24ab6bSSebastien Roy * Create the /etc/svc/volatile/dladm/ directory if it doesn't exist, load the 1722b24ab6bSSebastien Roy * datalink.conf data for this zone, and create/attach the door rendezvous 1732b24ab6bSSebastien Roy * file. 1742b24ab6bSSebastien Roy */ 1752b24ab6bSSebastien Roy int 1762b24ab6bSSebastien Roy dlmgmt_zone_init(zoneid_t zoneid) 1772b24ab6bSSebastien Roy { 1782b24ab6bSSebastien Roy char rootdir[MAXPATHLEN], tmpfsdir[MAXPATHLEN]; 1792b24ab6bSSebastien Roy int err; 1802b24ab6bSSebastien Roy struct stat statbuf; 1812b24ab6bSSebastien Roy 1822b24ab6bSSebastien Roy if (zoneid == GLOBAL_ZONEID) { 1832b24ab6bSSebastien Roy rootdir[0] = '\0'; 1842b24ab6bSSebastien Roy } else if (zone_getattr(zoneid, ZONE_ATTR_ROOT, rootdir, 1852b24ab6bSSebastien Roy sizeof (rootdir)) < 0) { 1862b24ab6bSSebastien Roy return (errno); 1872b24ab6bSSebastien Roy } 1882b24ab6bSSebastien Roy 1892b24ab6bSSebastien Roy /* 1902b24ab6bSSebastien Roy * Create the DLMGMT_TMPFS_DIR directory. 1912b24ab6bSSebastien Roy */ 1922b24ab6bSSebastien Roy (void) snprintf(tmpfsdir, sizeof (tmpfsdir), "%s%s", rootdir, 1932b24ab6bSSebastien Roy DLMGMT_TMPFS_DIR); 1942b24ab6bSSebastien Roy if (stat(tmpfsdir, &statbuf) < 0) { 1952b24ab6bSSebastien Roy if (mkdir(tmpfsdir, (mode_t)0755) < 0) 1962b24ab6bSSebastien Roy return (errno); 1972b24ab6bSSebastien Roy } else if ((statbuf.st_mode & S_IFMT) != S_IFDIR) { 1982b24ab6bSSebastien Roy return (ENOTDIR); 1992b24ab6bSSebastien Roy } 2002b24ab6bSSebastien Roy 2012b24ab6bSSebastien Roy if ((chmod(tmpfsdir, 0755) < 0) || 202*6ba597c5SAnurag S. Maskey (chown(tmpfsdir, UID_DLADM, GID_NETADM) < 0)) { 2032b24ab6bSSebastien Roy return (EPERM); 2042b24ab6bSSebastien Roy } 2052b24ab6bSSebastien Roy 2062b24ab6bSSebastien Roy if ((err = dlmgmt_db_init(zoneid)) != 0) 2072b24ab6bSSebastien Roy return (err); 2082b24ab6bSSebastien Roy return (dlmgmt_door_attach(zoneid, rootdir)); 2092b24ab6bSSebastien Roy } 2102b24ab6bSSebastien Roy 2112b24ab6bSSebastien Roy /* 2122b24ab6bSSebastien Roy * Initialize each running zone. 2132b24ab6bSSebastien Roy */ 2142b24ab6bSSebastien Roy static int 2152b24ab6bSSebastien Roy dlmgmt_allzones_init(void) 2162b24ab6bSSebastien Roy { 2172b24ab6bSSebastien Roy int err, i; 2182b24ab6bSSebastien Roy zoneid_t *zids = NULL; 2192b24ab6bSSebastien Roy uint_t nzids, nzids_saved; 2202b24ab6bSSebastien Roy 2212b24ab6bSSebastien Roy if (zone_list(NULL, &nzids) != 0) 2222b24ab6bSSebastien Roy return (errno); 2232b24ab6bSSebastien Roy again: 2242b24ab6bSSebastien Roy nzids *= 2; 2252b24ab6bSSebastien Roy if ((zids = malloc(nzids * sizeof (zoneid_t))) == NULL) 2262b24ab6bSSebastien Roy return (errno); 2272b24ab6bSSebastien Roy nzids_saved = nzids; 2282b24ab6bSSebastien Roy if (zone_list(zids, &nzids) != 0) { 2292b24ab6bSSebastien Roy free(zids); 2302b24ab6bSSebastien Roy return (errno); 2312b24ab6bSSebastien Roy } 2322b24ab6bSSebastien Roy if (nzids > nzids_saved) { 2332b24ab6bSSebastien Roy free(zids); 2342b24ab6bSSebastien Roy goto again; 2352b24ab6bSSebastien Roy } 2362b24ab6bSSebastien Roy 2372b24ab6bSSebastien Roy for (i = 0; i < nzids; i++) { 2382b24ab6bSSebastien Roy if ((err = dlmgmt_zone_init(zids[i])) != 0) 2392b24ab6bSSebastien Roy break; 2402b24ab6bSSebastien Roy } 2412b24ab6bSSebastien Roy free(zids); 2422b24ab6bSSebastien Roy return (err); 243d62bc4baSyz147064 } 244d62bc4baSyz147064 245d62bc4baSyz147064 static int 2462b24ab6bSSebastien Roy dlmgmt_init(void) 247d62bc4baSyz147064 { 248d62bc4baSyz147064 int err; 2492b24ab6bSSebastien Roy char *fmri, *c; 2502b24ab6bSSebastien Roy char filename[MAXPATHLEN]; 2512b24ab6bSSebastien Roy 2522b24ab6bSSebastien Roy if (dladm_open(&dld_handle) != DLADM_STATUS_OK) { 2532b24ab6bSSebastien Roy dlmgmt_log(LOG_ERR, "dladm_open() failed"); 2542b24ab6bSSebastien Roy return (EPERM); 2552b24ab6bSSebastien Roy } 256d62bc4baSyz147064 257b9e076dcSyz147064 if (signal(SIGTERM, dlmgmtd_exit) == SIG_ERR || 258b9e076dcSyz147064 signal(SIGINT, dlmgmtd_exit) == SIG_ERR) { 259b9e076dcSyz147064 err = errno; 260b9e076dcSyz147064 dlmgmt_log(LOG_ERR, "signal() for SIGTERM/INT failed: %s", 261b9e076dcSyz147064 strerror(err)); 262b9e076dcSyz147064 return (err); 263b9e076dcSyz147064 } 264b9e076dcSyz147064 2652b24ab6bSSebastien Roy /* 2662b24ab6bSSebastien Roy * First derive the name of the cache file from the FMRI name. This 2672b24ab6bSSebastien Roy * cache name is used to keep active datalink configuration. 2682b24ab6bSSebastien Roy */ 2692b24ab6bSSebastien Roy if (debug) { 2702b24ab6bSSebastien Roy (void) snprintf(cachefile, MAXPATHLEN, "%s/%s%s", 2712b24ab6bSSebastien Roy DLMGMT_TMPFS_DIR, progname, ".debug.cache"); 2722b24ab6bSSebastien Roy } else { 2732b24ab6bSSebastien Roy if ((fmri = getenv("SMF_FMRI")) == NULL) { 2742b24ab6bSSebastien Roy dlmgmt_log(LOG_ERR, "dlmgmtd is an smf(5) managed " 2752b24ab6bSSebastien Roy "service and should not be run from the command " 2762b24ab6bSSebastien Roy "line."); 2772b24ab6bSSebastien Roy return (EINVAL); 2782b24ab6bSSebastien Roy } 279d62bc4baSyz147064 2802b24ab6bSSebastien Roy /* 2812b24ab6bSSebastien Roy * The FMRI name is in the form of 2822b24ab6bSSebastien Roy * svc:/service/service:instance. We need to remove the 2832b24ab6bSSebastien Roy * prefix "svc:/" and replace '/' with '-'. The cache file 2842b24ab6bSSebastien Roy * name is in the form of "service:instance.cache". 2852b24ab6bSSebastien Roy */ 2862b24ab6bSSebastien Roy if ((c = strchr(fmri, '/')) != NULL) 2872b24ab6bSSebastien Roy c++; 2882b24ab6bSSebastien Roy else 2892b24ab6bSSebastien Roy c = fmri; 2902b24ab6bSSebastien Roy (void) snprintf(filename, MAXPATHLEN, "%s.cache", c); 2912b24ab6bSSebastien Roy c = filename; 2922b24ab6bSSebastien Roy while ((c = strchr(c, '/')) != NULL) 2932b24ab6bSSebastien Roy *c = '-'; 2942b24ab6bSSebastien Roy 2952b24ab6bSSebastien Roy (void) snprintf(cachefile, MAXPATHLEN, "%s/%s", 2962b24ab6bSSebastien Roy DLMGMT_TMPFS_DIR, filename); 2972b24ab6bSSebastien Roy } 2982b24ab6bSSebastien Roy 2992b24ab6bSSebastien Roy dlmgmt_linktable_init(); 3002b24ab6bSSebastien Roy if ((err = dlmgmt_door_init()) != 0) 3012b24ab6bSSebastien Roy goto done; 3022b24ab6bSSebastien Roy 3032b24ab6bSSebastien Roy /* 3042b24ab6bSSebastien Roy * Load datalink configuration and create dlmgmtd door files for all 3052b24ab6bSSebastien Roy * currently running zones. 3062b24ab6bSSebastien Roy */ 3072b24ab6bSSebastien Roy if ((err = dlmgmt_allzones_init()) != 0) 3082b24ab6bSSebastien Roy dlmgmt_door_fini(); 3092b24ab6bSSebastien Roy 3102b24ab6bSSebastien Roy done: 3112b24ab6bSSebastien Roy if (err != 0) 312d62bc4baSyz147064 dlmgmt_linktable_fini(); 313d62bc4baSyz147064 return (err); 314d62bc4baSyz147064 } 315d62bc4baSyz147064 316d62bc4baSyz147064 static void 3172b24ab6bSSebastien Roy dlmgmt_fini(void) 318d62bc4baSyz147064 { 319d62bc4baSyz147064 dlmgmt_door_fini(); 320d62bc4baSyz147064 dlmgmt_linktable_fini(); 3212b24ab6bSSebastien Roy if (dld_handle != NULL) { 3222b24ab6bSSebastien Roy dladm_close(dld_handle); 3232b24ab6bSSebastien Roy dld_handle = NULL; 3242b24ab6bSSebastien Roy } 325d62bc4baSyz147064 } 326d62bc4baSyz147064 327d62bc4baSyz147064 /* 328d62bc4baSyz147064 * This is called by the child process to inform the parent process to 329d62bc4baSyz147064 * exit with the given return value. 330d62bc4baSyz147064 */ 331d62bc4baSyz147064 static void 332d62bc4baSyz147064 dlmgmt_inform_parent_exit(int rv) 333d62bc4baSyz147064 { 334d62bc4baSyz147064 if (debug) 335d62bc4baSyz147064 return; 336d62bc4baSyz147064 337d62bc4baSyz147064 if (write(pfds[1], &rv, sizeof (int)) != sizeof (int)) { 338d62bc4baSyz147064 dlmgmt_log(LOG_WARNING, 339d62bc4baSyz147064 "dlmgmt_inform_parent_exit() failed: %s", strerror(errno)); 340d62bc4baSyz147064 (void) close(pfds[1]); 341d62bc4baSyz147064 exit(EXIT_FAILURE); 342d62bc4baSyz147064 } 343d62bc4baSyz147064 (void) close(pfds[1]); 344d62bc4baSyz147064 } 345d62bc4baSyz147064 346d62bc4baSyz147064 /*ARGSUSED*/ 347d62bc4baSyz147064 static void 348d62bc4baSyz147064 dlmgmtd_exit(int signo) 349d62bc4baSyz147064 { 350d62bc4baSyz147064 (void) close(pfds[1]); 351d62bc4baSyz147064 dlmgmt_fini(); 352d62bc4baSyz147064 exit(EXIT_FAILURE); 353d62bc4baSyz147064 } 354d62bc4baSyz147064 355d62bc4baSyz147064 static void 356d62bc4baSyz147064 usage(void) 357d62bc4baSyz147064 { 358d62bc4baSyz147064 (void) fprintf(stderr, "Usage: %s [-d]\n", progname); 359d62bc4baSyz147064 exit(EXIT_FAILURE); 360d62bc4baSyz147064 } 361d62bc4baSyz147064 362b9e076dcSyz147064 /* 3632b24ab6bSSebastien Roy * Restrict privileges to only those needed. 3642b24ab6bSSebastien Roy */ 3652b24ab6bSSebastien Roy int 3662b24ab6bSSebastien Roy dlmgmt_drop_privileges(void) 3672b24ab6bSSebastien Roy { 3682b24ab6bSSebastien Roy priv_set_t *pset; 3692b24ab6bSSebastien Roy priv_ptype_t ptype; 3702b24ab6bSSebastien Roy zoneid_t zoneid = getzoneid(); 3712b24ab6bSSebastien Roy int err = 0; 3722b24ab6bSSebastien Roy 3732b24ab6bSSebastien Roy if ((pset = priv_allocset()) == NULL) 3742b24ab6bSSebastien Roy return (errno); 3752b24ab6bSSebastien Roy 3762b24ab6bSSebastien Roy /* 3772b24ab6bSSebastien Roy * The global zone needs PRIV_PROC_FORK so that it can fork() when it 3782b24ab6bSSebastien Roy * issues db ops in non-global zones, PRIV_SYS_CONFIG to post 3792b24ab6bSSebastien Roy * sysevents, and PRIV_SYS_DL_CONFIG to initialize link properties in 3802b24ab6bSSebastien Roy * dlmgmt_upcall_linkprop_init(). 381b9e076dcSyz147064 * 382634e26ecSCasper H.S. Dik * We remove non-basic privileges from the permitted (and thus 383634e26ecSCasper H.S. Dik * effective) set. When executing in a non-global zone, dlmgmtd 384634e26ecSCasper H.S. Dik * only needs to read and write to files that it already owns. 3852b24ab6bSSebastien Roy */ 386634e26ecSCasper H.S. Dik priv_basicset(pset); 387634e26ecSCasper H.S. Dik (void) priv_delset(pset, PRIV_PROC_EXEC); 388634e26ecSCasper H.S. Dik (void) priv_delset(pset, PRIV_PROC_INFO); 389634e26ecSCasper H.S. Dik (void) priv_delset(pset, PRIV_PROC_SESSION); 390634e26ecSCasper H.S. Dik (void) priv_delset(pset, PRIV_FILE_LINK_ANY); 3912b24ab6bSSebastien Roy if (zoneid == GLOBAL_ZONEID) { 3922b24ab6bSSebastien Roy ptype = PRIV_EFFECTIVE; 393634e26ecSCasper H.S. Dik if (priv_addset(pset, PRIV_SYS_CONFIG) == -1 || 3942b24ab6bSSebastien Roy priv_addset(pset, PRIV_SYS_DL_CONFIG) == -1) 3952b24ab6bSSebastien Roy err = errno; 3962b24ab6bSSebastien Roy } else { 397634e26ecSCasper H.S. Dik (void) priv_delset(pset, PRIV_PROC_FORK); 3982b24ab6bSSebastien Roy ptype = PRIV_PERMITTED; 3992b24ab6bSSebastien Roy } 4002b24ab6bSSebastien Roy if (err == 0 && setppriv(PRIV_SET, ptype, pset) == -1) 4012b24ab6bSSebastien Roy err = errno; 4022b24ab6bSSebastien Roy done: 4032b24ab6bSSebastien Roy priv_freeset(pset); 4042b24ab6bSSebastien Roy return (err); 4052b24ab6bSSebastien Roy } 4062b24ab6bSSebastien Roy 4072b24ab6bSSebastien Roy int 4082b24ab6bSSebastien Roy dlmgmt_elevate_privileges(void) 4092b24ab6bSSebastien Roy { 4102b24ab6bSSebastien Roy priv_set_t *privset; 4112b24ab6bSSebastien Roy int err = 0; 4122b24ab6bSSebastien Roy 4132b24ab6bSSebastien Roy if ((privset = priv_str_to_set("zone", ",", NULL)) == NULL) 4142b24ab6bSSebastien Roy return (errno); 4152b24ab6bSSebastien Roy if (setppriv(PRIV_SET, PRIV_EFFECTIVE, privset) == -1) 4162b24ab6bSSebastien Roy err = errno; 4172b24ab6bSSebastien Roy priv_freeset(privset); 4182b24ab6bSSebastien Roy return (err); 4192b24ab6bSSebastien Roy } 4202b24ab6bSSebastien Roy 4212b24ab6bSSebastien Roy /* 4222b24ab6bSSebastien Roy * Set the uid of this daemon to the "dladm" user and drop privileges to only 4232b24ab6bSSebastien Roy * those needed. 424b9e076dcSyz147064 */ 425d62bc4baSyz147064 static int 4262b24ab6bSSebastien Roy dlmgmt_set_privileges(void) 427d62bc4baSyz147064 { 4282b24ab6bSSebastien Roy int err; 429d62bc4baSyz147064 4302b24ab6bSSebastien Roy (void) setgroups(0, NULL); 431*6ba597c5SAnurag S. Maskey if (setegid(GID_NETADM) == -1 || seteuid(UID_DLADM) == -1) 4322b24ab6bSSebastien Roy err = errno; 4332b24ab6bSSebastien Roy else 4342b24ab6bSSebastien Roy err = dlmgmt_drop_privileges(); 4352b24ab6bSSebastien Roy done: 4362b24ab6bSSebastien Roy return (err); 437b9e076dcSyz147064 } 438b9e076dcSyz147064 439d62bc4baSyz147064 /* 440d62bc4baSyz147064 * Keep the pfds fd open, close other fds. 441d62bc4baSyz147064 */ 442d62bc4baSyz147064 /*ARGSUSED*/ 443d62bc4baSyz147064 static int 444d62bc4baSyz147064 closefunc(void *arg, int fd) 445d62bc4baSyz147064 { 446d62bc4baSyz147064 if (fd != pfds[1]) 447d62bc4baSyz147064 (void) close(fd); 448d62bc4baSyz147064 return (0); 449d62bc4baSyz147064 } 450d62bc4baSyz147064 451d62bc4baSyz147064 static boolean_t 452d62bc4baSyz147064 dlmgmt_daemonize(void) 453d62bc4baSyz147064 { 454d62bc4baSyz147064 pid_t pid; 455d62bc4baSyz147064 int rv; 456d62bc4baSyz147064 457d62bc4baSyz147064 if (pipe(pfds) < 0) { 458d62bc4baSyz147064 (void) fprintf(stderr, "%s: pipe() failed: %s\n", 459d62bc4baSyz147064 progname, strerror(errno)); 460d62bc4baSyz147064 exit(EXIT_FAILURE); 461d62bc4baSyz147064 } 462d62bc4baSyz147064 463d62bc4baSyz147064 if ((pid = fork()) == -1) { 464d62bc4baSyz147064 (void) fprintf(stderr, "%s: fork() failed: %s\n", 465d62bc4baSyz147064 progname, strerror(errno)); 466d62bc4baSyz147064 exit(EXIT_FAILURE); 467d62bc4baSyz147064 } else if (pid > 0) { /* Parent */ 468d62bc4baSyz147064 (void) close(pfds[1]); 469d62bc4baSyz147064 470d62bc4baSyz147064 /* 471d62bc4baSyz147064 * Read the child process's return value from the pfds. 472d62bc4baSyz147064 * If the child process exits unexpected, read() returns -1. 473d62bc4baSyz147064 */ 474d62bc4baSyz147064 if (read(pfds[0], &rv, sizeof (int)) != sizeof (int)) { 475d62bc4baSyz147064 (void) kill(pid, SIGKILL); 476d62bc4baSyz147064 rv = EXIT_FAILURE; 477d62bc4baSyz147064 } 478d62bc4baSyz147064 479d62bc4baSyz147064 (void) close(pfds[0]); 480d62bc4baSyz147064 exit(rv); 481d62bc4baSyz147064 } 482d62bc4baSyz147064 483d62bc4baSyz147064 /* Child */ 484d62bc4baSyz147064 (void) close(pfds[0]); 485d62bc4baSyz147064 (void) setsid(); 486d62bc4baSyz147064 487d62bc4baSyz147064 /* 488d62bc4baSyz147064 * Close all files except pfds[1]. 489d62bc4baSyz147064 */ 490d62bc4baSyz147064 (void) fdwalk(closefunc, NULL); 491d62bc4baSyz147064 (void) chdir("/"); 492d62bc4baSyz147064 openlog(progname, LOG_PID, LOG_DAEMON); 493d62bc4baSyz147064 return (B_TRUE); 494d62bc4baSyz147064 } 495d62bc4baSyz147064 496d62bc4baSyz147064 int 497d62bc4baSyz147064 main(int argc, char *argv[]) 498d62bc4baSyz147064 { 4992b24ab6bSSebastien Roy int opt, err; 500d62bc4baSyz147064 501d62bc4baSyz147064 progname = strrchr(argv[0], '/'); 502d62bc4baSyz147064 if (progname != NULL) 503d62bc4baSyz147064 progname++; 504d62bc4baSyz147064 else 505d62bc4baSyz147064 progname = argv[0]; 506d62bc4baSyz147064 507d62bc4baSyz147064 /* 508d62bc4baSyz147064 * Process options. 509d62bc4baSyz147064 */ 510d62bc4baSyz147064 while ((opt = getopt(argc, argv, "d")) != EOF) { 511d62bc4baSyz147064 switch (opt) { 512d62bc4baSyz147064 case 'd': 513d62bc4baSyz147064 debug = B_TRUE; 514d62bc4baSyz147064 break; 515d62bc4baSyz147064 default: 516d62bc4baSyz147064 usage(); 517d62bc4baSyz147064 } 518d62bc4baSyz147064 } 519d62bc4baSyz147064 520d62bc4baSyz147064 if (!debug && !dlmgmt_daemonize()) 521d62bc4baSyz147064 return (EXIT_FAILURE); 522d62bc4baSyz147064 5232b24ab6bSSebastien Roy if ((err = dlmgmt_init()) != 0) { 5242b24ab6bSSebastien Roy dlmgmt_log(LOG_ERR, "unable to initialize daemon: %s", 5252b24ab6bSSebastien Roy strerror(err)); 526d62bc4baSyz147064 goto child_out; 5272b24ab6bSSebastien Roy } else if ((err = dlmgmt_set_privileges()) != 0) { 5282b24ab6bSSebastien Roy dlmgmt_log(LOG_ERR, "unable to set daemon privileges: %s", 5292b24ab6bSSebastien Roy strerror(err)); 5302b24ab6bSSebastien Roy dlmgmt_fini(); 531d62bc4baSyz147064 goto child_out; 532b9e076dcSyz147064 } 533d62bc4baSyz147064 534d62bc4baSyz147064 /* 535d62bc4baSyz147064 * Inform the parent process that it can successfully exit. 536d62bc4baSyz147064 */ 537d62bc4baSyz147064 dlmgmt_inform_parent_exit(EXIT_SUCCESS); 538d62bc4baSyz147064 539d62bc4baSyz147064 for (;;) 540d62bc4baSyz147064 (void) pause(); 541d62bc4baSyz147064 542d62bc4baSyz147064 child_out: 543d62bc4baSyz147064 /* return from main() forcibly exits an MT process */ 544d62bc4baSyz147064 dlmgmt_inform_parent_exit(EXIT_FAILURE); 545d62bc4baSyz147064 return (EXIT_FAILURE); 546d62bc4baSyz147064 } 547