1d62bc4baSyz /*
2d62bc4baSyz * CDDL HEADER START
3d62bc4baSyz *
4d62bc4baSyz * The contents of this file are subject to the terms of the
5d62bc4baSyz * Common Development and Distribution License (the "License").
6d62bc4baSyz * You may not use this file except in compliance with the License.
7d62bc4baSyz *
8d62bc4baSyz * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9d62bc4baSyz * or http://www.opensolaris.org/os/licensing.
10d62bc4baSyz * See the License for the specific language governing permissions
11d62bc4baSyz * and limitations under the License.
12d62bc4baSyz *
13d62bc4baSyz * When distributing Covered Code, include this CDDL HEADER in each
14d62bc4baSyz * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15d62bc4baSyz * If applicable, add the following below this CDDL HEADER, with the
16d62bc4baSyz * fields enclosed by brackets "[]" replaced with your own identifying
17d62bc4baSyz * information: Portions Copyright [yyyy] [name of copyright owner]
18d62bc4baSyz *
19d62bc4baSyz * CDDL HEADER END
20d62bc4baSyz */
21d62bc4baSyz
22d62bc4baSyz /*
23634e26ecSCasper H.S. Dik * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
24d62bc4baSyz * Use is subject to license terms.
25*85dff7a0SAndy Fiddaman * Copyright 2011 Joyent, Inc. All rights reserved.
26d62bc4baSyz */
27d62bc4baSyz
28d62bc4baSyz /*
29d62bc4baSyz * The dlmgmtd daemon is started by the datalink-management SMF service.
30d62bc4baSyz * This daemon is used to manage <link name, linkid> mapping and the
31d62bc4baSyz * persistent datalink configuration.
32d62bc4baSyz *
33d62bc4baSyz * Today, the <link name, linkid> mapping and the persistent configuration
34d62bc4baSyz * of datalinks is kept in /etc/dladm/datalink.conf, and the daemon keeps
35d62bc4baSyz * a copy of the datalinks in the memory (see dlmgmt_id_avl and
36d62bc4baSyz * dlmgmt_name_avl). The active <link name, linkid> mapping is kept in
37b9e076dcSyz * /etc/svc/volatile/dladm cache file, so that the mapping can be recovered
38b9e076dcSyz * when dlmgmtd exits for some reason (e.g., when dlmgmtd is accidentally
39b9e076dcSyz * killed).
40d62bc4baSyz */
41d62bc4baSyz
42d62bc4baSyz #include <assert.h>
43d62bc4baSyz #include <errno.h>
44d62bc4baSyz #include <fcntl.h>
452b24ab6bSSebastien Roy #include <priv.h>
46d62bc4baSyz #include <signal.h>
47d62bc4baSyz #include <stdlib.h>
48d62bc4baSyz #include <stdio.h>
49d62bc4baSyz #include <strings.h>
50d62bc4baSyz #include <syslog.h>
512b24ab6bSSebastien Roy #include <zone.h>
52d62bc4baSyz #include <sys/dld.h>
5382a2fc47SJames Carlson #include <sys/dld_ioc.h>
54b9e076dcSyz #include <sys/param.h>
55b9e076dcSyz #include <sys/stat.h>
56d62bc4baSyz #include <unistd.h>
574ac67f02SAnurag S. Maskey #include <libdladm_impl.h>
58d62bc4baSyz #include <libdlmgmt.h>
59d62bc4baSyz #include "dlmgmt_impl.h"
60d62bc4baSyz
61d62bc4baSyz const char *progname;
62d62bc4baSyz boolean_t debug;
63d62bc4baSyz static int pfds[2];
644ac67f02SAnurag S. Maskey /*
654ac67f02SAnurag S. Maskey * This file descriptor to DLMGMT_DOOR cannot be in the libdladm
664ac67f02SAnurag S. Maskey * handle because the door isn't created when the handle is created.
674ac67f02SAnurag S. Maskey */
68d62bc4baSyz static int dlmgmt_door_fd = -1;
694ac67f02SAnurag S. Maskey
704ac67f02SAnurag S. Maskey /*
712b24ab6bSSebastien Roy * This libdladm handle is global so that dlmgmt_upcall_linkprop_init() can
722b24ab6bSSebastien Roy * pass to libdladm. The handle is opened with "ALL" privileges, before
732b24ab6bSSebastien Roy * privileges are dropped in dlmgmt_drop_privileges(). It is not able to open
742b24ab6bSSebastien Roy * DLMGMT_DOOR at that time as it hasn't been created yet. This door in the
752b24ab6bSSebastien Roy * handle is opened in the first call to dladm_door_fd().
764ac67f02SAnurag S. Maskey */
774ac67f02SAnurag S. Maskey dladm_handle_t dld_handle = NULL;
78b9e076dcSyz
79b9e076dcSyz static void dlmgmtd_exit(int);
80b9e076dcSyz static int dlmgmt_init();
81b9e076dcSyz static void dlmgmt_fini();
822b24ab6bSSebastien Roy static int dlmgmt_set_privileges();
83d62bc4baSyz
84d62bc4baSyz static int
dlmgmt_set_doorfd(boolean_t start)85d62bc4baSyz dlmgmt_set_doorfd(boolean_t start)
86d62bc4baSyz {
87d62bc4baSyz dld_ioc_door_t did;
88d62bc4baSyz int err = 0;
89d62bc4baSyz
904ac67f02SAnurag S. Maskey assert(dld_handle != NULL);
91d62bc4baSyz
92d62bc4baSyz did.did_start_door = start;
93d62bc4baSyz
944ac67f02SAnurag S. Maskey if (ioctl(dladm_dld_fd(dld_handle), DLDIOC_DOORSERVER, &did) == -1)
95d62bc4baSyz err = errno;
96d62bc4baSyz
97d62bc4baSyz return (err);
98d62bc4baSyz }
99d62bc4baSyz
100d62bc4baSyz static int
dlmgmt_door_init(void)1012b24ab6bSSebastien Roy dlmgmt_door_init(void)
102d62bc4baSyz {
1032b24ab6bSSebastien Roy int err = 0;
104d62bc4baSyz
1052b24ab6bSSebastien Roy if ((dlmgmt_door_fd = door_create(dlmgmt_handler, NULL,
1062b24ab6bSSebastien Roy DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) {
107b9e076dcSyz err = errno;
1082b24ab6bSSebastien Roy dlmgmt_log(LOG_ERR, "door_create() failed: %s",
1092b24ab6bSSebastien Roy strerror(err));
110b9e076dcSyz return (err);
111b9e076dcSyz }
1122b24ab6bSSebastien Roy return (err);
1132b24ab6bSSebastien Roy }
114b9e076dcSyz
1152b24ab6bSSebastien Roy static void
dlmgmt_door_fini(void)1162b24ab6bSSebastien Roy dlmgmt_door_fini(void)
1172b24ab6bSSebastien Roy {
1182b24ab6bSSebastien Roy if (dlmgmt_door_fd == -1)
1192b24ab6bSSebastien Roy return;
1202b24ab6bSSebastien Roy
1212b24ab6bSSebastien Roy if (door_revoke(dlmgmt_door_fd) == -1) {
1222b24ab6bSSebastien Roy dlmgmt_log(LOG_WARNING, "door_revoke(%s) failed: %s",
1232b24ab6bSSebastien Roy DLMGMT_DOOR, strerror(errno));
1242b24ab6bSSebastien Roy }
1252b24ab6bSSebastien Roy (void) dlmgmt_set_doorfd(B_FALSE);
1262b24ab6bSSebastien Roy dlmgmt_door_fd = -1;
1272b24ab6bSSebastien Roy }
1282b24ab6bSSebastien Roy
129*85dff7a0SAndy Fiddaman static int
dlmgmt_door_attach(zoneid_t zoneid,char * rootdir)1302b24ab6bSSebastien Roy dlmgmt_door_attach(zoneid_t zoneid, char *rootdir)
1312b24ab6bSSebastien Roy {
1322b24ab6bSSebastien Roy int fd;
1332b24ab6bSSebastien Roy int err = 0;
1342b24ab6bSSebastien Roy char doorpath[MAXPATHLEN];
1352b24ab6bSSebastien Roy
1362b24ab6bSSebastien Roy (void) snprintf(doorpath, sizeof (doorpath), "%s%s", rootdir,
1372b24ab6bSSebastien Roy DLMGMT_DOOR);
1382b24ab6bSSebastien Roy
1392b24ab6bSSebastien Roy /*
1402b24ab6bSSebastien Roy * Create the door file for dlmgmtd.
1412b24ab6bSSebastien Roy */
1422b24ab6bSSebastien Roy if ((fd = open(doorpath, O_CREAT|O_RDONLY, 0644)) == -1) {
143d62bc4baSyz err = errno;
1442b24ab6bSSebastien Roy dlmgmt_log(LOG_ERR, "open(%s) failed: %s", doorpath,
145d62bc4baSyz strerror(err));
146d62bc4baSyz return (err);
147d62bc4baSyz }
1482b24ab6bSSebastien Roy (void) close(fd);
1496ba597c5SAnurag S. Maskey if (chown(doorpath, UID_DLADM, GID_NETADM) == -1)
1502b24ab6bSSebastien Roy return (errno);
1512b24ab6bSSebastien Roy
152fd4e42c3SSebastien Roy /*
153fd4e42c3SSebastien Roy * fdetach first in case a previous daemon instance exited
154fd4e42c3SSebastien Roy * ungracefully.
155fd4e42c3SSebastien Roy */
1562b24ab6bSSebastien Roy (void) fdetach(doorpath);
1572b24ab6bSSebastien Roy if (fattach(dlmgmt_door_fd, doorpath) != 0) {
158d62bc4baSyz err = errno;
1592b24ab6bSSebastien Roy dlmgmt_log(LOG_ERR, "fattach(%s) failed: %s", doorpath,
160d62bc4baSyz strerror(err));
1612b24ab6bSSebastien Roy } else if (zoneid == GLOBAL_ZONEID) {
1622b24ab6bSSebastien Roy if ((err = dlmgmt_set_doorfd(B_TRUE)) != 0) {
1632b24ab6bSSebastien Roy dlmgmt_log(LOG_ERR, "cannot set kernel doorfd: %s",
1642b24ab6bSSebastien Roy strerror(err));
1652b24ab6bSSebastien Roy }
166d62bc4baSyz }
167d62bc4baSyz
168d62bc4baSyz return (err);
169d62bc4baSyz }
170d62bc4baSyz
1712b24ab6bSSebastien Roy /*
1722b24ab6bSSebastien Roy * Create the /etc/svc/volatile/dladm/ directory if it doesn't exist, load the
1732b24ab6bSSebastien Roy * datalink.conf data for this zone, and create/attach the door rendezvous
1742b24ab6bSSebastien Roy * file.
1752b24ab6bSSebastien Roy */
1762b24ab6bSSebastien Roy int
dlmgmt_zone_init(zoneid_t zoneid)1772b24ab6bSSebastien Roy dlmgmt_zone_init(zoneid_t zoneid)
178d62bc4baSyz {
1792b24ab6bSSebastien Roy char rootdir[MAXPATHLEN], tmpfsdir[MAXPATHLEN];
1802b24ab6bSSebastien Roy int err;
1812b24ab6bSSebastien Roy struct stat statbuf;
1822b24ab6bSSebastien Roy
1832b24ab6bSSebastien Roy if (zoneid == GLOBAL_ZONEID) {
1842b24ab6bSSebastien Roy rootdir[0] = '\0';
1852b24ab6bSSebastien Roy } else if (zone_getattr(zoneid, ZONE_ATTR_ROOT, rootdir,
1862b24ab6bSSebastien Roy sizeof (rootdir)) < 0) {
1872b24ab6bSSebastien Roy return (errno);
1882b24ab6bSSebastien Roy }
189b9e076dcSyz
1902b24ab6bSSebastien Roy /*
1912b24ab6bSSebastien Roy * Create the DLMGMT_TMPFS_DIR directory.
1922b24ab6bSSebastien Roy */
1932b24ab6bSSebastien Roy (void) snprintf(tmpfsdir, sizeof (tmpfsdir), "%s%s", rootdir,
1942b24ab6bSSebastien Roy DLMGMT_TMPFS_DIR);
1952b24ab6bSSebastien Roy if (stat(tmpfsdir, &statbuf) < 0) {
1962b24ab6bSSebastien Roy if (mkdir(tmpfsdir, (mode_t)0755) < 0)
1972b24ab6bSSebastien Roy return (errno);
1982b24ab6bSSebastien Roy } else if ((statbuf.st_mode & S_IFMT) != S_IFDIR) {
1992b24ab6bSSebastien Roy return (ENOTDIR);
200d62bc4baSyz }
201b9e076dcSyz
2022b24ab6bSSebastien Roy if ((chmod(tmpfsdir, 0755) < 0) ||
2036ba597c5SAnurag S. Maskey (chown(tmpfsdir, UID_DLADM, GID_NETADM) < 0)) {
2042b24ab6bSSebastien Roy return (EPERM);
2052b24ab6bSSebastien Roy }
2062b24ab6bSSebastien Roy
207*85dff7a0SAndy Fiddaman if ((err = dlmgmt_db_init(zoneid, rootdir)) != 0)
2082b24ab6bSSebastien Roy return (err);
2092b24ab6bSSebastien Roy return (dlmgmt_door_attach(zoneid, rootdir));
210d62bc4baSyz }
211d62bc4baSyz
2122b24ab6bSSebastien Roy /*
2132b24ab6bSSebastien Roy * Initialize each running zone.
2142b24ab6bSSebastien Roy */
215d62bc4baSyz static int
dlmgmt_allzones_init(void)2162b24ab6bSSebastien Roy dlmgmt_allzones_init(void)
217d62bc4baSyz {
218*85dff7a0SAndy Fiddaman int i;
2192b24ab6bSSebastien Roy zoneid_t *zids = NULL;
2202b24ab6bSSebastien Roy uint_t nzids, nzids_saved;
2212b24ab6bSSebastien Roy
2222b24ab6bSSebastien Roy if (zone_list(NULL, &nzids) != 0)
2232b24ab6bSSebastien Roy return (errno);
2242b24ab6bSSebastien Roy again:
2252b24ab6bSSebastien Roy nzids *= 2;
2262b24ab6bSSebastien Roy if ((zids = malloc(nzids * sizeof (zoneid_t))) == NULL)
2272b24ab6bSSebastien Roy return (errno);
2282b24ab6bSSebastien Roy nzids_saved = nzids;
2292b24ab6bSSebastien Roy if (zone_list(zids, &nzids) != 0) {
2302b24ab6bSSebastien Roy free(zids);
2312b24ab6bSSebastien Roy return (errno);
2322b24ab6bSSebastien Roy }
2332b24ab6bSSebastien Roy if (nzids > nzids_saved) {
2342b24ab6bSSebastien Roy free(zids);
2352b24ab6bSSebastien Roy goto again;
2362b24ab6bSSebastien Roy }
2372b24ab6bSSebastien Roy
2382b24ab6bSSebastien Roy for (i = 0; i < nzids; i++) {
239*85dff7a0SAndy Fiddaman int res;
240*85dff7a0SAndy Fiddaman zone_status_t status;
241*85dff7a0SAndy Fiddaman
242*85dff7a0SAndy Fiddaman /*
243*85dff7a0SAndy Fiddaman * Skip over zones that have gone away or are going down
244*85dff7a0SAndy Fiddaman * since we got the list. Process all zones in the list,
245*85dff7a0SAndy Fiddaman * logging errors for any that failed.
246*85dff7a0SAndy Fiddaman */
247*85dff7a0SAndy Fiddaman if (zone_getattr(zids[i], ZONE_ATTR_STATUS, &status,
248*85dff7a0SAndy Fiddaman sizeof (status)) < 0) {
249*85dff7a0SAndy Fiddaman continue;
250*85dff7a0SAndy Fiddaman }
251*85dff7a0SAndy Fiddaman switch (status) {
252*85dff7a0SAndy Fiddaman case ZONE_IS_SHUTTING_DOWN:
253*85dff7a0SAndy Fiddaman case ZONE_IS_EMPTY:
254*85dff7a0SAndy Fiddaman case ZONE_IS_DOWN:
255*85dff7a0SAndy Fiddaman case ZONE_IS_DYING:
256*85dff7a0SAndy Fiddaman case ZONE_IS_DEAD:
257*85dff7a0SAndy Fiddaman case ZONE_IS_INITIALIZED:
258*85dff7a0SAndy Fiddaman case ZONE_IS_UNINITIALIZED:
259*85dff7a0SAndy Fiddaman continue;
260*85dff7a0SAndy Fiddaman default:
261*85dff7a0SAndy Fiddaman break;
262*85dff7a0SAndy Fiddaman }
263*85dff7a0SAndy Fiddaman if ((res = dlmgmt_zone_init(zids[i])) != 0) {
264*85dff7a0SAndy Fiddaman (void) fprintf(stderr, "zone (%ld) init error %s",
265*85dff7a0SAndy Fiddaman zids[i], strerror(res));
266*85dff7a0SAndy Fiddaman dlmgmt_log(LOG_ERR, "zone (%d) init error %s",
267*85dff7a0SAndy Fiddaman zids[i], strerror(res));
268*85dff7a0SAndy Fiddaman }
2692b24ab6bSSebastien Roy }
2702b24ab6bSSebastien Roy free(zids);
271*85dff7a0SAndy Fiddaman return (0);
2722b24ab6bSSebastien Roy }
2732b24ab6bSSebastien Roy
2742b24ab6bSSebastien Roy static int
dlmgmt_init(void)2752b24ab6bSSebastien Roy dlmgmt_init(void)
2762b24ab6bSSebastien Roy {
2772b24ab6bSSebastien Roy int err;
2782b24ab6bSSebastien Roy char *fmri, *c;
2792b24ab6bSSebastien Roy char filename[MAXPATHLEN];
2802b24ab6bSSebastien Roy
2812b24ab6bSSebastien Roy if (dladm_open(&dld_handle) != DLADM_STATUS_OK) {
2822b24ab6bSSebastien Roy dlmgmt_log(LOG_ERR, "dladm_open() failed");
2832b24ab6bSSebastien Roy return (EPERM);
2842b24ab6bSSebastien Roy }
285b9e076dcSyz
286b9e076dcSyz if (signal(SIGTERM, dlmgmtd_exit) == SIG_ERR ||
287b9e076dcSyz signal(SIGINT, dlmgmtd_exit) == SIG_ERR) {
288b9e076dcSyz err = errno;
289b9e076dcSyz dlmgmt_log(LOG_ERR, "signal() for SIGTERM/INT failed: %s",
290b9e076dcSyz strerror(err));
291b9e076dcSyz return (err);
292b9e076dcSyz }
293d62bc4baSyz
2942b24ab6bSSebastien Roy /*
2952b24ab6bSSebastien Roy * First derive the name of the cache file from the FMRI name. This
2962b24ab6bSSebastien Roy * cache name is used to keep active datalink configuration.
2972b24ab6bSSebastien Roy */
2982b24ab6bSSebastien Roy if (debug) {
2992b24ab6bSSebastien Roy (void) snprintf(cachefile, MAXPATHLEN, "%s/%s%s",
3002b24ab6bSSebastien Roy DLMGMT_TMPFS_DIR, progname, ".debug.cache");
3012b24ab6bSSebastien Roy } else {
3022b24ab6bSSebastien Roy if ((fmri = getenv("SMF_FMRI")) == NULL) {
303bbf21555SRichard Lowe dlmgmt_log(LOG_ERR, "dlmgmtd is an smf(7) managed "
3042b24ab6bSSebastien Roy "service and should not be run from the command "
3052b24ab6bSSebastien Roy "line.");
3062b24ab6bSSebastien Roy return (EINVAL);
3072b24ab6bSSebastien Roy }
308d62bc4baSyz
3092b24ab6bSSebastien Roy /*
3102b24ab6bSSebastien Roy * The FMRI name is in the form of
3112b24ab6bSSebastien Roy * svc:/service/service:instance. We need to remove the
3122b24ab6bSSebastien Roy * prefix "svc:/" and replace '/' with '-'. The cache file
3132b24ab6bSSebastien Roy * name is in the form of "service:instance.cache".
3142b24ab6bSSebastien Roy */
3152b24ab6bSSebastien Roy if ((c = strchr(fmri, '/')) != NULL)
3162b24ab6bSSebastien Roy c++;
3172b24ab6bSSebastien Roy else
3182b24ab6bSSebastien Roy c = fmri;
3192b24ab6bSSebastien Roy (void) snprintf(filename, MAXPATHLEN, "%s.cache", c);
3202b24ab6bSSebastien Roy c = filename;
3212b24ab6bSSebastien Roy while ((c = strchr(c, '/')) != NULL)
3222b24ab6bSSebastien Roy *c = '-';
3232b24ab6bSSebastien Roy
3242b24ab6bSSebastien Roy (void) snprintf(cachefile, MAXPATHLEN, "%s/%s",
3252b24ab6bSSebastien Roy DLMGMT_TMPFS_DIR, filename);
3262b24ab6bSSebastien Roy }
3272b24ab6bSSebastien Roy
3282b24ab6bSSebastien Roy dlmgmt_linktable_init();
3292b24ab6bSSebastien Roy if ((err = dlmgmt_door_init()) != 0)
3302b24ab6bSSebastien Roy goto done;
3312b24ab6bSSebastien Roy
3322b24ab6bSSebastien Roy /*
3332b24ab6bSSebastien Roy * Load datalink configuration and create dlmgmtd door files for all
3342b24ab6bSSebastien Roy * currently running zones.
3352b24ab6bSSebastien Roy */
3362b24ab6bSSebastien Roy if ((err = dlmgmt_allzones_init()) != 0)
3372b24ab6bSSebastien Roy dlmgmt_door_fini();
338d62bc4baSyz
3392b24ab6bSSebastien Roy done:
3402b24ab6bSSebastien Roy if (err != 0)
3412b24ab6bSSebastien Roy dlmgmt_linktable_fini();
342d62bc4baSyz return (err);
343d62bc4baSyz }
344d62bc4baSyz
345d62bc4baSyz static void
dlmgmt_fini(void)3462b24ab6bSSebastien Roy dlmgmt_fini(void)
347d62bc4baSyz {
348d62bc4baSyz dlmgmt_door_fini();
349d62bc4baSyz dlmgmt_linktable_fini();
3502b24ab6bSSebastien Roy if (dld_handle != NULL) {
3512b24ab6bSSebastien Roy dladm_close(dld_handle);
3522b24ab6bSSebastien Roy dld_handle = NULL;
3532b24ab6bSSebastien Roy }
354d62bc4baSyz }
355d62bc4baSyz
356d62bc4baSyz /*
357d62bc4baSyz * This is called by the child process to inform the parent process to
358d62bc4baSyz * exit with the given return value.
359d62bc4baSyz */
360d62bc4baSyz static void
dlmgmt_inform_parent_exit(int rv)361d62bc4baSyz dlmgmt_inform_parent_exit(int rv)
362d62bc4baSyz {
363d62bc4baSyz if (debug)
364d62bc4baSyz return;
365d62bc4baSyz
366d62bc4baSyz if (write(pfds[1], &rv, sizeof (int)) != sizeof (int)) {
367d62bc4baSyz dlmgmt_log(LOG_WARNING,
368d62bc4baSyz "dlmgmt_inform_parent_exit() failed: %s", strerror(errno));
369d62bc4baSyz (void) close(pfds[1]);
370d62bc4baSyz exit(EXIT_FAILURE);
371d62bc4baSyz }
372d62bc4baSyz (void) close(pfds[1]);
373d62bc4baSyz }
374d62bc4baSyz
375d62bc4baSyz /*ARGSUSED*/
376d62bc4baSyz static void
dlmgmtd_exit(int signo)377d62bc4baSyz dlmgmtd_exit(int signo)
378d62bc4baSyz {
379d62bc4baSyz (void) close(pfds[1]);
380d62bc4baSyz dlmgmt_fini();
381d62bc4baSyz exit(EXIT_FAILURE);
382d62bc4baSyz }
383d62bc4baSyz
384d62bc4baSyz static void
usage(void)385d62bc4baSyz usage(void)
386d62bc4baSyz {
387d62bc4baSyz (void) fprintf(stderr, "Usage: %s [-d]\n", progname);
388d62bc4baSyz exit(EXIT_FAILURE);
389d62bc4baSyz }
390d62bc4baSyz
391b9e076dcSyz /*
3922b24ab6bSSebastien Roy * Restrict privileges to only those needed.
393b9e076dcSyz */
3942b24ab6bSSebastien Roy int
dlmgmt_drop_privileges(void)3952b24ab6bSSebastien Roy dlmgmt_drop_privileges(void)
396d62bc4baSyz {
3972b24ab6bSSebastien Roy priv_set_t *pset;
3982b24ab6bSSebastien Roy priv_ptype_t ptype;
3992b24ab6bSSebastien Roy zoneid_t zoneid = getzoneid();
4002b24ab6bSSebastien Roy int err = 0;
401d62bc4baSyz
4022b24ab6bSSebastien Roy if ((pset = priv_allocset()) == NULL)
4032b24ab6bSSebastien Roy return (errno);
404b9e076dcSyz
4050dc974a9SCathy Zhou /*
4062b24ab6bSSebastien Roy * The global zone needs PRIV_PROC_FORK so that it can fork() when it
4072b24ab6bSSebastien Roy * issues db ops in non-global zones, PRIV_SYS_CONFIG to post
4082b24ab6bSSebastien Roy * sysevents, and PRIV_SYS_DL_CONFIG to initialize link properties in
4092b24ab6bSSebastien Roy * dlmgmt_upcall_linkprop_init().
4102b24ab6bSSebastien Roy *
411634e26ecSCasper H.S. Dik * We remove non-basic privileges from the permitted (and thus
412634e26ecSCasper H.S. Dik * effective) set. When executing in a non-global zone, dlmgmtd
413634e26ecSCasper H.S. Dik * only needs to read and write to files that it already owns.
4140dc974a9SCathy Zhou */
415634e26ecSCasper H.S. Dik priv_basicset(pset);
416634e26ecSCasper H.S. Dik (void) priv_delset(pset, PRIV_PROC_EXEC);
417634e26ecSCasper H.S. Dik (void) priv_delset(pset, PRIV_PROC_INFO);
418634e26ecSCasper H.S. Dik (void) priv_delset(pset, PRIV_PROC_SESSION);
419634e26ecSCasper H.S. Dik (void) priv_delset(pset, PRIV_FILE_LINK_ANY);
4202b24ab6bSSebastien Roy if (zoneid == GLOBAL_ZONEID) {
4212b24ab6bSSebastien Roy ptype = PRIV_EFFECTIVE;
422634e26ecSCasper H.S. Dik if (priv_addset(pset, PRIV_SYS_CONFIG) == -1 ||
4232b24ab6bSSebastien Roy priv_addset(pset, PRIV_SYS_DL_CONFIG) == -1)
4242b24ab6bSSebastien Roy err = errno;
4252b24ab6bSSebastien Roy } else {
426634e26ecSCasper H.S. Dik (void) priv_delset(pset, PRIV_PROC_FORK);
4272b24ab6bSSebastien Roy ptype = PRIV_PERMITTED;
428d62bc4baSyz }
4292b24ab6bSSebastien Roy if (err == 0 && setppriv(PRIV_SET, ptype, pset) == -1)
4302b24ab6bSSebastien Roy err = errno;
4312b24ab6bSSebastien Roy done:
4322b24ab6bSSebastien Roy priv_freeset(pset);
4332b24ab6bSSebastien Roy return (err);
4342b24ab6bSSebastien Roy }
435d62bc4baSyz
4362b24ab6bSSebastien Roy int
dlmgmt_elevate_privileges(void)4372b24ab6bSSebastien Roy dlmgmt_elevate_privileges(void)
4382b24ab6bSSebastien Roy {
4392b24ab6bSSebastien Roy priv_set_t *privset;
4402b24ab6bSSebastien Roy int err = 0;
4414ac67f02SAnurag S. Maskey
4422b24ab6bSSebastien Roy if ((privset = priv_str_to_set("zone", ",", NULL)) == NULL)
4432b24ab6bSSebastien Roy return (errno);
4442b24ab6bSSebastien Roy if (setppriv(PRIV_SET, PRIV_EFFECTIVE, privset) == -1)
4452b24ab6bSSebastien Roy err = errno;
4462b24ab6bSSebastien Roy priv_freeset(privset);
4472b24ab6bSSebastien Roy return (err);
448d62bc4baSyz }
449d62bc4baSyz
4502b24ab6bSSebastien Roy /*
4512b24ab6bSSebastien Roy * Set the uid of this daemon to the "dladm" user and drop privileges to only
4522b24ab6bSSebastien Roy * those needed.
4532b24ab6bSSebastien Roy */
4542b24ab6bSSebastien Roy static int
dlmgmt_set_privileges(void)4552b24ab6bSSebastien Roy dlmgmt_set_privileges(void)
456b9e076dcSyz {
4572b24ab6bSSebastien Roy int err;
4582b24ab6bSSebastien Roy
4592b24ab6bSSebastien Roy (void) setgroups(0, NULL);
4606ba597c5SAnurag S. Maskey if (setegid(GID_NETADM) == -1 || seteuid(UID_DLADM) == -1)
4612b24ab6bSSebastien Roy err = errno;
4622b24ab6bSSebastien Roy else
4632b24ab6bSSebastien Roy err = dlmgmt_drop_privileges();
4642b24ab6bSSebastien Roy done:
4652b24ab6bSSebastien Roy return (err);
466b9e076dcSyz }
467b9e076dcSyz
468d62bc4baSyz /*
469d62bc4baSyz * Keep the pfds fd open, close other fds.
470d62bc4baSyz */
471d62bc4baSyz /*ARGSUSED*/
472d62bc4baSyz static int
closefunc(void * arg,int fd)473d62bc4baSyz closefunc(void *arg, int fd)
474d62bc4baSyz {
475d62bc4baSyz if (fd != pfds[1])
476d62bc4baSyz (void) close(fd);
477d62bc4baSyz return (0);
478d62bc4baSyz }
479d62bc4baSyz
480d62bc4baSyz static boolean_t
dlmgmt_daemonize(void)481d62bc4baSyz dlmgmt_daemonize(void)
482d62bc4baSyz {
483d62bc4baSyz pid_t pid;
484d62bc4baSyz int rv;
485d62bc4baSyz
486d62bc4baSyz if (pipe(pfds) < 0) {
487d62bc4baSyz (void) fprintf(stderr, "%s: pipe() failed: %s\n",
488d62bc4baSyz progname, strerror(errno));
489d62bc4baSyz exit(EXIT_FAILURE);
490d62bc4baSyz }
491d62bc4baSyz
492d62bc4baSyz if ((pid = fork()) == -1) {
493d62bc4baSyz (void) fprintf(stderr, "%s: fork() failed: %s\n",
494d62bc4baSyz progname, strerror(errno));
495d62bc4baSyz exit(EXIT_FAILURE);
496d62bc4baSyz } else if (pid > 0) { /* Parent */
497d62bc4baSyz (void) close(pfds[1]);
498d62bc4baSyz
499d62bc4baSyz /*
500d62bc4baSyz * Read the child process's return value from the pfds.
501d62bc4baSyz * If the child process exits unexpected, read() returns -1.
502d62bc4baSyz */
503d62bc4baSyz if (read(pfds[0], &rv, sizeof (int)) != sizeof (int)) {
504d62bc4baSyz (void) kill(pid, SIGKILL);
505d62bc4baSyz rv = EXIT_FAILURE;
506d62bc4baSyz }
507d62bc4baSyz
508d62bc4baSyz (void) close(pfds[0]);
509d62bc4baSyz exit(rv);
510d62bc4baSyz }
511d62bc4baSyz
512d62bc4baSyz /* Child */
513d62bc4baSyz (void) close(pfds[0]);
514d62bc4baSyz (void) setsid();
515d62bc4baSyz
516d62bc4baSyz /*
517d62bc4baSyz * Close all files except pfds[1].
518d62bc4baSyz */
519d62bc4baSyz (void) fdwalk(closefunc, NULL);
520d62bc4baSyz (void) chdir("/");
521d62bc4baSyz openlog(progname, LOG_PID, LOG_DAEMON);
522d62bc4baSyz return (B_TRUE);
523d62bc4baSyz }
524d62bc4baSyz
525d62bc4baSyz int
main(int argc,char * argv[])526d62bc4baSyz main(int argc, char *argv[])
527d62bc4baSyz {
5282b24ab6bSSebastien Roy int opt, err;
529d62bc4baSyz
530d62bc4baSyz progname = strrchr(argv[0], '/');
531d62bc4baSyz if (progname != NULL)
532d62bc4baSyz progname++;
533d62bc4baSyz else
534d62bc4baSyz progname = argv[0];
535d62bc4baSyz
536d62bc4baSyz /*
537d62bc4baSyz * Process options.
538d62bc4baSyz */
539d62bc4baSyz while ((opt = getopt(argc, argv, "d")) != EOF) {
540d62bc4baSyz switch (opt) {
541d62bc4baSyz case 'd':
542d62bc4baSyz debug = B_TRUE;
543d62bc4baSyz break;
544d62bc4baSyz default:
545d62bc4baSyz usage();
546d62bc4baSyz }
547d62bc4baSyz }
548d62bc4baSyz
549d62bc4baSyz if (!debug && !dlmgmt_daemonize())
550d62bc4baSyz return (EXIT_FAILURE);
551d62bc4baSyz
5522b24ab6bSSebastien Roy if ((err = dlmgmt_init()) != 0) {
5532b24ab6bSSebastien Roy dlmgmt_log(LOG_ERR, "unable to initialize daemon: %s",
5542b24ab6bSSebastien Roy strerror(err));
555d62bc4baSyz goto child_out;
5562b24ab6bSSebastien Roy } else if ((err = dlmgmt_set_privileges()) != 0) {
5572b24ab6bSSebastien Roy dlmgmt_log(LOG_ERR, "unable to set daemon privileges: %s",
5582b24ab6bSSebastien Roy strerror(err));
5592b24ab6bSSebastien Roy dlmgmt_fini();
560d62bc4baSyz goto child_out;
561b9e076dcSyz }
562d62bc4baSyz
563d62bc4baSyz /*
564d62bc4baSyz * Inform the parent process that it can successfully exit.
565d62bc4baSyz */
566d62bc4baSyz dlmgmt_inform_parent_exit(EXIT_SUCCESS);
567d62bc4baSyz
568d62bc4baSyz for (;;)
569d62bc4baSyz (void) pause();
570d62bc4baSyz
571d62bc4baSyz child_out:
572d62bc4baSyz /* return from main() forcibly exits an MT process */
573d62bc4baSyz dlmgmt_inform_parent_exit(EXIT_FAILURE);
574d62bc4baSyz return (EXIT_FAILURE);
575d62bc4baSyz }
576