xref: /onnv-gate/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_main.c (revision 12748:40c62600acd3)
112016SGirish.Moodalbail@Sun.COM /*
212016SGirish.Moodalbail@Sun.COM  * CDDL HEADER START
312016SGirish.Moodalbail@Sun.COM  *
412016SGirish.Moodalbail@Sun.COM  * The contents of this file are subject to the terms of the
512016SGirish.Moodalbail@Sun.COM  * Common Development and Distribution License (the "License").
612016SGirish.Moodalbail@Sun.COM  * You may not use this file except in compliance with the License.
712016SGirish.Moodalbail@Sun.COM  *
812016SGirish.Moodalbail@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
912016SGirish.Moodalbail@Sun.COM  * or http://www.opensolaris.org/os/licensing.
1012016SGirish.Moodalbail@Sun.COM  * See the License for the specific language governing permissions
1112016SGirish.Moodalbail@Sun.COM  * and limitations under the License.
1212016SGirish.Moodalbail@Sun.COM  *
1312016SGirish.Moodalbail@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
1412016SGirish.Moodalbail@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1512016SGirish.Moodalbail@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
1612016SGirish.Moodalbail@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
1712016SGirish.Moodalbail@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
1812016SGirish.Moodalbail@Sun.COM  *
1912016SGirish.Moodalbail@Sun.COM  * CDDL HEADER END
2012016SGirish.Moodalbail@Sun.COM  */
2112016SGirish.Moodalbail@Sun.COM 
2212016SGirish.Moodalbail@Sun.COM /*
23*12748SSowmini.Varadhan@oracle.COM  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
2412016SGirish.Moodalbail@Sun.COM  */
2512016SGirish.Moodalbail@Sun.COM 
2612016SGirish.Moodalbail@Sun.COM /*
2712016SGirish.Moodalbail@Sun.COM  * The ipmgmtd daemon is started by ip-interface-management SMF service. This
2812016SGirish.Moodalbail@Sun.COM  * daemon is used to manage, mapping of 'address object' to 'interface name' and
2912016SGirish.Moodalbail@Sun.COM  * 'logical interface number', on which the address is created. It also provides
3012016SGirish.Moodalbail@Sun.COM  * a means to update the ipadm persistent data-store.
3112016SGirish.Moodalbail@Sun.COM  *
3212016SGirish.Moodalbail@Sun.COM  * The daemon tracks the <addrobj, lifname> mapping in-memory using a linked
3312016SGirish.Moodalbail@Sun.COM  * list `aobjmap'. Access to this list is synchronized using a readers-writers
3412016SGirish.Moodalbail@Sun.COM  * lock. The active <addrobj, lifname> mapping is kept in
3512016SGirish.Moodalbail@Sun.COM  * /etc/svc/volatile/ipadm/aobjmap.conf cache file, so that the mapping can be
3612016SGirish.Moodalbail@Sun.COM  * recovered when ipmgmtd exits for some reason (e.g., when ipmgmtd is restarted
3712016SGirish.Moodalbail@Sun.COM  * using svcadm or accidentally killed).
3812016SGirish.Moodalbail@Sun.COM  *
3912016SGirish.Moodalbail@Sun.COM  * Today, the persistent configuration of interfaces, addresses and protocol
4012016SGirish.Moodalbail@Sun.COM  * properties is kept in /etc/ipadm/ipadm.conf. The access to the persistent
4112016SGirish.Moodalbail@Sun.COM  * data store is synchronized using reader-writers lock `ipmgmt_dbconf_lock'.
4212016SGirish.Moodalbail@Sun.COM  *
4312016SGirish.Moodalbail@Sun.COM  * The communication between the library, libipadm.so and the daemon, is through
4412016SGirish.Moodalbail@Sun.COM  * doors RPC. The library interacts with the daemon using the commands defined
4512016SGirish.Moodalbail@Sun.COM  * by `ipmgmt_door_cmd_type_t'. Further any 'write' operation would require
4612016SGirish.Moodalbail@Sun.COM  * the `NETWORK_INTERFACE_CONFIG_AUTH' authorization.
4712016SGirish.Moodalbail@Sun.COM  *
4812016SGirish.Moodalbail@Sun.COM  * On reboot, the aforementioned SMF service starts the daemon before any other
4912016SGirish.Moodalbail@Sun.COM  * networking service that configures network IP interfaces is started.
5012016SGirish.Moodalbail@Sun.COM  * Afterwards, the network/physical SMF script instantiates the persisted
5112016SGirish.Moodalbail@Sun.COM  * network interfaces, interface properties and addresses.
5212016SGirish.Moodalbail@Sun.COM  */
5312016SGirish.Moodalbail@Sun.COM 
5412016SGirish.Moodalbail@Sun.COM #include <errno.h>
5512016SGirish.Moodalbail@Sun.COM #include <fcntl.h>
5612016SGirish.Moodalbail@Sun.COM #include <priv_utils.h>
5712016SGirish.Moodalbail@Sun.COM #include <signal.h>
5812016SGirish.Moodalbail@Sun.COM #include <stdlib.h>
5912016SGirish.Moodalbail@Sun.COM #include <stdio.h>
6012016SGirish.Moodalbail@Sun.COM #include <strings.h>
6112016SGirish.Moodalbail@Sun.COM #include <sys/param.h>
6212016SGirish.Moodalbail@Sun.COM #include <sys/stat.h>
6312016SGirish.Moodalbail@Sun.COM #include <unistd.h>
6412016SGirish.Moodalbail@Sun.COM #include "ipmgmt_impl.h"
65*12748SSowmini.Varadhan@oracle.COM #include <zone.h>
66*12748SSowmini.Varadhan@oracle.COM #include <libipadm.h>
67*12748SSowmini.Varadhan@oracle.COM #include <libdladm.h>
68*12748SSowmini.Varadhan@oracle.COM #include <libdllink.h>
69*12748SSowmini.Varadhan@oracle.COM #include <net/route.h>
70*12748SSowmini.Varadhan@oracle.COM #include <ipadm_ipmgmt.h>
71*12748SSowmini.Varadhan@oracle.COM #include <sys/brand.h>
7212016SGirish.Moodalbail@Sun.COM 
7312016SGirish.Moodalbail@Sun.COM const char		*progname;
7412016SGirish.Moodalbail@Sun.COM 
7512016SGirish.Moodalbail@Sun.COM /* readers-writers lock for reading/writing daemon data store */
7612016SGirish.Moodalbail@Sun.COM pthread_rwlock_t	ipmgmt_dbconf_lock;
7712016SGirish.Moodalbail@Sun.COM 
7812016SGirish.Moodalbail@Sun.COM /* tracks address object to {ifname|logical number|interface id} mapping */
7912016SGirish.Moodalbail@Sun.COM ipmgmt_aobjmap_list_t	aobjmap;
8012016SGirish.Moodalbail@Sun.COM 
8112016SGirish.Moodalbail@Sun.COM /* used to communicate failure to parent process, which spawned the daemon */
8212016SGirish.Moodalbail@Sun.COM static int		pfds[2];
8312016SGirish.Moodalbail@Sun.COM 
8412016SGirish.Moodalbail@Sun.COM /* file descriptor to IPMGMT_DOOR */
8512016SGirish.Moodalbail@Sun.COM static int		ipmgmt_door_fd = -1;
8612016SGirish.Moodalbail@Sun.COM 
8712016SGirish.Moodalbail@Sun.COM static void		ipmgmt_exit(int);
8812016SGirish.Moodalbail@Sun.COM static int		ipmgmt_init();
8912016SGirish.Moodalbail@Sun.COM static int		ipmgmt_init_privileges();
90*12748SSowmini.Varadhan@oracle.COM static void		ipmgmt_ngz_init();
91*12748SSowmini.Varadhan@oracle.COM static void		ipmgmt_ngz_persist_if();
92*12748SSowmini.Varadhan@oracle.COM 
93*12748SSowmini.Varadhan@oracle.COM static ipadm_handle_t iph;
94*12748SSowmini.Varadhan@oracle.COM typedef struct ipmgmt_pif_s {
95*12748SSowmini.Varadhan@oracle.COM 	struct ipmgmt_pif_s	*pif_next;
96*12748SSowmini.Varadhan@oracle.COM 	char			pif_ifname[LIFNAMSIZ];
97*12748SSowmini.Varadhan@oracle.COM 	boolean_t		pif_v4;
98*12748SSowmini.Varadhan@oracle.COM 	boolean_t		pif_v6;
99*12748SSowmini.Varadhan@oracle.COM } ipmgmt_pif_t;
100*12748SSowmini.Varadhan@oracle.COM 
101*12748SSowmini.Varadhan@oracle.COM static ipmgmt_pif_t *ngz_pifs;
10212016SGirish.Moodalbail@Sun.COM 
10312016SGirish.Moodalbail@Sun.COM static int
10412016SGirish.Moodalbail@Sun.COM ipmgmt_db_init()
10512016SGirish.Moodalbail@Sun.COM {
10612016SGirish.Moodalbail@Sun.COM 	int		fd, err;
10712016SGirish.Moodalbail@Sun.COM 
10812016SGirish.Moodalbail@Sun.COM 	/* creates the address object data store, if it doesn't exist */
10912016SGirish.Moodalbail@Sun.COM 	if ((fd = open(ADDROBJ_MAPPING_DB_FILE, O_CREAT|O_RDONLY,
11012016SGirish.Moodalbail@Sun.COM 	    IPADM_FILE_MODE)) == -1) {
11112016SGirish.Moodalbail@Sun.COM 		err = errno;
11212016SGirish.Moodalbail@Sun.COM 		ipmgmt_log(LOG_ERR, "could not open %s: %s",
11312016SGirish.Moodalbail@Sun.COM 		    ADDROBJ_MAPPING_DB_FILE, strerror(err));
11412016SGirish.Moodalbail@Sun.COM 		return (err);
11512016SGirish.Moodalbail@Sun.COM 	}
11612016SGirish.Moodalbail@Sun.COM 	(void) close(fd);
11712016SGirish.Moodalbail@Sun.COM 
11812016SGirish.Moodalbail@Sun.COM 	aobjmap.aobjmap_head = NULL;
11912016SGirish.Moodalbail@Sun.COM 	(void) pthread_rwlock_init(&aobjmap.aobjmap_rwlock, NULL);
12012016SGirish.Moodalbail@Sun.COM 
12112016SGirish.Moodalbail@Sun.COM 	/*
12212016SGirish.Moodalbail@Sun.COM 	 * If the daemon is recovering from a crash or restart, read the
12312016SGirish.Moodalbail@Sun.COM 	 * address object to logical interface mapping and build an in-memory
12412016SGirish.Moodalbail@Sun.COM 	 * representation of the mapping. That is, build `aobjmap' structure
12512016SGirish.Moodalbail@Sun.COM 	 * from address object data store.
12612016SGirish.Moodalbail@Sun.COM 	 */
12712016SGirish.Moodalbail@Sun.COM 	if ((err = ipadm_rw_db(ipmgmt_aobjmap_init, NULL,
12812016SGirish.Moodalbail@Sun.COM 	    ADDROBJ_MAPPING_DB_FILE, 0, IPADM_DB_READ)) != 0) {
12912016SGirish.Moodalbail@Sun.COM 		/* if there was nothing to initialize, it's fine */
13012016SGirish.Moodalbail@Sun.COM 		if (err != ENOENT)
13112016SGirish.Moodalbail@Sun.COM 			return (err);
13212016SGirish.Moodalbail@Sun.COM 		err = 0;
13312016SGirish.Moodalbail@Sun.COM 	}
13412016SGirish.Moodalbail@Sun.COM 
13512016SGirish.Moodalbail@Sun.COM 	(void) pthread_rwlock_init(&ipmgmt_dbconf_lock, NULL);
136*12748SSowmini.Varadhan@oracle.COM 
137*12748SSowmini.Varadhan@oracle.COM 	ipmgmt_ngz_persist_if(); /* create persistent interface info for NGZ */
138*12748SSowmini.Varadhan@oracle.COM 
13912016SGirish.Moodalbail@Sun.COM 	return (err);
14012016SGirish.Moodalbail@Sun.COM }
14112016SGirish.Moodalbail@Sun.COM 
14212016SGirish.Moodalbail@Sun.COM static int
14312016SGirish.Moodalbail@Sun.COM ipmgmt_door_init()
14412016SGirish.Moodalbail@Sun.COM {
14512016SGirish.Moodalbail@Sun.COM 	int fd;
14612016SGirish.Moodalbail@Sun.COM 	int err;
14712016SGirish.Moodalbail@Sun.COM 
14812016SGirish.Moodalbail@Sun.COM 	/* create the door file for ipmgmtd */
14912016SGirish.Moodalbail@Sun.COM 	if ((fd = open(IPMGMT_DOOR, O_CREAT|O_RDONLY, IPADM_FILE_MODE)) == -1) {
15012016SGirish.Moodalbail@Sun.COM 		err = errno;
15112016SGirish.Moodalbail@Sun.COM 		ipmgmt_log(LOG_ERR, "could not open %s: %s",
15212016SGirish.Moodalbail@Sun.COM 		    IPMGMT_DOOR, strerror(err));
15312016SGirish.Moodalbail@Sun.COM 		return (err);
15412016SGirish.Moodalbail@Sun.COM 	}
15512016SGirish.Moodalbail@Sun.COM 	(void) close(fd);
15612016SGirish.Moodalbail@Sun.COM 
15712016SGirish.Moodalbail@Sun.COM 	if ((ipmgmt_door_fd = door_create(ipmgmt_handler, NULL,
15812016SGirish.Moodalbail@Sun.COM 	    DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) {
15912016SGirish.Moodalbail@Sun.COM 		err = errno;
16012016SGirish.Moodalbail@Sun.COM 		ipmgmt_log(LOG_ERR, "failed to create door: %s", strerror(err));
16112016SGirish.Moodalbail@Sun.COM 		return (err);
16212016SGirish.Moodalbail@Sun.COM 	}
16312016SGirish.Moodalbail@Sun.COM 	/*
16412016SGirish.Moodalbail@Sun.COM 	 * fdetach first in case a previous daemon instance exited
16512016SGirish.Moodalbail@Sun.COM 	 * ungracefully.
16612016SGirish.Moodalbail@Sun.COM 	 */
16712016SGirish.Moodalbail@Sun.COM 	(void) fdetach(IPMGMT_DOOR);
16812016SGirish.Moodalbail@Sun.COM 	if (fattach(ipmgmt_door_fd, IPMGMT_DOOR) != 0) {
16912016SGirish.Moodalbail@Sun.COM 		err = errno;
17012016SGirish.Moodalbail@Sun.COM 		ipmgmt_log(LOG_ERR, "failed to attach door to %s: %s",
17112016SGirish.Moodalbail@Sun.COM 		    IPMGMT_DOOR, strerror(err));
17212016SGirish.Moodalbail@Sun.COM 		goto fail;
17312016SGirish.Moodalbail@Sun.COM 	}
17412016SGirish.Moodalbail@Sun.COM 	return (0);
17512016SGirish.Moodalbail@Sun.COM fail:
17612016SGirish.Moodalbail@Sun.COM 	(void) door_revoke(ipmgmt_door_fd);
17712016SGirish.Moodalbail@Sun.COM 	ipmgmt_door_fd = -1;
17812016SGirish.Moodalbail@Sun.COM 	return (err);
17912016SGirish.Moodalbail@Sun.COM }
18012016SGirish.Moodalbail@Sun.COM 
18112016SGirish.Moodalbail@Sun.COM static void
18212016SGirish.Moodalbail@Sun.COM ipmgmt_door_fini()
18312016SGirish.Moodalbail@Sun.COM {
18412016SGirish.Moodalbail@Sun.COM 	if (ipmgmt_door_fd == -1)
18512016SGirish.Moodalbail@Sun.COM 		return;
18612016SGirish.Moodalbail@Sun.COM 
18712016SGirish.Moodalbail@Sun.COM 	(void) fdetach(IPMGMT_DOOR);
18812016SGirish.Moodalbail@Sun.COM 	if (door_revoke(ipmgmt_door_fd) == -1) {
18912016SGirish.Moodalbail@Sun.COM 		ipmgmt_log(LOG_ERR, "failed to revoke access to door %s: %s",
19012016SGirish.Moodalbail@Sun.COM 		    IPMGMT_DOOR, strerror(errno));
19112016SGirish.Moodalbail@Sun.COM 	}
19212016SGirish.Moodalbail@Sun.COM }
19312016SGirish.Moodalbail@Sun.COM 
19412016SGirish.Moodalbail@Sun.COM static int
19512016SGirish.Moodalbail@Sun.COM ipmgmt_init()
19612016SGirish.Moodalbail@Sun.COM {
19712016SGirish.Moodalbail@Sun.COM 	int err;
19812016SGirish.Moodalbail@Sun.COM 
19912016SGirish.Moodalbail@Sun.COM 	if (signal(SIGTERM, ipmgmt_exit) == SIG_ERR ||
20012016SGirish.Moodalbail@Sun.COM 	    signal(SIGINT, ipmgmt_exit) == SIG_ERR) {
20112016SGirish.Moodalbail@Sun.COM 		err = errno;
20212016SGirish.Moodalbail@Sun.COM 		ipmgmt_log(LOG_ERR, "signal() for SIGTERM/INT failed: %s",
20312016SGirish.Moodalbail@Sun.COM 		    strerror(err));
20412016SGirish.Moodalbail@Sun.COM 		return (err);
20512016SGirish.Moodalbail@Sun.COM 	}
20612016SGirish.Moodalbail@Sun.COM 	if ((err = ipmgmt_db_init()) != 0 || (err = ipmgmt_door_init()) != 0)
20712016SGirish.Moodalbail@Sun.COM 		return (err);
20812016SGirish.Moodalbail@Sun.COM 	return (0);
20912016SGirish.Moodalbail@Sun.COM }
21012016SGirish.Moodalbail@Sun.COM 
21112016SGirish.Moodalbail@Sun.COM /*
21212016SGirish.Moodalbail@Sun.COM  * This is called by the child process to inform the parent process to
21312016SGirish.Moodalbail@Sun.COM  * exit with the given return value.
21412016SGirish.Moodalbail@Sun.COM  */
21512016SGirish.Moodalbail@Sun.COM static void
21612016SGirish.Moodalbail@Sun.COM ipmgmt_inform_parent_exit(int rv)
21712016SGirish.Moodalbail@Sun.COM {
21812016SGirish.Moodalbail@Sun.COM 	if (write(pfds[1], &rv, sizeof (int)) != sizeof (int)) {
21912016SGirish.Moodalbail@Sun.COM 		ipmgmt_log(LOG_WARNING,
22012016SGirish.Moodalbail@Sun.COM 		    "failed to inform parent process of status: %s",
22112016SGirish.Moodalbail@Sun.COM 		    strerror(errno));
22212016SGirish.Moodalbail@Sun.COM 		(void) close(pfds[1]);
22312016SGirish.Moodalbail@Sun.COM 		exit(EXIT_FAILURE);
22412016SGirish.Moodalbail@Sun.COM 	}
22512016SGirish.Moodalbail@Sun.COM 	(void) close(pfds[1]);
22612016SGirish.Moodalbail@Sun.COM }
22712016SGirish.Moodalbail@Sun.COM 
22812016SGirish.Moodalbail@Sun.COM /*ARGSUSED*/
22912016SGirish.Moodalbail@Sun.COM static void
23012016SGirish.Moodalbail@Sun.COM ipmgmt_exit(int signo)
23112016SGirish.Moodalbail@Sun.COM {
23212016SGirish.Moodalbail@Sun.COM 	(void) close(pfds[1]);
23312016SGirish.Moodalbail@Sun.COM 	ipmgmt_door_fini();
23412016SGirish.Moodalbail@Sun.COM 	exit(EXIT_FAILURE);
23512016SGirish.Moodalbail@Sun.COM }
23612016SGirish.Moodalbail@Sun.COM 
23712016SGirish.Moodalbail@Sun.COM /*
238*12748SSowmini.Varadhan@oracle.COM  * On the first reboot after installation of an ipkg zone,
239*12748SSowmini.Varadhan@oracle.COM  * ipmgmt_persist_if_cb() is used in non-global zones to track the interfaces
240*12748SSowmini.Varadhan@oracle.COM  * that have IP address configuration assignments from the global zone.
241*12748SSowmini.Varadhan@oracle.COM  * Persistent configuration for the interfaces is created on the first boot
242*12748SSowmini.Varadhan@oracle.COM  * by ipmgmtd, and the addresses assigned to the interfaces by the GZ
243*12748SSowmini.Varadhan@oracle.COM  * will be subsequently configured when the interface is enabled.
244*12748SSowmini.Varadhan@oracle.COM  * Note that ipmgmt_persist_if_cb() only sets up a list of interfaces
245*12748SSowmini.Varadhan@oracle.COM  * that need to be persisted- the actual update of the ipadm data-store happens
246*12748SSowmini.Varadhan@oracle.COM  * in ipmgmt_persist_if() after the appropriate privs/uid state has been set up.
247*12748SSowmini.Varadhan@oracle.COM  */
248*12748SSowmini.Varadhan@oracle.COM static void
249*12748SSowmini.Varadhan@oracle.COM ipmgmt_persist_if_cb(char *ifname, boolean_t v4, boolean_t v6)
250*12748SSowmini.Varadhan@oracle.COM {
251*12748SSowmini.Varadhan@oracle.COM 	ipmgmt_pif_t *pif;
252*12748SSowmini.Varadhan@oracle.COM 
253*12748SSowmini.Varadhan@oracle.COM 	pif = calloc(1, sizeof (*pif));
254*12748SSowmini.Varadhan@oracle.COM 	if (pif == NULL) {
255*12748SSowmini.Varadhan@oracle.COM 		ipmgmt_log(LOG_WARNING,
256*12748SSowmini.Varadhan@oracle.COM 		    "Could not allocate memory to configure %s", ifname);
257*12748SSowmini.Varadhan@oracle.COM 		return;
258*12748SSowmini.Varadhan@oracle.COM 	}
259*12748SSowmini.Varadhan@oracle.COM 	(void) strlcpy(pif->pif_ifname, ifname, sizeof (pif->pif_ifname));
260*12748SSowmini.Varadhan@oracle.COM 	pif->pif_v4 = v4;
261*12748SSowmini.Varadhan@oracle.COM 	pif->pif_v6 = v6;
262*12748SSowmini.Varadhan@oracle.COM 	pif->pif_next = ngz_pifs;
263*12748SSowmini.Varadhan@oracle.COM 	ngz_pifs = pif;
264*12748SSowmini.Varadhan@oracle.COM }
265*12748SSowmini.Varadhan@oracle.COM 
266*12748SSowmini.Varadhan@oracle.COM /*
267*12748SSowmini.Varadhan@oracle.COM  * ipmgmt_ngz_init() initializes exclusive-IP stack non-global zones by
268*12748SSowmini.Varadhan@oracle.COM  * extracting configuration that has been saved in the kernel and applying
269*12748SSowmini.Varadhan@oracle.COM  * it at zone boot.
270*12748SSowmini.Varadhan@oracle.COM  */
271*12748SSowmini.Varadhan@oracle.COM static void
272*12748SSowmini.Varadhan@oracle.COM ipmgmt_ngz_init()
273*12748SSowmini.Varadhan@oracle.COM {
274*12748SSowmini.Varadhan@oracle.COM 	zoneid_t zoneid;
275*12748SSowmini.Varadhan@oracle.COM 	boolean_t firstboot = B_TRUE, s10c = B_FALSE;
276*12748SSowmini.Varadhan@oracle.COM 	char brand[MAXNAMELEN];
277*12748SSowmini.Varadhan@oracle.COM 	ipadm_status_t ipstatus;
278*12748SSowmini.Varadhan@oracle.COM 
279*12748SSowmini.Varadhan@oracle.COM 	zoneid = getzoneid();
280*12748SSowmini.Varadhan@oracle.COM 	if (zoneid != GLOBAL_ZONEID) {
281*12748SSowmini.Varadhan@oracle.COM 
282*12748SSowmini.Varadhan@oracle.COM 		if (zone_getattr(zoneid, ZONE_ATTR_BRAND, brand,
283*12748SSowmini.Varadhan@oracle.COM 		    sizeof (brand)) < 0) {
284*12748SSowmini.Varadhan@oracle.COM 			ipmgmt_log(LOG_ERR, "Could not get brand name");
285*12748SSowmini.Varadhan@oracle.COM 			return;
286*12748SSowmini.Varadhan@oracle.COM 		}
287*12748SSowmini.Varadhan@oracle.COM 		/*
288*12748SSowmini.Varadhan@oracle.COM 		 * firstboot is always true for S10C zones, where ipadm is not
289*12748SSowmini.Varadhan@oracle.COM 		 * available for restoring persistent configuration.
290*12748SSowmini.Varadhan@oracle.COM 		 */
291*12748SSowmini.Varadhan@oracle.COM 		if (strcmp(brand, NATIVE_BRAND_NAME) == 0)
292*12748SSowmini.Varadhan@oracle.COM 			firstboot = ipmgmt_first_boot();
293*12748SSowmini.Varadhan@oracle.COM 		else
294*12748SSowmini.Varadhan@oracle.COM 			s10c = B_TRUE;
295*12748SSowmini.Varadhan@oracle.COM 
296*12748SSowmini.Varadhan@oracle.COM 		if (!firstboot)
297*12748SSowmini.Varadhan@oracle.COM 			return;
298*12748SSowmini.Varadhan@oracle.COM 
299*12748SSowmini.Varadhan@oracle.COM 		ipstatus = ipadm_open(&iph, IPH_IPMGMTD);
300*12748SSowmini.Varadhan@oracle.COM 		if (ipstatus != IPADM_SUCCESS) {
301*12748SSowmini.Varadhan@oracle.COM 			ipmgmt_log(LOG_ERR, "could not open ipadm handle",
302*12748SSowmini.Varadhan@oracle.COM 			    ipadm_status2str(ipstatus));
303*12748SSowmini.Varadhan@oracle.COM 			return;
304*12748SSowmini.Varadhan@oracle.COM 		}
305*12748SSowmini.Varadhan@oracle.COM 		/*
306*12748SSowmini.Varadhan@oracle.COM 		 * Only pass down the callback to persist the interface
307*12748SSowmini.Varadhan@oracle.COM 		 * for NATIVE (ipkg) zones.
308*12748SSowmini.Varadhan@oracle.COM 		 */
309*12748SSowmini.Varadhan@oracle.COM 		(void) ipadm_init_net_from_gz(iph, NULL,
310*12748SSowmini.Varadhan@oracle.COM 		    (s10c ? NULL : ipmgmt_persist_if_cb));
311*12748SSowmini.Varadhan@oracle.COM 		ipadm_close(iph);
312*12748SSowmini.Varadhan@oracle.COM 	}
313*12748SSowmini.Varadhan@oracle.COM }
314*12748SSowmini.Varadhan@oracle.COM 
315*12748SSowmini.Varadhan@oracle.COM /*
316*12748SSowmini.Varadhan@oracle.COM  * Set the uid of this daemon to the "netadm" user. Finish the following
31712016SGirish.Moodalbail@Sun.COM  * operations before setuid() because they need root privileges:
31812016SGirish.Moodalbail@Sun.COM  *
31912016SGirish.Moodalbail@Sun.COM  *    - create the /etc/svc/volatile/ipadm directory;
320*12748SSowmini.Varadhan@oracle.COM  *    - change its uid/gid to "netadm"/"netadm";
32112016SGirish.Moodalbail@Sun.COM  */
32212016SGirish.Moodalbail@Sun.COM static int
32312016SGirish.Moodalbail@Sun.COM ipmgmt_init_privileges()
32412016SGirish.Moodalbail@Sun.COM {
32512016SGirish.Moodalbail@Sun.COM 	struct stat	statbuf;
32612016SGirish.Moodalbail@Sun.COM 	int err;
32712016SGirish.Moodalbail@Sun.COM 
32812016SGirish.Moodalbail@Sun.COM 	/* create the IPADM_TMPFS_DIR directory */
32912016SGirish.Moodalbail@Sun.COM 	if (stat(IPADM_TMPFS_DIR, &statbuf) < 0) {
33012016SGirish.Moodalbail@Sun.COM 		if (mkdir(IPADM_TMPFS_DIR, (mode_t)0755) < 0) {
33112016SGirish.Moodalbail@Sun.COM 			err = errno;
33212016SGirish.Moodalbail@Sun.COM 			goto fail;
33312016SGirish.Moodalbail@Sun.COM 		}
33412016SGirish.Moodalbail@Sun.COM 	} else {
33512016SGirish.Moodalbail@Sun.COM 		if ((statbuf.st_mode & S_IFMT) != S_IFDIR) {
33612016SGirish.Moodalbail@Sun.COM 			err = ENOTDIR;
33712016SGirish.Moodalbail@Sun.COM 			goto fail;
33812016SGirish.Moodalbail@Sun.COM 		}
33912016SGirish.Moodalbail@Sun.COM 	}
34012016SGirish.Moodalbail@Sun.COM 
34112016SGirish.Moodalbail@Sun.COM 	if ((chmod(IPADM_TMPFS_DIR, 0755) < 0) ||
34212016SGirish.Moodalbail@Sun.COM 	    (chown(IPADM_TMPFS_DIR, UID_NETADM, GID_NETADM) < 0)) {
34312016SGirish.Moodalbail@Sun.COM 		err = errno;
34412016SGirish.Moodalbail@Sun.COM 		goto fail;
34512016SGirish.Moodalbail@Sun.COM 	}
34612016SGirish.Moodalbail@Sun.COM 
34712016SGirish.Moodalbail@Sun.COM 	/*
348*12748SSowmini.Varadhan@oracle.COM 	 * initialize any NGZ specific network information before dropping
349*12748SSowmini.Varadhan@oracle.COM 	 * privileges. We need these privileges to plumb IP interfaces handed
350*12748SSowmini.Varadhan@oracle.COM 	 * down from the GZ (for dlpi_open() etc.) and also to configure the
351*12748SSowmini.Varadhan@oracle.COM 	 * address itself (for any IPI_PRIV ioctls like SLIFADDR)
352*12748SSowmini.Varadhan@oracle.COM 	 */
353*12748SSowmini.Varadhan@oracle.COM 	ipmgmt_ngz_init();
354*12748SSowmini.Varadhan@oracle.COM 
355*12748SSowmini.Varadhan@oracle.COM 	/*
35612016SGirish.Moodalbail@Sun.COM 	 * limit the privileges of this daemon and set the uid of this
35712016SGirish.Moodalbail@Sun.COM 	 * daemon to UID_NETADM
35812016SGirish.Moodalbail@Sun.COM 	 */
35912016SGirish.Moodalbail@Sun.COM 	if (__init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET, UID_NETADM,
36012016SGirish.Moodalbail@Sun.COM 	    GID_NETADM, NULL) == -1) {
36112016SGirish.Moodalbail@Sun.COM 		err = EPERM;
36212016SGirish.Moodalbail@Sun.COM 		goto fail;
36312016SGirish.Moodalbail@Sun.COM 	}
36412016SGirish.Moodalbail@Sun.COM 
36512016SGirish.Moodalbail@Sun.COM 	return (0);
36612016SGirish.Moodalbail@Sun.COM fail:
36712016SGirish.Moodalbail@Sun.COM 	(void) ipmgmt_log(LOG_ERR, "failed to initialize the daemon: %s",
36812016SGirish.Moodalbail@Sun.COM 	    strerror(err));
36912016SGirish.Moodalbail@Sun.COM 	return (err);
37012016SGirish.Moodalbail@Sun.COM }
37112016SGirish.Moodalbail@Sun.COM 
37212016SGirish.Moodalbail@Sun.COM /*
37312016SGirish.Moodalbail@Sun.COM  * Keep the pfds fd open, close other fds.
37412016SGirish.Moodalbail@Sun.COM  */
37512016SGirish.Moodalbail@Sun.COM /*ARGSUSED*/
37612016SGirish.Moodalbail@Sun.COM static int
37712016SGirish.Moodalbail@Sun.COM closefunc(void *arg, int fd)
37812016SGirish.Moodalbail@Sun.COM {
37912016SGirish.Moodalbail@Sun.COM 	if (fd != pfds[1])
38012016SGirish.Moodalbail@Sun.COM 		(void) close(fd);
38112016SGirish.Moodalbail@Sun.COM 	return (0);
38212016SGirish.Moodalbail@Sun.COM }
38312016SGirish.Moodalbail@Sun.COM 
38412016SGirish.Moodalbail@Sun.COM /*
38512016SGirish.Moodalbail@Sun.COM  * We cannot use libc's daemon() because the door we create is associated with
38612016SGirish.Moodalbail@Sun.COM  * the process ID. If we create the door before the call to daemon(), it will
38712016SGirish.Moodalbail@Sun.COM  * be associated with the parent and it's incorrect. On the other hand if we
38812016SGirish.Moodalbail@Sun.COM  * create the door later, after the call to daemon(), parent process exits
38912016SGirish.Moodalbail@Sun.COM  * early and gives a false notion to SMF that 'ipmgmtd' is up and running,
39012016SGirish.Moodalbail@Sun.COM  * which is incorrect. So, we have our own daemon() equivalent.
39112016SGirish.Moodalbail@Sun.COM  */
39212016SGirish.Moodalbail@Sun.COM static boolean_t
39312016SGirish.Moodalbail@Sun.COM ipmgmt_daemonize(void)
39412016SGirish.Moodalbail@Sun.COM {
39512016SGirish.Moodalbail@Sun.COM 	pid_t pid;
39612016SGirish.Moodalbail@Sun.COM 	int rv;
39712016SGirish.Moodalbail@Sun.COM 
39812016SGirish.Moodalbail@Sun.COM 	if (pipe(pfds) < 0) {
39912016SGirish.Moodalbail@Sun.COM 		(void) fprintf(stderr, "%s: pipe() failed: %s\n",
40012016SGirish.Moodalbail@Sun.COM 		    progname, strerror(errno));
40112016SGirish.Moodalbail@Sun.COM 		exit(EXIT_FAILURE);
40212016SGirish.Moodalbail@Sun.COM 	}
40312016SGirish.Moodalbail@Sun.COM 
40412016SGirish.Moodalbail@Sun.COM 	if ((pid = fork()) == -1) {
40512016SGirish.Moodalbail@Sun.COM 		(void) fprintf(stderr, "%s: fork() failed: %s\n",
40612016SGirish.Moodalbail@Sun.COM 		    progname, strerror(errno));
40712016SGirish.Moodalbail@Sun.COM 		exit(EXIT_FAILURE);
40812016SGirish.Moodalbail@Sun.COM 	} else if (pid > 0) { /* Parent */
40912016SGirish.Moodalbail@Sun.COM 		(void) close(pfds[1]);
41012016SGirish.Moodalbail@Sun.COM 
41112016SGirish.Moodalbail@Sun.COM 		/*
41212016SGirish.Moodalbail@Sun.COM 		 * Parent should not exit early, it should wait for the child
41312016SGirish.Moodalbail@Sun.COM 		 * to return Success/Failure. If the parent exits early, then
41412016SGirish.Moodalbail@Sun.COM 		 * SMF will think 'ipmgmtd' is up and would start all the
41512016SGirish.Moodalbail@Sun.COM 		 * depended services.
41612016SGirish.Moodalbail@Sun.COM 		 *
41712016SGirish.Moodalbail@Sun.COM 		 * If the child process exits unexpectedly, read() returns -1.
41812016SGirish.Moodalbail@Sun.COM 		 */
41912016SGirish.Moodalbail@Sun.COM 		if (read(pfds[0], &rv, sizeof (int)) != sizeof (int)) {
42012016SGirish.Moodalbail@Sun.COM 			(void) kill(pid, SIGKILL);
42112016SGirish.Moodalbail@Sun.COM 			rv = EXIT_FAILURE;
42212016SGirish.Moodalbail@Sun.COM 		}
42312016SGirish.Moodalbail@Sun.COM 
42412016SGirish.Moodalbail@Sun.COM 		(void) close(pfds[0]);
42512016SGirish.Moodalbail@Sun.COM 		exit(rv);
42612016SGirish.Moodalbail@Sun.COM 	}
42712016SGirish.Moodalbail@Sun.COM 
42812016SGirish.Moodalbail@Sun.COM 	/* Child */
42912016SGirish.Moodalbail@Sun.COM 	(void) close(pfds[0]);
43012016SGirish.Moodalbail@Sun.COM 	(void) setsid();
43112016SGirish.Moodalbail@Sun.COM 
43212016SGirish.Moodalbail@Sun.COM 	/* close all files except pfds[1] */
43312016SGirish.Moodalbail@Sun.COM 	(void) fdwalk(closefunc, NULL);
43412016SGirish.Moodalbail@Sun.COM 	(void) chdir("/");
43512016SGirish.Moodalbail@Sun.COM 	openlog(progname, LOG_PID, LOG_DAEMON);
43612016SGirish.Moodalbail@Sun.COM 	return (B_TRUE);
43712016SGirish.Moodalbail@Sun.COM }
43812016SGirish.Moodalbail@Sun.COM 
43912016SGirish.Moodalbail@Sun.COM int
44012016SGirish.Moodalbail@Sun.COM main(int argc, char *argv[])
44112016SGirish.Moodalbail@Sun.COM {
44212016SGirish.Moodalbail@Sun.COM 	int opt;
44312016SGirish.Moodalbail@Sun.COM 	boolean_t fg = B_FALSE;
44412016SGirish.Moodalbail@Sun.COM 
44512016SGirish.Moodalbail@Sun.COM 	progname = strrchr(argv[0], '/');
44612016SGirish.Moodalbail@Sun.COM 	if (progname != NULL)
44712016SGirish.Moodalbail@Sun.COM 		progname++;
44812016SGirish.Moodalbail@Sun.COM 	else
44912016SGirish.Moodalbail@Sun.COM 		progname = argv[0];
45012016SGirish.Moodalbail@Sun.COM 
45112016SGirish.Moodalbail@Sun.COM 	/* Process options */
45212016SGirish.Moodalbail@Sun.COM 	while ((opt = getopt(argc, argv, "f")) != EOF) {
45312016SGirish.Moodalbail@Sun.COM 		switch (opt) {
45412016SGirish.Moodalbail@Sun.COM 		case 'f':
45512016SGirish.Moodalbail@Sun.COM 			fg = B_TRUE;
45612016SGirish.Moodalbail@Sun.COM 			break;
45712016SGirish.Moodalbail@Sun.COM 		default:
45812016SGirish.Moodalbail@Sun.COM 			(void) fprintf(stderr, "Usage: %s [-f]\n", progname);
45912016SGirish.Moodalbail@Sun.COM 			return (EXIT_FAILURE);
46012016SGirish.Moodalbail@Sun.COM 		}
46112016SGirish.Moodalbail@Sun.COM 	}
46212016SGirish.Moodalbail@Sun.COM 
46312016SGirish.Moodalbail@Sun.COM 	if (!fg && getenv("SMF_FMRI") == NULL) {
46412016SGirish.Moodalbail@Sun.COM 		(void) fprintf(stderr,
46512016SGirish.Moodalbail@Sun.COM 		    "ipmgmtd is a smf(5) managed service and cannot be run "
46612016SGirish.Moodalbail@Sun.COM 		    "from the command line.\n");
46712016SGirish.Moodalbail@Sun.COM 		return (EINVAL);
46812016SGirish.Moodalbail@Sun.COM 	}
46912016SGirish.Moodalbail@Sun.COM 
47012016SGirish.Moodalbail@Sun.COM 	if (!fg && !ipmgmt_daemonize())
47112016SGirish.Moodalbail@Sun.COM 		return (EXIT_FAILURE);
47212016SGirish.Moodalbail@Sun.COM 
47312016SGirish.Moodalbail@Sun.COM 	if (ipmgmt_init_privileges() != 0)
47412016SGirish.Moodalbail@Sun.COM 		goto child_out;
47512016SGirish.Moodalbail@Sun.COM 
47612016SGirish.Moodalbail@Sun.COM 	if (ipmgmt_init() != 0)
47712016SGirish.Moodalbail@Sun.COM 		goto child_out;
47812016SGirish.Moodalbail@Sun.COM 
47912016SGirish.Moodalbail@Sun.COM 	/* Inform the parent process that it can successfully exit */
48012016SGirish.Moodalbail@Sun.COM 	ipmgmt_inform_parent_exit(EXIT_SUCCESS);
48112016SGirish.Moodalbail@Sun.COM 
48212016SGirish.Moodalbail@Sun.COM 	for (;;)
48312016SGirish.Moodalbail@Sun.COM 		(void) pause();
48412016SGirish.Moodalbail@Sun.COM 
48512016SGirish.Moodalbail@Sun.COM child_out:
48612016SGirish.Moodalbail@Sun.COM 	/* return from main() forcibly exits an MT process */
48712016SGirish.Moodalbail@Sun.COM 	ipmgmt_inform_parent_exit(EXIT_FAILURE);
48812016SGirish.Moodalbail@Sun.COM 	return (EXIT_FAILURE);
48912016SGirish.Moodalbail@Sun.COM }
490*12748SSowmini.Varadhan@oracle.COM 
491*12748SSowmini.Varadhan@oracle.COM /*
492*12748SSowmini.Varadhan@oracle.COM  * Return TRUE if `ifname' has persistent configuration for the `af' address
493*12748SSowmini.Varadhan@oracle.COM  * family in the datastore
494*12748SSowmini.Varadhan@oracle.COM  */
495*12748SSowmini.Varadhan@oracle.COM static boolean_t
496*12748SSowmini.Varadhan@oracle.COM ipmgmt_persist_if_exists(char *ifname, sa_family_t af)
497*12748SSowmini.Varadhan@oracle.COM {
498*12748SSowmini.Varadhan@oracle.COM 	ipmgmt_getif_cbarg_t cbarg;
499*12748SSowmini.Varadhan@oracle.COM 	boolean_t exists = B_FALSE;
500*12748SSowmini.Varadhan@oracle.COM 	ipadm_if_info_t *ifp;
501*12748SSowmini.Varadhan@oracle.COM 
502*12748SSowmini.Varadhan@oracle.COM 	bzero(&cbarg, sizeof (cbarg));
503*12748SSowmini.Varadhan@oracle.COM 	cbarg.cb_ifname = ifname;
504*12748SSowmini.Varadhan@oracle.COM 	(void) ipmgmt_db_walk(ipmgmt_db_getif, &cbarg, IPADM_DB_READ);
505*12748SSowmini.Varadhan@oracle.COM 	if ((ifp = cbarg.cb_ifinfo) != NULL) {
506*12748SSowmini.Varadhan@oracle.COM 		if ((af == AF_INET && (ifp->ifi_pflags & IFIF_IPV4)) ||
507*12748SSowmini.Varadhan@oracle.COM 		    (af == AF_INET6 && (ifp->ifi_pflags & IFIF_IPV6))) {
508*12748SSowmini.Varadhan@oracle.COM 			exists = B_TRUE;
509*12748SSowmini.Varadhan@oracle.COM 		}
510*12748SSowmini.Varadhan@oracle.COM 	}
511*12748SSowmini.Varadhan@oracle.COM 	free(ifp);
512*12748SSowmini.Varadhan@oracle.COM 	return (exists);
513*12748SSowmini.Varadhan@oracle.COM }
514*12748SSowmini.Varadhan@oracle.COM 
515*12748SSowmini.Varadhan@oracle.COM /*
516*12748SSowmini.Varadhan@oracle.COM  * Persist any NGZ interfaces assigned to us from the global zone if they do
517*12748SSowmini.Varadhan@oracle.COM  * not already exist in the persistent db. We need to
518*12748SSowmini.Varadhan@oracle.COM  * do this before any calls to ipadm_enable_if() can succeed (i.e.,
519*12748SSowmini.Varadhan@oracle.COM  * before opening up for door_calls), and after setuid to 'netadm' so that
520*12748SSowmini.Varadhan@oracle.COM  * the persistent db is created with the right permissions.
521*12748SSowmini.Varadhan@oracle.COM  */
522*12748SSowmini.Varadhan@oracle.COM static void
523*12748SSowmini.Varadhan@oracle.COM ipmgmt_ngz_persist_if()
524*12748SSowmini.Varadhan@oracle.COM {
525*12748SSowmini.Varadhan@oracle.COM 	ipmgmt_pif_t *pif, *next;
526*12748SSowmini.Varadhan@oracle.COM 	ipmgmt_if_arg_t ifarg;
527*12748SSowmini.Varadhan@oracle.COM 
528*12748SSowmini.Varadhan@oracle.COM 	for (pif = ngz_pifs; pif != NULL; pif = next) {
529*12748SSowmini.Varadhan@oracle.COM 		next = pif->pif_next;
530*12748SSowmini.Varadhan@oracle.COM 		bzero(&ifarg, sizeof (ifarg));
531*12748SSowmini.Varadhan@oracle.COM 		(void) strlcpy(ifarg.ia_ifname, pif->pif_ifname,
532*12748SSowmini.Varadhan@oracle.COM 		    sizeof (ifarg.ia_ifname));
533*12748SSowmini.Varadhan@oracle.COM 		ifarg.ia_flags = IPMGMT_PERSIST;
534*12748SSowmini.Varadhan@oracle.COM 		if (pif->pif_v4 &&
535*12748SSowmini.Varadhan@oracle.COM 		    !ipmgmt_persist_if_exists(pif->pif_ifname, AF_INET)) {
536*12748SSowmini.Varadhan@oracle.COM 			ifarg.ia_family = AF_INET;
537*12748SSowmini.Varadhan@oracle.COM 			(void) ipmgmt_persist_if(&ifarg);
538*12748SSowmini.Varadhan@oracle.COM 		}
539*12748SSowmini.Varadhan@oracle.COM 		if (pif->pif_v6 &&
540*12748SSowmini.Varadhan@oracle.COM 		    !ipmgmt_persist_if_exists(pif->pif_ifname, AF_INET6)) {
541*12748SSowmini.Varadhan@oracle.COM 			ifarg.ia_family = AF_INET6;
542*12748SSowmini.Varadhan@oracle.COM 			(void) ipmgmt_persist_if(&ifarg);
543*12748SSowmini.Varadhan@oracle.COM 		}
544*12748SSowmini.Varadhan@oracle.COM 		free(pif);
545*12748SSowmini.Varadhan@oracle.COM 	}
546*12748SSowmini.Varadhan@oracle.COM 	ngz_pifs = NULL; /* no red herrings */
547*12748SSowmini.Varadhan@oracle.COM }
548