xref: /illumos-gate/usr/src/cmd/cmd-inet/lib/nwamd/util.c (revision f6da83d4)
1d71dbb73Sjbeck /*
2d71dbb73Sjbeck  * CDDL HEADER START
3d71dbb73Sjbeck  *
4d71dbb73Sjbeck  * The contents of this file are subject to the terms of the
5d71dbb73Sjbeck  * Common Development and Distribution License (the "License").
6d71dbb73Sjbeck  * You may not use this file except in compliance with the License.
7d71dbb73Sjbeck  *
8d71dbb73Sjbeck  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9d71dbb73Sjbeck  * or http://www.opensolaris.org/os/licensing.
10d71dbb73Sjbeck  * See the License for the specific language governing permissions
11d71dbb73Sjbeck  * and limitations under the License.
12d71dbb73Sjbeck  *
13d71dbb73Sjbeck  * When distributing Covered Code, include this CDDL HEADER in each
14d71dbb73Sjbeck  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15d71dbb73Sjbeck  * If applicable, add the following below this CDDL HEADER, with the
16d71dbb73Sjbeck  * fields enclosed by brackets "[]" replaced with your own identifying
17d71dbb73Sjbeck  * information: Portions Copyright [yyyy] [name of copyright owner]
18d71dbb73Sjbeck  *
19d71dbb73Sjbeck  * CDDL HEADER END
20d71dbb73Sjbeck  */
22d71dbb73Sjbeck /*
23*f6da83d4SAnurag S. Maskey  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24d71dbb73Sjbeck  */
26d71dbb73Sjbeck /*
276ba597c5SAnurag S. Maskey  * util.c contains a set of miscellaneous utility functions which,
286ba597c5SAnurag S. Maskey  * among other things:
29d71dbb73Sjbeck  * - start a child process
30d71dbb73Sjbeck  * - look up the zone name
316ba597c5SAnurag S. Maskey  * - look up/set SMF properties
326ba597c5SAnurag S. Maskey  * - drop/escalate privs
33d71dbb73Sjbeck  */
356ba597c5SAnurag S. Maskey #include <assert.h>
366ba597c5SAnurag S. Maskey #include <errno.h>
376ba597c5SAnurag S. Maskey #include <libdllink.h>
386ba597c5SAnurag S. Maskey #include <limits.h>
396ba597c5SAnurag S. Maskey #include <libscf.h>
406ba597c5SAnurag S. Maskey #include <net/if.h>
416ba597c5SAnurag S. Maskey #include <pthread.h>
426ba597c5SAnurag S. Maskey #include <pwd.h>
436ba597c5SAnurag S. Maskey #include <spawn.h>
44d71dbb73Sjbeck #include <stdarg.h>
45d71dbb73Sjbeck #include <stdio.h>
46d71dbb73Sjbeck #include <stdlib.h>
47d71dbb73Sjbeck #include <string.h>
486ba597c5SAnurag S. Maskey #include <strings.h>
49d71dbb73Sjbeck #include <stropts.h>
50d71dbb73Sjbeck #include <sys/socket.h>
516ba597c5SAnurag S. Maskey #include <sys/sockio.h>
526ba597c5SAnurag S. Maskey #include <sys/types.h>
536ba597c5SAnurag S. Maskey #include <unistd.h>
54d71dbb73Sjbeck #include <wait.h>
55d71dbb73Sjbeck #include <zone.h>
576ba597c5SAnurag S. Maskey #include "util.h"
586ba597c5SAnurag S. Maskey #include "llp.h"
60d71dbb73Sjbeck extern char **environ;
616ba597c5SAnurag S. Maskey extern sigset_t original_sigmask;
636ba597c5SAnurag S. Maskey /*
646ba597c5SAnurag S. Maskey  * A holder for all the resources needed to get a property value
656ba597c5SAnurag S. Maskey  * using libscf.
666ba597c5SAnurag S. Maskey  */
676ba597c5SAnurag S. Maskey typedef struct scf_resources {
686ba597c5SAnurag S. Maskey 	scf_handle_t *sr_handle;
696ba597c5SAnurag S. Maskey 	scf_instance_t *sr_inst;
706ba597c5SAnurag S. Maskey 	scf_snapshot_t *sr_snap;
716ba597c5SAnurag S. Maskey 	scf_propertygroup_t *sr_pg;
726ba597c5SAnurag S. Maskey 	scf_property_t *sr_prop;
736ba597c5SAnurag S. Maskey 	scf_value_t *sr_val;
746ba597c5SAnurag S. Maskey 	scf_transaction_t *sr_tx;
756ba597c5SAnurag S. Maskey 	scf_transaction_entry_t *sr_ent;
766ba597c5SAnurag S. Maskey } scf_resources_t;
776ba597c5SAnurag S. Maskey 
786ba597c5SAnurag S. Maskey static pthread_mutex_t uid_mutex = PTHREAD_MUTEX_INITIALIZER;
796ba597c5SAnurag S. Maskey static uid_t uid;
806ba597c5SAnurag S. Maskey static int uid_cnt;
826ba597c5SAnurag S. Maskey void
nwamd_escalate(void)8338f140aaSMichael Hunter nwamd_escalate(void) {
8438f140aaSMichael Hunter 	priv_set_t *priv_set;
8538f140aaSMichael Hunter 	priv_set = priv_str_to_set("zone", ",", NULL);
8638f140aaSMichael Hunter 
8738f140aaSMichael Hunter 	if (priv_set == NULL)
8838f140aaSMichael Hunter 		pfail("creating privilege set: %s", strerror(errno));
8938f140aaSMichael Hunter 
906ba597c5SAnurag S. Maskey 	(void) pthread_mutex_lock(&uid_mutex);
916ba597c5SAnurag S. Maskey 	if (uid == 0)
926ba597c5SAnurag S. Maskey 		uid = getuid();
936ba597c5SAnurag S. Maskey 	if (uid_cnt++ == 0) {
9438f140aaSMichael Hunter 		if (setppriv(PRIV_SET, PRIV_EFFECTIVE, priv_set) == -1) {
9538f140aaSMichael Hunter 			priv_freeset(priv_set);
9638f140aaSMichael Hunter 			pfail("setppriv effective: %s", strerror(errno));
9738f140aaSMichael Hunter 		}
98d71dbb73Sjbeck 	}
996ba597c5SAnurag S. Maskey 	(void) pthread_mutex_unlock(&uid_mutex);
10038f140aaSMichael Hunter 
10138f140aaSMichael Hunter 	priv_freeset(priv_set);
102d71dbb73Sjbeck }
104b00044a2SJames Carlson void
nwamd_deescalate(void)10538f140aaSMichael Hunter nwamd_deescalate(void) {
1066ba597c5SAnurag S. Maskey 	(void) pthread_mutex_lock(&uid_mutex);
1073773ed2dSAnurag S. Maskey 
1086ba597c5SAnurag S. Maskey 	assert(uid_cnt > 0);
1096ba597c5SAnurag S. Maskey 	if (--uid_cnt == 0) {
1103773ed2dSAnurag S. Maskey 		priv_set_t *priv_set, *allpriv_set;
1113773ed2dSAnurag S. Maskey 
11238f140aaSMichael Hunter 		/* build up our minimal set of privs. */
11338f140aaSMichael Hunter 		priv_set = priv_str_to_set("basic", ",", NULL);
11438f140aaSMichael Hunter 		allpriv_set = priv_str_to_set("zone", ",", NULL);
11538f140aaSMichael Hunter 		if (priv_set == NULL || allpriv_set == NULL)
11638f140aaSMichael Hunter 			pfail("converting privilege sets: %s", strerror(errno));
11738f140aaSMichael Hunter 
11838f140aaSMichael Hunter 		(void) priv_addset(priv_set, PRIV_FILE_CHOWN_SELF);
11938f140aaSMichael Hunter 		(void) priv_addset(priv_set, PRIV_FILE_DAC_READ);
12038f140aaSMichael Hunter 		(void) priv_addset(priv_set, PRIV_FILE_DAC_WRITE);
12138f140aaSMichael Hunter 		(void) priv_addset(priv_set, PRIV_NET_RAWACCESS);
12238f140aaSMichael Hunter 		(void) priv_addset(priv_set, PRIV_NET_PRIVADDR);
12338f140aaSMichael Hunter 		(void) priv_addset(priv_set, PRIV_PROC_AUDIT);
12438f140aaSMichael Hunter 		(void) priv_addset(priv_set, PRIV_PROC_OWNER);
12538f140aaSMichael Hunter 		(void) priv_addset(priv_set, PRIV_PROC_SETID);
12638f140aaSMichael Hunter 		(void) priv_addset(priv_set, PRIV_SYS_CONFIG);
12738f140aaSMichael Hunter 		(void) priv_addset(priv_set, PRIV_SYS_IP_CONFIG);
12838f140aaSMichael Hunter 		(void) priv_addset(priv_set, PRIV_SYS_IPC_CONFIG);
12938f140aaSMichael Hunter 		(void) priv_addset(priv_set, PRIV_SYS_MOUNT);
13038f140aaSMichael Hunter 		(void) priv_addset(priv_set, PRIV_SYS_NET_CONFIG);
13138f140aaSMichael Hunter 		(void) priv_addset(priv_set, PRIV_SYS_RES_CONFIG);
13238f140aaSMichael Hunter 		(void) priv_addset(priv_set, PRIV_SYS_RESOURCE);
13338f140aaSMichael Hunter 
13438f140aaSMichael Hunter 		/*
13538f140aaSMichael Hunter 		 * Since our zone might not have all these privs,
13638f140aaSMichael Hunter 		 * just ask for those that are available.
13738f140aaSMichael Hunter 		 */
13838f140aaSMichael Hunter 		priv_intersect(allpriv_set, priv_set);
13938f140aaSMichael Hunter 
14038f140aaSMichael Hunter 		if (setppriv(PRIV_SET, PRIV_INHERITABLE, priv_set) == -1) {
14138f140aaSMichael Hunter 			priv_freeset(allpriv_set);
14238f140aaSMichael Hunter 			priv_freeset(priv_set);
14338f140aaSMichael Hunter 			pfail("setppriv inheritable: %s", strerror(errno));
14438f140aaSMichael Hunter 		}
14538f140aaSMichael Hunter 		/*
14638f140aaSMichael Hunter 		 * Need to ensure permitted set contains all privs so we can
14738f140aaSMichael Hunter 		 * escalate later.
14838f140aaSMichael Hunter 		 */
14938f140aaSMichael Hunter 		if (setppriv(PRIV_SET, PRIV_PERMITTED, allpriv_set) == -1) {
15038f140aaSMichael Hunter 			priv_freeset(allpriv_set);
15138f140aaSMichael Hunter 			priv_freeset(priv_set);
15238f140aaSMichael Hunter 			pfail("setppriv permitted: %s", strerror(errno));
15338f140aaSMichael Hunter 		}
15438f140aaSMichael Hunter 		/*
15538f140aaSMichael Hunter 		 * We need to find a smaller set of privs that are important to
15638f140aaSMichael Hunter 		 * us.  Otherwise we really are not gaining much by doing this.
15738f140aaSMichael Hunter 		 */
15838f140aaSMichael Hunter 		if (setppriv(PRIV_SET, PRIV_EFFECTIVE, priv_set) == -1) {
15938f140aaSMichael Hunter 			priv_freeset(allpriv_set);
16038f140aaSMichael Hunter 			priv_freeset(priv_set);
16138f140aaSMichael Hunter 			pfail("setppriv effective: %s", strerror(errno));
16238f140aaSMichael Hunter 		}
1633773ed2dSAnurag S. Maskey 
1643773ed2dSAnurag S. Maskey 		priv_freeset(priv_set);
1653773ed2dSAnurag S. Maskey 		priv_freeset(allpriv_set);
1666ba597c5SAnurag S. Maskey 	}
1676ba597c5SAnurag S. Maskey 	(void) pthread_mutex_unlock(&uid_mutex);
168b00044a2SJames Carlson }
169b00044a2SJames Carlson 
170d71dbb73Sjbeck /*
171d71dbb73Sjbeck  *
172d71dbb73Sjbeck  * This starts a child process determined by command.  If command contains a
173d71dbb73Sjbeck  * slash then it is assumed to be a full path; otherwise the path is searched
174d71dbb73Sjbeck  * for an executable file with the name command.  Command is also used as
175d71dbb73Sjbeck  * argv[0] of the new process.  The rest of the arguments of the function
176d71dbb73Sjbeck  * up to the first NULL make up pointers to arguments of the new process.
177d71dbb73Sjbeck  *
178d71dbb73Sjbeck  * This function returns child exit status on success and -1 on failure.
179d71dbb73Sjbeck  *
180d71dbb73Sjbeck  * NOTE: original_sigmask must be set before this function is called.
181d71dbb73Sjbeck  */
182d71dbb73Sjbeck int
nwamd_start_childv(const char * command,char const * const * argv)1836ba597c5SAnurag S. Maskey nwamd_start_childv(const char *command, char const * const *argv)
184d71dbb73Sjbeck {
185d71dbb73Sjbeck 	posix_spawnattr_t attr;
186d71dbb73Sjbeck 	sigset_t fullset;
187d71dbb73Sjbeck 	int i, rc, status, n;
188d71dbb73Sjbeck 	pid_t pid;
189d71dbb73Sjbeck 	char vbuf[1024];
191d71dbb73Sjbeck 	vbuf[0] = 0;
192d71dbb73Sjbeck 	n = sizeof (vbuf);
193d71dbb73Sjbeck 	for (i = 1; argv[i] != NULL && n > 2; i++) {
194d71dbb73Sjbeck 		n -= strlcat(vbuf, " ", n);
195d71dbb73Sjbeck 		n -= strlcat(vbuf, argv[i], n);
196d71dbb73Sjbeck 	}
197d71dbb73Sjbeck 	if (argv[i] != NULL || n < 0)
1986ba597c5SAnurag S. Maskey 		nlog(LOG_ERR, "nwamd_start_childv can't log full arg vector");
200d71dbb73Sjbeck 	if ((rc = posix_spawnattr_init(&attr)) != 0) {
2016ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "posix_spawnattr_init %d %s\n",
2026ba597c5SAnurag S. Maskey 		    rc, strerror(rc));
203d71dbb73Sjbeck 		return (-1);
204d71dbb73Sjbeck 	}
205d71dbb73Sjbeck 	(void) sigfillset(&fullset);
206d71dbb73Sjbeck 	if ((rc = posix_spawnattr_setsigdefault(&attr, &fullset)) != 0) {
2076ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "setsigdefault %d %s\n", rc, strerror(rc));
208d71dbb73Sjbeck 		return (-1);
209d71dbb73Sjbeck 	}
210d71dbb73Sjbeck 	if ((rc = posix_spawnattr_setsigmask(&attr, &original_sigmask)) != 0) {
2116ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "setsigmask %d %s\n", rc, strerror(rc));
212d71dbb73Sjbeck 		return (-1);
213d71dbb73Sjbeck 	}
214d71dbb73Sjbeck 	if ((rc = posix_spawnattr_setflags(&attr,
2166ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "setflags %d %s\n", rc, strerror(rc));
217d71dbb73Sjbeck 		return (-1);
218d71dbb73Sjbeck 	}
220d71dbb73Sjbeck 	if ((rc = posix_spawnp(&pid, command, NULL, &attr, (char * const *)argv,
221d71dbb73Sjbeck 	    environ)) > 0) {
2226ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "posix_spawnp failed errno %d", rc);
223d71dbb73Sjbeck 		return (-1);
224d71dbb73Sjbeck 	}
226d71dbb73Sjbeck 	if ((rc = posix_spawnattr_destroy(&attr)) != 0) {
2276ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "posix_spawn_attr_destroy %d %s\n",
2286ba597c5SAnurag S. Maskey 		    rc, strerror(rc));
229d71dbb73Sjbeck 		return (-1);
230d71dbb73Sjbeck 	}
232d71dbb73Sjbeck 	(void) waitpid(pid, &status, 0);
233d71dbb73Sjbeck 	if (WIFSIGNALED(status) || WIFSTOPPED(status)) {
234d71dbb73Sjbeck 		i = WIFSIGNALED(status) ? WTERMSIG(status) : WSTOPSIG(status);
2356ba597c5SAnurag S. Maskey 		nlog(LOG_ERR, "'%s%s' %s with signal %d (%s)", command, vbuf,
236d71dbb73Sjbeck 		    (WIFSIGNALED(status) ? "terminated" : "stopped"), i,
237d71dbb73Sjbeck 		    strsignal(i));
238d71dbb73Sjbeck 		return (-2);
239d71dbb73Sjbeck 	} else {
2406ba597c5SAnurag S. Maskey 		nlog(LOG_INFO, "'%s%s' completed normally: %d", command, vbuf,
241d71dbb73Sjbeck 		    WEXITSTATUS(status));
242d71dbb73Sjbeck 		return (WEXITSTATUS(status));
243d71dbb73Sjbeck 	}
244d71dbb73Sjbeck }
2466ba597c5SAnurag S. Maskey /*
2476ba597c5SAnurag S. Maskey  * For global zone, check if the link is used by a non-global
2486ba597c5SAnurag S. Maskey  * zone, note that the non-global zones doesn't need this check,
2496ba597c5SAnurag S. Maskey  * because zoneadm has taken care of this when the zone boots.
2506ba597c5SAnurag S. Maskey  * In the global zone, we ignore events for local-zone-owned links
2516ba597c5SAnurag S. Maskey  * since these are taken care of by the local zone's network
2526ba597c5SAnurag S. Maskey  * configuration services.
2536ba597c5SAnurag S. Maskey  */
2546ba597c5SAnurag S. Maskey boolean_t
nwamd_link_belongs_to_this_zone(const char * linkname)2556ba597c5SAnurag S. Maskey nwamd_link_belongs_to_this_zone(const char *linkname)
256d71dbb73Sjbeck {
2576ba597c5SAnurag S. Maskey 	zoneid_t zoneid;
2586ba597c5SAnurag S. Maskey 	char zonename[ZONENAME_MAX];
2596ba597c5SAnurag S. Maskey 	int ret;
2606ba597c5SAnurag S. Maskey 
2616ba597c5SAnurag S. Maskey 	zoneid = getzoneid();
2626ba597c5SAnurag S. Maskey 	if (zoneid == GLOBAL_ZONEID) {
2636ba597c5SAnurag S. Maskey 		datalink_id_t linkid;
2646ba597c5SAnurag S. Maskey 		dladm_status_t status;
2656ba597c5SAnurag S. Maskey 		char errstr[DLADM_STRSIZE];
2666ba597c5SAnurag S. Maskey 
2676ba597c5SAnurag S. Maskey 		if ((status = dladm_name2info(dld_handle, linkname, &linkid,
2686ba597c5SAnurag S. Maskey 		    NULL, NULL, NULL)) != DLADM_STATUS_OK) {
2696ba597c5SAnurag S. Maskey 			nlog(LOG_DEBUG, "nwamd_link_belongs_to_this_zone: "
2706ba597c5SAnurag S. Maskey 			    "could not get linkid for %s: %s",
2716ba597c5SAnurag S. Maskey 			    linkname, dladm_status2str(status, errstr));
2726ba597c5SAnurag S. Maskey 			return (B_FALSE);
2736ba597c5SAnurag S. Maskey 		}
2746ba597c5SAnurag S. Maskey 		zoneid = ALL_ZONES;
2756ba597c5SAnurag S. Maskey 		ret = zone_check_datalink(&zoneid, linkid);
2766ba597c5SAnurag S. Maskey 		if (ret == 0) {
2776ba597c5SAnurag S. Maskey 			(void) getzonenamebyid(zoneid, zonename, ZONENAME_MAX);
2786ba597c5SAnurag S. Maskey 			nlog(LOG_DEBUG, "nwamd_link_belongs_to_this_zone: "
2796ba597c5SAnurag S. Maskey 			    "%s is used by non-global zone: %s",
2806ba597c5SAnurag S. Maskey 			    linkname, zonename);
2816ba597c5SAnurag S. Maskey 			return (B_FALSE);
282d71dbb73Sjbeck 		}
2836ba597c5SAnurag S. Maskey 	}
2846ba597c5SAnurag S. Maskey 	return (B_TRUE);
2856ba597c5SAnurag S. Maskey }
2876ba597c5SAnurag S. Maskey /*
2886ba597c5SAnurag S. Maskey  * Inputs:
2896ba597c5SAnurag S. Maskey  *   res is a pointer to the scf_resources_t to be released.
2906ba597c5SAnurag S. Maskey  */
2916ba597c5SAnurag S. Maskey static void
release_scf_resources(scf_resources_t * res)2926ba597c5SAnurag S. Maskey release_scf_resources(scf_resources_t *res)
2936ba597c5SAnurag S. Maskey {
2946ba597c5SAnurag S. Maskey 	scf_entry_destroy(res->sr_ent);
2956ba597c5SAnurag S. Maskey 	scf_transaction_destroy(res->sr_tx);
2966ba597c5SAnurag S. Maskey 	scf_value_destroy(res->sr_val);
2976ba597c5SAnurag S. Maskey 	scf_property_destroy(res->sr_prop);
2986ba597c5SAnurag S. Maskey 	scf_pg_destroy(res->sr_pg);
2996ba597c5SAnurag S. Maskey 	scf_snapshot_destroy(res->sr_snap);
3006ba597c5SAnurag S. Maskey 	scf_instance_destroy(res->sr_inst);
3016ba597c5SAnurag S. Maskey 	(void) scf_handle_unbind(res->sr_handle);
3026ba597c5SAnurag S. Maskey 	scf_handle_destroy(res->sr_handle);
3036ba597c5SAnurag S. Maskey }
305d71dbb73Sjbeck /*
3066ba597c5SAnurag S. Maskey  * Inputs:
3076ba597c5SAnurag S. Maskey  *   fmri is the instance to look up
3086ba597c5SAnurag S. Maskey  * Outputs:
3096ba597c5SAnurag S. Maskey  *   res is a pointer to an scf_resources_t.  This is an internal
3106ba597c5SAnurag S. Maskey  *   structure that holds all the handles needed to get a specific
3116ba597c5SAnurag S. Maskey  *   property from the running snapshot; on a successful return it
3126ba597c5SAnurag S. Maskey  *   contains the scf_value_t that should be passed to the desired
3136ba597c5SAnurag S. Maskey  *   scf_value_get_foo() function, and must be freed after use by
3146ba597c5SAnurag S. Maskey  *   calling release_scf_resources().  On a failure return, any
3156ba597c5SAnurag S. Maskey  *   resources that may have been assigned to res are released, so
3166ba597c5SAnurag S. Maskey  *   the caller does not need to do any cleanup in the failure case.
3176ba597c5SAnurag S. Maskey  * Returns:
3186ba597c5SAnurag S. Maskey  *    0 on success
3196ba597c5SAnurag S. Maskey  *   -1 on failure
320d71dbb73Sjbeck  */
3216ba597c5SAnurag S. Maskey 
3226ba597c5SAnurag S. Maskey static int
create_scf_resources(const char * fmri,scf_resources_t * res)3236ba597c5SAnurag S. Maskey create_scf_resources(const char *fmri, scf_resources_t *res)
3246ba597c5SAnurag S. Maskey {
3256ba597c5SAnurag S. Maskey 	res->sr_tx = NULL;
3266ba597c5SAnurag S. Maskey 	res->sr_ent = NULL;
3276ba597c5SAnurag S. Maskey 	res->sr_inst = NULL;
3286ba597c5SAnurag S. Maskey 	res->sr_snap = NULL;
3296ba597c5SAnurag S. Maskey 	res->sr_pg = NULL;
3306ba597c5SAnurag S. Maskey 	res->sr_prop = NULL;
3316ba597c5SAnurag S. Maskey 	res->sr_val = NULL;
3326ba597c5SAnurag S. Maskey 
3336ba597c5SAnurag S. Maskey 	if ((res->sr_handle = scf_handle_create(SCF_VERSION)) == NULL) {
3346ba597c5SAnurag S. Maskey 		return (-1);
3356ba597c5SAnurag S. Maskey 	}
3366ba597c5SAnurag S. Maskey 
3376ba597c5SAnurag S. Maskey 	if (scf_handle_bind(res->sr_handle) != 0) {
3386ba597c5SAnurag S. Maskey 		scf_handle_destroy(res->sr_handle);
3396ba597c5SAnurag S. Maskey 		return (-1);
3406ba597c5SAnurag S. Maskey 	}
3416ba597c5SAnurag S. Maskey 	if ((res->sr_inst = scf_instance_create(res->sr_handle)) == NULL) {
3426ba597c5SAnurag S. Maskey 		goto failure;
3436ba597c5SAnurag S. Maskey 	}
3446ba597c5SAnurag S. Maskey 	if (scf_handle_decode_fmri(res->sr_handle, fmri, NULL, NULL,
3456ba597c5SAnurag S. Maskey 	    res->sr_inst, NULL, NULL, SCF_DECODE_FMRI_REQUIRE_INSTANCE) != 0) {
3466ba597c5SAnurag S. Maskey 		goto failure;
3476ba597c5SAnurag S. Maskey 	}
3486ba597c5SAnurag S. Maskey 	if ((res->sr_snap = scf_snapshot_create(res->sr_handle)) == NULL) {
3496ba597c5SAnurag S. Maskey 		goto failure;
3506ba597c5SAnurag S. Maskey 	}
3516ba597c5SAnurag S. Maskey 	if (scf_instance_get_snapshot(res->sr_inst, "running",
3526ba597c5SAnurag S. Maskey 	    res->sr_snap) != 0) {
3536ba597c5SAnurag S. Maskey 		goto failure;
3546ba597c5SAnurag S. Maskey 	}
3556ba597c5SAnurag S. Maskey 	if ((res->sr_pg = scf_pg_create(res->sr_handle)) == NULL) {
3566ba597c5SAnurag S. Maskey 		goto failure;
3576ba597c5SAnurag S. Maskey 	}
3586ba597c5SAnurag S. Maskey 	if ((res->sr_prop = scf_property_create(res->sr_handle)) == NULL) {
3596ba597c5SAnurag S. Maskey 		goto failure;
3606ba597c5SAnurag S. Maskey 	}
3616ba597c5SAnurag S. Maskey 	if ((res->sr_val = scf_value_create(res->sr_handle)) == NULL) {
3626ba597c5SAnurag S. Maskey 		goto failure;
3636ba597c5SAnurag S. Maskey 	}
3646ba597c5SAnurag S. Maskey 	if ((res->sr_tx = scf_transaction_create(res->sr_handle)) == NULL) {
3656ba597c5SAnurag S. Maskey 		goto failure;
3666ba597c5SAnurag S. Maskey 	}
3676ba597c5SAnurag S. Maskey 	if ((res->sr_ent = scf_entry_create(res->sr_handle)) == NULL) {
3686ba597c5SAnurag S. Maskey 		goto failure;
3696ba597c5SAnurag S. Maskey 	}
3706ba597c5SAnurag S. Maskey 	return (0);
3716ba597c5SAnurag S. Maskey 
3726ba597c5SAnurag S. Maskey failure:
3736ba597c5SAnurag S. Maskey 	nlog(LOG_ERR, "create_scf_resources failed: %s",
3746ba597c5SAnurag S. Maskey 	    scf_strerror(scf_error()));
3756ba597c5SAnurag S. Maskey 	release_scf_resources(res);
3766ba597c5SAnurag S. Maskey 	return (-1);
3776ba597c5SAnurag S. Maskey }
3786ba597c5SAnurag S. Maskey 
3796ba597c5SAnurag S. Maskey /*
3806ba597c5SAnurag S. Maskey  * Inputs:
3816ba597c5SAnurag S. Maskey  *   fmri is the instance to look up
3826ba597c5SAnurag S. Maskey  *   pg is the property group to look up
3836ba597c5SAnurag S. Maskey  *   prop is the property within that group to look up
3846ba597c5SAnurag S. Maskey  *   running specifies if running snapshot is to be used
3856ba597c5SAnurag S. Maskey  * Outputs:
3866ba597c5SAnurag S. Maskey  *   res is a pointer to an scf_resources_t.  This is an internal
3876ba597c5SAnurag S. Maskey  *   structure that holds all the handles needed to get a specific
3886ba597c5SAnurag S. Maskey  *   property from the running snapshot; on a successful return it
3896ba597c5SAnurag S. Maskey  *   contains the scf_value_t that should be passed to the desired
3906ba597c5SAnurag S. Maskey  *   scf_value_get_foo() function, and must be freed after use by
3916ba597c5SAnurag S. Maskey  *   calling release_scf_resources().  On a failure return, any
3926ba597c5SAnurag S. Maskey  *   resources that may have been assigned to res are released, so
3936ba597c5SAnurag S. Maskey  *   the caller does not need to do any cleanup in the failure case.
3946ba597c5SAnurag S. Maskey  * Returns:
3956ba597c5SAnurag S. Maskey  *    0 on success
3966ba597c5SAnurag S. Maskey  *   -1 on failure
3976ba597c5SAnurag S. Maskey  */
3986ba597c5SAnurag S. Maskey static int
get_property_value(const char * fmri,const char * pg,const char * prop,boolean_t running,scf_resources_t * res)3996ba597c5SAnurag S. Maskey get_property_value(const char *fmri, const char *pg, const char *prop,
4006ba597c5SAnurag S. Maskey     boolean_t running, scf_resources_t *res)
401d71dbb73Sjbeck {
4026ba597c5SAnurag S. Maskey 	if (create_scf_resources(fmri, res) != 0)
4036ba597c5SAnurag S. Maskey 		return (-1);
4046ba597c5SAnurag S. Maskey 
4056ba597c5SAnurag S. Maskey 	if (scf_instance_get_pg_composed(res->sr_inst,
4066ba597c5SAnurag S. Maskey 	    running ? res->sr_snap : NULL, pg, res->sr_pg) != 0) {
4076ba597c5SAnurag S. Maskey 		goto failure;
4086ba597c5SAnurag S. Maskey 	}
4096ba597c5SAnurag S. Maskey 	if (scf_pg_get_property(res->sr_pg, prop, res->sr_prop) != 0) {
4106ba597c5SAnurag S. Maskey 		goto failure;
4116ba597c5SAnurag S. Maskey 	}
4126ba597c5SAnurag S. Maskey 	if (scf_property_get_value(res->sr_prop, res->sr_val) != 0) {
4136ba597c5SAnurag S. Maskey 		goto failure;
4146ba597c5SAnurag S. Maskey 	}
4156ba597c5SAnurag S. Maskey 	return (0);
4176ba597c5SAnurag S. Maskey failure:
4186ba597c5SAnurag S. Maskey 	release_scf_resources(res);
4196ba597c5SAnurag S. Maskey 	return (-1);
420d71dbb73Sjbeck }
4226ba597c5SAnurag S. Maskey /*
4236ba597c5SAnurag S. Maskey  * Inputs:
4246ba597c5SAnurag S. Maskey  *   lfmri is the instance fmri to look up
4256ba597c5SAnurag S. Maskey  *   lpg is the property group to look up
4266ba597c5SAnurag S. Maskey  *   lprop is the property within that group to look up
4276ba597c5SAnurag S. Maskey  * Outputs:
4286ba597c5SAnurag S. Maskey  *   answer is a pointer to the property value
4296ba597c5SAnurag S. Maskey  * Returns:
4306ba597c5SAnurag S. Maskey  *    0 on success
4316ba597c5SAnurag S. Maskey  *   -1 on failure
4326ba597c5SAnurag S. Maskey  * If successful, the property value is retured in *answer.
4336ba597c5SAnurag S. Maskey  * Otherwise, *answer is undefined, and it is up to the caller to decide
4346ba597c5SAnurag S. Maskey  * how to handle that case.
4356ba597c5SAnurag S. Maskey  */
4366ba597c5SAnurag S. Maskey int
nwamd_lookup_boolean_property(const char * lfmri,const char * lpg,const char * lprop,boolean_t * answer)4376ba597c5SAnurag S. Maskey nwamd_lookup_boolean_property(const char *lfmri, const char *lpg,
4386ba597c5SAnurag S. Maskey     const char *lprop, boolean_t *answer)
4396ba597c5SAnurag S. Maskey {
4406ba597c5SAnurag S. Maskey 	int result = -1;
4416ba597c5SAnurag S. Maskey 	scf_resources_t res;
4426ba597c5SAnurag S. Maskey 	uint8_t prop_val;
4436ba597c5SAnurag S. Maskey 
4446ba597c5SAnurag S. Maskey 	if (get_property_value(lfmri, lpg, lprop, B_TRUE, &res) != 0) {
4456ba597c5SAnurag S. Maskey