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 /* 23fd4e42c3SSebastien Roy * Copyright 2009 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> 44*2b24ab6bSSebastien Roy #include <priv.h> 45d62bc4baSyz147064 #include <signal.h> 46d62bc4baSyz147064 #include <stdlib.h> 47d62bc4baSyz147064 #include <stdio.h> 48d62bc4baSyz147064 #include <strings.h> 49d62bc4baSyz147064 #include <syslog.h> 50*2b24ab6bSSebastien 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 /* 70*2b24ab6bSSebastien Roy * This libdladm handle is global so that dlmgmt_upcall_linkprop_init() can 71*2b24ab6bSSebastien Roy * pass to libdladm. The handle is opened with "ALL" privileges, before 72*2b24ab6bSSebastien Roy * privileges are dropped in dlmgmt_drop_privileges(). It is not able to open 73*2b24ab6bSSebastien Roy * DLMGMT_DOOR at that time as it hasn't been created yet. This door in the 74*2b24ab6bSSebastien 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(); 81*2b24ab6bSSebastien 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 100*2b24ab6bSSebastien Roy dlmgmt_door_init(void) 101d62bc4baSyz147064 { 102*2b24ab6bSSebastien 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 115*2b24ab6bSSebastien 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); 125*2b24ab6bSSebastien Roy dlmgmt_door_fd = -1; 126*2b24ab6bSSebastien Roy } 127*2b24ab6bSSebastien Roy 128*2b24ab6bSSebastien Roy int 129*2b24ab6bSSebastien Roy dlmgmt_door_attach(zoneid_t zoneid, char *rootdir) 130*2b24ab6bSSebastien Roy { 131*2b24ab6bSSebastien Roy int fd; 132*2b24ab6bSSebastien Roy int err = 0; 133*2b24ab6bSSebastien Roy char doorpath[MAXPATHLEN]; 134*2b24ab6bSSebastien Roy 135*2b24ab6bSSebastien Roy (void) snprintf(doorpath, sizeof (doorpath), "%s%s", rootdir, 136*2b24ab6bSSebastien Roy DLMGMT_DOOR); 137*2b24ab6bSSebastien Roy 138*2b24ab6bSSebastien Roy /* 139*2b24ab6bSSebastien Roy * Create the door file for dlmgmtd. 140*2b24ab6bSSebastien Roy */ 141*2b24ab6bSSebastien Roy if ((fd = open(doorpath, O_CREAT|O_RDONLY, 0644)) == -1) { 142*2b24ab6bSSebastien Roy err = errno; 143*2b24ab6bSSebastien Roy dlmgmt_log(LOG_ERR, "open(%s) failed: %s", doorpath, 144*2b24ab6bSSebastien Roy strerror(err)); 145*2b24ab6bSSebastien Roy return (err); 146*2b24ab6bSSebastien Roy } 147*2b24ab6bSSebastien Roy (void) close(fd); 148*2b24ab6bSSebastien Roy if (chown(doorpath, UID_DLADM, GID_SYS) == -1) 149*2b24ab6bSSebastien Roy return (errno); 150*2b24ab6bSSebastien Roy 151*2b24ab6bSSebastien Roy /* 152*2b24ab6bSSebastien Roy * fdetach first in case a previous daemon instance exited 153*2b24ab6bSSebastien Roy * ungracefully. 154*2b24ab6bSSebastien Roy */ 155*2b24ab6bSSebastien Roy (void) fdetach(doorpath); 156*2b24ab6bSSebastien Roy if (fattach(dlmgmt_door_fd, doorpath) != 0) { 157*2b24ab6bSSebastien Roy err = errno; 158*2b24ab6bSSebastien Roy dlmgmt_log(LOG_ERR, "fattach(%s) failed: %s", doorpath, 159*2b24ab6bSSebastien Roy strerror(err)); 160*2b24ab6bSSebastien Roy } else if (zoneid == GLOBAL_ZONEID) { 161*2b24ab6bSSebastien Roy if ((err = dlmgmt_set_doorfd(B_TRUE)) != 0) { 162*2b24ab6bSSebastien Roy dlmgmt_log(LOG_ERR, "cannot set kernel doorfd: %s", 163*2b24ab6bSSebastien Roy strerror(err)); 164*2b24ab6bSSebastien Roy } 165*2b24ab6bSSebastien Roy } 166*2b24ab6bSSebastien Roy 167*2b24ab6bSSebastien Roy return (err); 168*2b24ab6bSSebastien Roy } 169*2b24ab6bSSebastien Roy 170*2b24ab6bSSebastien Roy /* 171*2b24ab6bSSebastien Roy * Create the /etc/svc/volatile/dladm/ directory if it doesn't exist, load the 172*2b24ab6bSSebastien Roy * datalink.conf data for this zone, and create/attach the door rendezvous 173*2b24ab6bSSebastien Roy * file. 174*2b24ab6bSSebastien Roy */ 175*2b24ab6bSSebastien Roy int 176*2b24ab6bSSebastien Roy dlmgmt_zone_init(zoneid_t zoneid) 177*2b24ab6bSSebastien Roy { 178*2b24ab6bSSebastien Roy char rootdir[MAXPATHLEN], tmpfsdir[MAXPATHLEN]; 179*2b24ab6bSSebastien Roy int err; 180*2b24ab6bSSebastien Roy struct stat statbuf; 181*2b24ab6bSSebastien Roy 182*2b24ab6bSSebastien Roy if (zoneid == GLOBAL_ZONEID) { 183*2b24ab6bSSebastien Roy rootdir[0] = '\0'; 184*2b24ab6bSSebastien Roy } else if (zone_getattr(zoneid, ZONE_ATTR_ROOT, rootdir, 185*2b24ab6bSSebastien Roy sizeof (rootdir)) < 0) { 186*2b24ab6bSSebastien Roy return (errno); 187*2b24ab6bSSebastien Roy } 188*2b24ab6bSSebastien Roy 189*2b24ab6bSSebastien Roy /* 190*2b24ab6bSSebastien Roy * Create the DLMGMT_TMPFS_DIR directory. 191*2b24ab6bSSebastien Roy */ 192*2b24ab6bSSebastien Roy (void) snprintf(tmpfsdir, sizeof (tmpfsdir), "%s%s", rootdir, 193*2b24ab6bSSebastien Roy DLMGMT_TMPFS_DIR); 194*2b24ab6bSSebastien Roy if (stat(tmpfsdir, &statbuf) < 0) { 195*2b24ab6bSSebastien Roy if (mkdir(tmpfsdir, (mode_t)0755) < 0) 196*2b24ab6bSSebastien Roy return (errno); 197*2b24ab6bSSebastien Roy } else if ((statbuf.st_mode & S_IFMT) != S_IFDIR) { 198*2b24ab6bSSebastien Roy return (ENOTDIR); 199*2b24ab6bSSebastien Roy } 200*2b24ab6bSSebastien Roy 201*2b24ab6bSSebastien Roy if ((chmod(tmpfsdir, 0755) < 0) || 202*2b24ab6bSSebastien Roy (chown(tmpfsdir, UID_DLADM, GID_SYS) < 0)) { 203*2b24ab6bSSebastien Roy return (EPERM); 204*2b24ab6bSSebastien Roy } 205*2b24ab6bSSebastien Roy 206*2b24ab6bSSebastien Roy if ((err = dlmgmt_db_init(zoneid)) != 0) 207*2b24ab6bSSebastien Roy return (err); 208*2b24ab6bSSebastien Roy return (dlmgmt_door_attach(zoneid, rootdir)); 209*2b24ab6bSSebastien Roy } 210*2b24ab6bSSebastien Roy 211*2b24ab6bSSebastien Roy /* 212*2b24ab6bSSebastien Roy * Initialize each running zone. 213*2b24ab6bSSebastien Roy */ 214*2b24ab6bSSebastien Roy static int 215*2b24ab6bSSebastien Roy dlmgmt_allzones_init(void) 216*2b24ab6bSSebastien Roy { 217*2b24ab6bSSebastien Roy int err, i; 218*2b24ab6bSSebastien Roy zoneid_t *zids = NULL; 219*2b24ab6bSSebastien Roy uint_t nzids, nzids_saved; 220*2b24ab6bSSebastien Roy 221*2b24ab6bSSebastien Roy if (zone_list(NULL, &nzids) != 0) 222*2b24ab6bSSebastien Roy return (errno); 223*2b24ab6bSSebastien Roy again: 224*2b24ab6bSSebastien Roy nzids *= 2; 225*2b24ab6bSSebastien Roy if ((zids = malloc(nzids * sizeof (zoneid_t))) == NULL) 226*2b24ab6bSSebastien Roy return (errno); 227*2b24ab6bSSebastien Roy nzids_saved = nzids; 228*2b24ab6bSSebastien Roy if (zone_list(zids, &nzids) != 0) { 229*2b24ab6bSSebastien Roy free(zids); 230*2b24ab6bSSebastien Roy return (errno); 231*2b24ab6bSSebastien Roy } 232*2b24ab6bSSebastien Roy if (nzids > nzids_saved) { 233*2b24ab6bSSebastien Roy free(zids); 234*2b24ab6bSSebastien Roy goto again; 235*2b24ab6bSSebastien Roy } 236*2b24ab6bSSebastien Roy 237*2b24ab6bSSebastien Roy for (i = 0; i < nzids; i++) { 238*2b24ab6bSSebastien Roy if ((err = dlmgmt_zone_init(zids[i])) != 0) 239*2b24ab6bSSebastien Roy break; 240*2b24ab6bSSebastien Roy } 241*2b24ab6bSSebastien Roy free(zids); 242*2b24ab6bSSebastien Roy return (err); 243d62bc4baSyz147064 } 244d62bc4baSyz147064 245d62bc4baSyz147064 static int 246*2b24ab6bSSebastien Roy dlmgmt_init(void) 247d62bc4baSyz147064 { 248d62bc4baSyz147064 int err; 249*2b24ab6bSSebastien Roy char *fmri, *c; 250*2b24ab6bSSebastien Roy char filename[MAXPATHLEN]; 251*2b24ab6bSSebastien Roy 252*2b24ab6bSSebastien Roy if (dladm_open(&dld_handle) != DLADM_STATUS_OK) { 253*2b24ab6bSSebastien Roy dlmgmt_log(LOG_ERR, "dladm_open() failed"); 254*2b24ab6bSSebastien Roy return (EPERM); 255*2b24ab6bSSebastien 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 265*2b24ab6bSSebastien Roy /* 266*2b24ab6bSSebastien Roy * First derive the name of the cache file from the FMRI name. This 267*2b24ab6bSSebastien Roy * cache name is used to keep active datalink configuration. 268*2b24ab6bSSebastien Roy */ 269*2b24ab6bSSebastien Roy if (debug) { 270*2b24ab6bSSebastien Roy (void) snprintf(cachefile, MAXPATHLEN, "%s/%s%s", 271*2b24ab6bSSebastien Roy DLMGMT_TMPFS_DIR, progname, ".debug.cache"); 272*2b24ab6bSSebastien Roy } else { 273*2b24ab6bSSebastien Roy if ((fmri = getenv("SMF_FMRI")) == NULL) { 274*2b24ab6bSSebastien Roy dlmgmt_log(LOG_ERR, "dlmgmtd is an smf(5) managed " 275*2b24ab6bSSebastien Roy "service and should not be run from the command " 276*2b24ab6bSSebastien Roy "line."); 277*2b24ab6bSSebastien Roy return (EINVAL); 278*2b24ab6bSSebastien Roy } 279d62bc4baSyz147064 280*2b24ab6bSSebastien Roy /* 281*2b24ab6bSSebastien Roy * The FMRI name is in the form of 282*2b24ab6bSSebastien Roy * svc:/service/service:instance. We need to remove the 283*2b24ab6bSSebastien Roy * prefix "svc:/" and replace '/' with '-'. The cache file 284*2b24ab6bSSebastien Roy * name is in the form of "service:instance.cache". 285*2b24ab6bSSebastien Roy */ 286*2b24ab6bSSebastien Roy if ((c = strchr(fmri, '/')) != NULL) 287*2b24ab6bSSebastien Roy c++; 288*2b24ab6bSSebastien Roy else 289*2b24ab6bSSebastien Roy c = fmri; 290*2b24ab6bSSebastien Roy (void) snprintf(filename, MAXPATHLEN, "%s.cache", c); 291*2b24ab6bSSebastien Roy c = filename; 292*2b24ab6bSSebastien Roy while ((c = strchr(c, '/')) != NULL) 293*2b24ab6bSSebastien Roy *c = '-'; 294*2b24ab6bSSebastien Roy 295*2b24ab6bSSebastien Roy (void) snprintf(cachefile, MAXPATHLEN, "%s/%s", 296*2b24ab6bSSebastien Roy DLMGMT_TMPFS_DIR, filename); 297*2b24ab6bSSebastien Roy } 298*2b24ab6bSSebastien Roy 299*2b24ab6bSSebastien Roy dlmgmt_linktable_init(); 300*2b24ab6bSSebastien Roy if ((err = dlmgmt_door_init()) != 0) 301*2b24ab6bSSebastien Roy goto done; 302*2b24ab6bSSebastien Roy 303*2b24ab6bSSebastien Roy /* 304*2b24ab6bSSebastien Roy * Load datalink configuration and create dlmgmtd door files for all 305*2b24ab6bSSebastien Roy * currently running zones. 306*2b24ab6bSSebastien Roy */ 307*2b24ab6bSSebastien Roy if ((err = dlmgmt_allzones_init()) != 0) 308*2b24ab6bSSebastien Roy dlmgmt_door_fini(); 309*2b24ab6bSSebastien Roy 310*2b24ab6bSSebastien Roy done: 311*2b24ab6bSSebastien Roy if (err != 0) 312d62bc4baSyz147064 dlmgmt_linktable_fini(); 313d62bc4baSyz147064 return (err); 314d62bc4baSyz147064 } 315d62bc4baSyz147064 316d62bc4baSyz147064 static void 317*2b24ab6bSSebastien Roy dlmgmt_fini(void) 318d62bc4baSyz147064 { 319d62bc4baSyz147064 dlmgmt_door_fini(); 320d62bc4baSyz147064 dlmgmt_linktable_fini(); 321*2b24ab6bSSebastien Roy if (dld_handle != NULL) { 322*2b24ab6bSSebastien Roy dladm_close(dld_handle); 323*2b24ab6bSSebastien Roy dld_handle = NULL; 324*2b24ab6bSSebastien 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 /* 363*2b24ab6bSSebastien Roy * Restrict privileges to only those needed. 364*2b24ab6bSSebastien Roy */ 365*2b24ab6bSSebastien Roy int 366*2b24ab6bSSebastien Roy dlmgmt_drop_privileges(void) 367*2b24ab6bSSebastien Roy { 368*2b24ab6bSSebastien Roy priv_set_t *pset; 369*2b24ab6bSSebastien Roy priv_ptype_t ptype; 370*2b24ab6bSSebastien Roy zoneid_t zoneid = getzoneid(); 371*2b24ab6bSSebastien Roy int err = 0; 372*2b24ab6bSSebastien Roy 373*2b24ab6bSSebastien Roy if ((pset = priv_allocset()) == NULL) 374*2b24ab6bSSebastien Roy return (errno); 375*2b24ab6bSSebastien Roy 376*2b24ab6bSSebastien Roy /* 377*2b24ab6bSSebastien Roy * The global zone needs PRIV_PROC_FORK so that it can fork() when it 378*2b24ab6bSSebastien Roy * issues db ops in non-global zones, PRIV_SYS_CONFIG to post 379*2b24ab6bSSebastien Roy * sysevents, and PRIV_SYS_DL_CONFIG to initialize link properties in 380*2b24ab6bSSebastien Roy * dlmgmt_upcall_linkprop_init(). 381b9e076dcSyz147064 * 382*2b24ab6bSSebastien Roy * We remove all privileges from the permitted (and thus effective) 383*2b24ab6bSSebastien Roy * set in the non-global zone. When executing in a non-global zone, 384*2b24ab6bSSebastien Roy * dlmgmtd only needs to read and write to files that it already owns. 385*2b24ab6bSSebastien Roy */ 386*2b24ab6bSSebastien Roy priv_emptyset(pset); 387*2b24ab6bSSebastien Roy if (zoneid == GLOBAL_ZONEID) { 388*2b24ab6bSSebastien Roy ptype = PRIV_EFFECTIVE; 389*2b24ab6bSSebastien Roy if (priv_addset(pset, PRIV_PROC_FORK) == -1 || 390*2b24ab6bSSebastien Roy priv_addset(pset, PRIV_SYS_CONFIG) == -1 || 391*2b24ab6bSSebastien Roy priv_addset(pset, PRIV_SYS_DL_CONFIG) == -1) 392*2b24ab6bSSebastien Roy err = errno; 393*2b24ab6bSSebastien Roy } else { 394*2b24ab6bSSebastien Roy ptype = PRIV_PERMITTED; 395*2b24ab6bSSebastien Roy } 396*2b24ab6bSSebastien Roy if (err == 0 && setppriv(PRIV_SET, ptype, pset) == -1) 397*2b24ab6bSSebastien Roy err = errno; 398*2b24ab6bSSebastien Roy done: 399*2b24ab6bSSebastien Roy priv_freeset(pset); 400*2b24ab6bSSebastien Roy return (err); 401*2b24ab6bSSebastien Roy } 402*2b24ab6bSSebastien Roy 403*2b24ab6bSSebastien Roy int 404*2b24ab6bSSebastien Roy dlmgmt_elevate_privileges(void) 405*2b24ab6bSSebastien Roy { 406*2b24ab6bSSebastien Roy priv_set_t *privset; 407*2b24ab6bSSebastien Roy int err = 0; 408*2b24ab6bSSebastien Roy 409*2b24ab6bSSebastien Roy if ((privset = priv_str_to_set("zone", ",", NULL)) == NULL) 410*2b24ab6bSSebastien Roy return (errno); 411*2b24ab6bSSebastien Roy if (setppriv(PRIV_SET, PRIV_EFFECTIVE, privset) == -1) 412*2b24ab6bSSebastien Roy err = errno; 413*2b24ab6bSSebastien Roy priv_freeset(privset); 414*2b24ab6bSSebastien Roy return (err); 415*2b24ab6bSSebastien Roy } 416*2b24ab6bSSebastien Roy 417*2b24ab6bSSebastien Roy /* 418*2b24ab6bSSebastien Roy * Set the uid of this daemon to the "dladm" user and drop privileges to only 419*2b24ab6bSSebastien Roy * those needed. 420b9e076dcSyz147064 */ 421d62bc4baSyz147064 static int 422*2b24ab6bSSebastien Roy dlmgmt_set_privileges(void) 423d62bc4baSyz147064 { 424*2b24ab6bSSebastien Roy int err; 425d62bc4baSyz147064 426*2b24ab6bSSebastien Roy (void) setgroups(0, NULL); 427*2b24ab6bSSebastien Roy if (setegid(GID_SYS) == -1 || seteuid(UID_DLADM) == -1) 428*2b24ab6bSSebastien Roy err = errno; 429*2b24ab6bSSebastien Roy else 430*2b24ab6bSSebastien Roy err = dlmgmt_drop_privileges(); 431*2b24ab6bSSebastien Roy done: 432*2b24ab6bSSebastien Roy return (err); 433b9e076dcSyz147064 } 434b9e076dcSyz147064 435d62bc4baSyz147064 /* 436d62bc4baSyz147064 * Keep the pfds fd open, close other fds. 437d62bc4baSyz147064 */ 438d62bc4baSyz147064 /*ARGSUSED*/ 439d62bc4baSyz147064 static int 440d62bc4baSyz147064 closefunc(void *arg, int fd) 441d62bc4baSyz147064 { 442d62bc4baSyz147064 if (fd != pfds[1]) 443d62bc4baSyz147064 (void) close(fd); 444d62bc4baSyz147064 return (0); 445d62bc4baSyz147064 } 446d62bc4baSyz147064 447d62bc4baSyz147064 static boolean_t 448d62bc4baSyz147064 dlmgmt_daemonize(void) 449d62bc4baSyz147064 { 450d62bc4baSyz147064 pid_t pid; 451d62bc4baSyz147064 int rv; 452d62bc4baSyz147064 453d62bc4baSyz147064 if (pipe(pfds) < 0) { 454d62bc4baSyz147064 (void) fprintf(stderr, "%s: pipe() failed: %s\n", 455d62bc4baSyz147064 progname, strerror(errno)); 456d62bc4baSyz147064 exit(EXIT_FAILURE); 457d62bc4baSyz147064 } 458d62bc4baSyz147064 459d62bc4baSyz147064 if ((pid = fork()) == -1) { 460d62bc4baSyz147064 (void) fprintf(stderr, "%s: fork() failed: %s\n", 461d62bc4baSyz147064 progname, strerror(errno)); 462d62bc4baSyz147064 exit(EXIT_FAILURE); 463d62bc4baSyz147064 } else if (pid > 0) { /* Parent */ 464d62bc4baSyz147064 (void) close(pfds[1]); 465d62bc4baSyz147064 466d62bc4baSyz147064 /* 467d62bc4baSyz147064 * Read the child process's return value from the pfds. 468d62bc4baSyz147064 * If the child process exits unexpected, read() returns -1. 469d62bc4baSyz147064 */ 470d62bc4baSyz147064 if (read(pfds[0], &rv, sizeof (int)) != sizeof (int)) { 471d62bc4baSyz147064 (void) kill(pid, SIGKILL); 472d62bc4baSyz147064 rv = EXIT_FAILURE; 473d62bc4baSyz147064 } 474d62bc4baSyz147064 475d62bc4baSyz147064 (void) close(pfds[0]); 476d62bc4baSyz147064 exit(rv); 477d62bc4baSyz147064 } 478d62bc4baSyz147064 479d62bc4baSyz147064 /* Child */ 480d62bc4baSyz147064 (void) close(pfds[0]); 481d62bc4baSyz147064 (void) setsid(); 482d62bc4baSyz147064 483d62bc4baSyz147064 /* 484d62bc4baSyz147064 * Close all files except pfds[1]. 485d62bc4baSyz147064 */ 486d62bc4baSyz147064 (void) fdwalk(closefunc, NULL); 487d62bc4baSyz147064 (void) chdir("/"); 488d62bc4baSyz147064 openlog(progname, LOG_PID, LOG_DAEMON); 489d62bc4baSyz147064 return (B_TRUE); 490d62bc4baSyz147064 } 491d62bc4baSyz147064 492d62bc4baSyz147064 int 493d62bc4baSyz147064 main(int argc, char *argv[]) 494d62bc4baSyz147064 { 495*2b24ab6bSSebastien Roy int opt, err; 496d62bc4baSyz147064 497d62bc4baSyz147064 progname = strrchr(argv[0], '/'); 498d62bc4baSyz147064 if (progname != NULL) 499d62bc4baSyz147064 progname++; 500d62bc4baSyz147064 else 501d62bc4baSyz147064 progname = argv[0]; 502d62bc4baSyz147064 503d62bc4baSyz147064 /* 504d62bc4baSyz147064 * Process options. 505d62bc4baSyz147064 */ 506d62bc4baSyz147064 while ((opt = getopt(argc, argv, "d")) != EOF) { 507d62bc4baSyz147064 switch (opt) { 508d62bc4baSyz147064 case 'd': 509d62bc4baSyz147064 debug = B_TRUE; 510d62bc4baSyz147064 break; 511d62bc4baSyz147064 default: 512d62bc4baSyz147064 usage(); 513d62bc4baSyz147064 } 514d62bc4baSyz147064 } 515d62bc4baSyz147064 516d62bc4baSyz147064 if (!debug && !dlmgmt_daemonize()) 517d62bc4baSyz147064 return (EXIT_FAILURE); 518d62bc4baSyz147064 519*2b24ab6bSSebastien Roy if ((err = dlmgmt_init()) != 0) { 520*2b24ab6bSSebastien Roy dlmgmt_log(LOG_ERR, "unable to initialize daemon: %s", 521*2b24ab6bSSebastien Roy strerror(err)); 522d62bc4baSyz147064 goto child_out; 523*2b24ab6bSSebastien Roy } else if ((err = dlmgmt_set_privileges()) != 0) { 524*2b24ab6bSSebastien Roy dlmgmt_log(LOG_ERR, "unable to set daemon privileges: %s", 525*2b24ab6bSSebastien Roy strerror(err)); 526*2b24ab6bSSebastien Roy dlmgmt_fini(); 527d62bc4baSyz147064 goto child_out; 528b9e076dcSyz147064 } 529d62bc4baSyz147064 530d62bc4baSyz147064 /* 531d62bc4baSyz147064 * Inform the parent process that it can successfully exit. 532d62bc4baSyz147064 */ 533d62bc4baSyz147064 dlmgmt_inform_parent_exit(EXIT_SUCCESS); 534d62bc4baSyz147064 535d62bc4baSyz147064 for (;;) 536d62bc4baSyz147064 (void) pause(); 537d62bc4baSyz147064 538d62bc4baSyz147064 child_out: 539d62bc4baSyz147064 /* return from main() forcibly exits an MT process */ 540d62bc4baSyz147064 dlmgmt_inform_parent_exit(EXIT_FAILURE); 541d62bc4baSyz147064 return (EXIT_FAILURE); 542d62bc4baSyz147064 } 543