xref: /titanic_52/usr/src/cmd/allocate/allocate3.c (revision 10ddde3aee60d88fa580028fcf7642a87e80a2c6)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
545916cd2Sjpk  * Common Development and Distribution License (the "License").
645916cd2Sjpk  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
2145916cd2Sjpk 
227c478bd9Sstevel@tonic-gate /*
23f48205beScasper  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate #include <auth_attr.h>
307c478bd9Sstevel@tonic-gate #include <auth_list.h>
317c478bd9Sstevel@tonic-gate #include <dirent.h>
327c478bd9Sstevel@tonic-gate #include <errno.h>
337c478bd9Sstevel@tonic-gate #include <fcntl.h>
347c478bd9Sstevel@tonic-gate #include <libintl.h>
357c478bd9Sstevel@tonic-gate #include <locale.h>
367c478bd9Sstevel@tonic-gate #include <pwd.h>
377c478bd9Sstevel@tonic-gate #include <signal.h>
387c478bd9Sstevel@tonic-gate #include <stdio.h>
397c478bd9Sstevel@tonic-gate #include <stdlib.h>
407c478bd9Sstevel@tonic-gate #include <string.h>
4145916cd2Sjpk #include <strings.h>
427c478bd9Sstevel@tonic-gate #include <unistd.h>
437c478bd9Sstevel@tonic-gate #include <bsm/devices.h>
4445916cd2Sjpk #include <sys/acl.h>
4545916cd2Sjpk #include <tsol/label.h>
4645916cd2Sjpk #include <syslog.h>
4745916cd2Sjpk #include <limits.h>
4845916cd2Sjpk #include <user_attr.h>
4945916cd2Sjpk #include <secdb.h>
5045916cd2Sjpk #include <sys/mkdev.h>
517c478bd9Sstevel@tonic-gate #include <sys/acl.h>
527c478bd9Sstevel@tonic-gate #include <sys/file.h>
537c478bd9Sstevel@tonic-gate #include <sys/procfs.h>
547c478bd9Sstevel@tonic-gate #include <sys/param.h>
557c478bd9Sstevel@tonic-gate #include <sys/resource.h>
567c478bd9Sstevel@tonic-gate #include <sys/stat.h>
577c478bd9Sstevel@tonic-gate #include <sys/time.h>
587c478bd9Sstevel@tonic-gate #include <sys/types.h>
597c478bd9Sstevel@tonic-gate #include <sys/wait.h>
6045916cd2Sjpk #include <utime.h>
6145916cd2Sjpk #include <libgen.h>
6245916cd2Sjpk #include <zone.h>
6345916cd2Sjpk #include <nss_dbdefs.h>
6445916cd2Sjpk #include <bsm/devalloc.h>
65facf4a8dSllai1 #include <libdevinfo.h>
667c478bd9Sstevel@tonic-gate #include "allocate.h"
677c478bd9Sstevel@tonic-gate 
6845916cd2Sjpk extern void print_error(int, char *);
6945916cd2Sjpk 
7045916cd2Sjpk #if	defined(DEBUG) || defined(lint)
717c478bd9Sstevel@tonic-gate #define	dprintf(s, a) (void) fprintf(stderr, s, a)
727c478bd9Sstevel@tonic-gate #define	dperror(s) perror(s)
737c478bd9Sstevel@tonic-gate #else	/* !DEBUG */
7445916cd2Sjpk #define	dprintf(s, a)	0
7545916cd2Sjpk #define	dperror(s)	0
767c478bd9Sstevel@tonic-gate #endif	/* DEBUG */
777c478bd9Sstevel@tonic-gate 
7845916cd2Sjpk #define	DEV_ERRORED(sbuf)	(((sbuf).st_mode & ~S_IFMT) == ALLOC_ERR_MODE)
79*10ddde3aSaj #define	DEV_ALLOCATED(sbuf)	((sbuf).st_uid != DA_UID || \
8045916cd2Sjpk 			!(((sbuf).st_mode & ~S_IFMT) == DEALLOC_MODE || \
81*10ddde3aSaj 			DEV_ERRORED(sbuf)))
827c478bd9Sstevel@tonic-gate 
8345916cd2Sjpk #define	ALLOC_CLEAN		"-A"
8445916cd2Sjpk #define	DEALLOC_CLEAN		"-D"
8545916cd2Sjpk #define	DAC_DIR			"/etc/security/dev"
867c478bd9Sstevel@tonic-gate #define	DEVICE_AUTH_SEPARATOR	","
8745916cd2Sjpk #define	LOCALDEVICE		"/dev/console"
887c478bd9Sstevel@tonic-gate #define	PROCFS			"/proc/"
8945916cd2Sjpk #define	SFF_NO_ERROR		0x1
9045916cd2Sjpk 
9145916cd2Sjpk #define	ALLOC_BY_NONE		-1
9245916cd2Sjpk #define	CHECK_DRANGE		1
9345916cd2Sjpk #define	CHECK_URANGE		2
9445916cd2Sjpk #define	CHECK_ZLABEL		3
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate extern void audit_allocate_list(char *);
977c478bd9Sstevel@tonic-gate extern void audit_allocate_device(char *);
987c478bd9Sstevel@tonic-gate 
9945916cd2Sjpk extern int	system_labeled;
1007c478bd9Sstevel@tonic-gate extern char	*newenv[];
1017c478bd9Sstevel@tonic-gate 
10245916cd2Sjpk struct state_file {
10345916cd2Sjpk 	int	sf_flags;
10445916cd2Sjpk 	char	sf_path[MAXPATHLEN];
10545916cd2Sjpk };
10645916cd2Sjpk 
10745916cd2Sjpk struct file_info {
10845916cd2Sjpk 	struct stat	fi_stat;
10945916cd2Sjpk 	char		*fi_message;
11045916cd2Sjpk };
11145916cd2Sjpk 
11245916cd2Sjpk struct zone_path {
11345916cd2Sjpk 	int	count;
11445916cd2Sjpk 	char	**path;
11545916cd2Sjpk };
11645916cd2Sjpk 
117facf4a8dSllai1 struct dev_names {
11845916cd2Sjpk 	char **dnames;
11945916cd2Sjpk };
12045916cd2Sjpk 
12145916cd2Sjpk static int _dev_file_name(struct state_file *, devmap_t *);
122*10ddde3aSaj static int lock_dev(char *, struct stat *);
12345916cd2Sjpk static int _check_label(devalloc_t *, char *, uid_t, int);
12445916cd2Sjpk static int create_znode(char *, struct zone_path *, devmap_t *);
12545916cd2Sjpk static int remove_znode(char *, devmap_t *);
12645916cd2Sjpk static int update_device(char **, char *, int);
12745916cd2Sjpk 
1287c478bd9Sstevel@tonic-gate /*
12945916cd2Sjpk  * checks if the invoking user is local to the device
1307c478bd9Sstevel@tonic-gate  */
13145916cd2Sjpk /*ARGSUSED*/
13245916cd2Sjpk int
13345916cd2Sjpk _is_local(uid_t uid)
1347c478bd9Sstevel@tonic-gate {
13545916cd2Sjpk 	struct stat	statbuf;
1367c478bd9Sstevel@tonic-gate 
13745916cd2Sjpk 	if (stat(LOCALDEVICE, &statbuf) == 0 &&
13845916cd2Sjpk 	    statbuf.st_uid == uid)
1397c478bd9Sstevel@tonic-gate 		return (1);
14045916cd2Sjpk 
1417c478bd9Sstevel@tonic-gate 	return (0);
1427c478bd9Sstevel@tonic-gate }
1437c478bd9Sstevel@tonic-gate 
14445916cd2Sjpk /*
14545916cd2Sjpk  * Checks if the user with the specified uid has the specified authorization
14645916cd2Sjpk  */
14745916cd2Sjpk int
14845916cd2Sjpk _is_authorized(char *auths, uid_t uid)
1497c478bd9Sstevel@tonic-gate {
15045916cd2Sjpk 	char		*dcp, *authlist, *lasts;
15145916cd2Sjpk 	char		pw_buf[NSS_BUFLEN_PASSWD];
15245916cd2Sjpk 	struct passwd	pw_ent;
1537c478bd9Sstevel@tonic-gate 
15445916cd2Sjpk 	/*
15545916cd2Sjpk 	 * first, the easy cases
15645916cd2Sjpk 	 */
15745916cd2Sjpk 	if (strcmp(auths, "@") == 0)
15845916cd2Sjpk 		return (1);
15945916cd2Sjpk 	if (strcmp(auths, "*") == 0)
16045916cd2Sjpk 		return (ALLOC_BY_NONE);
16145916cd2Sjpk 	if (getpwuid_r(uid, &pw_ent, pw_buf, sizeof (pw_buf)) == NULL)
16245916cd2Sjpk 		return (0);
16345916cd2Sjpk 	if (strpbrk(auths, DEVICE_AUTH_SEPARATOR) == NULL)
16445916cd2Sjpk 		return (chkauthattr(auths, pw_ent.pw_name));
16545916cd2Sjpk 	authlist = strdup(auths);
16645916cd2Sjpk 	if (authlist == NULL)
16745916cd2Sjpk 		return (0);
16845916cd2Sjpk 	for (dcp = authlist;
16945916cd2Sjpk 	    (dcp = strtok_r(dcp, DEVICE_AUTH_SEPARATOR, &lasts)) != NULL;
17045916cd2Sjpk 	    dcp = NULL) {
17145916cd2Sjpk 		if (chkauthattr(dcp, pw_ent.pw_name))
17245916cd2Sjpk 			break;
17345916cd2Sjpk 	}
17445916cd2Sjpk 	free(authlist);
1757c478bd9Sstevel@tonic-gate 
17645916cd2Sjpk 	return (dcp != NULL);
1777c478bd9Sstevel@tonic-gate }
17845916cd2Sjpk 
17945916cd2Sjpk /*
18045916cd2Sjpk  * Checks if the specified user has authorization for the device
18145916cd2Sjpk  */
18245916cd2Sjpk int
18345916cd2Sjpk _is_dev_authorized(devalloc_t *da, uid_t uid)
18445916cd2Sjpk {
18545916cd2Sjpk 	int	ares;
18645916cd2Sjpk 	char	*auth_list, *dcp, *subauth = NULL;
18745916cd2Sjpk 
18845916cd2Sjpk 	auth_list = da->da_devauth;
18945916cd2Sjpk 	if (auth_list == NULL)
19045916cd2Sjpk 		return (0);
19145916cd2Sjpk 	dcp = strpbrk(auth_list, KV_TOKEN_DELIMIT);
19245916cd2Sjpk 	if (dcp == NULL)
19345916cd2Sjpk 		return (_is_authorized(auth_list, uid));
19445916cd2Sjpk 	if (_is_local(uid)) {
19545916cd2Sjpk 		/* the local authorization is before the separator */
19645916cd2Sjpk 		ares = dcp - auth_list;
19745916cd2Sjpk 		subauth = malloc(ares + 1);
19845916cd2Sjpk 		if (subauth == NULL)
19945916cd2Sjpk 			return (0);
20045916cd2Sjpk 		(void) strlcpy(subauth, auth_list, (ares + 1));
20145916cd2Sjpk 		auth_list = subauth;
20245916cd2Sjpk 	} else
20345916cd2Sjpk 		auth_list = dcp + 1;
20445916cd2Sjpk 	ares = _is_authorized(auth_list, uid);
20545916cd2Sjpk 	if (subauth != NULL)
20645916cd2Sjpk 		free(subauth);
20745916cd2Sjpk 
20845916cd2Sjpk 	return (ares);
2097c478bd9Sstevel@tonic-gate }
21045916cd2Sjpk 
21145916cd2Sjpk int
21245916cd2Sjpk check_devs(devmap_t *dm)
21345916cd2Sjpk {
21445916cd2Sjpk 	int	status = 0;
21545916cd2Sjpk 	char	**file;
21645916cd2Sjpk 
21745916cd2Sjpk 	if (dm->dmap_devarray == NULL)
21845916cd2Sjpk 		return (NODMAPERR);
21945916cd2Sjpk 	for (file = dm->dmap_devarray; *file != NULL; file++) {
22045916cd2Sjpk 		if ((status = access(*file, F_OK)) == -1) {
22145916cd2Sjpk 			dprintf("Unable to access file %s\n", *file);
22245916cd2Sjpk 			break;
22345916cd2Sjpk 		}
22445916cd2Sjpk 	}
22545916cd2Sjpk 
22645916cd2Sjpk 	return (status);
22745916cd2Sjpk }
22845916cd2Sjpk 
22945916cd2Sjpk int
23045916cd2Sjpk print_da_defs(da_defs_t *da_defs)
23145916cd2Sjpk {
23245916cd2Sjpk 	char	optbuf[BUFSIZ];
23345916cd2Sjpk 	char	*p = NULL;
23445916cd2Sjpk 
23545916cd2Sjpk 	if (da_defs->devopts == NULL) {
23645916cd2Sjpk 		dprintf("No default attributes for %s\n", da_defs->devtype);
23745916cd2Sjpk 		return (DEFATTRSERR);
23845916cd2Sjpk 	}
23945916cd2Sjpk 	(void) printf("dev_type=%s\n", da_defs->devtype);
24045916cd2Sjpk 	if (_kva2str(da_defs->devopts, optbuf, sizeof (optbuf), KV_ASSIGN,
24145916cd2Sjpk 	    KV_TOKEN_DELIMIT) == 0) {
24245916cd2Sjpk 		if (p = rindex(optbuf, ':'))
24345916cd2Sjpk 			*p = '\0';
24445916cd2Sjpk 		(void) printf("\t%s\n", optbuf);
24545916cd2Sjpk 	}
24645916cd2Sjpk 
2477c478bd9Sstevel@tonic-gate 	return (0);
2487c478bd9Sstevel@tonic-gate }
2497c478bd9Sstevel@tonic-gate 
25045916cd2Sjpk void
25145916cd2Sjpk print_dev_attrs(int optflag, devalloc_t *da, devmap_t *dm,
25245916cd2Sjpk     struct file_info *fip)
2537c478bd9Sstevel@tonic-gate {
25445916cd2Sjpk 	char	*p = NULL;
25545916cd2Sjpk 	char	optbuf[BUFSIZ];
2567c478bd9Sstevel@tonic-gate 
25745916cd2Sjpk 	(void) printf("device=%s%s", dm->dmap_devname, KV_DELIMITER);
25845916cd2Sjpk 	(void) printf("type=%s%s", dm->dmap_devtype, KV_DELIMITER);
25945916cd2Sjpk 	(void) printf("auths=%s%s",
26045916cd2Sjpk 	    (da->da_devauth ? da->da_devauth : ""), KV_DELIMITER);
26145916cd2Sjpk 	(void) printf("clean=%s%s",
26245916cd2Sjpk 	    (da->da_devexec ? da->da_devexec : ""), KV_DELIMITER);
26345916cd2Sjpk 	if (da->da_devopts != NULL) {
26445916cd2Sjpk 		if (_kva2str(da->da_devopts, optbuf, sizeof (optbuf),
26545916cd2Sjpk 		    KV_ASSIGN, KV_TOKEN_DELIMIT) == 0) {
26645916cd2Sjpk 			if (p = rindex(optbuf, ':'))
26745916cd2Sjpk 				*p = '\0';
26845916cd2Sjpk 			(void) printf("%s", optbuf);
26945916cd2Sjpk 		}
27045916cd2Sjpk 	}
27145916cd2Sjpk 	(void) printf("%s", KV_DELIMITER);
27245916cd2Sjpk 	if (optflag & WINDOWING) {
273*10ddde3aSaj 		if ((fip->fi_message != NULL) &&
274*10ddde3aSaj 		    (strcmp(fip->fi_message, DAOPT_CLASS) == 0))
275*10ddde3aSaj 			(void) printf("owner=/FREE%s", KV_DELIMITER);
27645916cd2Sjpk 		else if (DEV_ERRORED(fip->fi_stat))
27745916cd2Sjpk 			(void) printf("owner=/ERROR%s", KV_DELIMITER);
27845916cd2Sjpk 		else if (!DEV_ALLOCATED(fip->fi_stat))
27945916cd2Sjpk 			(void) printf("owner=/FREE%s", KV_DELIMITER);
28045916cd2Sjpk 		else
281f48205beScasper 			(void) printf("owner=%u%s", fip->fi_stat.st_uid,
28245916cd2Sjpk 			    KV_DELIMITER);
28345916cd2Sjpk 	}
28445916cd2Sjpk 	(void) printf("files=%s", dm->dmap_devlist);
28545916cd2Sjpk 	(void) printf("\n");
28645916cd2Sjpk }
28745916cd2Sjpk 
28845916cd2Sjpk void
28945916cd2Sjpk print_dev(devmap_t *dm)
29045916cd2Sjpk {
29145916cd2Sjpk 	char	**file;
29245916cd2Sjpk 
29345916cd2Sjpk 	(void) printf(gettext("device: %s "), dm->dmap_devname);
29445916cd2Sjpk 	(void) printf(gettext("type: %s "), dm->dmap_devtype);
2957c478bd9Sstevel@tonic-gate 	(void) printf(gettext("files:"));
29645916cd2Sjpk 	file = dm->dmap_devarray;
29745916cd2Sjpk 	if (file != NULL) {
29845916cd2Sjpk 		for (; *file != NULL; file++)
29945916cd2Sjpk 			(void) printf(" %s", *file);
3007c478bd9Sstevel@tonic-gate 	}
3017c478bd9Sstevel@tonic-gate 	(void) printf("\n");
3027c478bd9Sstevel@tonic-gate }
3037c478bd9Sstevel@tonic-gate 
30445916cd2Sjpk /* ARGSUSED */
30545916cd2Sjpk int
30645916cd2Sjpk _list_device(int optflag, uid_t uid, devalloc_t *da, char *zonename)
3077c478bd9Sstevel@tonic-gate {
30845916cd2Sjpk 	int			bytes = 0;
30945916cd2Sjpk 	int			error = 0;
31045916cd2Sjpk 	int			is_authorized = 0;
31145916cd2Sjpk 	char			*fname = NULL;
3127c478bd9Sstevel@tonic-gate 	char			file_name[MAXPATHLEN];
31345916cd2Sjpk 	devmap_t		*dm;
31445916cd2Sjpk 	struct file_info	fi;
31545916cd2Sjpk 	struct state_file	sf;
3167c478bd9Sstevel@tonic-gate 
317*10ddde3aSaj 	fi.fi_message = NULL;
31845916cd2Sjpk 	setdmapent();
31945916cd2Sjpk 	if ((dm = getdmapnam(da->da_devname)) == NULL) {
32045916cd2Sjpk 		enddmapent();
32145916cd2Sjpk 		dprintf("Unable to find %s in the maps database\n",
32245916cd2Sjpk 		    da->da_devname);
32345916cd2Sjpk 		return (NODMAPERR);
3247c478bd9Sstevel@tonic-gate 	}
32545916cd2Sjpk 	enddmapent();
326*10ddde3aSaj 
327*10ddde3aSaj 	if ((optflag & CLASS) &&
328*10ddde3aSaj 	    (!(optflag & (LISTALL | LISTFREE | LISTALLOC)))) {
329*10ddde3aSaj 		fi.fi_message = DAOPT_CLASS;
330*10ddde3aSaj 		if (optflag & LISTATTRS)
331*10ddde3aSaj 			print_dev_attrs(optflag, da, dm, &fi);
332*10ddde3aSaj 		else
333*10ddde3aSaj 			print_dev(dm);
334*10ddde3aSaj 		goto out;
335*10ddde3aSaj 	}
336*10ddde3aSaj 
33745916cd2Sjpk 	if (system_labeled) {
33845916cd2Sjpk 		if ((error = _dev_file_name(&sf, dm)) != 0) {
33945916cd2Sjpk 			freedmapent(dm);
34045916cd2Sjpk 			dprintf("Unable to find %s device files\n",
34145916cd2Sjpk 			    da->da_devname);
34245916cd2Sjpk 			error = NODMAPERR;
34345916cd2Sjpk 			goto out;
3447c478bd9Sstevel@tonic-gate 		}
34545916cd2Sjpk 		fname = sf.sf_path;
34645916cd2Sjpk 	} else {
34745916cd2Sjpk 		bytes = snprintf(file_name, MAXPATHLEN, "%s/%s", DAC_DIR,
34845916cd2Sjpk 		    da->da_devname);
34945916cd2Sjpk 		if (bytes <= 0) {
35045916cd2Sjpk 			error = DEVNAMEERR;
35145916cd2Sjpk 			goto out;
35245916cd2Sjpk 		} else if (bytes >= MAXPATHLEN) {
35345916cd2Sjpk 			dprintf("device name %s is too long.\n",
35445916cd2Sjpk 			    da->da_devname);
35545916cd2Sjpk 			error = DEVLONGERR;
35645916cd2Sjpk 			goto out;
3577c478bd9Sstevel@tonic-gate 		}
35845916cd2Sjpk 		fname = file_name;
35945916cd2Sjpk 	}
36045916cd2Sjpk 	if (stat(fname, &fi.fi_stat) != 0) {
36145916cd2Sjpk 		dprintf("Unable to stat %s\n", fname);
3627c478bd9Sstevel@tonic-gate 		dperror("Error:");
36345916cd2Sjpk 		error = DACACCERR;
36445916cd2Sjpk 		goto out;
36545916cd2Sjpk 	}
36645916cd2Sjpk 	if (optflag & USERID)
36745916cd2Sjpk 		is_authorized = 1;
36845916cd2Sjpk 	else
36945916cd2Sjpk 		is_authorized = _is_dev_authorized(da, uid);
37045916cd2Sjpk 	if (optflag & LISTFREE) {	/* list_devices -n */
37145916cd2Sjpk 		/*
37245916cd2Sjpk 		 * list all free devices
37345916cd2Sjpk 		 */
37445916cd2Sjpk 		if (DEV_ALLOCATED(fi.fi_stat)) {
37545916cd2Sjpk 				error = PREALLOCERR;
37645916cd2Sjpk 				goto out;
37745916cd2Sjpk 		}
37845916cd2Sjpk 		if (system_labeled) {
37945916cd2Sjpk 			/*
38045916cd2Sjpk 			 * for this free device, check if -
38145916cd2Sjpk 			 * 1. user has authorization to allocate
38245916cd2Sjpk 			 * 2. the zone label is within the label range of the
38345916cd2Sjpk 			 *    device
38445916cd2Sjpk 			 */
38545916cd2Sjpk 			if (is_authorized == ALLOC_BY_NONE) {
38645916cd2Sjpk 				error = DAUTHERR;
38745916cd2Sjpk 				goto out;
38845916cd2Sjpk 			} else if (is_authorized == 0) {
38945916cd2Sjpk 				error = UAUTHERR;
39045916cd2Sjpk 				goto out;
39145916cd2Sjpk 			}
39245916cd2Sjpk 			if (_check_label(da, zonename, uid,
39345916cd2Sjpk 			    CHECK_DRANGE) != 0) {
39445916cd2Sjpk 				error = LABELRNGERR;
39545916cd2Sjpk 				goto out;
39645916cd2Sjpk 			}
39745916cd2Sjpk 		}
39845916cd2Sjpk 	} else if (optflag & LISTALLOC) {	/*  list_devices -u */
39945916cd2Sjpk 		/*
40045916cd2Sjpk 		 * list all allocated devices
40145916cd2Sjpk 		 */
40245916cd2Sjpk 		if (!DEV_ALLOCATED(fi.fi_stat)) {
40345916cd2Sjpk 			error = DEVNALLOCERR;
40445916cd2Sjpk 			goto out;
40545916cd2Sjpk 		}
40645916cd2Sjpk 		if (fi.fi_stat.st_uid != uid) {
40745916cd2Sjpk 			error = DEVSTATEERR;
40845916cd2Sjpk 			goto out;
40945916cd2Sjpk 		}
41045916cd2Sjpk 		if (system_labeled) {
41145916cd2Sjpk 			/*
41245916cd2Sjpk 			 * check if the zone label equals the label at which
41345916cd2Sjpk 			 * the device is allocated.
41445916cd2Sjpk 			 */
41545916cd2Sjpk 			if (_check_label(da, zonename, uid,
41645916cd2Sjpk 			    CHECK_ZLABEL) != 0) {
41745916cd2Sjpk 				error = LABELRNGERR;
41845916cd2Sjpk 				goto out;
41945916cd2Sjpk 			}
42045916cd2Sjpk 		}
42145916cd2Sjpk 	} else if (optflag & LISTALL) {		/* list_devices -l */
42245916cd2Sjpk 		/*
42345916cd2Sjpk 		 * list all devices - free and allocated - available
42445916cd2Sjpk 		 */
42545916cd2Sjpk 		if (DEV_ALLOCATED(fi.fi_stat)) {
42645916cd2Sjpk 			if (optflag & WINDOWING &&
42745916cd2Sjpk 			    (is_authorized == ALLOC_BY_NONE)) {
42845916cd2Sjpk 				/*
42945916cd2Sjpk 				 * don't complain if we're here for the GUI.
43045916cd2Sjpk 				 */
43145916cd2Sjpk 				error = 0;
43245916cd2Sjpk 			} else if (fi.fi_stat.st_uid != uid) {
43345916cd2Sjpk 				if (!(optflag & WINDOWING)) {
43445916cd2Sjpk 					error = ALLOCUERR;
43545916cd2Sjpk 					goto out;
43645916cd2Sjpk 				}
43745916cd2Sjpk 			}
43845916cd2Sjpk 			if (system_labeled && !(optflag & WINDOWING)) {
43945916cd2Sjpk 				/*
44045916cd2Sjpk 				 * if we're not displaying in the GUI,
44145916cd2Sjpk 				 * check if the zone label equals the label
44245916cd2Sjpk 				 * at which the device is allocated.
44345916cd2Sjpk 				 */
44445916cd2Sjpk 				if (_check_label(da, zonename, uid,
44545916cd2Sjpk 				    CHECK_ZLABEL) != 0) {
44645916cd2Sjpk 					error = LABELRNGERR;
44745916cd2Sjpk 					goto out;
44845916cd2Sjpk 				}
44945916cd2Sjpk 			}
45045916cd2Sjpk 		} else if (system_labeled && !(optflag & WINDOWING)) {
45145916cd2Sjpk 			/*
45245916cd2Sjpk 			 * if we're not displaying in the GUI,
45345916cd2Sjpk 			 * for this free device, check if -
45445916cd2Sjpk 			 * 1. user has authorization to allocate
45545916cd2Sjpk 			 * 2. the zone label is within the label range of the
45645916cd2Sjpk 			 *    device
45745916cd2Sjpk 			 */
45845916cd2Sjpk 			if (is_authorized == ALLOC_BY_NONE) {
45945916cd2Sjpk 				error = DAUTHERR;
46045916cd2Sjpk 				goto out;
46145916cd2Sjpk 			} else if (is_authorized == 0) {
46245916cd2Sjpk 				error = UAUTHERR;
46345916cd2Sjpk 				goto out;
46445916cd2Sjpk 			}
46545916cd2Sjpk 			if (_check_label(da, zonename, uid,
46645916cd2Sjpk 			    CHECK_DRANGE) != 0) {
46745916cd2Sjpk 				error = LABELRNGERR;
46845916cd2Sjpk 				goto out;
46945916cd2Sjpk 			}
47045916cd2Sjpk 		}
47145916cd2Sjpk 	}
47245916cd2Sjpk 	if (system_labeled && DEV_ERRORED(fi.fi_stat) && !(optflag & LISTALL)) {
47345916cd2Sjpk 		error = DEVSTATEERR;
47445916cd2Sjpk 		goto out;
47545916cd2Sjpk 	}
47645916cd2Sjpk 	if (check_devs(dm) == -1) {
47745916cd2Sjpk 		error = DSPMISSERR;
47845916cd2Sjpk 		goto out;
47945916cd2Sjpk 	}
48045916cd2Sjpk 	if (optflag & LISTATTRS)
48145916cd2Sjpk 		print_dev_attrs(optflag, da, dm, &fi);
48245916cd2Sjpk 	else
48345916cd2Sjpk 		print_dev(dm);
48445916cd2Sjpk 
48545916cd2Sjpk 	error = 0;
48645916cd2Sjpk 
48745916cd2Sjpk out:
48845916cd2Sjpk 	freedmapent(dm);
48945916cd2Sjpk 	return (error);
4907c478bd9Sstevel@tonic-gate }
4917c478bd9Sstevel@tonic-gate 
49245916cd2Sjpk /* ARGSUSED */
49345916cd2Sjpk int
49445916cd2Sjpk list_devices(int optflag, uid_t uid, char *device, char *zonename)
49545916cd2Sjpk {
49645916cd2Sjpk 	int		error = 0;
497*10ddde3aSaj 	char		*class = NULL;
49845916cd2Sjpk 	da_defs_t	*da_defs;
49945916cd2Sjpk 	devalloc_t	*da;
5007c478bd9Sstevel@tonic-gate 
50145916cd2Sjpk 	if (system_labeled && optflag & WINDOWING && !(optflag & LISTATTRS)) {
50245916cd2Sjpk 		/*
50345916cd2Sjpk 		 * Private interface for GUI.
50445916cd2Sjpk 		 */
50545916cd2Sjpk 		(void) puts(DA_DB_LOCK);
5067c478bd9Sstevel@tonic-gate 		return (0);
5077c478bd9Sstevel@tonic-gate 	}
50845916cd2Sjpk 	if (optflag & USERID) {
50945916cd2Sjpk 		/*
51045916cd2Sjpk 		 * we need device.revoke to list someone else's devices
51145916cd2Sjpk 		 */
51245916cd2Sjpk 		if (!_is_authorized(DEVICE_REVOKE_AUTH, getuid()))
51345916cd2Sjpk 			return (UAUTHERR);
51445916cd2Sjpk 	}
51545916cd2Sjpk 	if (system_labeled) {
51645916cd2Sjpk 		if (!(optflag & USERID) &&
51745916cd2Sjpk 		    !_is_authorized(DEFAULT_DEV_ALLOC_AUTH, uid))
51845916cd2Sjpk 			/*
51945916cd2Sjpk 			 * we need device.allocate to list our devices
52045916cd2Sjpk 			 */
52145916cd2Sjpk 			return (UAUTHERR);
52245916cd2Sjpk 		if (optflag & LISTDEFS) {
52345916cd2Sjpk 			/*
52445916cd2Sjpk 			 * list default attrs from devalloc_defaults
52545916cd2Sjpk 			 */
52645916cd2Sjpk 			setdadefent();
52745916cd2Sjpk 			if (device) {
52845916cd2Sjpk 				/*
52945916cd2Sjpk 				 * list default attrs for this device type
53045916cd2Sjpk 				 */
53145916cd2Sjpk 				da_defs = getdadeftype(device);
53245916cd2Sjpk 				if (da_defs == NULL) {
53345916cd2Sjpk 					enddadefent();
53445916cd2Sjpk 					dprintf("No default attributes for "
53545916cd2Sjpk 					    "%s\n", device);
53645916cd2Sjpk 					return (DEFATTRSERR);
53745916cd2Sjpk 				}
53845916cd2Sjpk 				error = print_da_defs(da_defs);
53945916cd2Sjpk 				freedadefent(da_defs);
54045916cd2Sjpk 			} else {
54145916cd2Sjpk 				/*
54245916cd2Sjpk 				 * list everything in devalloc_defaults
54345916cd2Sjpk 				 */
54445916cd2Sjpk 				while ((da_defs = getdadefent()) != NULL) {
54545916cd2Sjpk 					(void) print_da_defs(da_defs);
54645916cd2Sjpk 					freedadefent(da_defs);
54745916cd2Sjpk 				}
54845916cd2Sjpk 			}
54945916cd2Sjpk 			enddadefent();
55045916cd2Sjpk 			return (error);
55145916cd2Sjpk 		}
5527c478bd9Sstevel@tonic-gate 	}
553*10ddde3aSaj 	/*
554*10ddde3aSaj 	 * Lock the database to make sure no body writes to it while we are
555*10ddde3aSaj 	 * reading.
556*10ddde3aSaj 	 */
557*10ddde3aSaj 	(void) lock_dev(NULL, NULL);
5587c478bd9Sstevel@tonic-gate 	setdaent();
5597c478bd9Sstevel@tonic-gate 	if (device) {
560*10ddde3aSaj 		if (optflag & CLASS) {
561*10ddde3aSaj 			/*
562*10ddde3aSaj 			 * list all devices of this class.
563*10ddde3aSaj 			 */
564*10ddde3aSaj 			while ((da = getdaent()) != NULL) {
565*10ddde3aSaj 				class =	 kva_match(da->da_devopts, DAOPT_CLASS);
566*10ddde3aSaj 				if (class && (strcmp(class, device) == 0)) {
567*10ddde3aSaj 					(void) _list_device(optflag, uid, da,
568*10ddde3aSaj 					    zonename);
569*10ddde3aSaj 				}
570*10ddde3aSaj 				freedaent(da);
571*10ddde3aSaj 			}
572*10ddde3aSaj 		} else {
57345916cd2Sjpk 			/*
57445916cd2Sjpk 			 * list this device
57545916cd2Sjpk 			 */
57645916cd2Sjpk 			if ((da = getdanam(device)) == NULL) {
5777c478bd9Sstevel@tonic-gate 				enddaent();
57845916cd2Sjpk 				return (NODAERR);
57945916cd2Sjpk 			}
58045916cd2Sjpk 			error = _list_device(optflag, uid, da, zonename);
58145916cd2Sjpk 			freedaent(da);
582*10ddde3aSaj 		}
58345916cd2Sjpk 	} else {
58445916cd2Sjpk 		/*
58545916cd2Sjpk 		 * list all devices
58645916cd2Sjpk 		 */
58745916cd2Sjpk 		while ((da = getdaent()) != NULL) {
58845916cd2Sjpk 			(void) _list_device(optflag, uid, da, zonename);
58945916cd2Sjpk 			freedaent(da);
59045916cd2Sjpk 		}
59145916cd2Sjpk 	}
59245916cd2Sjpk 	enddaent();
59345916cd2Sjpk 
59445916cd2Sjpk 	return (error);
5957c478bd9Sstevel@tonic-gate }
5967c478bd9Sstevel@tonic-gate 
5977c478bd9Sstevel@tonic-gate /*
5987c478bd9Sstevel@tonic-gate  * Set the DAC characteristics of the file.
5997c478bd9Sstevel@tonic-gate  * This uses a fancy chmod() by setting a minimal ACL which sets the mode
6007c478bd9Sstevel@tonic-gate  * and discards any existing ACL.
6017c478bd9Sstevel@tonic-gate  */
60245916cd2Sjpk int
60345916cd2Sjpk _newdac(char *file, uid_t owner, gid_t group, o_mode_t mode)
6047c478bd9Sstevel@tonic-gate {
6057c478bd9Sstevel@tonic-gate 	int	err = 0;
6067c478bd9Sstevel@tonic-gate 
60745916cd2Sjpk 	if (mode == ALLOC_MODE) {
6087c478bd9Sstevel@tonic-gate 		if (chown(file, owner, group) == -1) {
60945916cd2Sjpk 			dperror("newdac: unable to chown");
61045916cd2Sjpk 			err = CHOWNERR;
61145916cd2Sjpk 		}
61245916cd2Sjpk 	} else do {
61345916cd2Sjpk 		if (chown(file, owner, group) == -1) {
61445916cd2Sjpk 			dperror("newdac: unable to chown");
61545916cd2Sjpk 			err = CHOWNERR;
6167c478bd9Sstevel@tonic-gate 		}
6177c478bd9Sstevel@tonic-gate 	} while (fdetach(file) == 0);
6187c478bd9Sstevel@tonic-gate 
61945916cd2Sjpk 	if (err)
62045916cd2Sjpk 		return (err);
62145916cd2Sjpk 
62245916cd2Sjpk 	if (strncmp(file, "/dev/", strlen("/dev/")) != 0) {
62345916cd2Sjpk 		/*
62445916cd2Sjpk 		 * This could be a SunRay device that is in /tmp.
62545916cd2Sjpk 		 */
62645916cd2Sjpk 		if (chmod(file, mode) == -1) {
62745916cd2Sjpk 			dperror("newdac: unable to chmod");
62845916cd2Sjpk 			err = SETACLERR;
62945916cd2Sjpk 		}
63045916cd2Sjpk 	} else {
631fa9e4066Sahrens 		err = acl_strip(file, owner, group, (mode_t)mode);
63245916cd2Sjpk 	}
633fa9e4066Sahrens 
634fa9e4066Sahrens 	if (err != 0) {
63545916cd2Sjpk 		dperror("newdac: unable to setacl");
63645916cd2Sjpk 		err = SETACLERR;
6377c478bd9Sstevel@tonic-gate 	}
6387c478bd9Sstevel@tonic-gate 
6397c478bd9Sstevel@tonic-gate 	return (err);
6407c478bd9Sstevel@tonic-gate }
6417c478bd9Sstevel@tonic-gate 
642*10ddde3aSaj /*
643*10ddde3aSaj  * lock_dev -
644*10ddde3aSaj  *	locks a section of DA_DB_LOCK.
645*10ddde3aSaj  *	returns lock fd if successful, else -1 on error.
646*10ddde3aSaj  */
6477c478bd9Sstevel@tonic-gate static int
648*10ddde3aSaj lock_dev(char *file, struct stat *statbuf)
6497c478bd9Sstevel@tonic-gate {
650*10ddde3aSaj 	static int	lockfd = -1;
651*10ddde3aSaj 	int		ret;
652*10ddde3aSaj 	int		count = 0;
653*10ddde3aSaj 	int		retry = 10;
654*10ddde3aSaj 	off_t		size = 0;
655*10ddde3aSaj 	off_t		offset;
656*10ddde3aSaj 	char		*lockfile;
6577c478bd9Sstevel@tonic-gate 
658*10ddde3aSaj 	if (system_labeled)
659*10ddde3aSaj 		lockfile = DA_DB_LOCK;
660*10ddde3aSaj 	else
661*10ddde3aSaj 		lockfile = file;
662*10ddde3aSaj 
663*10ddde3aSaj 	if (statbuf) {
664*10ddde3aSaj 		offset = statbuf->st_rdev;
6657c478bd9Sstevel@tonic-gate 		dprintf("locking %s\n", file);
666*10ddde3aSaj 	} else {
667*10ddde3aSaj 		offset = 0;
668*10ddde3aSaj 		dprintf("locking %s\n", lockfile);
6697c478bd9Sstevel@tonic-gate 	}
670*10ddde3aSaj 	if ((lockfd == -1) &&
671*10ddde3aSaj 	    (lockfd = open(lockfile, O_RDWR | O_CREAT, 0600)) == -1) {
672*10ddde3aSaj 		dperror("lock_dev: cannot open lock file");
673*10ddde3aSaj 		return (-1);
674*10ddde3aSaj 	}
675*10ddde3aSaj 	if (system_labeled) {
676*10ddde3aSaj 		(void) _newdac(lockfile, DA_UID, DA_GID, 0600);
677*10ddde3aSaj 		if (lseek(lockfd, offset, SEEK_SET) == -1) {
678*10ddde3aSaj 			dperror("lock_dev: cannot position lock file");
679*10ddde3aSaj 			return (-1);
680*10ddde3aSaj 		}
681*10ddde3aSaj 		size = 1;
682*10ddde3aSaj 	}
683*10ddde3aSaj 	errno = 0;
684*10ddde3aSaj 	while (retry) {
685*10ddde3aSaj 		count++;
686*10ddde3aSaj 		ret = lockf(lockfd, F_TLOCK, size);
687*10ddde3aSaj 		if (ret == 0)
688*10ddde3aSaj 			return (lockfd);
689*10ddde3aSaj 		if ((errno != EACCES) && (errno != EAGAIN)) {
69045916cd2Sjpk 			dperror("lock_dev: cannot set lock");
691*10ddde3aSaj 			return (-1);
692*10ddde3aSaj 		}
693*10ddde3aSaj 		retry--;
694*10ddde3aSaj 		(void) sleep(count);
695*10ddde3aSaj 		errno = 0;
6967c478bd9Sstevel@tonic-gate 	}
6977c478bd9Sstevel@tonic-gate 
698*10ddde3aSaj 	return (-1);
6997c478bd9Sstevel@tonic-gate }
7007c478bd9Sstevel@tonic-gate 
70145916cd2Sjpk int
70245916cd2Sjpk mk_alloc(devmap_t *list, uid_t uid, struct zone_path *zpath)
7037c478bd9Sstevel@tonic-gate {
70445916cd2Sjpk 	int	i;
70545916cd2Sjpk 	int	error = 0;
70645916cd2Sjpk 	char	**file;
70745916cd2Sjpk 	gid_t	gid = getgid();
70845916cd2Sjpk 	mode_t	mode = ALLOC_MODE;
7097c478bd9Sstevel@tonic-gate 
71045916cd2Sjpk 	file = list->dmap_devarray;
71145916cd2Sjpk 	if (file == NULL)
71245916cd2Sjpk 		return (NODMAPERR);
71345916cd2Sjpk 	for (; *file != NULL; file++) {
71445916cd2Sjpk 		dprintf("Allocating %s\n", *file);
71545916cd2Sjpk 		if ((error = _newdac(*file, uid, gid, mode)) != 0) {
716*10ddde3aSaj 			(void) _newdac(*file, ALLOC_ERRID, DA_GID,
7177c478bd9Sstevel@tonic-gate 			    ALLOC_ERR_MODE);
71845916cd2Sjpk 			break;
71945916cd2Sjpk 		}
72045916cd2Sjpk 	}
72145916cd2Sjpk 	if (system_labeled && zpath->count && (error == 0)) {
72245916cd2Sjpk 		/*
72345916cd2Sjpk 		 * mark as allocated any new device nodes that we
72445916cd2Sjpk 		 * created in local zone
72545916cd2Sjpk 		 */
72645916cd2Sjpk 		for (i = 0; i < zpath->count; i++) {
72745916cd2Sjpk 			dprintf("Allocating %s\n", zpath->path[i]);
72845916cd2Sjpk 			if ((error = _newdac(zpath->path[i], uid, gid,
72945916cd2Sjpk 			    mode)) != 0) {
73045916cd2Sjpk 				(void) _newdac(zpath->path[i], ALLOC_ERRID,
731*10ddde3aSaj 				    DA_GID, ALLOC_ERR_MODE);
73245916cd2Sjpk 				break;
73345916cd2Sjpk 			}
73445916cd2Sjpk 		}
7357c478bd9Sstevel@tonic-gate 	}
7367c478bd9Sstevel@tonic-gate 
73745916cd2Sjpk 	return (error);
7387c478bd9Sstevel@tonic-gate }
7397c478bd9Sstevel@tonic-gate 
7407c478bd9Sstevel@tonic-gate /*
7417c478bd9Sstevel@tonic-gate  * mk_revoke() is used instead of system("/usr/sbin/fuser -k file")
7427c478bd9Sstevel@tonic-gate  * because "/usr/sbin/fuser -k file" kills all processes
7437c478bd9Sstevel@tonic-gate  * working with the file, even "vold" (bug #4095152).
7447c478bd9Sstevel@tonic-gate  */
74545916cd2Sjpk int
74645916cd2Sjpk mk_revoke(int optflag, char *file)
7477c478bd9Sstevel@tonic-gate {
7487c478bd9Sstevel@tonic-gate 	int		r = 0, p[2], fp, lock;
74945916cd2Sjpk 	int		fuserpid;
75045916cd2Sjpk 	char		buf[MAXPATHLEN];
7517c478bd9Sstevel@tonic-gate 	FILE		*ptr;
75245916cd2Sjpk 	pid_t		c_pid;
7537c478bd9Sstevel@tonic-gate 	prpsinfo_t	info;
7547c478bd9Sstevel@tonic-gate 
7557c478bd9Sstevel@tonic-gate 	(void) strcpy(buf, PROCFS);
7567c478bd9Sstevel@tonic-gate 	/*
75745916cd2Sjpk 	 * vfork() and execl() just to make the same output
7587c478bd9Sstevel@tonic-gate 	 * as before fixing of bug #4095152.
7597c478bd9Sstevel@tonic-gate 	 * The problem is that the "fuser" command prints
7607c478bd9Sstevel@tonic-gate 	 * one part of output into stderr and another into stdout,
7617c478bd9Sstevel@tonic-gate 	 * but user sees them mixed. Of course, better to change "fuser"
7627c478bd9Sstevel@tonic-gate 	 * or to intercept and not to print its output.
7637c478bd9Sstevel@tonic-gate 	 */
76445916cd2Sjpk 	if (!(optflag & SILENT)) {
7657c478bd9Sstevel@tonic-gate 		c_pid = vfork();
7667c478bd9Sstevel@tonic-gate 		if (c_pid == -1)
7677c478bd9Sstevel@tonic-gate 			return (-1);
7687c478bd9Sstevel@tonic-gate 		if (c_pid == 0) {
7697c478bd9Sstevel@tonic-gate 			dprintf("first exec fuser %s\n", file);
77045916cd2Sjpk 			(void) execl("/usr/sbin/fuser", "fuser", file, NULL);
7717c478bd9Sstevel@tonic-gate 			dperror("first exec fuser");
7727c478bd9Sstevel@tonic-gate 			_exit(1);
7737c478bd9Sstevel@tonic-gate 		}
7747c478bd9Sstevel@tonic-gate 
7757c478bd9Sstevel@tonic-gate 		(void) waitpid(c_pid, &lock, 0);
7767c478bd9Sstevel@tonic-gate 		dprintf("exit status %x\n", lock);
7777c478bd9Sstevel@tonic-gate 		if (WEXITSTATUS(lock) != 0)
7787c478bd9Sstevel@tonic-gate 			return (-1);
7797c478bd9Sstevel@tonic-gate 	}
78045916cd2Sjpk 	dprintf("first continuing c_pid=%d\n", (int)c_pid);
7817c478bd9Sstevel@tonic-gate 	if (pipe(p)) {
7827c478bd9Sstevel@tonic-gate 		dperror("pipe");
7837c478bd9Sstevel@tonic-gate 		return (-1);
7847c478bd9Sstevel@tonic-gate 	}
78545916cd2Sjpk 	/* vfork() and execl() to catch output and to process it */
7867c478bd9Sstevel@tonic-gate 	c_pid = vfork();
7877c478bd9Sstevel@tonic-gate 	if (c_pid == -1) {
7887c478bd9Sstevel@tonic-gate 		dperror("second vfork");
7897c478bd9Sstevel@tonic-gate 		return (-1);
7907c478bd9Sstevel@tonic-gate 	}
79145916cd2Sjpk 	dprintf("second continuing c_pid=%d\n", (int)c_pid);
7927c478bd9Sstevel@tonic-gate 	if (c_pid == 0) {
7937c478bd9Sstevel@tonic-gate 		(void) close(p[0]);
7947c478bd9Sstevel@tonic-gate 		(void) close(1);
7957c478bd9Sstevel@tonic-gate 		(void) fcntl(p[1], F_DUPFD, 1);
7967c478bd9Sstevel@tonic-gate 		(void) close(p[1]);
7977c478bd9Sstevel@tonic-gate 		(void) close(2);
7987c478bd9Sstevel@tonic-gate 		dprintf("second exec fuser %s\n", file);
79945916cd2Sjpk 		(void) execl("/usr/sbin/fuser", "fuser", file, NULL);
8007c478bd9Sstevel@tonic-gate 		dperror("second exec fuser");
8017c478bd9Sstevel@tonic-gate 		_exit(1);
8027c478bd9Sstevel@tonic-gate 	}
8037c478bd9Sstevel@tonic-gate 	(void) close(p[1]);
8047c478bd9Sstevel@tonic-gate 	if ((ptr = fdopen(p[0], "r")) != NULL) {
8057c478bd9Sstevel@tonic-gate 		while (!feof(ptr)) {
80645916cd2Sjpk 			if (fscanf(ptr, "%d", &fuserpid) > 0) {
80745916cd2Sjpk 				(void) sprintf(buf + strlen(PROCFS), "%d",
80845916cd2Sjpk 				    fuserpid);
8097c478bd9Sstevel@tonic-gate 				if ((fp = open(buf, O_RDONLY)) == -1) {
8107c478bd9Sstevel@tonic-gate 					dperror(buf);
8117c478bd9Sstevel@tonic-gate 					continue;
8127c478bd9Sstevel@tonic-gate 				}
81345916cd2Sjpk 				if (ioctl(fp, PIOCPSINFO,
81445916cd2Sjpk 				    (char *)&info) == -1) {
81545916cd2Sjpk 					dprintf("%d psinfo failed", fuserpid);
8167c478bd9Sstevel@tonic-gate 					dperror("");
8177c478bd9Sstevel@tonic-gate 					(void) close(fp);
8187c478bd9Sstevel@tonic-gate 					continue;
8197c478bd9Sstevel@tonic-gate 				}
8207c478bd9Sstevel@tonic-gate 				(void) close(fp);
8217c478bd9Sstevel@tonic-gate 				if (strcmp(info.pr_fname, "vold") == NULL) {
82245916cd2Sjpk 					dprintf("%d matched vold name\n",
82345916cd2Sjpk 					    fuserpid);
8247c478bd9Sstevel@tonic-gate 					continue;
8257c478bd9Sstevel@tonic-gate 				}
8267c478bd9Sstevel@tonic-gate 				dprintf("killing %s", info.pr_fname);
82745916cd2Sjpk 				dprintf("(%d)\n", fuserpid);
82845916cd2Sjpk 				if ((r =
82945916cd2Sjpk 				    kill((pid_t)fuserpid, SIGKILL)) == -1) {
83045916cd2Sjpk 					dprintf("kill %d", fuserpid);
8317c478bd9Sstevel@tonic-gate 					dperror("");
8327c478bd9Sstevel@tonic-gate 					break;
8337c478bd9Sstevel@tonic-gate 				}
8347c478bd9Sstevel@tonic-gate 			}
8357c478bd9Sstevel@tonic-gate 		}
8367c478bd9Sstevel@tonic-gate 	} else {
83745916cd2Sjpk 		dperror("fdopen(p[0], r)");
8387c478bd9Sstevel@tonic-gate 		r = -1;
8397c478bd9Sstevel@tonic-gate 	}
8407c478bd9Sstevel@tonic-gate 	(void) fclose(ptr);
84145916cd2Sjpk 
8427c478bd9Sstevel@tonic-gate 	return (r);
8437c478bd9Sstevel@tonic-gate }
8447c478bd9Sstevel@tonic-gate 
84545916cd2Sjpk int
84645916cd2Sjpk mk_unalloc(int optflag, devmap_t *list)
8477c478bd9Sstevel@tonic-gate {
8487c478bd9Sstevel@tonic-gate 	int	error = 0;
8497c478bd9Sstevel@tonic-gate 	int	status;
85045916cd2Sjpk 	char	**file;
8517c478bd9Sstevel@tonic-gate 
85245916cd2Sjpk 	audit_allocate_list(list->dmap_devlist);
85345916cd2Sjpk 	file = list->dmap_devarray;
85445916cd2Sjpk 	if (file == NULL)
85545916cd2Sjpk 		return (NODMAPERR);
85645916cd2Sjpk 	for (; *file != NULL; file++) {
85745916cd2Sjpk 		dprintf("Deallocating %s\n", *file);
85845916cd2Sjpk 		if (mk_revoke(optflag, *file) < 0) {
85945916cd2Sjpk 			dprintf("mk_unalloc: unable to revoke %s\n", *file);
86045916cd2Sjpk 			dperror("");
86145916cd2Sjpk 			error = CNTFRCERR;
86245916cd2Sjpk 		}
863*10ddde3aSaj 		status = _newdac(*file, DA_UID, DA_GID, DEALLOC_MODE);
86445916cd2Sjpk 		if (error == 0)
86545916cd2Sjpk 			error = status;
86645916cd2Sjpk 
86745916cd2Sjpk 	}
86845916cd2Sjpk 
86945916cd2Sjpk 	return (error);
87045916cd2Sjpk }
87145916cd2Sjpk 
87245916cd2Sjpk int
87345916cd2Sjpk mk_error(devmap_t *list)
87445916cd2Sjpk {
87545916cd2Sjpk 	int	status = 0;
87645916cd2Sjpk 	char	**file;
87745916cd2Sjpk 
87845916cd2Sjpk 	audit_allocate_list(list->dmap_devlist);
87945916cd2Sjpk 	file = list->dmap_devarray;
88045916cd2Sjpk 	if (file == NULL)
88145916cd2Sjpk 		return (NODMAPERR);
88245916cd2Sjpk 	for (; *file != NULL; file++) {
88345916cd2Sjpk 		dprintf("Putting %s in error state\n", *file);
884*10ddde3aSaj 		status = _newdac(*file, ALLOC_ERRID, DA_GID, ALLOC_ERR_MODE);
88545916cd2Sjpk 	}
88645916cd2Sjpk 
88745916cd2Sjpk 	return (status);
88845916cd2Sjpk }
88945916cd2Sjpk 
89045916cd2Sjpk int
89145916cd2Sjpk exec_clean(int optflag, char *devname, char *path, uid_t uid, char *zonename,
89245916cd2Sjpk     char *clean_arg)
89345916cd2Sjpk {
89445916cd2Sjpk 	int		c;
89545916cd2Sjpk 	int		status = 0, exit_status;
89645916cd2Sjpk 	char		*mode, *cmd, *wdwcmd, *zoneroot;
89745916cd2Sjpk 	char		*devzone = zonename;
89845916cd2Sjpk 	char		wdwpath[PATH_MAX];
89945916cd2Sjpk 	char		zonepath[MAXPATHLEN];
90045916cd2Sjpk 	char		title[100];
90145916cd2Sjpk 	char		pw_buf[NSS_BUFLEN_PASSWD];
90245916cd2Sjpk 	struct passwd	pw_ent;
90345916cd2Sjpk 
90445916cd2Sjpk 	zonepath[0] = '\0';
90545916cd2Sjpk 	if (system_labeled) {
90645916cd2Sjpk 		if ((zoneroot = getzonerootbyname(zonename)) == NULL) {
90745916cd2Sjpk 			if (strcmp(clean_arg, ALLOC_CLEAN) == 0) {
90845916cd2Sjpk 				return (-1);
90945916cd2Sjpk 			} else if (optflag & FORCE) {
91045916cd2Sjpk 				(void) strcpy(zonepath, "/");
91145916cd2Sjpk 				devzone = GLOBAL_ZONENAME;
91245916cd2Sjpk 			} else {
91345916cd2Sjpk 				dprintf("unable to get label for %s zone\n",
91445916cd2Sjpk 				    zonename);
91545916cd2Sjpk 				return (-1);
91645916cd2Sjpk 			}
91745916cd2Sjpk 		} else {
91845916cd2Sjpk 			(void) strcpy(zonepath, zoneroot);
91945916cd2Sjpk 			free(zoneroot);
92045916cd2Sjpk 		}
92145916cd2Sjpk 	}
92245916cd2Sjpk 	if (getpwuid_r(uid, &pw_ent, pw_buf, sizeof (pw_buf)) == NULL)
92345916cd2Sjpk 		return (-1);
92445916cd2Sjpk 	if (optflag & FORCE_ALL)
9257c478bd9Sstevel@tonic-gate 		mode = "-I";
92645916cd2Sjpk 	else if (optflag & FORCE)
9277c478bd9Sstevel@tonic-gate 		mode = "-f";
9287c478bd9Sstevel@tonic-gate 	else
9297c478bd9Sstevel@tonic-gate 		mode = "-s";
93045916cd2Sjpk 	if (path == NULL)
93145916cd2Sjpk 		return (0);
9327c478bd9Sstevel@tonic-gate 	if ((cmd = strrchr(path, '/')) == NULL)
9337c478bd9Sstevel@tonic-gate 		cmd = path;
9347c478bd9Sstevel@tonic-gate 	else
9357c478bd9Sstevel@tonic-gate 		cmd++;	/* skip leading '/' */
9367c478bd9Sstevel@tonic-gate 	c = vfork();
9377c478bd9Sstevel@tonic-gate 	switch (c) {
9387c478bd9Sstevel@tonic-gate 	case -1:
9397c478bd9Sstevel@tonic-gate 		return (-1);
9407c478bd9Sstevel@tonic-gate 	case 0:
9417c478bd9Sstevel@tonic-gate 		(void) setuid(0);
94245916cd2Sjpk 		if (system_labeled && (optflag & WINDOWING)) {
94345916cd2Sjpk 			/* First try .windowing version of script */
94445916cd2Sjpk 			(void) strncpy(wdwpath, path, PATH_MAX);
94545916cd2Sjpk 			(void) strncat(wdwpath, ".windowing", PATH_MAX);
94645916cd2Sjpk 			if ((wdwcmd = strrchr(wdwpath, '/')) == NULL)
94745916cd2Sjpk 				wdwcmd = wdwpath;
94845916cd2Sjpk 			(void) execl(wdwpath, wdwcmd, mode, devname, clean_arg,
94945916cd2Sjpk 			    pw_ent.pw_name, devzone, zonepath, NULL);
95045916cd2Sjpk 			/* If that failed, run regular version via dtterm */
95145916cd2Sjpk 			(void) snprintf(title, sizeof (title),
95245916cd2Sjpk 			    "Device %s for %s",
95345916cd2Sjpk 			    strcmp(clean_arg, ALLOC_CLEAN) == 0 ?
95445916cd2Sjpk 			    "allocation" : "deallocation", devname);
95545916cd2Sjpk 			(void) execl("/usr/dt/bin/dtterm", "dtterm",
95645916cd2Sjpk 			    "-title", title, "-geometry", "x10+100+400",
95745916cd2Sjpk 			    "-e", "/etc/security/lib/wdwwrapper",
95845916cd2Sjpk 			    path, mode, devname, clean_arg, pw_ent.pw_name,
95945916cd2Sjpk 			    devzone, zonepath, NULL);
96045916cd2Sjpk 			/*
96145916cd2Sjpk 			 * And if that failed, continue on to try
96245916cd2Sjpk 			 * running regular version directly.
96345916cd2Sjpk 			 */
96445916cd2Sjpk 		}
9657c478bd9Sstevel@tonic-gate 		dprintf("clean script: %s, ", path);
9667c478bd9Sstevel@tonic-gate 		dprintf("cmd=%s, ", cmd);
9677c478bd9Sstevel@tonic-gate 		dprintf("mode=%s, ", mode);
96845916cd2Sjpk 		if (system_labeled) {
96945916cd2Sjpk 			dprintf("devname=%s ", devname);
97045916cd2Sjpk 			dprintf("zonename=%s ", devzone);
97145916cd2Sjpk 			dprintf("zonepath=%s ", zonepath);
97245916cd2Sjpk 			dprintf("username=%s\n", pw_ent.pw_name);
97345916cd2Sjpk 			(void) execl(path, cmd, mode, devname, clean_arg,
97445916cd2Sjpk 			    pw_ent.pw_name, devzone, zonepath, NULL);
97545916cd2Sjpk 		} else {
97645916cd2Sjpk 			dprintf("devname=%s\n", devname);
97745916cd2Sjpk 			(void) execle(path, cmd, mode, devname, NULL, newenv);
97845916cd2Sjpk 		}
9797c478bd9Sstevel@tonic-gate 		dprintf("Unable to execute clean up script %s\n", path);
9807c478bd9Sstevel@tonic-gate 		dperror("");
98145916cd2Sjpk 		exit(CNTDEXECERR);
9827c478bd9Sstevel@tonic-gate 	default:
98345916cd2Sjpk 		(void) waitpid(c, &status, 0);
98445916cd2Sjpk 		dprintf("Child %d", c);
98545916cd2Sjpk 		if (WIFEXITED(status)) {
98645916cd2Sjpk 			exit_status = WEXITSTATUS(status);
98745916cd2Sjpk 			dprintf(" exited, status: %d\n", exit_status);
98845916cd2Sjpk 			return (exit_status);
98945916cd2Sjpk 		} else if (WIFSIGNALED(status)) {
99045916cd2Sjpk 			dprintf(" killed, signal %d\n", WTERMSIG(status));
99145916cd2Sjpk 		} else {
99245916cd2Sjpk 			dprintf(": exit status %d\n", status);
99345916cd2Sjpk 		}
9947c478bd9Sstevel@tonic-gate 		return (-1);
9957c478bd9Sstevel@tonic-gate 	}
9967c478bd9Sstevel@tonic-gate }
9977c478bd9Sstevel@tonic-gate 
99845916cd2Sjpk int
99945916cd2Sjpk _deallocate_dev(int optflag, devalloc_t *da, devmap_t *dm_in, uid_t uid,
1000*10ddde3aSaj     char *zonename, int *lock_fd)
10017c478bd9Sstevel@tonic-gate {
100245916cd2Sjpk 	int			bytes = 0;
10037c478bd9Sstevel@tonic-gate 	int			error = 0;
100445916cd2Sjpk 	int			is_authorized = 0;
100545916cd2Sjpk 	uid_t			nuid;
100645916cd2Sjpk 	char			*fname = NULL;
100745916cd2Sjpk 	char			file_name[MAXPATHLEN];
100845916cd2Sjpk 	char			*devzone = NULL;
100945916cd2Sjpk 	devmap_t		*dm = NULL, *dm_new = NULL;
101045916cd2Sjpk 	struct stat		stat_buf;
101145916cd2Sjpk 	struct state_file	sf;
10127c478bd9Sstevel@tonic-gate 
101345916cd2Sjpk 	if (dm_in == NULL) {
101445916cd2Sjpk 		setdmapent();
101545916cd2Sjpk 		if ((dm_new = getdmapnam(da->da_devname)) == NULL) {
101645916cd2Sjpk 			enddmapent();
101745916cd2Sjpk 			dprintf("Unable to find %s in device map database\n",
101845916cd2Sjpk 			    da->da_devname);
101945916cd2Sjpk 			return (NODMAPERR);
102045916cd2Sjpk 		}
102145916cd2Sjpk 		enddmapent();
102245916cd2Sjpk 		dm = dm_new;
102345916cd2Sjpk 	} else {
102445916cd2Sjpk 		dm = dm_in;
102545916cd2Sjpk 	}
102645916cd2Sjpk 	if (system_labeled) {
102745916cd2Sjpk 		if (_dev_file_name(&sf, dm) != 0) {
102845916cd2Sjpk 			if (dm_new)
102945916cd2Sjpk 				freedmapent(dm_new);
103045916cd2Sjpk 			dprintf("Unable to find %s device files\n",
103145916cd2Sjpk 			    da->da_devname);
103245916cd2Sjpk 			error = NODMAPERR;
103345916cd2Sjpk 			goto out;
103445916cd2Sjpk 		}
103545916cd2Sjpk 		fname = sf.sf_path;
103645916cd2Sjpk 	} else {
103745916cd2Sjpk 		bytes = snprintf(file_name,  MAXPATHLEN, "%s/%s", DAC_DIR,
103845916cd2Sjpk 		    da->da_devname);
103945916cd2Sjpk 		if (bytes <= 0) {
104045916cd2Sjpk 			error = DEVNAMEERR;
104145916cd2Sjpk 			goto out;
104245916cd2Sjpk 		} else if (bytes >= MAXPATHLEN) {
104345916cd2Sjpk 			dprintf("device name %s is too long.\n",
104445916cd2Sjpk 			    da->da_devname);
104545916cd2Sjpk 			error = DEVLONGERR;
104645916cd2Sjpk 			goto out;
104745916cd2Sjpk 		}
104845916cd2Sjpk 		fname = file_name;
10497c478bd9Sstevel@tonic-gate 	}
10507c478bd9Sstevel@tonic-gate 
105145916cd2Sjpk 	audit_allocate_device(fname);
10527c478bd9Sstevel@tonic-gate 
105345916cd2Sjpk 	if (stat(fname, &stat_buf) != 0) {
105445916cd2Sjpk 		dprintf("Unable to stat %s\n", fname);
105545916cd2Sjpk 		error = DACACCERR;
105645916cd2Sjpk 		goto out;
105745916cd2Sjpk 	}
105845916cd2Sjpk 	is_authorized = _is_dev_authorized(da, uid);
105945916cd2Sjpk 	if (!(optflag & (FORCE | FORCE_ALL)) && !is_authorized) {
106045916cd2Sjpk 		dprintf("User %d is unauthorized to deallocate\n", (int)uid);
106145916cd2Sjpk 		error = UAUTHERR;
106245916cd2Sjpk 		goto out;
106345916cd2Sjpk 	}
106445916cd2Sjpk 	if (system_labeled) {
106545916cd2Sjpk 		/*
106645916cd2Sjpk 		 * unless we're here to deallocate by force, check if the
106745916cd2Sjpk 		 * label at which the device is currently allocated is
106845916cd2Sjpk 		 * within the user label range.
106945916cd2Sjpk 		 */
107045916cd2Sjpk 		if (!(optflag & FORCE) &&
107145916cd2Sjpk 		    _check_label(da, zonename, uid, CHECK_URANGE) != 0) {
107245916cd2Sjpk 			error = LABELRNGERR;
107345916cd2Sjpk 			goto out;
107445916cd2Sjpk 		}
107545916cd2Sjpk 	}
107645916cd2Sjpk 	if (!(optflag & FORCE) && stat_buf.st_uid != uid &&
107745916cd2Sjpk 	    DEV_ALLOCATED(stat_buf)) {
107845916cd2Sjpk 		error = ALLOCUERR;
107945916cd2Sjpk 		goto out;
108045916cd2Sjpk 	}
108145916cd2Sjpk 	if (!DEV_ALLOCATED(stat_buf)) {
108245916cd2Sjpk 		if (DEV_ERRORED(stat_buf)) {
108345916cd2Sjpk 			if (!(optflag & FORCE)) {
108445916cd2Sjpk 				error = DEVSTATEERR;
108545916cd2Sjpk 				goto out;
108645916cd2Sjpk 			}
108745916cd2Sjpk 		} else {
108845916cd2Sjpk 			error = DEVNALLOCERR;
108945916cd2Sjpk 			goto out;
109045916cd2Sjpk 		}
109145916cd2Sjpk 	}
109245916cd2Sjpk 	/* All checks passed, time to lock and deallocate */
1093*10ddde3aSaj 	if ((*lock_fd = lock_dev(fname, &stat_buf)) == -1) {
1094*10ddde3aSaj 		error = DEVLKERR;
109545916cd2Sjpk 		goto out;
1096*10ddde3aSaj 	}
109745916cd2Sjpk 	if (system_labeled) {
109845916cd2Sjpk 		devzone = kva_match(da->da_devopts, DAOPT_ZONE);
1099*10ddde3aSaj 		if (devzone == NULL) {
1100*10ddde3aSaj 			devzone = GLOBAL_ZONENAME;
1101*10ddde3aSaj 		} else if (strcmp(devzone, GLOBAL_ZONENAME) != 0) {
110245916cd2Sjpk 			if ((remove_znode(devzone, dm) != 0) &&
110345916cd2Sjpk 			    !(optflag & FORCE)) {
110445916cd2Sjpk 				error = ZONEERR;
110545916cd2Sjpk 				goto out;
110645916cd2Sjpk 			}
110745916cd2Sjpk 		}
110845916cd2Sjpk 	}
110945916cd2Sjpk 	if ((error = mk_unalloc(optflag, dm)) != 0) {
111045916cd2Sjpk 		if (!(optflag & FORCE))
111145916cd2Sjpk 			goto out;
111245916cd2Sjpk 	}
111345916cd2Sjpk 	if (system_labeled == 0) {
1114*10ddde3aSaj 		if ((error = _newdac(fname, DA_UID, DA_GID,
111545916cd2Sjpk 		    DEALLOC_MODE)) != 0) {
1116*10ddde3aSaj 			(void) _newdac(file_name, DA_UID, DA_GID,
111745916cd2Sjpk 			    ALLOC_ERR_MODE);
111845916cd2Sjpk 			goto out;
111945916cd2Sjpk 		}
112045916cd2Sjpk 	}
112145916cd2Sjpk 	/*
112245916cd2Sjpk 	 * if we are deallocating device owned by someone else,
112345916cd2Sjpk 	 * pass the owner's uid to the cleaning script.
112445916cd2Sjpk 	 */
112545916cd2Sjpk 	nuid = (stat_buf.st_uid == uid) ? uid : stat_buf.st_uid;
112645916cd2Sjpk 	error = exec_clean(optflag, da->da_devname, da->da_devexec, nuid,
112745916cd2Sjpk 	    devzone, DEALLOC_CLEAN);
112845916cd2Sjpk 	if (error != 0) {
112945916cd2Sjpk 		if (!(optflag & (FORCE | FORCE_ALL))) {
113045916cd2Sjpk 			error = CLEANERR;
113145916cd2Sjpk 			(void) mk_error(dm);
113245916cd2Sjpk 		} else {
113345916cd2Sjpk 			error = 0;
113445916cd2Sjpk 		}
113545916cd2Sjpk 	}
113645916cd2Sjpk 
113745916cd2Sjpk out:
113845916cd2Sjpk 	if (dm_new)
113945916cd2Sjpk 		freedmapent(dm_new);
114045916cd2Sjpk 	return (error);
114145916cd2Sjpk }
114245916cd2Sjpk 
114345916cd2Sjpk int
1144*10ddde3aSaj _allocate_dev(int optflag, uid_t uid, devalloc_t *da, char *zonename,
1145*10ddde3aSaj 	int *lock_fd)
114645916cd2Sjpk {
114745916cd2Sjpk 	int			i;
114845916cd2Sjpk 	int			bytes = 0;
114945916cd2Sjpk 	int			error = 0;
115045916cd2Sjpk 	int			is_authorized = 0;
115145916cd2Sjpk 	int			dealloc_optflag = 0;
115245916cd2Sjpk 	char			*fname = NULL;
115345916cd2Sjpk 	char			file_name[MAXPATHLEN];
115445916cd2Sjpk 	devmap_t 		*dm;
115545916cd2Sjpk 	struct stat 		stat_buf;
115645916cd2Sjpk 	struct state_file	sf;
115745916cd2Sjpk 	struct zone_path	zpath;
115845916cd2Sjpk 
115945916cd2Sjpk 	zpath.count = 0;
116045916cd2Sjpk 	zpath.path = NULL;
116145916cd2Sjpk 	setdmapent();
116245916cd2Sjpk 	if ((dm = getdmapnam(da->da_devname)) == NULL) {
116345916cd2Sjpk 		enddmapent();
116445916cd2Sjpk 		dprintf("Unable to find %s in device map database\n",
116545916cd2Sjpk 		    da->da_devname);
116645916cd2Sjpk 		return (NODMAPERR);
116745916cd2Sjpk 	}
116845916cd2Sjpk 	enddmapent();
116945916cd2Sjpk 	if (system_labeled) {
117045916cd2Sjpk 		if (_dev_file_name(&sf, dm) != 0) {
117145916cd2Sjpk 			freedmapent(dm);
117245916cd2Sjpk 			dprintf("Unable to find %s device files\n",
117345916cd2Sjpk 			    da->da_devname);
117445916cd2Sjpk 			error = NODMAPERR;
117545916cd2Sjpk 			goto out;
117645916cd2Sjpk 		}
117745916cd2Sjpk 		fname = sf.sf_path;
117845916cd2Sjpk 	} else {
117945916cd2Sjpk 		bytes = snprintf(file_name,  MAXPATHLEN, "%s/%s", DAC_DIR,
118045916cd2Sjpk 		    da->da_devname);
118145916cd2Sjpk 		if (bytes <= 0) {
118245916cd2Sjpk 			error = DEVNAMEERR;
118345916cd2Sjpk 			goto out;
118445916cd2Sjpk 		} else if (bytes >= MAXPATHLEN) {
118545916cd2Sjpk 			dprintf("device name %s is too long.\n",
118645916cd2Sjpk 			    da->da_devname);
118745916cd2Sjpk 			error = DEVLONGERR;
118845916cd2Sjpk 			goto out;
118945916cd2Sjpk 		}
119045916cd2Sjpk 		fname = file_name;
119145916cd2Sjpk 	}
119245916cd2Sjpk 
119345916cd2Sjpk 	(void) audit_allocate_device(fname);
119445916cd2Sjpk 
119545916cd2Sjpk 	if (stat(fname, &stat_buf) != 0) {
119645916cd2Sjpk 		dprintf("Unable to stat %s\n", fname);
11977c478bd9Sstevel@tonic-gate 		dperror("Error:");
119845916cd2Sjpk 		error = DACACCERR;
119945916cd2Sjpk 		goto out;
12007c478bd9Sstevel@tonic-gate 	}
120145916cd2Sjpk 	if (DEV_ERRORED(stat_buf)) {
120245916cd2Sjpk 		error = DEVSTATEERR;
120345916cd2Sjpk 		goto out;
120445916cd2Sjpk 	}
120545916cd2Sjpk 	is_authorized = _is_dev_authorized(da, uid);
120645916cd2Sjpk 	if (is_authorized == ALLOC_BY_NONE) {
120745916cd2Sjpk 		dprintf("Device %s is not allocatable\n", da->da_devname);
120845916cd2Sjpk 		error = UAUTHERR;
120945916cd2Sjpk 		goto out;
121045916cd2Sjpk 	} else if (!is_authorized && !(optflag & USERNAME)) {
121145916cd2Sjpk 		dprintf("User %d is unauthorized to allocate\n", (int)uid);
121245916cd2Sjpk 		error = UAUTHERR;
121345916cd2Sjpk 		goto out;
121445916cd2Sjpk 	}
121545916cd2Sjpk 	if (system_labeled) {
121645916cd2Sjpk 		/*
121745916cd2Sjpk 		 * check if label of the zone to which the device is being
121845916cd2Sjpk 		 * allocated is within the device label range.
121945916cd2Sjpk 		 */
122045916cd2Sjpk 		if (_check_label(da, zonename, uid, CHECK_DRANGE) != 0) {
122145916cd2Sjpk 			error = LABELRNGERR;
122245916cd2Sjpk 			goto out;
122345916cd2Sjpk 		}
122445916cd2Sjpk 	}
122545916cd2Sjpk 	if (check_devs(dm) == -1) {
122645916cd2Sjpk 		error = DSPMISSERR;
122745916cd2Sjpk 		goto out;
122845916cd2Sjpk 	}
12297c478bd9Sstevel@tonic-gate 	if (DEV_ALLOCATED(stat_buf)) {
123045916cd2Sjpk 		if (optflag & FORCE) {
123145916cd2Sjpk 			if (optflag & SILENT)
123245916cd2Sjpk 				dealloc_optflag = FORCE|SILENT;
123340e2b7c9Spaulson 			else
123445916cd2Sjpk 				dealloc_optflag = FORCE;
123545916cd2Sjpk 			if (_deallocate_dev(dealloc_optflag, da, dm, uid,
1236*10ddde3aSaj 			    zonename, lock_fd)) {
12377c478bd9Sstevel@tonic-gate 				dprintf("Couldn't force deallocate device %s\n",
123845916cd2Sjpk 				    da->da_devname);
123945916cd2Sjpk 				error = CNTFRCERR;
124045916cd2Sjpk 				goto out;
12417c478bd9Sstevel@tonic-gate 			}
12427c478bd9Sstevel@tonic-gate 		} else if (stat_buf.st_uid == uid) {
124345916cd2Sjpk 			error = PREALLOCERR;
124445916cd2Sjpk 			goto out;
12457c478bd9Sstevel@tonic-gate 		} else {
124645916cd2Sjpk 			error = ALLOCUERR;
124745916cd2Sjpk 			goto out;
124845916cd2Sjpk 		}
124945916cd2Sjpk 	}
125045916cd2Sjpk 	/* All checks passed, time to lock and allocate */
1251*10ddde3aSaj 	if ((*lock_fd = lock_dev(fname, &stat_buf)) == -1) {
1252*10ddde3aSaj 		error = DEVLKERR;
125345916cd2Sjpk 		goto out;
1254*10ddde3aSaj 	}
125545916cd2Sjpk 	if (system_labeled) {
125645916cd2Sjpk 		/*
125745916cd2Sjpk 		 * Run the cleaning program; it also mounts allocated
125845916cd2Sjpk 		 * device if required.
125945916cd2Sjpk 		 */
126045916cd2Sjpk 		error = exec_clean(optflag, da->da_devname, da->da_devexec, uid,
126145916cd2Sjpk 		    zonename, ALLOC_CLEAN);
1262*10ddde3aSaj 		if (error != DEVCLEAN_OK) {
1263*10ddde3aSaj 			switch (error) {
1264*10ddde3aSaj 			case DEVCLEAN_ERROR:
1265*10ddde3aSaj 			case DEVCLEAN_SYSERR:
1266*10ddde3aSaj 				dprintf("allocate: "
1267*10ddde3aSaj 				    "Error in device clean program %s\n",
1268*10ddde3aSaj 				    da->da_devexec);
126945916cd2Sjpk 				error = CLEANERR;
127045916cd2Sjpk 				(void) mk_error(dm);
127145916cd2Sjpk 				goto out;
1272*10ddde3aSaj 			case DEVCLEAN_BADMOUNT:
1273*10ddde3aSaj 				dprintf("allocate: Failed to mount device %s\n",
1274*10ddde3aSaj 				    da->da_devexec);
1275*10ddde3aSaj 				goto out;
1276*10ddde3aSaj 			case DEVCLEAN_MOUNTOK:
1277*10ddde3aSaj 				break;
1278*10ddde3aSaj 			default:
1279*10ddde3aSaj 				error = 0;
1280*10ddde3aSaj 				goto out;
1281*10ddde3aSaj 			}
128245916cd2Sjpk 		}
128345916cd2Sjpk 		/*
128445916cd2Sjpk 		 * If not mounted, create zonelinks, if this is not the
128545916cd2Sjpk 		 * global zone.
128645916cd2Sjpk 		 */
128745916cd2Sjpk 		if ((strcmp(zonename, GLOBAL_ZONENAME) != 0) &&
1288*10ddde3aSaj 		    (error != DEVCLEAN_MOUNTOK)) {
128945916cd2Sjpk 			if (create_znode(zonename, &zpath, dm) != 0) {
129045916cd2Sjpk 				error = ZONEERR;
129145916cd2Sjpk 				goto out;
129245916cd2Sjpk 			}
129345916cd2Sjpk 		}
129445916cd2Sjpk 	}
129545916cd2Sjpk 
129645916cd2Sjpk 	(void) audit_allocate_list(dm->dmap_devlist);
129745916cd2Sjpk 
129845916cd2Sjpk 	if ((error = mk_alloc(dm, uid, &zpath)) != 0) {
129945916cd2Sjpk 		(void) mk_unalloc(optflag, dm);
130045916cd2Sjpk 		goto out;
130145916cd2Sjpk 	}
130245916cd2Sjpk 
130345916cd2Sjpk 	if (system_labeled == 0) {
130445916cd2Sjpk 		if ((error = _newdac(file_name, uid, getgid(),
130545916cd2Sjpk 		    ALLOC_MODE)) != 0) {
1306*10ddde3aSaj 			(void) _newdac(file_name, DA_UID, DA_GID,
130745916cd2Sjpk 			    ALLOC_ERR_MODE);
130845916cd2Sjpk 			goto out;
130945916cd2Sjpk 		}
131045916cd2Sjpk 	}
131145916cd2Sjpk 	error = 0;
131245916cd2Sjpk out:
131345916cd2Sjpk 	if (zpath.count) {
131445916cd2Sjpk 		for (i = 0; i < zpath.count; i++)
131545916cd2Sjpk 			free(zpath.path[i]);
131645916cd2Sjpk 		free(zpath.path);
131745916cd2Sjpk 	}
131845916cd2Sjpk 	freedmapent(dm);
131945916cd2Sjpk 	return (error);
132045916cd2Sjpk }
132145916cd2Sjpk 
132245916cd2Sjpk void
1323facf4a8dSllai1 _store_devnames(int *count, struct dev_names *dnms, char *zonename,
132445916cd2Sjpk     devalloc_t *da, int flag)
132545916cd2Sjpk {
132645916cd2Sjpk 	int i;
132745916cd2Sjpk 
132845916cd2Sjpk 	dnms->dnames = (char **)realloc(dnms->dnames,
132945916cd2Sjpk 	    (*count + 1) * sizeof (char *));
133045916cd2Sjpk 	if (da) {
133145916cd2Sjpk 		dnms->dnames[*count] = strdup(da->da_devname);
133245916cd2Sjpk 		(*count)++;
133345916cd2Sjpk 	} else {
133445916cd2Sjpk 		dnms->dnames[*count] = NULL;
133545916cd2Sjpk 		if (flag == DA_ADD_ZONE)
133645916cd2Sjpk 			(void) update_device(dnms->dnames, zonename,
133745916cd2Sjpk 			    DA_ADD_ZONE);
133845916cd2Sjpk 		else if (flag == DA_REMOVE_ZONE)
133945916cd2Sjpk 			(void) update_device(dnms->dnames, NULL,
134045916cd2Sjpk 			    DA_REMOVE_ZONE);
134145916cd2Sjpk 		for (i = 0; i < *count; i++)
134245916cd2Sjpk 			free(dnms->dnames[i]);
134345916cd2Sjpk 		free(dnms->dnames);
134445916cd2Sjpk 	}
134545916cd2Sjpk }
134645916cd2Sjpk 
134745916cd2Sjpk int
134845916cd2Sjpk allocate(int optflag, uid_t uid, char *device, char *zonename)
134945916cd2Sjpk {
135045916cd2Sjpk 	int		count = 0;
135145916cd2Sjpk 	int		error = 0;
1352*10ddde3aSaj 	int		lock_fd = -1;
135345916cd2Sjpk 	devalloc_t	*da;
1354facf4a8dSllai1 	struct dev_names dnms;
135545916cd2Sjpk 
135645916cd2Sjpk 	if (optflag & (FORCE | USERID | USERNAME)) {
135745916cd2Sjpk 		if (!_is_authorized(DEVICE_REVOKE_AUTH, getuid()))
135845916cd2Sjpk 			return (UAUTHERR);
135945916cd2Sjpk 	}
136045916cd2Sjpk 	dnms.dnames = NULL;
136145916cd2Sjpk 	setdaent();
136245916cd2Sjpk 	if (optflag & TYPE) {
136345916cd2Sjpk 		/*
136445916cd2Sjpk 		 * allocate devices of this type
136545916cd2Sjpk 		 */
136645916cd2Sjpk 		while ((da = getdatype(device)) != NULL) {
136745916cd2Sjpk 			if (system_labeled &&
136845916cd2Sjpk 			    da_check_logindevperm(da->da_devname)) {
136945916cd2Sjpk 				freedaent(da);
13707c478bd9Sstevel@tonic-gate 				continue;
13717c478bd9Sstevel@tonic-gate 			}
137245916cd2Sjpk 			dprintf("trying to allocate %s\n", da->da_devname);
1373*10ddde3aSaj 			error = _allocate_dev(optflag, uid, da, zonename,
1374*10ddde3aSaj 			    &lock_fd);
137545916cd2Sjpk 			if (system_labeled && (error == 0)) {
137645916cd2Sjpk 				/*
137745916cd2Sjpk 				 * we need to record in device_allocate the
137845916cd2Sjpk 				 * label (zone name) at which this device is
137945916cd2Sjpk 				 * being allocated. store this device entry.
138045916cd2Sjpk 				 */
138145916cd2Sjpk 				_store_devnames(&count, &dnms, zonename, da, 0);
13827c478bd9Sstevel@tonic-gate 			}
138345916cd2Sjpk 			freedaent(da);
138445916cd2Sjpk 			error = 0;
13857c478bd9Sstevel@tonic-gate 		}
138645916cd2Sjpk 	} else {
138745916cd2Sjpk 		/*
138845916cd2Sjpk 		 * allocate this device
138945916cd2Sjpk 		 */
139045916cd2Sjpk 		if ((da = getdanam(device)) == NULL) {
13917c478bd9Sstevel@tonic-gate 			enddaent();
139245916cd2Sjpk 			return (NODAERR);
139345916cd2Sjpk 		}
139445916cd2Sjpk 		if (system_labeled && da_check_logindevperm(device)) {
139545916cd2Sjpk 			freedaent(da);
139645916cd2Sjpk 			return (LOGINDEVPERMERR);
139745916cd2Sjpk 		}
139845916cd2Sjpk 		dprintf("trying to allocate %s\n", da->da_devname);
1399*10ddde3aSaj 		error = _allocate_dev(optflag, uid, da, zonename, &lock_fd);
140045916cd2Sjpk 		/*
140145916cd2Sjpk 		 * we need to record in device_allocate the label (zone name)
140245916cd2Sjpk 		 * at which this device is being allocated. store this device
140345916cd2Sjpk 		 * entry.
140445916cd2Sjpk 		 */
140545916cd2Sjpk 		if (system_labeled && (error == 0))
140645916cd2Sjpk 			_store_devnames(&count, &dnms, zonename, da, 0);
140745916cd2Sjpk 		freedaent(da);
1408*10ddde3aSaj 		if (error == DEVCLEAN_BADMOUNT)
1409*10ddde3aSaj 			error = 0;
141045916cd2Sjpk 	}
141145916cd2Sjpk 	enddaent();
1412*10ddde3aSaj 	if (lock_fd != -1)
1413*10ddde3aSaj 		(void) close(lock_fd);
141445916cd2Sjpk 	/*
141545916cd2Sjpk 	 * add to device_allocate labels (zone names) for the devices we
141645916cd2Sjpk 	 * allocated.
141745916cd2Sjpk 	 */
141845916cd2Sjpk 	if (dnms.dnames)
141945916cd2Sjpk 		_store_devnames(&count, &dnms, zonename, NULL, DA_ADD_ZONE);
142045916cd2Sjpk 
14217c478bd9Sstevel@tonic-gate 	return (error);
14227c478bd9Sstevel@tonic-gate }
142345916cd2Sjpk 
142445916cd2Sjpk /* ARGSUSED */
142545916cd2Sjpk int
142645916cd2Sjpk deallocate(int optflag, uid_t uid, char *device, char *zonename)
142745916cd2Sjpk {
142845916cd2Sjpk 	int		count = 0;
142945916cd2Sjpk 	int		error = 0;
1430*10ddde3aSaj 	int		lock_fd = -1;
1431*10ddde3aSaj 	char		*class = NULL;
143245916cd2Sjpk 	devalloc_t	*da;
1433facf4a8dSllai1 	struct dev_names dnms;
143445916cd2Sjpk 
143545916cd2Sjpk 	if (optflag & (FORCE | FORCE_ALL)) {
143645916cd2Sjpk 		if (!_is_authorized(DEVICE_REVOKE_AUTH, getuid()))
143745916cd2Sjpk 		return (UAUTHERR);
143845916cd2Sjpk 	}
143945916cd2Sjpk 	if (optflag & FORCE_ALL)
144045916cd2Sjpk 		optflag |= FORCE;
144145916cd2Sjpk 	dnms.dnames = NULL;
144245916cd2Sjpk 	setdaent();
144345916cd2Sjpk 	if (optflag & FORCE_ALL) {
144445916cd2Sjpk 		/*
144545916cd2Sjpk 		 * deallocate all devices
144645916cd2Sjpk 		 */
144745916cd2Sjpk 		while ((da = getdaent()) != NULL) {
144845916cd2Sjpk 			if (system_labeled &&
144945916cd2Sjpk 			    da_check_logindevperm(da->da_devname)) {
145045916cd2Sjpk 				freedaent(da);
145145916cd2Sjpk 				continue;
145245916cd2Sjpk 			}
145345916cd2Sjpk 			dprintf("trying to deallocate %s\n", da->da_devname);
145445916cd2Sjpk 			error = _deallocate_dev(optflag, da, NULL, uid,
1455*10ddde3aSaj 			    zonename, &lock_fd);
145645916cd2Sjpk 			if (system_labeled && (error == 0)) {
145745916cd2Sjpk 				/*
145845916cd2Sjpk 				 * we need to remove this device's allocation
145945916cd2Sjpk 				 * label (zone name) from device_allocate.
146045916cd2Sjpk 				 * store this device name.
146145916cd2Sjpk 				 */
146245916cd2Sjpk 				_store_devnames(&count, &dnms, zonename, da, 0);
146345916cd2Sjpk 			}
146445916cd2Sjpk 			freedaent(da);
146545916cd2Sjpk 			error = 0;
146645916cd2Sjpk 		}
1467*10ddde3aSaj 	} else if (system_labeled && (optflag & TYPE)) {
146845916cd2Sjpk 		/*
146945916cd2Sjpk 		 * deallocate all devices of this type
147045916cd2Sjpk 		 */
147145916cd2Sjpk 		while ((da = getdatype(device)) != NULL) {
147245916cd2Sjpk 			if (da_check_logindevperm(da->da_devname)) {
147345916cd2Sjpk 				freedaent(da);
147445916cd2Sjpk 				continue;
147545916cd2Sjpk 			}
147645916cd2Sjpk 			dprintf("trying to deallocate %s\n", da->da_devname);
147745916cd2Sjpk 			error = _deallocate_dev(optflag, da, NULL, uid,
1478*10ddde3aSaj 			    zonename, &lock_fd);
147945916cd2Sjpk 			if (error == 0) {
148045916cd2Sjpk 				/*
148145916cd2Sjpk 				 * we need to remove this device's allocation
148245916cd2Sjpk 				 * label (zone name) from device_allocate.
148345916cd2Sjpk 				 * store this device name.
148445916cd2Sjpk 				 */
148545916cd2Sjpk 				_store_devnames(&count, &dnms, zonename, da, 0);
148645916cd2Sjpk 			}
148745916cd2Sjpk 			freedaent(da);
148845916cd2Sjpk 			error = 0;
148945916cd2Sjpk 		}
1490*10ddde3aSaj 	} else if (system_labeled && (optflag & CLASS)) {
1491*10ddde3aSaj 		/*
1492*10ddde3aSaj 		 * deallocate all devices of this class (for sunray)
1493*10ddde3aSaj 		 */
1494*10ddde3aSaj 		while ((da = getdaent()) != NULL) {
1495*10ddde3aSaj 			class =  kva_match(da->da_devopts, DAOPT_CLASS);
1496*10ddde3aSaj 			if (class && (strcmp(class, device) == 0)) {
1497*10ddde3aSaj 				dprintf("trying to deallocate %s\n",
1498*10ddde3aSaj 				    da->da_devname);
1499*10ddde3aSaj 				error = _deallocate_dev(optflag, da, NULL, uid,
1500*10ddde3aSaj 				    zonename, &lock_fd);
1501*10ddde3aSaj 				if (error == 0) {
1502*10ddde3aSaj 					/*
1503*10ddde3aSaj 					 * we need to remove this device's
1504*10ddde3aSaj 					 * allocation label (zone name) from
1505*10ddde3aSaj 					 * device_allocate. store this device
1506*10ddde3aSaj 					 * name.
1507*10ddde3aSaj 					 */
1508*10ddde3aSaj 					_store_devnames(&count, &dnms, zonename,
1509*10ddde3aSaj 					    da, 0);
1510*10ddde3aSaj 				}
1511*10ddde3aSaj 				error = 0;
1512*10ddde3aSaj 			}
1513*10ddde3aSaj 			freedaent(da);
1514*10ddde3aSaj 		}
151545916cd2Sjpk 	} else if (!(optflag & TYPE)) {
151645916cd2Sjpk 		/*
151745916cd2Sjpk 		 * deallocate this device
151845916cd2Sjpk 		 */
151945916cd2Sjpk 		if ((da = getdanam(device)) == NULL) {
152045916cd2Sjpk 			enddaent();
152145916cd2Sjpk 			return (NODAERR);
152245916cd2Sjpk 		}
152345916cd2Sjpk 		if (system_labeled && da_check_logindevperm(da->da_devname)) {
152445916cd2Sjpk 			freedaent(da);
152545916cd2Sjpk 			return (LOGINDEVPERMERR);
152645916cd2Sjpk 		}
152745916cd2Sjpk 		dprintf("trying to deallocate %s\n", da->da_devname);
1528*10ddde3aSaj 		error = _deallocate_dev(optflag, da, NULL, uid, zonename,
1529*10ddde3aSaj 		    &lock_fd);
153045916cd2Sjpk 		if (system_labeled && (error == 0)) {
153145916cd2Sjpk 			/*
153245916cd2Sjpk 			 * we need to remove this device's allocation label
153345916cd2Sjpk 			 * (zone name) from device_allocate. store this
153445916cd2Sjpk 			 * device name.
153545916cd2Sjpk 			 */
153645916cd2Sjpk 			_store_devnames(&count, &dnms, zonename, da, 0);
153745916cd2Sjpk 		}
153845916cd2Sjpk 		freedaent(da);
1539*10ddde3aSaj 		if (error == DEVCLEAN_BADMOUNT)
1540*10ddde3aSaj 			error = 0;
154145916cd2Sjpk 	}
154245916cd2Sjpk 	enddaent();
1543*10ddde3aSaj 	if (lock_fd != -1)
1544*10ddde3aSaj 		(void) close(lock_fd);
154545916cd2Sjpk 	/*
154645916cd2Sjpk 	 * remove from device_allocate labels (zone names) for the devices we
154745916cd2Sjpk 	 * deallocated.
154845916cd2Sjpk 	 */
154945916cd2Sjpk 	if (dnms.dnames)
155045916cd2Sjpk 		_store_devnames(&count, &dnms, zonename, NULL, DA_REMOVE_ZONE);
155145916cd2Sjpk 
155245916cd2Sjpk 	return (error);
155345916cd2Sjpk }
155445916cd2Sjpk 
155545916cd2Sjpk static int
155645916cd2Sjpk _dev_file_name(struct state_file *sfp, devmap_t *dm)
155745916cd2Sjpk {
155845916cd2Sjpk 	sfp->sf_flags = 0;
155945916cd2Sjpk 	/* if devlist is generated, never leave device in error state */
156045916cd2Sjpk 	if (dm->dmap_devlist[0] == '`')
156145916cd2Sjpk 		sfp->sf_flags |= SFF_NO_ERROR;
156245916cd2Sjpk 	if (dm->dmap_devarray == NULL ||
156345916cd2Sjpk 	    dm->dmap_devarray[0] == NULL)
156445916cd2Sjpk 		return (NODMAPERR);
156545916cd2Sjpk 	(void) strncpy(sfp->sf_path, dm->dmap_devarray[0],
156645916cd2Sjpk 	    sizeof (sfp->sf_path));
156745916cd2Sjpk 	sfp->sf_path[sizeof (sfp->sf_path) - 1] = '\0';
156845916cd2Sjpk 	if (sfp->sf_path[0] == '\0') {
156945916cd2Sjpk 		dprintf("dev_file_name: no device list for %s\n",
157045916cd2Sjpk 		    dm->dmap_devname);
157145916cd2Sjpk 		return (NODMAPERR);
157245916cd2Sjpk 	}
157345916cd2Sjpk 
157445916cd2Sjpk 	return (0);
157545916cd2Sjpk }
157645916cd2Sjpk 
157745916cd2Sjpk /*
157845916cd2Sjpk  * _check_label -
157945916cd2Sjpk  *	checks the device label range against zone label, which is also
158045916cd2Sjpk  *	user's current label.
158145916cd2Sjpk  *	returns 0 if in range, -1 for all other conditions.
158245916cd2Sjpk  *
158345916cd2Sjpk  */
158445916cd2Sjpk 
158545916cd2Sjpk static int
158645916cd2Sjpk _check_label(devalloc_t *da, char *zonename, uid_t uid, int flag)
158745916cd2Sjpk {
158845916cd2Sjpk 	int		err;
158945916cd2Sjpk 	int		in_range = 0;
159045916cd2Sjpk 	char		*alloczone, *lstr;
159145916cd2Sjpk 	char		pw_buf[NSS_BUFLEN_PASSWD];
159245916cd2Sjpk 	blrange_t	*range;
159345916cd2Sjpk 	m_label_t	*zlabel;
159445916cd2Sjpk 	struct passwd	pw_ent;
159545916cd2Sjpk 
159645916cd2Sjpk 	if ((da == NULL) || (zonename == NULL))
159745916cd2Sjpk 		return (-1);
159845916cd2Sjpk 
159945916cd2Sjpk 	if ((zlabel = getzonelabelbyname(zonename)) == NULL) {
160045916cd2Sjpk 		dprintf("unable to get label for %s zone\n", zonename);
160145916cd2Sjpk 		return (-1);
160245916cd2Sjpk 	}
160345916cd2Sjpk 	if (flag == CHECK_DRANGE) {
160445916cd2Sjpk 		blrange_t	drange;
160545916cd2Sjpk 
160645916cd2Sjpk 		drange.lower_bound = blabel_alloc();
160745916cd2Sjpk 		lstr = kva_match(da->da_devopts, DAOPT_MINLABEL);
160845916cd2Sjpk 		if (lstr == NULL) {
160945916cd2Sjpk 			bsllow(drange.lower_bound);
161045916cd2Sjpk 		} else if (stobsl(lstr, drange.lower_bound, NO_CORRECTION,
161145916cd2Sjpk 		    &err) == 0) {
161245916cd2Sjpk 			dprintf("bad min_label for device %s\n",
161345916cd2Sjpk 			    da->da_devname);
161445916cd2Sjpk 			free(zlabel);
161545916cd2Sjpk 			blabel_free(drange.lower_bound);
161645916cd2Sjpk 			return (-1);
161745916cd2Sjpk 		}
161845916cd2Sjpk 		drange.upper_bound = blabel_alloc();
161945916cd2Sjpk 		lstr = kva_match(da->da_devopts, DAOPT_MAXLABEL);
162045916cd2Sjpk 		if (lstr == NULL) {
162145916cd2Sjpk 			bslhigh(drange.upper_bound);
162245916cd2Sjpk 		} else if (stobsl(lstr, drange.upper_bound, NO_CORRECTION,
162345916cd2Sjpk 		    &err) == 0) {
162445916cd2Sjpk 			dprintf("bad max_label for device %s\n",
162545916cd2Sjpk 			    da->da_devname);
162645916cd2Sjpk 			free(zlabel);
162745916cd2Sjpk 			blabel_free(drange.lower_bound);
162845916cd2Sjpk 			blabel_free(drange.upper_bound);
162945916cd2Sjpk 			return (-1);
163045916cd2Sjpk 		}
163145916cd2Sjpk 		if (blinrange(zlabel, &drange) == 0) {
163245916cd2Sjpk 			char	*zlbl = NULL, *min = NULL, *max = NULL;
163345916cd2Sjpk 
163445916cd2Sjpk 			(void) bsltos(zlabel, &zlbl, 0, 0);
163545916cd2Sjpk 			(void) bsltos(drange.lower_bound, &min, 0, 0);
163645916cd2Sjpk 			(void) bsltos(drange.upper_bound, &max, 0, 0);
163745916cd2Sjpk 			dprintf("%s zone label ", zonename);
163845916cd2Sjpk 			dprintf("%s outside device label range: ", zlbl);
163945916cd2Sjpk 			dprintf("min - %s, ", min);
164045916cd2Sjpk 			dprintf("max - %s\n", max);
164145916cd2Sjpk 			free(zlabel);
164245916cd2Sjpk 			blabel_free(drange.lower_bound);
164345916cd2Sjpk 			blabel_free(drange.upper_bound);
164445916cd2Sjpk 			return (-1);
164545916cd2Sjpk 		}
164645916cd2Sjpk 	} else if (flag == CHECK_URANGE) {
164745916cd2Sjpk 		if (getpwuid_r(uid, &pw_ent, pw_buf, sizeof (pw_buf)) == NULL) {
164845916cd2Sjpk 			dprintf("Unable to get passwd entry for userid %d\n",
164945916cd2Sjpk 			    (int)uid);
165045916cd2Sjpk 			free(zlabel);
165145916cd2Sjpk 			return (-1);
165245916cd2Sjpk 		}
165345916cd2Sjpk 		if ((range = getuserrange(pw_ent.pw_name)) == NULL) {
165445916cd2Sjpk 			dprintf("Unable to get label range for userid %d\n",
165545916cd2Sjpk 			    (int)uid);
165645916cd2Sjpk 			free(zlabel);
165745916cd2Sjpk 			return (-1);
165845916cd2Sjpk 		}
165945916cd2Sjpk 		in_range = blinrange(zlabel, range);
166045916cd2Sjpk 		free(zlabel);
166145916cd2Sjpk 		blabel_free(range->lower_bound);
166245916cd2Sjpk 		blabel_free(range->upper_bound);
166345916cd2Sjpk 		free(range);
166445916cd2Sjpk 		if (in_range == 0) {
166545916cd2Sjpk 			dprintf("%s device label ", da->da_devname);
166645916cd2Sjpk 			dprintf("out of user %d label range\n", (int)uid);
166745916cd2Sjpk 			return (-1);
166845916cd2Sjpk 		}
166945916cd2Sjpk 	} else if (flag == CHECK_ZLABEL) {
167045916cd2Sjpk 		alloczone = kva_match(da->da_devopts, DAOPT_ZONE);
167145916cd2Sjpk 		if (alloczone == NULL) {
167245916cd2Sjpk 			free(zlabel);
167345916cd2Sjpk 			return (-1);
167445916cd2Sjpk 		}
167545916cd2Sjpk 		if (strcmp(zonename, alloczone) != 0) {
167645916cd2Sjpk 			dprintf("%s zone is different than ", zonename);
167745916cd2Sjpk 			dprintf("%s zone to which the device ", alloczone);
167845916cd2Sjpk 			dprintf("%s is allocated\n", da->da_devname);
167945916cd2Sjpk 			free(zlabel);
168045916cd2Sjpk 			return (-1);
168145916cd2Sjpk 		}
168245916cd2Sjpk 	}
168345916cd2Sjpk 	free(zlabel);
168445916cd2Sjpk 
168545916cd2Sjpk 	return (0);
168645916cd2Sjpk }
168745916cd2Sjpk 
168845916cd2Sjpk int
168945916cd2Sjpk create_znode(char *zonename, struct zone_path *zpath, devmap_t *list)
169045916cd2Sjpk {
169145916cd2Sjpk 	int		size;
169245916cd2Sjpk 	int		len = 0;
169345916cd2Sjpk 	int		fcount = 0;
169445916cd2Sjpk 	char		*p, *tmpfile, *zoneroot;
169545916cd2Sjpk 	char		**file;
169645916cd2Sjpk 	char		zonepath[MAXPATHLEN];
1697facf4a8dSllai1 	di_prof_t	prof = NULL;
169845916cd2Sjpk 
169945916cd2Sjpk 	file = list->dmap_devarray;
170045916cd2Sjpk 	if (file == NULL)
170145916cd2Sjpk 		return (NODMAPERR);
170245916cd2Sjpk 	if ((zoneroot = getzonerootbyname(zonename)) == NULL) {
170345916cd2Sjpk 		dprintf("unable to get label for %s zone\n", zonename);
170445916cd2Sjpk 		return (1);
170545916cd2Sjpk 	}
170645916cd2Sjpk 	(void) strcpy(zonepath, zoneroot);
170745916cd2Sjpk 	free(zoneroot);
170845916cd2Sjpk 	len = strlen(zonepath);
170945916cd2Sjpk 	size = sizeof (zonepath);
1710facf4a8dSllai1 	(void) strlcat(zonepath, "/dev", size);
1711facf4a8dSllai1 	if (di_prof_init(zonepath, &prof)) {
1712facf4a8dSllai1 		dprintf("failed to initialize dev profile at %s\n", zonepath);
171345916cd2Sjpk 		return (1);
171445916cd2Sjpk 	}
1715facf4a8dSllai1 	zonepath[len] = '\0';
1716facf4a8dSllai1 	for (; *file != NULL; file++) {
171745916cd2Sjpk 		/*
171845916cd2Sjpk 		 * First time initialization
171945916cd2Sjpk 		 */
172045916cd2Sjpk 		tmpfile = strdup(*file);
172145916cd2Sjpk 
172245916cd2Sjpk 		/*
172345916cd2Sjpk 		 * Most devices have pathnames starting in /dev
172445916cd2Sjpk 		 * but SunRay devices do not. In SRRS 3.1 they use /tmp.
172545916cd2Sjpk 		 *
172645916cd2Sjpk 		 * If the device pathname is not in /dev then create
172745916cd2Sjpk 		 * a symbolic link to it and put the device in /dev
172845916cd2Sjpk 		 */
172945916cd2Sjpk 		if (strncmp(tmpfile, "/dev/", strlen("/dev/")) != 0) {
173045916cd2Sjpk 			char	*linkdir;
173145916cd2Sjpk 			char	srclinkdir[MAXPATHLEN];
173245916cd2Sjpk 			char	dstlinkdir[MAXPATHLEN];
173345916cd2Sjpk 
173445916cd2Sjpk 			linkdir = strchr(tmpfile + 1, '/');
173545916cd2Sjpk 			p = strchr(linkdir + 1, '/');
173645916cd2Sjpk 			*p = '\0';
173745916cd2Sjpk 			(void) strcpy(dstlinkdir, "/dev");
173845916cd2Sjpk 			(void) strncat(dstlinkdir, linkdir, MAXPATHLEN);
173945916cd2Sjpk 			(void) snprintf(srclinkdir, MAXPATHLEN, "%s/root%s",
174045916cd2Sjpk 			    zonepath, tmpfile);
174145916cd2Sjpk 			(void) symlink(dstlinkdir, srclinkdir);
174245916cd2Sjpk 			*p = '/';
174345916cd2Sjpk 			(void) strncat(dstlinkdir, p, MAXPATHLEN);
174445916cd2Sjpk 			free(tmpfile);
174545916cd2Sjpk 			tmpfile = strdup(dstlinkdir);
174645916cd2Sjpk 		}
1747facf4a8dSllai1 		if (di_prof_add_dev(prof, tmpfile)) {
1748facf4a8dSllai1 			dprintf("failed to add %s to profile\n", tmpfile);
1749facf4a8dSllai1 			di_prof_fini(prof);
175045916cd2Sjpk 			return (1);
175145916cd2Sjpk 		}
175245916cd2Sjpk 		if (strlcat(zonepath, tmpfile, size) >= size) {
175345916cd2Sjpk 			dprintf("Buffer overflow in create_znode for %s\n",
175445916cd2Sjpk 			    *file);
175545916cd2Sjpk 			free(tmpfile);
1756facf4a8dSllai1 			di_prof_fini(prof);
175745916cd2Sjpk 			return (1);
175845916cd2Sjpk 		}
175945916cd2Sjpk 		free(tmpfile);
176045916cd2Sjpk 		fcount++;
176145916cd2Sjpk 		if ((zpath->path = (char **)realloc(zpath->path,
1762facf4a8dSllai1 		    (fcount * sizeof (char *)))) == NULL) {
1763facf4a8dSllai1 			di_prof_fini(prof);
176445916cd2Sjpk 			return (1);
1765facf4a8dSllai1 		}
176645916cd2Sjpk 		zpath->path[zpath->count] = strdup(zonepath);
176745916cd2Sjpk 		zpath->count = fcount;
176845916cd2Sjpk 		zonepath[len] = '\0';
176945916cd2Sjpk 	}
177045916cd2Sjpk 
1771facf4a8dSllai1 	if (di_prof_commit(prof))
1772facf4a8dSllai1 		dprintf("failed to add devices to zone %s\n", zonename);
1773facf4a8dSllai1 	di_prof_fini(prof);
1774facf4a8dSllai1 
177545916cd2Sjpk 	return (0);
177645916cd2Sjpk }
177745916cd2Sjpk 
177845916cd2Sjpk int
177945916cd2Sjpk remove_znode(char *zonename, devmap_t *dm)
178045916cd2Sjpk {
178145916cd2Sjpk 	int		len = 0;
178245916cd2Sjpk 	char		*zoneroot;
178345916cd2Sjpk 	char		**file;
178445916cd2Sjpk 	char		zonepath[MAXPATHLEN];
1785facf4a8dSllai1 	di_prof_t	prof = NULL;
178645916cd2Sjpk 
178745916cd2Sjpk 	file = dm->dmap_devarray;
178845916cd2Sjpk 	if (file == NULL)
178945916cd2Sjpk 		return (NODMAPERR);
179045916cd2Sjpk 	if ((zoneroot = getzonerootbyname(zonename)) == NULL) {
179145916cd2Sjpk 		(void) snprintf(zonepath, MAXPATHLEN, "/zone/%s", zonename);
179245916cd2Sjpk 	} else {
179345916cd2Sjpk 		(void)  strcpy(zonepath, zoneroot);
179445916cd2Sjpk 		free(zoneroot);
179545916cd2Sjpk 	}
179645916cd2Sjpk 	/*
179745916cd2Sjpk 	 * To support SunRay we will just deal with the
179845916cd2Sjpk 	 * file in /dev, not the symlinks.
179945916cd2Sjpk 	 */
180045916cd2Sjpk 	(void) strncat(zonepath, "/dev", MAXPATHLEN);
180145916cd2Sjpk 	len = strlen(zonepath);
1802facf4a8dSllai1 	if (di_prof_init(zonepath, &prof)) {
1803facf4a8dSllai1 		dprintf("failed to initialize dev profile at %s\n", zonepath);
1804facf4a8dSllai1 		return (1);
1805facf4a8dSllai1 	}
180645916cd2Sjpk 	for (; *file != NULL; file++) {
180745916cd2Sjpk 		char *devrelpath;
180845916cd2Sjpk 
180945916cd2Sjpk 		/*
181045916cd2Sjpk 		 * remove device node from zone.
181145916cd2Sjpk 		 *
181245916cd2Sjpk 		 * SunRay devices don't start with /dev
181345916cd2Sjpk 		 * so skip over first directory to make
181445916cd2Sjpk 		 * sure it is /dev. SunRay devices in zones
181545916cd2Sjpk 		 * will have a symlink into /dev but
181645916cd2Sjpk 		 * we don't ever delete it.
181745916cd2Sjpk 		 */
181845916cd2Sjpk 		devrelpath = strchr(*file + 1, '/');
181945916cd2Sjpk 
1820facf4a8dSllai1 		if (di_prof_add_exclude(prof, devrelpath + 1)) {
1821facf4a8dSllai1 			dprintf("Failed exclude %s in dev profile\n", *file);
1822facf4a8dSllai1 			di_prof_fini(prof);
182345916cd2Sjpk 			return (1);
182445916cd2Sjpk 		}
182545916cd2Sjpk 		zonepath[len] = '\0';
182645916cd2Sjpk 	}
182745916cd2Sjpk 
1828facf4a8dSllai1 	if (di_prof_commit(prof))
1829facf4a8dSllai1 		dprintf("failed to remove devices from zone %s\n", zonename);
1830facf4a8dSllai1 	di_prof_fini(prof);
183145916cd2Sjpk 	return (0);
183245916cd2Sjpk }
183345916cd2Sjpk 
183445916cd2Sjpk int
183545916cd2Sjpk update_device(char **devnames, char *zonename, int flag)
183645916cd2Sjpk {
183745916cd2Sjpk 	int		len, rc;
183845916cd2Sjpk 	char		*optstr = NULL;
183945916cd2Sjpk 	da_args		dargs;
184045916cd2Sjpk 	devinfo_t	devinfo;
184145916cd2Sjpk 
184245916cd2Sjpk 	dargs.optflag = flag;
184345916cd2Sjpk 	dargs.optflag |= DA_UPDATE|DA_ALLOC_ONLY;
184445916cd2Sjpk 	dargs.rootdir = NULL;
184545916cd2Sjpk 	dargs.devnames = devnames;
184645916cd2Sjpk 	devinfo.devname = devinfo.devtype = devinfo.devauths = devinfo.devexec =
184745916cd2Sjpk 	    devinfo.devlist = NULL;
184845916cd2Sjpk 	if (dargs.optflag & DA_ADD_ZONE) {
184945916cd2Sjpk 		len = strlen(DAOPT_ZONE) + strlen(zonename) + 3;
185045916cd2Sjpk 		if ((optstr = (char *)malloc(len)) == NULL)
185145916cd2Sjpk 			return (-1);
185245916cd2Sjpk 		(void) snprintf(optstr, len, "%s%s%s", DAOPT_ZONE, KV_ASSIGN,
185345916cd2Sjpk 		    zonename);
185445916cd2Sjpk 		devinfo.devopts = optstr;
185545916cd2Sjpk 	}
185645916cd2Sjpk 	dargs.devinfo = &devinfo;
185745916cd2Sjpk 
185845916cd2Sjpk 	rc = da_update_device(&dargs);
185945916cd2Sjpk 
186045916cd2Sjpk 	if (optstr)
186145916cd2Sjpk 		free(optstr);
186245916cd2Sjpk 
186345916cd2Sjpk 	return (rc);
186445916cd2Sjpk }
1865