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
dlmgmt_set_doorfd(boolean_t start)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
dlmgmt_door_init(void)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
dlmgmt_door_fini(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
dlmgmt_door_attach(zoneid_t zoneid,char * rootdir)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
dlmgmt_zone_init(zoneid_t zoneid)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
dlmgmt_allzones_init(void)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
dlmgmt_init(void)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
dlmgmt_fini(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
dlmgmt_inform_parent_exit(int rv)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
dlmgmtd_exit(int signo)348d62bc4baSyz147064 dlmgmtd_exit(int signo)
349d62bc4baSyz147064 {
350d62bc4baSyz147064 (void) close(pfds[1]);
351d62bc4baSyz147064 dlmgmt_fini();
352d62bc4baSyz147064 exit(EXIT_FAILURE);
353d62bc4baSyz147064 }
354d62bc4baSyz147064
355d62bc4baSyz147064 static void
usage(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
dlmgmt_drop_privileges(void)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
dlmgmt_elevate_privileges(void)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
dlmgmt_set_privileges(void)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
closefunc(void * arg,int fd)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
dlmgmt_daemonize(void)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
main(int argc,char * argv[])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