xref: /titanic_44/usr/src/cmd/allocate/allocate3.c (revision 45916cd2fec6e79bca5dee0421bd39e3c2910d1e)
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
5*45916cd2Sjpk  * Common Development and Distribution License (the "License").
6*45916cd2Sjpk  * 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  */
21*45916cd2Sjpk 
227c478bd9Sstevel@tonic-gate /*
2340e2b7c9Spaulson  * Copyright 2006 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>
41*45916cd2Sjpk #include <strings.h>
427c478bd9Sstevel@tonic-gate #include <unistd.h>
437c478bd9Sstevel@tonic-gate #include <bsm/devices.h>
44*45916cd2Sjpk #include <sys/acl.h>
45*45916cd2Sjpk #include <tsol/label.h>
46*45916cd2Sjpk #include <syslog.h>
47*45916cd2Sjpk #include <limits.h>
48*45916cd2Sjpk #include <user_attr.h>
49*45916cd2Sjpk #include <secdb.h>
50*45916cd2Sjpk #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>
60*45916cd2Sjpk #include <utime.h>
61*45916cd2Sjpk #include <libgen.h>
62*45916cd2Sjpk #include <zone.h>
63*45916cd2Sjpk #include <nss_dbdefs.h>
64*45916cd2Sjpk #include <bsm/devalloc.h>
657c478bd9Sstevel@tonic-gate #include "allocate.h"
667c478bd9Sstevel@tonic-gate 
67*45916cd2Sjpk extern void print_error(int, char *);
68*45916cd2Sjpk 
69*45916cd2Sjpk #if	defined(DEBUG) || defined(lint)
707c478bd9Sstevel@tonic-gate #define	dprintf(s, a) (void) fprintf(stderr, s, a)
717c478bd9Sstevel@tonic-gate #define	dperror(s) perror(s)
727c478bd9Sstevel@tonic-gate #else	/* !DEBUG */
73*45916cd2Sjpk #define	dprintf(s, a)	0
74*45916cd2Sjpk #define	dperror(s)	0
757c478bd9Sstevel@tonic-gate #endif	/* DEBUG */
767c478bd9Sstevel@tonic-gate 
77*45916cd2Sjpk #define	DEV_ERRORED(sbuf)	(((sbuf).st_mode & ~S_IFMT) == ALLOC_ERR_MODE)
78*45916cd2Sjpk #define	DEV_INVALID(sbuf)	(((sbuf).st_mode & ~S_IFMT) == ALLOC_INVALID)
797c478bd9Sstevel@tonic-gate #define	DEV_ALLOCATED(sbuf)	((sbuf).st_uid != ALLOC_UID || \
80*45916cd2Sjpk 			!(((sbuf).st_mode & ~S_IFMT) == DEALLOC_MODE || \
81*45916cd2Sjpk 			DEV_ERRORED(sbuf) || DEV_INVALID(sbuf)))
827c478bd9Sstevel@tonic-gate 
83*45916cd2Sjpk #define	ALLOC_CLEAN		"-A"
84*45916cd2Sjpk #define	DEALLOC_CLEAN		"-D"
85*45916cd2Sjpk #define	DAC_DIR			"/etc/security/dev"
867c478bd9Sstevel@tonic-gate #define	DEVICE_AUTH_SEPARATOR	","
87*45916cd2Sjpk #define	LOCALDEVICE		"/dev/console"
887c478bd9Sstevel@tonic-gate #define	PROCFS			"/proc/"
89*45916cd2Sjpk #define	SFF_NO_ERROR		0x1
90*45916cd2Sjpk 
91*45916cd2Sjpk #define	ALLOC_BY_NONE		-1
92*45916cd2Sjpk #define	CHECK_DRANGE		1
93*45916cd2Sjpk #define	CHECK_URANGE		2
94*45916cd2Sjpk #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 
99*45916cd2Sjpk extern int	system_labeled;
1007c478bd9Sstevel@tonic-gate extern char	*newenv[];
1017c478bd9Sstevel@tonic-gate 
102*45916cd2Sjpk struct state_file {
103*45916cd2Sjpk 	int	sf_flags;
104*45916cd2Sjpk 	char	sf_path[MAXPATHLEN];
105*45916cd2Sjpk };
106*45916cd2Sjpk 
107*45916cd2Sjpk struct file_info {
108*45916cd2Sjpk 	struct stat	fi_stat;
109*45916cd2Sjpk 	char		*fi_message;
110*45916cd2Sjpk };
111*45916cd2Sjpk 
112*45916cd2Sjpk struct zone_path {
113*45916cd2Sjpk 	int	count;
114*45916cd2Sjpk 	char	**path;
115*45916cd2Sjpk };
116*45916cd2Sjpk 
117*45916cd2Sjpk struct devnames {
118*45916cd2Sjpk 	char **dnames;
119*45916cd2Sjpk };
120*45916cd2Sjpk 
121*45916cd2Sjpk static int _dev_file_name(struct state_file *, devmap_t *);
122*45916cd2Sjpk static int lock_dev(char *);
123*45916cd2Sjpk static int _check_label(devalloc_t *, char *, uid_t, int);
124*45916cd2Sjpk static int create_znode(char *, struct zone_path *, devmap_t *);
125*45916cd2Sjpk static int remove_znode(char *, devmap_t *);
126*45916cd2Sjpk static int update_device(char **, char *, int);
127*45916cd2Sjpk 
1287c478bd9Sstevel@tonic-gate /*
129*45916cd2Sjpk  * checks if the invoking user is local to the device
1307c478bd9Sstevel@tonic-gate  */
131*45916cd2Sjpk /*ARGSUSED*/
132*45916cd2Sjpk int
133*45916cd2Sjpk _is_local(uid_t uid)
1347c478bd9Sstevel@tonic-gate {
135*45916cd2Sjpk 	struct stat	statbuf;
1367c478bd9Sstevel@tonic-gate 
137*45916cd2Sjpk 	if (stat(LOCALDEVICE, &statbuf) == 0 &&
138*45916cd2Sjpk 	    statbuf.st_uid == uid)
1397c478bd9Sstevel@tonic-gate 		return (1);
140*45916cd2Sjpk 
1417c478bd9Sstevel@tonic-gate 	return (0);
1427c478bd9Sstevel@tonic-gate }
1437c478bd9Sstevel@tonic-gate 
144*45916cd2Sjpk /*
145*45916cd2Sjpk  * Checks if the user with the specified uid has the specified authorization
146*45916cd2Sjpk  */
147*45916cd2Sjpk int
148*45916cd2Sjpk _is_authorized(char *auths, uid_t uid)
1497c478bd9Sstevel@tonic-gate {
150*45916cd2Sjpk 	char		*dcp, *authlist, *lasts;
151*45916cd2Sjpk 	char		pw_buf[NSS_BUFLEN_PASSWD];
152*45916cd2Sjpk 	struct passwd	pw_ent;
1537c478bd9Sstevel@tonic-gate 
154*45916cd2Sjpk 	/*
155*45916cd2Sjpk 	 * first, the easy cases
156*45916cd2Sjpk 	 */
157*45916cd2Sjpk 	if (strcmp(auths, "@") == 0)
158*45916cd2Sjpk 		return (1);
159*45916cd2Sjpk 	if (strcmp(auths, "*") == 0)
160*45916cd2Sjpk 		return (ALLOC_BY_NONE);
161*45916cd2Sjpk 	if (getpwuid_r(uid, &pw_ent, pw_buf, sizeof (pw_buf)) == NULL)
162*45916cd2Sjpk 		return (0);
163*45916cd2Sjpk 	if (strpbrk(auths, DEVICE_AUTH_SEPARATOR) == NULL)
164*45916cd2Sjpk 		return (chkauthattr(auths, pw_ent.pw_name));
165*45916cd2Sjpk 	authlist = strdup(auths);
166*45916cd2Sjpk 	if (authlist == NULL)
167*45916cd2Sjpk 		return (0);
168*45916cd2Sjpk 	for (dcp = authlist;
169*45916cd2Sjpk 	    (dcp = strtok_r(dcp, DEVICE_AUTH_SEPARATOR, &lasts)) != NULL;
170*45916cd2Sjpk 	    dcp = NULL) {
171*45916cd2Sjpk 		if (chkauthattr(dcp, pw_ent.pw_name))
172*45916cd2Sjpk 			break;
173*45916cd2Sjpk 	}
174*45916cd2Sjpk 	free(authlist);
1757c478bd9Sstevel@tonic-gate 
176*45916cd2Sjpk 	return (dcp != NULL);
1777c478bd9Sstevel@tonic-gate }
178*45916cd2Sjpk 
179*45916cd2Sjpk /*
180*45916cd2Sjpk  * Checks if the specified user has authorization for the device
181*45916cd2Sjpk  */
182*45916cd2Sjpk int
183*45916cd2Sjpk _is_dev_authorized(devalloc_t *da, uid_t uid)
184*45916cd2Sjpk {
185*45916cd2Sjpk 	int	ares;
186*45916cd2Sjpk 	char	*auth_list, *dcp, *subauth = NULL;
187*45916cd2Sjpk 
188*45916cd2Sjpk 	auth_list = da->da_devauth;
189*45916cd2Sjpk 	if (auth_list == NULL)
190*45916cd2Sjpk 		return (0);
191*45916cd2Sjpk 	dcp = strpbrk(auth_list, KV_TOKEN_DELIMIT);
192*45916cd2Sjpk 	if (dcp == NULL)
193*45916cd2Sjpk 		return (_is_authorized(auth_list, uid));
194*45916cd2Sjpk 	if (_is_local(uid)) {
195*45916cd2Sjpk 		/* the local authorization is before the separator */
196*45916cd2Sjpk 		ares = dcp - auth_list;
197*45916cd2Sjpk 		subauth = malloc(ares + 1);
198*45916cd2Sjpk 		if (subauth == NULL)
199*45916cd2Sjpk 			return (0);
200*45916cd2Sjpk 		(void) strlcpy(subauth, auth_list, (ares + 1));
201*45916cd2Sjpk 		auth_list = subauth;
202*45916cd2Sjpk 	} else
203*45916cd2Sjpk 		auth_list = dcp + 1;
204*45916cd2Sjpk 	ares = _is_authorized(auth_list, uid);
205*45916cd2Sjpk 	if (subauth != NULL)
206*45916cd2Sjpk 		free(subauth);
207*45916cd2Sjpk 
208*45916cd2Sjpk 	return (ares);
2097c478bd9Sstevel@tonic-gate }
210*45916cd2Sjpk 
211*45916cd2Sjpk int
212*45916cd2Sjpk check_devs(devmap_t *dm)
213*45916cd2Sjpk {
214*45916cd2Sjpk 	int	status = 0;
215*45916cd2Sjpk 	char	**file;
216*45916cd2Sjpk 
217*45916cd2Sjpk 	if (dm->dmap_devarray == NULL)
218*45916cd2Sjpk 		return (NODMAPERR);
219*45916cd2Sjpk 	for (file = dm->dmap_devarray; *file != NULL; file++) {
220*45916cd2Sjpk 		if ((status = access(*file, F_OK)) == -1) {
221*45916cd2Sjpk 			dprintf("Unable to access file %s\n", *file);
222*45916cd2Sjpk 			break;
223*45916cd2Sjpk 		}
224*45916cd2Sjpk 	}
225*45916cd2Sjpk 
226*45916cd2Sjpk 	return (status);
227*45916cd2Sjpk }
228*45916cd2Sjpk 
229*45916cd2Sjpk int
230*45916cd2Sjpk print_da_defs(da_defs_t *da_defs)
231*45916cd2Sjpk {
232*45916cd2Sjpk 	char	optbuf[BUFSIZ];
233*45916cd2Sjpk 	char	*p = NULL;
234*45916cd2Sjpk 
235*45916cd2Sjpk 	if (da_defs->devopts == NULL) {
236*45916cd2Sjpk 		dprintf("No default attributes for %s\n", da_defs->devtype);
237*45916cd2Sjpk 		return (DEFATTRSERR);
238*45916cd2Sjpk 	}
239*45916cd2Sjpk 	(void) printf("dev_type=%s\n", da_defs->devtype);
240*45916cd2Sjpk 	if (_kva2str(da_defs->devopts, optbuf, sizeof (optbuf), KV_ASSIGN,
241*45916cd2Sjpk 	    KV_TOKEN_DELIMIT) == 0) {
242*45916cd2Sjpk 		if (p = rindex(optbuf, ':'))
243*45916cd2Sjpk 			*p = '\0';
244*45916cd2Sjpk 		(void) printf("\t%s\n", optbuf);
245*45916cd2Sjpk 	}
246*45916cd2Sjpk 
2477c478bd9Sstevel@tonic-gate 	return (0);
2487c478bd9Sstevel@tonic-gate }
2497c478bd9Sstevel@tonic-gate 
250*45916cd2Sjpk void
251*45916cd2Sjpk print_dev_attrs(int optflag, devalloc_t *da, devmap_t *dm,
252*45916cd2Sjpk     struct file_info *fip)
2537c478bd9Sstevel@tonic-gate {
254*45916cd2Sjpk 	char	*p = NULL;
255*45916cd2Sjpk 	char	optbuf[BUFSIZ];
2567c478bd9Sstevel@tonic-gate 
257*45916cd2Sjpk 	(void) printf("device=%s%s", dm->dmap_devname, KV_DELIMITER);
258*45916cd2Sjpk 	(void) printf("type=%s%s", dm->dmap_devtype, KV_DELIMITER);
259*45916cd2Sjpk 	(void) printf("auths=%s%s",
260*45916cd2Sjpk 	    (da->da_devauth ? da->da_devauth : ""), KV_DELIMITER);
261*45916cd2Sjpk 	(void) printf("clean=%s%s",
262*45916cd2Sjpk 	    (da->da_devexec ? da->da_devexec : ""), KV_DELIMITER);
263*45916cd2Sjpk 	if (da->da_devopts != NULL) {
264*45916cd2Sjpk 		if (_kva2str(da->da_devopts, optbuf, sizeof (optbuf),
265*45916cd2Sjpk 		    KV_ASSIGN, KV_TOKEN_DELIMIT) == 0) {
266*45916cd2Sjpk 			if (p = rindex(optbuf, ':'))
267*45916cd2Sjpk 				*p = '\0';
268*45916cd2Sjpk 			(void) printf("%s", optbuf);
269*45916cd2Sjpk 		}
270*45916cd2Sjpk 	}
271*45916cd2Sjpk 	(void) printf("%s", KV_DELIMITER);
272*45916cd2Sjpk 	if (optflag & WINDOWING) {
273*45916cd2Sjpk 		if (DEV_INVALID(fip->fi_stat))
274*45916cd2Sjpk 			(void) printf("owner=/INVALID:%s%s", fip->fi_message,
275*45916cd2Sjpk 			    KV_DELIMITER);
276*45916cd2Sjpk 		else if (DEV_ERRORED(fip->fi_stat))
277*45916cd2Sjpk 			(void) printf("owner=/ERROR%s", KV_DELIMITER);
278*45916cd2Sjpk 		else if (!DEV_ALLOCATED(fip->fi_stat))
279*45916cd2Sjpk 			(void) printf("owner=/FREE%s", KV_DELIMITER);
280*45916cd2Sjpk 		else
281*45916cd2Sjpk 			(void) printf("owner=%ld%s", fip->fi_stat.st_uid,
282*45916cd2Sjpk 			    KV_DELIMITER);
283*45916cd2Sjpk 	}
284*45916cd2Sjpk 	(void) printf("files=%s", dm->dmap_devlist);
285*45916cd2Sjpk 	(void) printf("\n");
286*45916cd2Sjpk }
287*45916cd2Sjpk 
288*45916cd2Sjpk void
289*45916cd2Sjpk print_dev(devmap_t *dm)
290*45916cd2Sjpk {
291*45916cd2Sjpk 	char	**file;
292*45916cd2Sjpk 
293*45916cd2Sjpk 	(void) printf(gettext("device: %s "), dm->dmap_devname);
294*45916cd2Sjpk 	(void) printf(gettext("type: %s "), dm->dmap_devtype);
2957c478bd9Sstevel@tonic-gate 	(void) printf(gettext("files:"));
296*45916cd2Sjpk 	file = dm->dmap_devarray;
297*45916cd2Sjpk 	if (file != NULL) {
298*45916cd2Sjpk 		for (; *file != NULL; file++)
299*45916cd2Sjpk 			(void) printf(" %s", *file);
3007c478bd9Sstevel@tonic-gate 	}
3017c478bd9Sstevel@tonic-gate 	(void) printf("\n");
3027c478bd9Sstevel@tonic-gate }
3037c478bd9Sstevel@tonic-gate 
304*45916cd2Sjpk /* ARGSUSED */
305*45916cd2Sjpk int
306*45916cd2Sjpk _list_device(int optflag, uid_t uid, devalloc_t *da, char *zonename)
3077c478bd9Sstevel@tonic-gate {
308*45916cd2Sjpk 	int			bytes = 0;
309*45916cd2Sjpk 	int			error = 0;
310*45916cd2Sjpk 	int			is_authorized = 0;
311*45916cd2Sjpk 	char			*fname = NULL;
3127c478bd9Sstevel@tonic-gate 	char			file_name[MAXPATHLEN];
313*45916cd2Sjpk 	devmap_t		*dm;
314*45916cd2Sjpk 	struct file_info	fi;
315*45916cd2Sjpk 	struct state_file	sf;
3167c478bd9Sstevel@tonic-gate 
317*45916cd2Sjpk 	setdmapent();
318*45916cd2Sjpk 	if ((dm = getdmapnam(da->da_devname)) == NULL) {
319*45916cd2Sjpk 		enddmapent();
320*45916cd2Sjpk 		dprintf("Unable to find %s in the maps database\n",
321*45916cd2Sjpk 		    da->da_devname);
322*45916cd2Sjpk 		return (NODMAPERR);
3237c478bd9Sstevel@tonic-gate 	}
324*45916cd2Sjpk 	enddmapent();
325*45916cd2Sjpk 	if (system_labeled) {
326*45916cd2Sjpk 		if ((error = _dev_file_name(&sf, dm)) != 0) {
327*45916cd2Sjpk 			freedmapent(dm);
328*45916cd2Sjpk 			dprintf("Unable to find %s device files\n",
329*45916cd2Sjpk 			    da->da_devname);
330*45916cd2Sjpk 			error = NODMAPERR;
331*45916cd2Sjpk 			goto out;
3327c478bd9Sstevel@tonic-gate 		}
333*45916cd2Sjpk 		fname = sf.sf_path;
334*45916cd2Sjpk 	} else {
335*45916cd2Sjpk 		bytes = snprintf(file_name, MAXPATHLEN, "%s/%s", DAC_DIR,
336*45916cd2Sjpk 		    da->da_devname);
337*45916cd2Sjpk 		if (bytes <= 0) {
338*45916cd2Sjpk 			error = DEVNAMEERR;
339*45916cd2Sjpk 			goto out;
340*45916cd2Sjpk 		} else if (bytes >= MAXPATHLEN) {
341*45916cd2Sjpk 			dprintf("device name %s is too long.\n",
342*45916cd2Sjpk 			    da->da_devname);
343*45916cd2Sjpk 			error = DEVLONGERR;
344*45916cd2Sjpk 			goto out;
3457c478bd9Sstevel@tonic-gate 		}
346*45916cd2Sjpk 		fname = file_name;
347*45916cd2Sjpk 	}
348*45916cd2Sjpk 	if (stat(fname, &fi.fi_stat) != 0) {
349*45916cd2Sjpk 		dprintf("Unable to stat %s\n", fname);
3507c478bd9Sstevel@tonic-gate 		dperror("Error:");
351*45916cd2Sjpk 		error = DACACCERR;
352*45916cd2Sjpk 		goto out;
353*45916cd2Sjpk 	}
354*45916cd2Sjpk 	if (optflag & USERID)
355*45916cd2Sjpk 		is_authorized = 1;
356*45916cd2Sjpk 	else
357*45916cd2Sjpk 		is_authorized = _is_dev_authorized(da, uid);
358*45916cd2Sjpk 	if (optflag & LISTFREE) {	/* list_devices -n */
359*45916cd2Sjpk 		/*
360*45916cd2Sjpk 		 * list all free devices
361*45916cd2Sjpk 		 */
362*45916cd2Sjpk 		if (DEV_ALLOCATED(fi.fi_stat)) {
363*45916cd2Sjpk 				error = PREALLOCERR;
364*45916cd2Sjpk 				goto out;
365*45916cd2Sjpk 		}
366*45916cd2Sjpk 		if (system_labeled) {
367*45916cd2Sjpk 			/*
368*45916cd2Sjpk 			 * for this free device, check if -
369*45916cd2Sjpk 			 * 1. user has authorization to allocate
370*45916cd2Sjpk 			 * 2. the zone label is within the label range of the
371*45916cd2Sjpk 			 *    device
372*45916cd2Sjpk 			 */
373*45916cd2Sjpk 			if (is_authorized == ALLOC_BY_NONE) {
374*45916cd2Sjpk 				error = DAUTHERR;
375*45916cd2Sjpk 				goto out;
376*45916cd2Sjpk 			} else if (is_authorized == 0) {
377*45916cd2Sjpk 				error = UAUTHERR;
378*45916cd2Sjpk 				goto out;
379*45916cd2Sjpk 			}
380*45916cd2Sjpk 			if (_check_label(da, zonename, uid,
381*45916cd2Sjpk 			    CHECK_DRANGE) != 0) {
382*45916cd2Sjpk 				error = LABELRNGERR;
383*45916cd2Sjpk 				goto out;
384*45916cd2Sjpk 			}
385*45916cd2Sjpk 		}
386*45916cd2Sjpk 	} else if (optflag & LISTALLOC) {	/*  list_devices -u */
387*45916cd2Sjpk 		/*
388*45916cd2Sjpk 		 * list all allocated devices
389*45916cd2Sjpk 		 */
390*45916cd2Sjpk 		if (!DEV_ALLOCATED(fi.fi_stat)) {
391*45916cd2Sjpk 			error = DEVNALLOCERR;
392*45916cd2Sjpk 			goto out;
393*45916cd2Sjpk 		}
394*45916cd2Sjpk 		if (fi.fi_stat.st_uid != uid) {
395*45916cd2Sjpk 			error = DEVSTATEERR;
396*45916cd2Sjpk 			goto out;
397*45916cd2Sjpk 		}
398*45916cd2Sjpk 		if (system_labeled) {
399*45916cd2Sjpk 			/*
400*45916cd2Sjpk 			 * check if the zone label equals the label at which
401*45916cd2Sjpk 			 * the device is allocated.
402*45916cd2Sjpk 			 */
403*45916cd2Sjpk 			if (_check_label(da, zonename, uid,
404*45916cd2Sjpk 			    CHECK_ZLABEL) != 0) {
405*45916cd2Sjpk 				error = LABELRNGERR;
406*45916cd2Sjpk 				goto out;
407*45916cd2Sjpk 			}
408*45916cd2Sjpk 		}
409*45916cd2Sjpk 	} else if (optflag & LISTALL) {		/* list_devices -l */
410*45916cd2Sjpk 		/*
411*45916cd2Sjpk 		 * list all devices - free and allocated - available
412*45916cd2Sjpk 		 */
413*45916cd2Sjpk 		if (DEV_ALLOCATED(fi.fi_stat)) {
414*45916cd2Sjpk 			if (optflag & WINDOWING &&
415*45916cd2Sjpk 			    (is_authorized == ALLOC_BY_NONE)) {
416*45916cd2Sjpk 				/*
417*45916cd2Sjpk 				 * don't complain if we're here for the GUI.
418*45916cd2Sjpk 				 */
419*45916cd2Sjpk 				error = 0;
420*45916cd2Sjpk 			} else if (fi.fi_stat.st_uid != uid) {
421*45916cd2Sjpk 				if (!(optflag & WINDOWING)) {
422*45916cd2Sjpk 					error = ALLOCUERR;
423*45916cd2Sjpk 					goto out;
424*45916cd2Sjpk 				}
425*45916cd2Sjpk 			}
426*45916cd2Sjpk 			if (system_labeled && !(optflag & WINDOWING)) {
427*45916cd2Sjpk 				/*
428*45916cd2Sjpk 				 * if we're not displaying in the GUI,
429*45916cd2Sjpk 				 * check if the zone label equals the label
430*45916cd2Sjpk 				 * at which the device is allocated.
431*45916cd2Sjpk 				 */
432*45916cd2Sjpk 				if (_check_label(da, zonename, uid,
433*45916cd2Sjpk 				    CHECK_ZLABEL) != 0) {
434*45916cd2Sjpk 					error = LABELRNGERR;
435*45916cd2Sjpk 					goto out;
436*45916cd2Sjpk 				}
437*45916cd2Sjpk 			}
438*45916cd2Sjpk 		} else if (system_labeled && !(optflag & WINDOWING)) {
439*45916cd2Sjpk 			/*
440*45916cd2Sjpk 			 * if we're not displaying in the GUI,
441*45916cd2Sjpk 			 * for this free device, check if -
442*45916cd2Sjpk 			 * 1. user has authorization to allocate
443*45916cd2Sjpk 			 * 2. the zone label is within the label range of the
444*45916cd2Sjpk 			 *    device
445*45916cd2Sjpk 			 */
446*45916cd2Sjpk 			if (is_authorized == ALLOC_BY_NONE) {
447*45916cd2Sjpk 				error = DAUTHERR;
448*45916cd2Sjpk 				goto out;
449*45916cd2Sjpk 			} else if (is_authorized == 0) {
450*45916cd2Sjpk 				error = UAUTHERR;
451*45916cd2Sjpk 				goto out;
452*45916cd2Sjpk 			}
453*45916cd2Sjpk 			if (_check_label(da, zonename, uid,
454*45916cd2Sjpk 			    CHECK_DRANGE) != 0) {
455*45916cd2Sjpk 				error = LABELRNGERR;
456*45916cd2Sjpk 				goto out;
457*45916cd2Sjpk 			}
458*45916cd2Sjpk 		}
459*45916cd2Sjpk 	}
460*45916cd2Sjpk 	if (system_labeled && DEV_ERRORED(fi.fi_stat) && !(optflag & LISTALL)) {
461*45916cd2Sjpk 		error = DEVSTATEERR;
462*45916cd2Sjpk 		goto out;
463*45916cd2Sjpk 	}
464*45916cd2Sjpk 	if (check_devs(dm) == -1) {
465*45916cd2Sjpk 		error = DSPMISSERR;
466*45916cd2Sjpk 		goto out;
467*45916cd2Sjpk 	}
468*45916cd2Sjpk 	if (optflag & LISTATTRS)
469*45916cd2Sjpk 		print_dev_attrs(optflag, da, dm, &fi);
470*45916cd2Sjpk 	else
471*45916cd2Sjpk 		print_dev(dm);
472*45916cd2Sjpk 
473*45916cd2Sjpk 	error = 0;
474*45916cd2Sjpk 
475*45916cd2Sjpk out:
476*45916cd2Sjpk 	freedmapent(dm);
477*45916cd2Sjpk 	return (error);
4787c478bd9Sstevel@tonic-gate }
4797c478bd9Sstevel@tonic-gate 
480*45916cd2Sjpk /* ARGSUSED */
481*45916cd2Sjpk int
482*45916cd2Sjpk list_devices(int optflag, uid_t uid, char *device, char *zonename)
483*45916cd2Sjpk {
484*45916cd2Sjpk 	int		error = 0;
485*45916cd2Sjpk 	da_defs_t	*da_defs;
486*45916cd2Sjpk 	devalloc_t	*da;
4877c478bd9Sstevel@tonic-gate 
488*45916cd2Sjpk 	if (system_labeled && optflag & WINDOWING && !(optflag & LISTATTRS)) {
489*45916cd2Sjpk 		/*
490*45916cd2Sjpk 		 * Private interface for GUI.
491*45916cd2Sjpk 		 */
492*45916cd2Sjpk 		(void) lock_dev(NULL);
493*45916cd2Sjpk 		(void) puts(DA_DB_LOCK);
4947c478bd9Sstevel@tonic-gate 		return (0);
4957c478bd9Sstevel@tonic-gate 	}
496*45916cd2Sjpk 	if (optflag & USERID) {
497*45916cd2Sjpk 		/*
498*45916cd2Sjpk 		 * we need device.revoke to list someone else's devices
499*45916cd2Sjpk 		 */
500*45916cd2Sjpk 		if (!_is_authorized(DEVICE_REVOKE_AUTH, getuid()))
501*45916cd2Sjpk 			return (UAUTHERR);
502*45916cd2Sjpk 	}
503*45916cd2Sjpk 	if (system_labeled) {
504*45916cd2Sjpk 		if (!(optflag & USERID) &&
505*45916cd2Sjpk 		    !_is_authorized(DEFAULT_DEV_ALLOC_AUTH, uid))
506*45916cd2Sjpk 			/*
507*45916cd2Sjpk 			 * we need device.allocate to list our devices
508*45916cd2Sjpk 			 */
509*45916cd2Sjpk 			return (UAUTHERR);
510*45916cd2Sjpk 		if (optflag & LISTDEFS) {
511*45916cd2Sjpk 			/*
512*45916cd2Sjpk 			 * list default attrs from devalloc_defaults
513*45916cd2Sjpk 			 */
514*45916cd2Sjpk 			setdadefent();
515*45916cd2Sjpk 			if (device) {
516*45916cd2Sjpk 				/*
517*45916cd2Sjpk 				 * list default attrs for this device type
518*45916cd2Sjpk 				 */
519*45916cd2Sjpk 				da_defs = getdadeftype(device);
520*45916cd2Sjpk 				if (da_defs == NULL) {
521*45916cd2Sjpk 					enddadefent();
522*45916cd2Sjpk 					dprintf("No default attributes for "
523*45916cd2Sjpk 					    "%s\n", device);
524*45916cd2Sjpk 					return (DEFATTRSERR);
525*45916cd2Sjpk 				}
526*45916cd2Sjpk 				error = print_da_defs(da_defs);
527*45916cd2Sjpk 				freedadefent(da_defs);
528*45916cd2Sjpk 			} else {
529*45916cd2Sjpk 				/*
530*45916cd2Sjpk 				 * list everything in devalloc_defaults
531*45916cd2Sjpk 				 */
532*45916cd2Sjpk 				while ((da_defs = getdadefent()) != NULL) {
533*45916cd2Sjpk 					(void) print_da_defs(da_defs);
534*45916cd2Sjpk 					freedadefent(da_defs);
535*45916cd2Sjpk 				}
536*45916cd2Sjpk 			}
537*45916cd2Sjpk 			enddadefent();
538*45916cd2Sjpk 			return (error);
539*45916cd2Sjpk 		}
5407c478bd9Sstevel@tonic-gate 	}
5417c478bd9Sstevel@tonic-gate 	setdaent();
5427c478bd9Sstevel@tonic-gate 	if (device) {
543*45916cd2Sjpk 		/*
544*45916cd2Sjpk 		 * list this device
545*45916cd2Sjpk 		 */
546*45916cd2Sjpk 		if ((da = getdanam(device)) == NULL) {
5477c478bd9Sstevel@tonic-gate 			enddaent();
548*45916cd2Sjpk 			return (NODAERR);
549*45916cd2Sjpk 		}
550*45916cd2Sjpk 		error = _list_device(optflag, uid, da, zonename);
551*45916cd2Sjpk 		freedaent(da);
552*45916cd2Sjpk 	} else {
553*45916cd2Sjpk 		/*
554*45916cd2Sjpk 		 * list all devices
555*45916cd2Sjpk 		 */
556*45916cd2Sjpk 		while ((da = getdaent()) != NULL) {
557*45916cd2Sjpk 			(void) _list_device(optflag, uid, da, zonename);
558*45916cd2Sjpk 			freedaent(da);
559*45916cd2Sjpk 		}
560*45916cd2Sjpk 	}
561*45916cd2Sjpk 	enddaent();
562*45916cd2Sjpk 
563*45916cd2Sjpk 	return (error);
5647c478bd9Sstevel@tonic-gate }
5657c478bd9Sstevel@tonic-gate 
5667c478bd9Sstevel@tonic-gate /*
5677c478bd9Sstevel@tonic-gate  * Set the DAC characteristics of the file.
5687c478bd9Sstevel@tonic-gate  * This uses a fancy chmod() by setting a minimal ACL which sets the mode
5697c478bd9Sstevel@tonic-gate  * and discards any existing ACL.
5707c478bd9Sstevel@tonic-gate  */
571*45916cd2Sjpk int
572*45916cd2Sjpk _newdac(char *file, uid_t owner, gid_t group, o_mode_t mode)
5737c478bd9Sstevel@tonic-gate {
5747c478bd9Sstevel@tonic-gate 	int	err = 0;
5757c478bd9Sstevel@tonic-gate 
576*45916cd2Sjpk 	if (mode == ALLOC_MODE) {
5777c478bd9Sstevel@tonic-gate 		if (chown(file, owner, group) == -1) {
578*45916cd2Sjpk 			dperror("newdac: unable to chown");
579*45916cd2Sjpk 			err = CHOWNERR;
580*45916cd2Sjpk 		}
581*45916cd2Sjpk 	} else do {
582*45916cd2Sjpk 		if (chown(file, owner, group) == -1) {
583*45916cd2Sjpk 			dperror("newdac: unable to chown");
584*45916cd2Sjpk 			err = CHOWNERR;
5857c478bd9Sstevel@tonic-gate 		}
5867c478bd9Sstevel@tonic-gate 	} while (fdetach(file) == 0);
5877c478bd9Sstevel@tonic-gate 
588*45916cd2Sjpk 	if (err)
589*45916cd2Sjpk 		return (err);
590*45916cd2Sjpk 
591*45916cd2Sjpk 	if (strncmp(file, "/dev/", strlen("/dev/")) != 0) {
592*45916cd2Sjpk 		/*
593*45916cd2Sjpk 		 * This could be a SunRay device that is in /tmp.
594*45916cd2Sjpk 		 */
595*45916cd2Sjpk 		if (chmod(file, mode) == -1) {
596*45916cd2Sjpk 			dperror("newdac: unable to chmod");
597*45916cd2Sjpk 			err = SETACLERR;
598*45916cd2Sjpk 		}
599*45916cd2Sjpk 	} else {
600fa9e4066Sahrens 		err = acl_strip(file, owner, group, (mode_t)mode);
601*45916cd2Sjpk 	}
602fa9e4066Sahrens 
603fa9e4066Sahrens 	if (err != 0) {
604*45916cd2Sjpk 		dperror("newdac: unable to setacl");
605*45916cd2Sjpk 		err = SETACLERR;
6067c478bd9Sstevel@tonic-gate 	}
6077c478bd9Sstevel@tonic-gate 
6087c478bd9Sstevel@tonic-gate 	return (err);
6097c478bd9Sstevel@tonic-gate }
6107c478bd9Sstevel@tonic-gate 
6117c478bd9Sstevel@tonic-gate static int
6127c478bd9Sstevel@tonic-gate lock_dev(char *file)
6137c478bd9Sstevel@tonic-gate {
614*45916cd2Sjpk 	int	lockfd = -1;
6157c478bd9Sstevel@tonic-gate 
616*45916cd2Sjpk 	if ((file == NULL) || system_labeled)
617*45916cd2Sjpk 		file = DA_DEV_LOCK;
6187c478bd9Sstevel@tonic-gate 	dprintf("locking %s\n", file);
619*45916cd2Sjpk 	if ((lockfd = open(file, O_RDWR | O_CREAT, 0600)) == -1) {
620*45916cd2Sjpk 		dperror("lock_dev: cannot open lock file");
621*45916cd2Sjpk 		return (DEVLKERR);
6227c478bd9Sstevel@tonic-gate 	}
623*45916cd2Sjpk 	if (lockf(lockfd, F_TLOCK, 0) == -1) {
624*45916cd2Sjpk 		dperror("lock_dev: cannot set lock");
625*45916cd2Sjpk 		return (DEVLKERR);
6267c478bd9Sstevel@tonic-gate 	}
6277c478bd9Sstevel@tonic-gate 
6287c478bd9Sstevel@tonic-gate 	return (0);
6297c478bd9Sstevel@tonic-gate }
6307c478bd9Sstevel@tonic-gate 
631*45916cd2Sjpk int
632*45916cd2Sjpk mk_alloc(devmap_t *list, uid_t uid, struct zone_path *zpath)
6337c478bd9Sstevel@tonic-gate {
634*45916cd2Sjpk 	int	i;
635*45916cd2Sjpk 	int	error = 0;
636*45916cd2Sjpk 	char	**file;
637*45916cd2Sjpk 	gid_t	gid = getgid();
638*45916cd2Sjpk 	mode_t	mode = ALLOC_MODE;
6397c478bd9Sstevel@tonic-gate 
640*45916cd2Sjpk 	file = list->dmap_devarray;
641*45916cd2Sjpk 	if (file == NULL)
642*45916cd2Sjpk 		return (NODMAPERR);
643*45916cd2Sjpk 	for (; *file != NULL; file++) {
644*45916cd2Sjpk 		dprintf("Allocating %s\n", *file);
645*45916cd2Sjpk 		if ((error = _newdac(*file, uid, gid, mode)) != 0) {
646*45916cd2Sjpk 			(void) _newdac(*file, ALLOC_ERRID, ALLOC_GID,
6477c478bd9Sstevel@tonic-gate 			    ALLOC_ERR_MODE);
648*45916cd2Sjpk 			break;
649*45916cd2Sjpk 		}
650*45916cd2Sjpk 	}
651*45916cd2Sjpk 	if (system_labeled && zpath->count && (error == 0)) {
652*45916cd2Sjpk 		/*
653*45916cd2Sjpk 		 * mark as allocated any new device nodes that we
654*45916cd2Sjpk 		 * created in local zone
655*45916cd2Sjpk 		 */
656*45916cd2Sjpk 		for (i = 0; i < zpath->count; i++) {
657*45916cd2Sjpk 			dprintf("Allocating %s\n", zpath->path[i]);
658*45916cd2Sjpk 			if ((error = _newdac(zpath->path[i], uid, gid,
659*45916cd2Sjpk 			    mode)) != 0) {
660*45916cd2Sjpk 				(void) _newdac(zpath->path[i], ALLOC_ERRID,
661*45916cd2Sjpk 				    ALLOC_GID, ALLOC_ERR_MODE);
662*45916cd2Sjpk 				break;
663*45916cd2Sjpk 			}
664*45916cd2Sjpk 		}
6657c478bd9Sstevel@tonic-gate 	}
6667c478bd9Sstevel@tonic-gate 
667*45916cd2Sjpk 	return (error);
6687c478bd9Sstevel@tonic-gate }
6697c478bd9Sstevel@tonic-gate 
6707c478bd9Sstevel@tonic-gate /*
6717c478bd9Sstevel@tonic-gate  * mk_revoke() is used instead of system("/usr/sbin/fuser -k file")
6727c478bd9Sstevel@tonic-gate  * because "/usr/sbin/fuser -k file" kills all processes
6737c478bd9Sstevel@tonic-gate  * working with the file, even "vold" (bug #4095152).
6747c478bd9Sstevel@tonic-gate  */
675*45916cd2Sjpk int
676*45916cd2Sjpk mk_revoke(int optflag, char *file)
6777c478bd9Sstevel@tonic-gate {
6787c478bd9Sstevel@tonic-gate 	int		r = 0, p[2], fp, lock;
679*45916cd2Sjpk 	int		fuserpid;
680*45916cd2Sjpk 	char		buf[MAXPATHLEN];
6817c478bd9Sstevel@tonic-gate 	FILE		*ptr;
682*45916cd2Sjpk 	pid_t		c_pid;
6837c478bd9Sstevel@tonic-gate 	prpsinfo_t	info;
6847c478bd9Sstevel@tonic-gate 
6857c478bd9Sstevel@tonic-gate 	(void) strcpy(buf, PROCFS);
6867c478bd9Sstevel@tonic-gate 	/*
687*45916cd2Sjpk 	 * vfork() and execl() just to make the same output
6887c478bd9Sstevel@tonic-gate 	 * as before fixing of bug #4095152.
6897c478bd9Sstevel@tonic-gate 	 * The problem is that the "fuser" command prints
6907c478bd9Sstevel@tonic-gate 	 * one part of output into stderr and another into stdout,
6917c478bd9Sstevel@tonic-gate 	 * but user sees them mixed. Of course, better to change "fuser"
6927c478bd9Sstevel@tonic-gate 	 * or to intercept and not to print its output.
6937c478bd9Sstevel@tonic-gate 	 */
694*45916cd2Sjpk 	if (!(optflag & SILENT)) {
6957c478bd9Sstevel@tonic-gate 		c_pid = vfork();
6967c478bd9Sstevel@tonic-gate 		if (c_pid == -1)
6977c478bd9Sstevel@tonic-gate 			return (-1);
6987c478bd9Sstevel@tonic-gate 		if (c_pid == 0) {
6997c478bd9Sstevel@tonic-gate 			dprintf("first exec fuser %s\n", file);
700*45916cd2Sjpk 			(void) execl("/usr/sbin/fuser", "fuser", file, NULL);
7017c478bd9Sstevel@tonic-gate 			dperror("first exec fuser");
7027c478bd9Sstevel@tonic-gate 			_exit(1);
7037c478bd9Sstevel@tonic-gate 		}
7047c478bd9Sstevel@tonic-gate 
7057c478bd9Sstevel@tonic-gate 		(void) waitpid(c_pid, &lock, 0);
7067c478bd9Sstevel@tonic-gate 		dprintf("exit status %x\n", lock);
7077c478bd9Sstevel@tonic-gate 		if (WEXITSTATUS(lock) != 0)
7087c478bd9Sstevel@tonic-gate 			return (-1);
7097c478bd9Sstevel@tonic-gate 	}
710*45916cd2Sjpk 	dprintf("first continuing c_pid=%d\n", (int)c_pid);
7117c478bd9Sstevel@tonic-gate 	if (pipe(p)) {
7127c478bd9Sstevel@tonic-gate 		dperror("pipe");
7137c478bd9Sstevel@tonic-gate 		return (-1);
7147c478bd9Sstevel@tonic-gate 	}
715*45916cd2Sjpk 	/* vfork() and execl() to catch output and to process it */
7167c478bd9Sstevel@tonic-gate 	c_pid = vfork();
7177c478bd9Sstevel@tonic-gate 	if (c_pid == -1) {
7187c478bd9Sstevel@tonic-gate 		dperror("second vfork");
7197c478bd9Sstevel@tonic-gate 		return (-1);
7207c478bd9Sstevel@tonic-gate 	}
721*45916cd2Sjpk 	dprintf("second continuing c_pid=%d\n", (int)c_pid);
7227c478bd9Sstevel@tonic-gate 	if (c_pid == 0) {
7237c478bd9Sstevel@tonic-gate 		(void) close(p[0]);
7247c478bd9Sstevel@tonic-gate 		(void) close(1);
7257c478bd9Sstevel@tonic-gate 		(void) fcntl(p[1], F_DUPFD, 1);
7267c478bd9Sstevel@tonic-gate 		(void) close(p[1]);
7277c478bd9Sstevel@tonic-gate 		(void) close(2);
7287c478bd9Sstevel@tonic-gate 		dprintf("second exec fuser %s\n", file);
729*45916cd2Sjpk 		(void) execl("/usr/sbin/fuser", "fuser", file, NULL);
7307c478bd9Sstevel@tonic-gate 		dperror("second exec fuser");
7317c478bd9Sstevel@tonic-gate 		_exit(1);
7327c478bd9Sstevel@tonic-gate 	}
7337c478bd9Sstevel@tonic-gate 	(void) close(p[1]);
7347c478bd9Sstevel@tonic-gate 	if ((ptr = fdopen(p[0], "r")) != NULL) {
7357c478bd9Sstevel@tonic-gate 		while (!feof(ptr)) {
736*45916cd2Sjpk 			if (fscanf(ptr, "%d", &fuserpid) > 0) {
737*45916cd2Sjpk 				(void) sprintf(buf + strlen(PROCFS), "%d",
738*45916cd2Sjpk 				    fuserpid);
7397c478bd9Sstevel@tonic-gate 				if ((fp = open(buf, O_RDONLY)) == -1) {
7407c478bd9Sstevel@tonic-gate 					dperror(buf);
7417c478bd9Sstevel@tonic-gate 					continue;
7427c478bd9Sstevel@tonic-gate 				}
743*45916cd2Sjpk 				if (ioctl(fp, PIOCPSINFO,
744*45916cd2Sjpk 				    (char *)&info) == -1) {
745*45916cd2Sjpk 					dprintf("%d psinfo failed", fuserpid);
7467c478bd9Sstevel@tonic-gate 					dperror("");
7477c478bd9Sstevel@tonic-gate 					(void) close(fp);
7487c478bd9Sstevel@tonic-gate 					continue;
7497c478bd9Sstevel@tonic-gate 				}
7507c478bd9Sstevel@tonic-gate 				(void) close(fp);
7517c478bd9Sstevel@tonic-gate 				if (strcmp(info.pr_fname, "vold") == NULL) {
752*45916cd2Sjpk 					dprintf("%d matched vold name\n",
753*45916cd2Sjpk 					    fuserpid);
7547c478bd9Sstevel@tonic-gate 					continue;
7557c478bd9Sstevel@tonic-gate 				}
7567c478bd9Sstevel@tonic-gate 				dprintf("killing %s", info.pr_fname);
757*45916cd2Sjpk 				dprintf("(%d)\n", fuserpid);
758*45916cd2Sjpk 				if ((r =
759*45916cd2Sjpk 				    kill((pid_t)fuserpid, SIGKILL)) == -1) {
760*45916cd2Sjpk 					dprintf("kill %d", fuserpid);
7617c478bd9Sstevel@tonic-gate 					dperror("");
7627c478bd9Sstevel@tonic-gate 					break;
7637c478bd9Sstevel@tonic-gate 				}
7647c478bd9Sstevel@tonic-gate 			}
7657c478bd9Sstevel@tonic-gate 		}
7667c478bd9Sstevel@tonic-gate 	} else {
767*45916cd2Sjpk 		dperror("fdopen(p[0], r)");
7687c478bd9Sstevel@tonic-gate 		r = -1;
7697c478bd9Sstevel@tonic-gate 	}
7707c478bd9Sstevel@tonic-gate 	(void) fclose(ptr);
771*45916cd2Sjpk 
7727c478bd9Sstevel@tonic-gate 	return (r);
7737c478bd9Sstevel@tonic-gate }
7747c478bd9Sstevel@tonic-gate 
775*45916cd2Sjpk int
776*45916cd2Sjpk mk_unalloc(int optflag, devmap_t *list)
7777c478bd9Sstevel@tonic-gate {
7787c478bd9Sstevel@tonic-gate 	int	error = 0;
7797c478bd9Sstevel@tonic-gate 	int	status;
780*45916cd2Sjpk 	char	**file;
7817c478bd9Sstevel@tonic-gate 
782*45916cd2Sjpk 	audit_allocate_list(list->dmap_devlist);
783*45916cd2Sjpk 	file = list->dmap_devarray;
784*45916cd2Sjpk 	if (file == NULL)
785*45916cd2Sjpk 		return (NODMAPERR);
786*45916cd2Sjpk 	for (; *file != NULL; file++) {
787*45916cd2Sjpk 		dprintf("Deallocating %s\n", *file);
788*45916cd2Sjpk 		if (mk_revoke(optflag, *file) < 0) {
789*45916cd2Sjpk 			dprintf("mk_unalloc: unable to revoke %s\n", *file);
790*45916cd2Sjpk 			dperror("");
791*45916cd2Sjpk 			error = CNTFRCERR;
792*45916cd2Sjpk 		}
793*45916cd2Sjpk 		status = _newdac(*file, ALLOC_UID, ALLOC_GID, DEALLOC_MODE);
794*45916cd2Sjpk 		if (error == 0)
795*45916cd2Sjpk 			error = status;
796*45916cd2Sjpk 
797*45916cd2Sjpk 	}
798*45916cd2Sjpk 
799*45916cd2Sjpk 	return (error);
800*45916cd2Sjpk }
801*45916cd2Sjpk 
802*45916cd2Sjpk int
803*45916cd2Sjpk mk_error(devmap_t *list)
804*45916cd2Sjpk {
805*45916cd2Sjpk 	int	status = 0;
806*45916cd2Sjpk 	char	**file;
807*45916cd2Sjpk 
808*45916cd2Sjpk 	audit_allocate_list(list->dmap_devlist);
809*45916cd2Sjpk 	file = list->dmap_devarray;
810*45916cd2Sjpk 	if (file == NULL)
811*45916cd2Sjpk 		return (NODMAPERR);
812*45916cd2Sjpk 	for (; *file != NULL; file++) {
813*45916cd2Sjpk 		dprintf("Putting %s in error state\n", *file);
814*45916cd2Sjpk 		status = _newdac(*file, ALLOC_ERRID, ALLOC_GID, ALLOC_ERR_MODE);
815*45916cd2Sjpk 	}
816*45916cd2Sjpk 
817*45916cd2Sjpk 	return (status);
818*45916cd2Sjpk }
819*45916cd2Sjpk 
820*45916cd2Sjpk int
821*45916cd2Sjpk exec_clean(int optflag, char *devname, char *path, uid_t uid, char *zonename,
822*45916cd2Sjpk     char *clean_arg)
823*45916cd2Sjpk {
824*45916cd2Sjpk 	int		c;
825*45916cd2Sjpk 	int		status = 0, exit_status;
826*45916cd2Sjpk 	char		*mode, *cmd, *wdwcmd, *zoneroot;
827*45916cd2Sjpk 	char		*devzone = zonename;
828*45916cd2Sjpk 	char		wdwpath[PATH_MAX];
829*45916cd2Sjpk 	char		zonepath[MAXPATHLEN];
830*45916cd2Sjpk 	char		title[100];
831*45916cd2Sjpk 	char		pw_buf[NSS_BUFLEN_PASSWD];
832*45916cd2Sjpk 	struct passwd	pw_ent;
833*45916cd2Sjpk 
834*45916cd2Sjpk 	zonepath[0] = '\0';
835*45916cd2Sjpk 	if (system_labeled) {
836*45916cd2Sjpk 		if ((zoneroot = getzonerootbyname(zonename)) == NULL) {
837*45916cd2Sjpk 			if (strcmp(clean_arg, ALLOC_CLEAN) == 0) {
838*45916cd2Sjpk 				return (-1);
839*45916cd2Sjpk 			} else if (optflag & FORCE) {
840*45916cd2Sjpk 				(void) strcpy(zonepath, "/");
841*45916cd2Sjpk 				devzone = GLOBAL_ZONENAME;
842*45916cd2Sjpk 			} else {
843*45916cd2Sjpk 				dprintf("unable to get label for %s zone\n",
844*45916cd2Sjpk 				    zonename);
845*45916cd2Sjpk 				return (-1);
846*45916cd2Sjpk 			}
847*45916cd2Sjpk 		} else {
848*45916cd2Sjpk 			(void) strcpy(zonepath, zoneroot);
849*45916cd2Sjpk 			free(zoneroot);
850*45916cd2Sjpk 		}
851*45916cd2Sjpk 	}
852*45916cd2Sjpk 	if (getpwuid_r(uid, &pw_ent, pw_buf, sizeof (pw_buf)) == NULL)
853*45916cd2Sjpk 		return (-1);
854*45916cd2Sjpk 	if (optflag & FORCE_ALL)
8557c478bd9Sstevel@tonic-gate 		mode = "-I";
856*45916cd2Sjpk 	else if (optflag & FORCE)
8577c478bd9Sstevel@tonic-gate 		mode = "-f";
8587c478bd9Sstevel@tonic-gate 	else
8597c478bd9Sstevel@tonic-gate 		mode = "-s";
860*45916cd2Sjpk 	if (path == NULL)
861*45916cd2Sjpk 		return (0);
8627c478bd9Sstevel@tonic-gate 	if ((cmd = strrchr(path, '/')) == NULL)
8637c478bd9Sstevel@tonic-gate 		cmd = path;
8647c478bd9Sstevel@tonic-gate 	else
8657c478bd9Sstevel@tonic-gate 		cmd++;	/* skip leading '/' */
8667c478bd9Sstevel@tonic-gate 	c = vfork();
8677c478bd9Sstevel@tonic-gate 	switch (c) {
8687c478bd9Sstevel@tonic-gate 	case -1:
8697c478bd9Sstevel@tonic-gate 		return (-1);
8707c478bd9Sstevel@tonic-gate 	case 0:
8717c478bd9Sstevel@tonic-gate 		(void) setuid(0);
872*45916cd2Sjpk 		if (system_labeled && (optflag & WINDOWING)) {
873*45916cd2Sjpk 			/* First try .windowing version of script */
874*45916cd2Sjpk 			(void) strncpy(wdwpath, path, PATH_MAX);
875*45916cd2Sjpk 			(void) strncat(wdwpath, ".windowing", PATH_MAX);
876*45916cd2Sjpk 			if ((wdwcmd = strrchr(wdwpath, '/')) == NULL)
877*45916cd2Sjpk 				wdwcmd = wdwpath;
878*45916cd2Sjpk 			(void) execl(wdwpath, wdwcmd, mode, devname, clean_arg,
879*45916cd2Sjpk 			    pw_ent.pw_name, devzone, zonepath, NULL);
880*45916cd2Sjpk 			/* If that failed, run regular version via dtterm */
881*45916cd2Sjpk 			(void) snprintf(title, sizeof (title),
882*45916cd2Sjpk 			    "Device %s for %s",
883*45916cd2Sjpk 			    strcmp(clean_arg, ALLOC_CLEAN) == 0 ?
884*45916cd2Sjpk 			    "allocation" : "deallocation", devname);
885*45916cd2Sjpk 			(void) execl("/usr/dt/bin/dtterm", "dtterm",
886*45916cd2Sjpk 			    "-title", title, "-geometry", "x10+100+400",
887*45916cd2Sjpk 			    "-e", "/etc/security/lib/wdwwrapper",
888*45916cd2Sjpk 			    path, mode, devname, clean_arg, pw_ent.pw_name,
889*45916cd2Sjpk 			    devzone, zonepath, NULL);
890*45916cd2Sjpk 			/*
891*45916cd2Sjpk 			 * And if that failed, continue on to try
892*45916cd2Sjpk 			 * running regular version directly.
893*45916cd2Sjpk 			 */
894*45916cd2Sjpk 		}
8957c478bd9Sstevel@tonic-gate 		dprintf("clean script: %s, ", path);
8967c478bd9Sstevel@tonic-gate 		dprintf("cmd=%s, ", cmd);
8977c478bd9Sstevel@tonic-gate 		dprintf("mode=%s, ", mode);
898*45916cd2Sjpk 		if (system_labeled) {
899*45916cd2Sjpk 			dprintf("devname=%s ", devname);
900*45916cd2Sjpk 			dprintf("zonename=%s ", devzone);
901*45916cd2Sjpk 			dprintf("zonepath=%s ", zonepath);
902*45916cd2Sjpk 			dprintf("username=%s\n", pw_ent.pw_name);
903*45916cd2Sjpk 			(void) execl(path, cmd, mode, devname, clean_arg,
904*45916cd2Sjpk 			    pw_ent.pw_name, devzone, zonepath, NULL);
905*45916cd2Sjpk 		} else {
906*45916cd2Sjpk 			dprintf("devname=%s\n", devname);
907*45916cd2Sjpk 			(void) execle(path, cmd, mode, devname, NULL, newenv);
908*45916cd2Sjpk 		}
9097c478bd9Sstevel@tonic-gate 		dprintf("Unable to execute clean up script %s\n", path);
9107c478bd9Sstevel@tonic-gate 		dperror("");
911*45916cd2Sjpk 		exit(CNTDEXECERR);
9127c478bd9Sstevel@tonic-gate 	default:
913*45916cd2Sjpk 		(void) waitpid(c, &status, 0);
914*45916cd2Sjpk 		dprintf("Child %d", c);
915*45916cd2Sjpk 		if (WIFEXITED(status)) {
916*45916cd2Sjpk 			exit_status = WEXITSTATUS(status);
917*45916cd2Sjpk 			dprintf(" exited, status: %d\n", exit_status);
918*45916cd2Sjpk 			return (exit_status);
919*45916cd2Sjpk 		} else if (WIFSIGNALED(status)) {
920*45916cd2Sjpk 			dprintf(" killed, signal %d\n", WTERMSIG(status));
921*45916cd2Sjpk 		} else {
922*45916cd2Sjpk 			dprintf(": exit status %d\n", status);
923*45916cd2Sjpk 		}
9247c478bd9Sstevel@tonic-gate 		return (-1);
9257c478bd9Sstevel@tonic-gate 	}
9267c478bd9Sstevel@tonic-gate }
9277c478bd9Sstevel@tonic-gate 
928*45916cd2Sjpk int
929*45916cd2Sjpk _deallocate_dev(int optflag, devalloc_t *da, devmap_t *dm_in, uid_t uid,
930*45916cd2Sjpk     char *zonename)
9317c478bd9Sstevel@tonic-gate {
932*45916cd2Sjpk 	int			bytes = 0;
9337c478bd9Sstevel@tonic-gate 	int			error = 0;
934*45916cd2Sjpk 	int			is_authorized = 0;
935*45916cd2Sjpk 	uid_t			nuid;
936*45916cd2Sjpk 	char			*fname = NULL;
937*45916cd2Sjpk 	char			file_name[MAXPATHLEN];
938*45916cd2Sjpk 	char			*devzone = NULL;
939*45916cd2Sjpk 	devmap_t		*dm = NULL, *dm_new = NULL;
940*45916cd2Sjpk 	struct stat		stat_buf;
941*45916cd2Sjpk 	struct state_file	sf;
9427c478bd9Sstevel@tonic-gate 
943*45916cd2Sjpk 	if (dm_in == NULL) {
944*45916cd2Sjpk 		setdmapent();
945*45916cd2Sjpk 		if ((dm_new = getdmapnam(da->da_devname)) == NULL) {
946*45916cd2Sjpk 			enddmapent();
947*45916cd2Sjpk 			dprintf("Unable to find %s in device map database\n",
948*45916cd2Sjpk 			    da->da_devname);
949*45916cd2Sjpk 			return (NODMAPERR);
950*45916cd2Sjpk 		}
951*45916cd2Sjpk 		enddmapent();
952*45916cd2Sjpk 		dm = dm_new;
953*45916cd2Sjpk 	} else {
954*45916cd2Sjpk 		dm = dm_in;
955*45916cd2Sjpk 	}
956*45916cd2Sjpk 	if (system_labeled) {
957*45916cd2Sjpk 		if (_dev_file_name(&sf, dm) != 0) {
958*45916cd2Sjpk 			if (dm_new)
959*45916cd2Sjpk 				freedmapent(dm_new);
960*45916cd2Sjpk 			dprintf("Unable to find %s device files\n",
961*45916cd2Sjpk 			    da->da_devname);
962*45916cd2Sjpk 			error = NODMAPERR;
963*45916cd2Sjpk 			goto out;
964*45916cd2Sjpk 		}
965*45916cd2Sjpk 		fname = sf.sf_path;
966*45916cd2Sjpk 	} else {
967*45916cd2Sjpk 		bytes = snprintf(file_name,  MAXPATHLEN, "%s/%s", DAC_DIR,
968*45916cd2Sjpk 		    da->da_devname);
969*45916cd2Sjpk 		if (bytes <= 0) {
970*45916cd2Sjpk 			error = DEVNAMEERR;
971*45916cd2Sjpk 			goto out;
972*45916cd2Sjpk 		} else if (bytes >= MAXPATHLEN) {
973*45916cd2Sjpk 			dprintf("device name %s is too long.\n",
974*45916cd2Sjpk 			    da->da_devname);
975*45916cd2Sjpk 			error = DEVLONGERR;
976*45916cd2Sjpk 			goto out;
977*45916cd2Sjpk 		}
978*45916cd2Sjpk 		fname = file_name;
9797c478bd9Sstevel@tonic-gate 	}
9807c478bd9Sstevel@tonic-gate 
981*45916cd2Sjpk 	audit_allocate_device(fname);
9827c478bd9Sstevel@tonic-gate 
983*45916cd2Sjpk 	if (stat(fname, &stat_buf) != 0) {
984*45916cd2Sjpk 		dprintf("Unable to stat %s\n", fname);
985*45916cd2Sjpk 		error = DACACCERR;
986*45916cd2Sjpk 		goto out;
987*45916cd2Sjpk 	}
988*45916cd2Sjpk 	is_authorized = _is_dev_authorized(da, uid);
989*45916cd2Sjpk 	if (!(optflag & (FORCE | FORCE_ALL)) && !is_authorized) {
990*45916cd2Sjpk 		dprintf("User %d is unauthorized to deallocate\n", (int)uid);
991*45916cd2Sjpk 		error = UAUTHERR;
992*45916cd2Sjpk 		goto out;
993*45916cd2Sjpk 	}
994*45916cd2Sjpk 	if (system_labeled) {
995*45916cd2Sjpk 		/*
996*45916cd2Sjpk 		 * unless we're here to deallocate by force, check if the
997*45916cd2Sjpk 		 * label at which the device is currently allocated is
998*45916cd2Sjpk 		 * within the user label range.
999*45916cd2Sjpk 		 */
1000*45916cd2Sjpk 		if (!(optflag & FORCE) &&
1001*45916cd2Sjpk 		    _check_label(da, zonename, uid, CHECK_URANGE) != 0) {
1002*45916cd2Sjpk 			error = LABELRNGERR;
1003*45916cd2Sjpk 			goto out;
1004*45916cd2Sjpk 		}
1005*45916cd2Sjpk 	}
1006*45916cd2Sjpk 	if (!(optflag & FORCE) && stat_buf.st_uid != uid &&
1007*45916cd2Sjpk 	    DEV_ALLOCATED(stat_buf)) {
1008*45916cd2Sjpk 		error = ALLOCUERR;
1009*45916cd2Sjpk 		goto out;
1010*45916cd2Sjpk 	}
1011*45916cd2Sjpk 	if (!DEV_ALLOCATED(stat_buf)) {
1012*45916cd2Sjpk 		if (DEV_ERRORED(stat_buf)) {
1013*45916cd2Sjpk 			if (!(optflag & FORCE)) {
1014*45916cd2Sjpk 				error = DEVSTATEERR;
1015*45916cd2Sjpk 				goto out;
1016*45916cd2Sjpk 			}
1017*45916cd2Sjpk 		} else {
1018*45916cd2Sjpk 			error = DEVNALLOCERR;
1019*45916cd2Sjpk 			goto out;
1020*45916cd2Sjpk 		}
1021*45916cd2Sjpk 	}
1022*45916cd2Sjpk 	/* All checks passed, time to lock and deallocate */
1023*45916cd2Sjpk 	if ((error = lock_dev(fname)) != 0)
1024*45916cd2Sjpk 		goto out;
1025*45916cd2Sjpk 	if (system_labeled) {
1026*45916cd2Sjpk 		devzone = kva_match(da->da_devopts, DAOPT_ZONE);
1027*45916cd2Sjpk 		if (devzone && (strcmp(devzone, GLOBAL_ZONENAME) != 0)) {
1028*45916cd2Sjpk 			if ((remove_znode(devzone, dm) != 0) &&
1029*45916cd2Sjpk 			    !(optflag & FORCE)) {
1030*45916cd2Sjpk 				error = ZONEERR;
1031*45916cd2Sjpk 				goto out;
1032*45916cd2Sjpk 			}
1033*45916cd2Sjpk 		}
1034*45916cd2Sjpk 	}
1035*45916cd2Sjpk 	if ((error = mk_unalloc(optflag, dm)) != 0) {
1036*45916cd2Sjpk 		if (!(optflag & FORCE))
1037*45916cd2Sjpk 			goto out;
1038*45916cd2Sjpk 	}
1039*45916cd2Sjpk 	if (system_labeled == 0) {
1040*45916cd2Sjpk 		if ((error = _newdac(fname, ALLOC_UID, ALLOC_GID,
1041*45916cd2Sjpk 		    DEALLOC_MODE)) != 0) {
1042*45916cd2Sjpk 			(void) _newdac(file_name, ALLOC_UID, ALLOC_GID,
1043*45916cd2Sjpk 			    ALLOC_ERR_MODE);
1044*45916cd2Sjpk 			goto out;
1045*45916cd2Sjpk 		}
1046*45916cd2Sjpk 	}
1047*45916cd2Sjpk 	/*
1048*45916cd2Sjpk 	 * if we are deallocating device owned by someone else,
1049*45916cd2Sjpk 	 * pass the owner's uid to the cleaning script.
1050*45916cd2Sjpk 	 */
1051*45916cd2Sjpk 	nuid = (stat_buf.st_uid == uid) ? uid : stat_buf.st_uid;
1052*45916cd2Sjpk 	error = exec_clean(optflag, da->da_devname, da->da_devexec, nuid,
1053*45916cd2Sjpk 	    devzone, DEALLOC_CLEAN);
1054*45916cd2Sjpk 	if (error != 0) {
1055*45916cd2Sjpk 		if (!(optflag & (FORCE | FORCE_ALL))) {
1056*45916cd2Sjpk 			error = CLEANERR;
1057*45916cd2Sjpk 			(void) mk_error(dm);
1058*45916cd2Sjpk 		} else {
1059*45916cd2Sjpk 			error = 0;
1060*45916cd2Sjpk 		}
1061*45916cd2Sjpk 	}
1062*45916cd2Sjpk 
1063*45916cd2Sjpk out:
1064*45916cd2Sjpk 	if (dm_new)
1065*45916cd2Sjpk 		freedmapent(dm_new);
1066*45916cd2Sjpk 	return (error);
1067*45916cd2Sjpk }
1068*45916cd2Sjpk 
1069*45916cd2Sjpk int
1070*45916cd2Sjpk _allocate_dev(int optflag, uid_t uid, devalloc_t *da, char *zonename)
1071*45916cd2Sjpk {
1072*45916cd2Sjpk 	int			i;
1073*45916cd2Sjpk 	int			bytes = 0;
1074*45916cd2Sjpk 	int			error = 0;
1075*45916cd2Sjpk 	int			is_authorized = 0;
1076*45916cd2Sjpk 	int			dealloc_optflag = 0;
1077*45916cd2Sjpk 	char			*fname = NULL;
1078*45916cd2Sjpk 	char			file_name[MAXPATHLEN];
1079*45916cd2Sjpk 	devmap_t 		*dm;
1080*45916cd2Sjpk 	struct stat 		stat_buf;
1081*45916cd2Sjpk 	struct state_file	sf;
1082*45916cd2Sjpk 	struct zone_path	zpath;
1083*45916cd2Sjpk 
1084*45916cd2Sjpk 	zpath.count = 0;
1085*45916cd2Sjpk 	zpath.path = NULL;
1086*45916cd2Sjpk 	setdmapent();
1087*45916cd2Sjpk 	if ((dm = getdmapnam(da->da_devname)) == NULL) {
1088*45916cd2Sjpk 		enddmapent();
1089*45916cd2Sjpk 		dprintf("Unable to find %s in device map database\n",
1090*45916cd2Sjpk 		    da->da_devname);
1091*45916cd2Sjpk 		return (NODMAPERR);
1092*45916cd2Sjpk 	}
1093*45916cd2Sjpk 	enddmapent();
1094*45916cd2Sjpk 	if (system_labeled) {
1095*45916cd2Sjpk 		if (_dev_file_name(&sf, dm) != 0) {
1096*45916cd2Sjpk 			freedmapent(dm);
1097*45916cd2Sjpk 			dprintf("Unable to find %s device files\n",
1098*45916cd2Sjpk 			    da->da_devname);
1099*45916cd2Sjpk 			error = NODMAPERR;
1100*45916cd2Sjpk 			goto out;
1101*45916cd2Sjpk 		}
1102*45916cd2Sjpk 		fname = sf.sf_path;
1103*45916cd2Sjpk 	} else {
1104*45916cd2Sjpk 		bytes = snprintf(file_name,  MAXPATHLEN, "%s/%s", DAC_DIR,
1105*45916cd2Sjpk 		    da->da_devname);
1106*45916cd2Sjpk 		if (bytes <= 0) {
1107*45916cd2Sjpk 			error = DEVNAMEERR;
1108*45916cd2Sjpk 			goto out;
1109*45916cd2Sjpk 		} else if (bytes >= MAXPATHLEN) {
1110*45916cd2Sjpk 			dprintf("device name %s is too long.\n",
1111*45916cd2Sjpk 			    da->da_devname);
1112*45916cd2Sjpk 			error = DEVLONGERR;
1113*45916cd2Sjpk 			goto out;
1114*45916cd2Sjpk 		}
1115*45916cd2Sjpk 		fname = file_name;
1116*45916cd2Sjpk 	}
1117*45916cd2Sjpk 
1118*45916cd2Sjpk 	(void) audit_allocate_device(fname);
1119*45916cd2Sjpk 
1120*45916cd2Sjpk 	if (stat(fname, &stat_buf) != 0) {
1121*45916cd2Sjpk 		dprintf("Unable to stat %s\n", fname);
11227c478bd9Sstevel@tonic-gate 		dperror("Error:");
1123*45916cd2Sjpk 		error = DACACCERR;
1124*45916cd2Sjpk 		goto out;
11257c478bd9Sstevel@tonic-gate 	}
1126*45916cd2Sjpk 	if (DEV_ERRORED(stat_buf)) {
1127*45916cd2Sjpk 		error = DEVSTATEERR;
1128*45916cd2Sjpk 		goto out;
1129*45916cd2Sjpk 	}
1130*45916cd2Sjpk 	is_authorized = _is_dev_authorized(da, uid);
1131*45916cd2Sjpk 	if (is_authorized == ALLOC_BY_NONE) {
1132*45916cd2Sjpk 		dprintf("Device %s is not allocatable\n", da->da_devname);
1133*45916cd2Sjpk 		error = UAUTHERR;
1134*45916cd2Sjpk 		goto out;
1135*45916cd2Sjpk 	} else if (!is_authorized && !(optflag & USERNAME)) {
1136*45916cd2Sjpk 		dprintf("User %d is unauthorized to allocate\n", (int)uid);
1137*45916cd2Sjpk 		error = UAUTHERR;
1138*45916cd2Sjpk 		goto out;
1139*45916cd2Sjpk 	}
1140*45916cd2Sjpk 	if (system_labeled) {
1141*45916cd2Sjpk 		/*
1142*45916cd2Sjpk 		 * check if label of the zone to which the device is being
1143*45916cd2Sjpk 		 * allocated is within the device label range.
1144*45916cd2Sjpk 		 */
1145*45916cd2Sjpk 		if (_check_label(da, zonename, uid, CHECK_DRANGE) != 0) {
1146*45916cd2Sjpk 			error = LABELRNGERR;
1147*45916cd2Sjpk 			goto out;
1148*45916cd2Sjpk 		}
1149*45916cd2Sjpk 	}
1150*45916cd2Sjpk 	if (check_devs(dm) == -1) {
1151*45916cd2Sjpk 		error = DSPMISSERR;
1152*45916cd2Sjpk 		goto out;
1153*45916cd2Sjpk 	}
11547c478bd9Sstevel@tonic-gate 	if (DEV_ALLOCATED(stat_buf)) {
1155*45916cd2Sjpk 		if (optflag & FORCE) {
1156*45916cd2Sjpk 			if (optflag & SILENT)
1157*45916cd2Sjpk 				dealloc_optflag = FORCE|SILENT;
115840e2b7c9Spaulson 			else
1159*45916cd2Sjpk 				dealloc_optflag = FORCE;
1160*45916cd2Sjpk 			if (_deallocate_dev(dealloc_optflag, da, dm, uid,
1161*45916cd2Sjpk 			    zonename)) {
11627c478bd9Sstevel@tonic-gate 				dprintf("Couldn't force deallocate device %s\n",
1163*45916cd2Sjpk 				    da->da_devname);
1164*45916cd2Sjpk 				error = CNTFRCERR;
1165*45916cd2Sjpk 				goto out;
11667c478bd9Sstevel@tonic-gate 			}
11677c478bd9Sstevel@tonic-gate 		} else if (stat_buf.st_uid == uid) {
1168*45916cd2Sjpk 			error = PREALLOCERR;
1169*45916cd2Sjpk 			goto out;
11707c478bd9Sstevel@tonic-gate 		} else {
1171*45916cd2Sjpk 			error = ALLOCUERR;
1172*45916cd2Sjpk 			goto out;
1173*45916cd2Sjpk 		}
1174*45916cd2Sjpk 	}
1175*45916cd2Sjpk 	/* All checks passed, time to lock and allocate */
1176*45916cd2Sjpk 	if ((error = lock_dev(fname)) != 0)
1177*45916cd2Sjpk 		goto out;
1178*45916cd2Sjpk 	if (system_labeled) {
1179*45916cd2Sjpk 		/*
1180*45916cd2Sjpk 		 * Run the cleaning program; it also mounts allocated
1181*45916cd2Sjpk 		 * device if required.
1182*45916cd2Sjpk 		 */
1183*45916cd2Sjpk 		error = exec_clean(optflag, da->da_devname, da->da_devexec, uid,
1184*45916cd2Sjpk 		    zonename, ALLOC_CLEAN);
1185*45916cd2Sjpk 		if ((error != 0) && (error != CLEAN_MOUNT)) {
1186*45916cd2Sjpk 			error = CLEANERR;
1187*45916cd2Sjpk 			(void) mk_error(dm);
1188*45916cd2Sjpk 			goto out;
1189*45916cd2Sjpk 		}
1190*45916cd2Sjpk 		/*
1191*45916cd2Sjpk 		 * If not mounted, create zonelinks, if this is not the
1192*45916cd2Sjpk 		 * global zone.
1193*45916cd2Sjpk 		 */
1194*45916cd2Sjpk 		if ((strcmp(zonename, GLOBAL_ZONENAME) != 0) &&
1195*45916cd2Sjpk 		    (error != CLEAN_MOUNT)) {
1196*45916cd2Sjpk 			if (create_znode(zonename, &zpath, dm) != 0) {
1197*45916cd2Sjpk 				error = ZONEERR;
1198*45916cd2Sjpk 				goto out;
1199*45916cd2Sjpk 			}
1200*45916cd2Sjpk 		}
1201*45916cd2Sjpk 	}
1202*45916cd2Sjpk 
1203*45916cd2Sjpk 	(void) audit_allocate_list(dm->dmap_devlist);
1204*45916cd2Sjpk 
1205*45916cd2Sjpk 	if ((error = mk_alloc(dm, uid, &zpath)) != 0) {
1206*45916cd2Sjpk 		(void) mk_unalloc(optflag, dm);
1207*45916cd2Sjpk 		goto out;
1208*45916cd2Sjpk 	}
1209*45916cd2Sjpk 
1210*45916cd2Sjpk 	if (system_labeled == 0) {
1211*45916cd2Sjpk 		if ((error = _newdac(file_name, uid, getgid(),
1212*45916cd2Sjpk 		    ALLOC_MODE)) != 0) {
1213*45916cd2Sjpk 			(void) _newdac(file_name, ALLOC_UID, ALLOC_GID,
1214*45916cd2Sjpk 			    ALLOC_ERR_MODE);
1215*45916cd2Sjpk 			goto out;
1216*45916cd2Sjpk 		}
1217*45916cd2Sjpk 	}
1218*45916cd2Sjpk 	error = 0;
1219*45916cd2Sjpk out:
1220*45916cd2Sjpk 	if (zpath.count) {
1221*45916cd2Sjpk 		for (i = 0; i < zpath.count; i++)
1222*45916cd2Sjpk 			free(zpath.path[i]);
1223*45916cd2Sjpk 		free(zpath.path);
1224*45916cd2Sjpk 	}
1225*45916cd2Sjpk 	freedmapent(dm);
1226*45916cd2Sjpk 	return (error);
1227*45916cd2Sjpk }
1228*45916cd2Sjpk 
1229*45916cd2Sjpk void
1230*45916cd2Sjpk _store_devnames(int *count, struct devnames *dnms, char *zonename,
1231*45916cd2Sjpk     devalloc_t *da, int flag)
1232*45916cd2Sjpk {
1233*45916cd2Sjpk 	int i;
1234*45916cd2Sjpk 
1235*45916cd2Sjpk 	dnms->dnames = (char **)realloc(dnms->dnames,
1236*45916cd2Sjpk 	    (*count + 1) * sizeof (char *));
1237*45916cd2Sjpk 	if (da) {
1238*45916cd2Sjpk 		dnms->dnames[*count] = strdup(da->da_devname);
1239*45916cd2Sjpk 		(*count)++;
1240*45916cd2Sjpk 	} else {
1241*45916cd2Sjpk 		dnms->dnames[*count] = NULL;
1242*45916cd2Sjpk 		if (flag == DA_ADD_ZONE)
1243*45916cd2Sjpk 			(void) update_device(dnms->dnames, zonename,
1244*45916cd2Sjpk 			    DA_ADD_ZONE);
1245*45916cd2Sjpk 		else if (flag == DA_REMOVE_ZONE)
1246*45916cd2Sjpk 			(void) update_device(dnms->dnames, NULL,
1247*45916cd2Sjpk 			    DA_REMOVE_ZONE);
1248*45916cd2Sjpk 		for (i = 0; i < *count; i++)
1249*45916cd2Sjpk 			free(dnms->dnames[i]);
1250*45916cd2Sjpk 		free(dnms->dnames);
1251*45916cd2Sjpk 	}
1252*45916cd2Sjpk }
1253*45916cd2Sjpk 
1254*45916cd2Sjpk int
1255*45916cd2Sjpk allocate(int optflag, uid_t uid, char *device, char *zonename)
1256*45916cd2Sjpk {
1257*45916cd2Sjpk 	int		count = 0;
1258*45916cd2Sjpk 	int		error = 0;
1259*45916cd2Sjpk 	devalloc_t	*da;
1260*45916cd2Sjpk 	struct devnames	dnms;
1261*45916cd2Sjpk 
1262*45916cd2Sjpk 	if (optflag & (FORCE | USERID | USERNAME)) {
1263*45916cd2Sjpk 		if (!_is_authorized(DEVICE_REVOKE_AUTH, getuid()))
1264*45916cd2Sjpk 			return (UAUTHERR);
1265*45916cd2Sjpk 	}
1266*45916cd2Sjpk 	dnms.dnames = NULL;
1267*45916cd2Sjpk 	setdaent();
1268*45916cd2Sjpk 	if (optflag & TYPE) {
1269*45916cd2Sjpk 		/*
1270*45916cd2Sjpk 		 * allocate devices of this type
1271*45916cd2Sjpk 		 */
1272*45916cd2Sjpk 		while ((da = getdatype(device)) != NULL) {
1273*45916cd2Sjpk 			if (system_labeled &&
1274*45916cd2Sjpk 			    da_check_logindevperm(da->da_devname)) {
1275*45916cd2Sjpk 				freedaent(da);
12767c478bd9Sstevel@tonic-gate 				continue;
12777c478bd9Sstevel@tonic-gate 			}
1278*45916cd2Sjpk 			dprintf("trying to allocate %s\n", da->da_devname);
1279*45916cd2Sjpk 			error = _allocate_dev(optflag, uid, da, zonename);
1280*45916cd2Sjpk 			if (system_labeled && (error == 0)) {
1281*45916cd2Sjpk 				/*
1282*45916cd2Sjpk 				 * we need to record in device_allocate the
1283*45916cd2Sjpk 				 * label (zone name) at which this device is
1284*45916cd2Sjpk 				 * being allocated. store this device entry.
1285*45916cd2Sjpk 				 */
1286*45916cd2Sjpk 				_store_devnames(&count, &dnms, zonename, da, 0);
12877c478bd9Sstevel@tonic-gate 			}
1288*45916cd2Sjpk 			freedaent(da);
1289*45916cd2Sjpk 			error = 0;
12907c478bd9Sstevel@tonic-gate 		}
1291*45916cd2Sjpk 	} else {
1292*45916cd2Sjpk 		/*
1293*45916cd2Sjpk 		 * allocate this device
1294*45916cd2Sjpk 		 */
1295*45916cd2Sjpk 		if ((da = getdanam(device)) == NULL) {
12967c478bd9Sstevel@tonic-gate 			enddaent();
1297*45916cd2Sjpk 			return (NODAERR);
1298*45916cd2Sjpk 		}
1299*45916cd2Sjpk 		if (system_labeled && da_check_logindevperm(device)) {
1300*45916cd2Sjpk 			freedaent(da);
1301*45916cd2Sjpk 			return (LOGINDEVPERMERR);
1302*45916cd2Sjpk 		}
1303*45916cd2Sjpk 		dprintf("trying to allocate %s\n", da->da_devname);
1304*45916cd2Sjpk 		error = _allocate_dev(optflag, uid, da, zonename);
1305*45916cd2Sjpk 		/*
1306*45916cd2Sjpk 		 * we need to record in device_allocate the label (zone name)
1307*45916cd2Sjpk 		 * at which this device is being allocated. store this device
1308*45916cd2Sjpk 		 * entry.
1309*45916cd2Sjpk 		 */
1310*45916cd2Sjpk 		if (system_labeled && (error == 0))
1311*45916cd2Sjpk 			_store_devnames(&count, &dnms, zonename, da, 0);
1312*45916cd2Sjpk 		freedaent(da);
1313*45916cd2Sjpk 	}
1314*45916cd2Sjpk 	enddaent();
1315*45916cd2Sjpk 	/*
1316*45916cd2Sjpk 	 * add to device_allocate labels (zone names) for the devices we
1317*45916cd2Sjpk 	 * allocated.
1318*45916cd2Sjpk 	 */
1319*45916cd2Sjpk 	if (dnms.dnames)
1320*45916cd2Sjpk 		_store_devnames(&count, &dnms, zonename, NULL, DA_ADD_ZONE);
1321*45916cd2Sjpk 
13227c478bd9Sstevel@tonic-gate 	return (error);
13237c478bd9Sstevel@tonic-gate }
1324*45916cd2Sjpk 
1325*45916cd2Sjpk /* ARGSUSED */
1326*45916cd2Sjpk int
1327*45916cd2Sjpk deallocate(int optflag, uid_t uid, char *device, char *zonename)
1328*45916cd2Sjpk {
1329*45916cd2Sjpk 	int		count = 0;
1330*45916cd2Sjpk 	int		error = 0;
1331*45916cd2Sjpk 	devalloc_t	*da;
1332*45916cd2Sjpk 	struct devnames dnms;
1333*45916cd2Sjpk 
1334*45916cd2Sjpk 	if (optflag & (FORCE | FORCE_ALL)) {
1335*45916cd2Sjpk 		if (!_is_authorized(DEVICE_REVOKE_AUTH, getuid()))
1336*45916cd2Sjpk 		return (UAUTHERR);
1337*45916cd2Sjpk 	}
1338*45916cd2Sjpk 	if (optflag & FORCE_ALL)
1339*45916cd2Sjpk 		optflag |= FORCE;
1340*45916cd2Sjpk 	dnms.dnames = NULL;
1341*45916cd2Sjpk 	setdaent();
1342*45916cd2Sjpk 	if (optflag & FORCE_ALL) {
1343*45916cd2Sjpk 		/*
1344*45916cd2Sjpk 		 * deallocate all devices
1345*45916cd2Sjpk 		 */
1346*45916cd2Sjpk 		while ((da = getdaent()) != NULL) {
1347*45916cd2Sjpk 			if (system_labeled &&
1348*45916cd2Sjpk 			    da_check_logindevperm(da->da_devname)) {
1349*45916cd2Sjpk 				freedaent(da);
1350*45916cd2Sjpk 				continue;
1351*45916cd2Sjpk 			}
1352*45916cd2Sjpk 			dprintf("trying to deallocate %s\n", da->da_devname);
1353*45916cd2Sjpk 			error = _deallocate_dev(optflag, da, NULL, uid,
1354*45916cd2Sjpk 			    zonename);
1355*45916cd2Sjpk 			if (system_labeled && (error == 0)) {
1356*45916cd2Sjpk 				/*
1357*45916cd2Sjpk 				 * we need to remove this device's allocation
1358*45916cd2Sjpk 				 * label (zone name) from device_allocate.
1359*45916cd2Sjpk 				 * store this device name.
1360*45916cd2Sjpk 				 */
1361*45916cd2Sjpk 				_store_devnames(&count, &dnms, zonename, da, 0);
1362*45916cd2Sjpk 			}
1363*45916cd2Sjpk 			freedaent(da);
1364*45916cd2Sjpk 			error = 0;
1365*45916cd2Sjpk 		}
1366*45916cd2Sjpk 	} else if (system_labeled && optflag & TYPE) {
1367*45916cd2Sjpk 		/*
1368*45916cd2Sjpk 		 * deallocate all devices of this type
1369*45916cd2Sjpk 		 */
1370*45916cd2Sjpk 		while ((da = getdatype(device)) != NULL) {
1371*45916cd2Sjpk 			if (da_check_logindevperm(da->da_devname)) {
1372*45916cd2Sjpk 				freedaent(da);
1373*45916cd2Sjpk 				continue;
1374*45916cd2Sjpk 			}
1375*45916cd2Sjpk 			dprintf("trying to deallocate %s\n", da->da_devname);
1376*45916cd2Sjpk 			error = _deallocate_dev(optflag, da, NULL, uid,
1377*45916cd2Sjpk 			    zonename);
1378*45916cd2Sjpk 			if (error == 0) {
1379*45916cd2Sjpk 				/*
1380*45916cd2Sjpk 				 * we need to remove this device's allocation
1381*45916cd2Sjpk 				 * label (zone name) from device_allocate.
1382*45916cd2Sjpk 				 * store this device name.
1383*45916cd2Sjpk 				 */
1384*45916cd2Sjpk 				_store_devnames(&count, &dnms, zonename, da, 0);
1385*45916cd2Sjpk 			}
1386*45916cd2Sjpk 			freedaent(da);
1387*45916cd2Sjpk 			error = 0;
1388*45916cd2Sjpk 		}
1389*45916cd2Sjpk 	} else if (!(optflag & TYPE)) {
1390*45916cd2Sjpk 		/*
1391*45916cd2Sjpk 		 * deallocate this device
1392*45916cd2Sjpk 		 */
1393*45916cd2Sjpk 		if ((da = getdanam(device)) == NULL) {
1394*45916cd2Sjpk 			enddaent();
1395*45916cd2Sjpk 			return (NODAERR);
1396*45916cd2Sjpk 		}
1397*45916cd2Sjpk 		if (system_labeled && da_check_logindevperm(da->da_devname)) {
1398*45916cd2Sjpk 			freedaent(da);
1399*45916cd2Sjpk 			return (LOGINDEVPERMERR);
1400*45916cd2Sjpk 		}
1401*45916cd2Sjpk 		dprintf("trying to deallocate %s\n", da->da_devname);
1402*45916cd2Sjpk 		error = _deallocate_dev(optflag, da, NULL, uid, zonename);
1403*45916cd2Sjpk 		if (system_labeled && (error == 0)) {
1404*45916cd2Sjpk 			/*
1405*45916cd2Sjpk 			 * we need to remove this device's allocation label
1406*45916cd2Sjpk 			 * (zone name) from device_allocate. store this
1407*45916cd2Sjpk 			 * device name.
1408*45916cd2Sjpk 			 */
1409*45916cd2Sjpk 			_store_devnames(&count, &dnms, zonename, da, 0);
1410*45916cd2Sjpk 		}
1411*45916cd2Sjpk 		freedaent(da);
1412*45916cd2Sjpk 	}
1413*45916cd2Sjpk 	enddaent();
1414*45916cd2Sjpk 	/*
1415*45916cd2Sjpk 	 * remove from device_allocate labels (zone names) for the devices we
1416*45916cd2Sjpk 	 * deallocated.
1417*45916cd2Sjpk 	 */
1418*45916cd2Sjpk 	if (dnms.dnames)
1419*45916cd2Sjpk 		_store_devnames(&count, &dnms, zonename, NULL, DA_REMOVE_ZONE);
1420*45916cd2Sjpk 
1421*45916cd2Sjpk 	return (error);
1422*45916cd2Sjpk }
1423*45916cd2Sjpk 
1424*45916cd2Sjpk static int
1425*45916cd2Sjpk _dev_file_name(struct state_file *sfp, devmap_t *dm)
1426*45916cd2Sjpk {
1427*45916cd2Sjpk 	sfp->sf_flags = 0;
1428*45916cd2Sjpk 	/* if devlist is generated, never leave device in error state */
1429*45916cd2Sjpk 	if (dm->dmap_devlist[0] == '`')
1430*45916cd2Sjpk 		sfp->sf_flags |= SFF_NO_ERROR;
1431*45916cd2Sjpk 	if (dm->dmap_devarray == NULL ||
1432*45916cd2Sjpk 	    dm->dmap_devarray[0] == NULL)
1433*45916cd2Sjpk 		return (NODMAPERR);
1434*45916cd2Sjpk 	(void) strncpy(sfp->sf_path, dm->dmap_devarray[0],
1435*45916cd2Sjpk 	    sizeof (sfp->sf_path));
1436*45916cd2Sjpk 	sfp->sf_path[sizeof (sfp->sf_path) - 1] = '\0';
1437*45916cd2Sjpk 	if (sfp->sf_path[0] == '\0') {
1438*45916cd2Sjpk 		dprintf("dev_file_name: no device list for %s\n",
1439*45916cd2Sjpk 		    dm->dmap_devname);
1440*45916cd2Sjpk 		return (NODMAPERR);
1441*45916cd2Sjpk 	}
1442*45916cd2Sjpk 
1443*45916cd2Sjpk 	return (0);
1444*45916cd2Sjpk }
1445*45916cd2Sjpk 
1446*45916cd2Sjpk /*
1447*45916cd2Sjpk  * _check_label -
1448*45916cd2Sjpk  *	checks the device label range against zone label, which is also
1449*45916cd2Sjpk  *	user's current label.
1450*45916cd2Sjpk  *	returns 0 if in range, -1 for all other conditions.
1451*45916cd2Sjpk  *
1452*45916cd2Sjpk  */
1453*45916cd2Sjpk 
1454*45916cd2Sjpk static int
1455*45916cd2Sjpk _check_label(devalloc_t *da, char *zonename, uid_t uid, int flag)
1456*45916cd2Sjpk {
1457*45916cd2Sjpk 	int		err;
1458*45916cd2Sjpk 	int		in_range = 0;
1459*45916cd2Sjpk 	char		*alloczone, *lstr;
1460*45916cd2Sjpk 	char		pw_buf[NSS_BUFLEN_PASSWD];
1461*45916cd2Sjpk 	blrange_t	*range;
1462*45916cd2Sjpk 	m_label_t	*zlabel;
1463*45916cd2Sjpk 	struct passwd	pw_ent;
1464*45916cd2Sjpk 
1465*45916cd2Sjpk 	if ((da == NULL) || (zonename == NULL))
1466*45916cd2Sjpk 		return (-1);
1467*45916cd2Sjpk 
1468*45916cd2Sjpk 	if ((zlabel = getzonelabelbyname(zonename)) == NULL) {
1469*45916cd2Sjpk 		dprintf("unable to get label for %s zone\n", zonename);
1470*45916cd2Sjpk 		return (-1);
1471*45916cd2Sjpk 	}
1472*45916cd2Sjpk 	if (flag == CHECK_DRANGE) {
1473*45916cd2Sjpk 		blrange_t	drange;
1474*45916cd2Sjpk 
1475*45916cd2Sjpk 		drange.lower_bound = blabel_alloc();
1476*45916cd2Sjpk 		lstr = kva_match(da->da_devopts, DAOPT_MINLABEL);
1477*45916cd2Sjpk 		if (lstr == NULL) {
1478*45916cd2Sjpk 			bsllow(drange.lower_bound);
1479*45916cd2Sjpk 		} else if (stobsl(lstr, drange.lower_bound, NO_CORRECTION,
1480*45916cd2Sjpk 		    &err) == 0) {
1481*45916cd2Sjpk 			dprintf("bad min_label for device %s\n",
1482*45916cd2Sjpk 			    da->da_devname);
1483*45916cd2Sjpk 			free(zlabel);
1484*45916cd2Sjpk 			blabel_free(drange.lower_bound);
1485*45916cd2Sjpk 			return (-1);
1486*45916cd2Sjpk 		}
1487*45916cd2Sjpk 		drange.upper_bound = blabel_alloc();
1488*45916cd2Sjpk 		lstr = kva_match(da->da_devopts, DAOPT_MAXLABEL);
1489*45916cd2Sjpk 		if (lstr == NULL) {
1490*45916cd2Sjpk 			bslhigh(drange.upper_bound);
1491*45916cd2Sjpk 		} else if (stobsl(lstr, drange.upper_bound, NO_CORRECTION,
1492*45916cd2Sjpk 		    &err) == 0) {
1493*45916cd2Sjpk 			dprintf("bad max_label for device %s\n",
1494*45916cd2Sjpk 			    da->da_devname);
1495*45916cd2Sjpk 			free(zlabel);
1496*45916cd2Sjpk 			blabel_free(drange.lower_bound);
1497*45916cd2Sjpk 			blabel_free(drange.upper_bound);
1498*45916cd2Sjpk 			return (-1);
1499*45916cd2Sjpk 		}
1500*45916cd2Sjpk 		if (blinrange(zlabel, &drange) == 0) {
1501*45916cd2Sjpk 			char	*zlbl = NULL, *min = NULL, *max = NULL;
1502*45916cd2Sjpk 
1503*45916cd2Sjpk 			(void) bsltos(zlabel, &zlbl, 0, 0);
1504*45916cd2Sjpk 			(void) bsltos(drange.lower_bound, &min, 0, 0);
1505*45916cd2Sjpk 			(void) bsltos(drange.upper_bound, &max, 0, 0);
1506*45916cd2Sjpk 			dprintf("%s zone label ", zonename);
1507*45916cd2Sjpk 			dprintf("%s outside device label range: ", zlbl);
1508*45916cd2Sjpk 			dprintf("min - %s, ", min);
1509*45916cd2Sjpk 			dprintf("max - %s\n", max);
1510*45916cd2Sjpk 			free(zlabel);
1511*45916cd2Sjpk 			blabel_free(drange.lower_bound);
1512*45916cd2Sjpk 			blabel_free(drange.upper_bound);
1513*45916cd2Sjpk 			return (-1);
1514*45916cd2Sjpk 		}
1515*45916cd2Sjpk 	} else if (flag == CHECK_URANGE) {
1516*45916cd2Sjpk 		if (getpwuid_r(uid, &pw_ent, pw_buf, sizeof (pw_buf)) == NULL) {
1517*45916cd2Sjpk 			dprintf("Unable to get passwd entry for userid %d\n",
1518*45916cd2Sjpk 			    (int)uid);
1519*45916cd2Sjpk 			free(zlabel);
1520*45916cd2Sjpk 			return (-1);
1521*45916cd2Sjpk 		}
1522*45916cd2Sjpk 		if ((range = getuserrange(pw_ent.pw_name)) == NULL) {
1523*45916cd2Sjpk 			dprintf("Unable to get label range for userid %d\n",
1524*45916cd2Sjpk 			    (int)uid);
1525*45916cd2Sjpk 			free(zlabel);
1526*45916cd2Sjpk 			return (-1);
1527*45916cd2Sjpk 		}
1528*45916cd2Sjpk 		in_range = blinrange(zlabel, range);
1529*45916cd2Sjpk 		free(zlabel);
1530*45916cd2Sjpk 		blabel_free(range->lower_bound);
1531*45916cd2Sjpk 		blabel_free(range->upper_bound);
1532*45916cd2Sjpk 		free(range);
1533*45916cd2Sjpk 		if (in_range == 0) {
1534*45916cd2Sjpk 			dprintf("%s device label ", da->da_devname);
1535*45916cd2Sjpk 			dprintf("out of user %d label range\n", (int)uid);
1536*45916cd2Sjpk 			return (-1);
1537*45916cd2Sjpk 		}
1538*45916cd2Sjpk 	} else if (flag == CHECK_ZLABEL) {
1539*45916cd2Sjpk 		alloczone = kva_match(da->da_devopts, DAOPT_ZONE);
1540*45916cd2Sjpk 		if (alloczone == NULL) {
1541*45916cd2Sjpk 			free(zlabel);
1542*45916cd2Sjpk 			return (-1);
1543*45916cd2Sjpk 		}
1544*45916cd2Sjpk 		if (strcmp(zonename, alloczone) != 0) {
1545*45916cd2Sjpk 			dprintf("%s zone is different than ", zonename);
1546*45916cd2Sjpk 			dprintf("%s zone to which the device ", alloczone);
1547*45916cd2Sjpk 			dprintf("%s is allocated\n", da->da_devname);
1548*45916cd2Sjpk 			free(zlabel);
1549*45916cd2Sjpk 			return (-1);
1550*45916cd2Sjpk 		}
1551*45916cd2Sjpk 	}
1552*45916cd2Sjpk 	free(zlabel);
1553*45916cd2Sjpk 
1554*45916cd2Sjpk 	return (0);
1555*45916cd2Sjpk }
1556*45916cd2Sjpk 
1557*45916cd2Sjpk int
1558*45916cd2Sjpk create_znode(char *zonename, struct zone_path *zpath, devmap_t *list)
1559*45916cd2Sjpk {
1560*45916cd2Sjpk 	int		i;
1561*45916cd2Sjpk 	int		size;
1562*45916cd2Sjpk 	int		len = 0;
1563*45916cd2Sjpk 	int		fcount = 0;
1564*45916cd2Sjpk 	char		*p, *tmpfile, *zoneroot;
1565*45916cd2Sjpk 	char		**file;
1566*45916cd2Sjpk 	char		zonepath[MAXPATHLEN];
1567*45916cd2Sjpk 	struct stat	statb;
1568*45916cd2Sjpk 
1569*45916cd2Sjpk 	file = list->dmap_devarray;
1570*45916cd2Sjpk 	if (file == NULL)
1571*45916cd2Sjpk 		return (NODMAPERR);
1572*45916cd2Sjpk 	if ((zoneroot = getzonerootbyname(zonename)) == NULL) {
1573*45916cd2Sjpk 		dprintf("unable to get label for %s zone\n", zonename);
1574*45916cd2Sjpk 		return (1);
1575*45916cd2Sjpk 	}
1576*45916cd2Sjpk 	(void) strcpy(zonepath, zoneroot);
1577*45916cd2Sjpk 	free(zoneroot);
1578*45916cd2Sjpk 	if ((p = strstr(zonepath, "/root")) == NULL)
1579*45916cd2Sjpk 		return (1);
1580*45916cd2Sjpk 	*p = '\0';
1581*45916cd2Sjpk 	len = strlen(zonepath);
1582*45916cd2Sjpk 	size = sizeof (zonepath);
1583*45916cd2Sjpk 	for (; *file != NULL; file++) {
1584*45916cd2Sjpk 		if (stat(*file, &statb) == -1) {
1585*45916cd2Sjpk 			dprintf("Couldn't stat the file %s\n", *file);
1586*45916cd2Sjpk 			return (1);
1587*45916cd2Sjpk 		}
1588*45916cd2Sjpk 		/*
1589*45916cd2Sjpk 		 * First time initialization
1590*45916cd2Sjpk 		 */
1591*45916cd2Sjpk 		tmpfile = strdup(*file);
1592*45916cd2Sjpk 
1593*45916cd2Sjpk 		/*
1594*45916cd2Sjpk 		 * Most devices have pathnames starting in /dev
1595*45916cd2Sjpk 		 * but SunRay devices do not. In SRRS 3.1 they use /tmp.
1596*45916cd2Sjpk 		 *
1597*45916cd2Sjpk 		 * If the device pathname is not in /dev then create
1598*45916cd2Sjpk 		 * a symbolic link to it and put the device in /dev
1599*45916cd2Sjpk 		 */
1600*45916cd2Sjpk 		if (strncmp(tmpfile, "/dev/", strlen("/dev/")) != 0) {
1601*45916cd2Sjpk 			char	*linkdir;
1602*45916cd2Sjpk 			char	srclinkdir[MAXPATHLEN];
1603*45916cd2Sjpk 			char	dstlinkdir[MAXPATHLEN];
1604*45916cd2Sjpk 
1605*45916cd2Sjpk 			linkdir = strchr(tmpfile + 1, '/');
1606*45916cd2Sjpk 			p = strchr(linkdir + 1, '/');
1607*45916cd2Sjpk 			*p = '\0';
1608*45916cd2Sjpk 			(void) strcpy(dstlinkdir, "/dev");
1609*45916cd2Sjpk 			(void) strncat(dstlinkdir, linkdir, MAXPATHLEN);
1610*45916cd2Sjpk 			(void) snprintf(srclinkdir, MAXPATHLEN, "%s/root%s",
1611*45916cd2Sjpk 				zonepath, tmpfile);
1612*45916cd2Sjpk 			(void) symlink(dstlinkdir, srclinkdir);
1613*45916cd2Sjpk 			*p = '/';
1614*45916cd2Sjpk 			(void) strncat(dstlinkdir, p, MAXPATHLEN);
1615*45916cd2Sjpk 			free(tmpfile);
1616*45916cd2Sjpk 			tmpfile = strdup(dstlinkdir);
1617*45916cd2Sjpk 		}
1618*45916cd2Sjpk 		if ((p = rindex(tmpfile, '/')) == NULL) {
1619*45916cd2Sjpk 			dprintf("bad path in create_znode for %s\n",
1620*45916cd2Sjpk 			    tmpfile);
1621*45916cd2Sjpk 			return (1);
1622*45916cd2Sjpk 		}
1623*45916cd2Sjpk 		*p = '\0';
1624*45916cd2Sjpk 		(void) strcat(zonepath, tmpfile);
1625*45916cd2Sjpk 		*p = '/';
1626*45916cd2Sjpk 		if ((mkdirp(zonepath, 0755) != 0) && (errno != EEXIST)) {
1627*45916cd2Sjpk 			dprintf("Unable to create directory %s\n", zonepath);
1628*45916cd2Sjpk 			return (1);
1629*45916cd2Sjpk 		}
1630*45916cd2Sjpk 		zonepath[len] = '\0';
1631*45916cd2Sjpk 		if (strlcat(zonepath, tmpfile, size) >= size) {
1632*45916cd2Sjpk 			dprintf("Buffer overflow in create_znode for %s\n",
1633*45916cd2Sjpk 			    *file);
1634*45916cd2Sjpk 			free(tmpfile);
1635*45916cd2Sjpk 			return (1);
1636*45916cd2Sjpk 		}
1637*45916cd2Sjpk 		free(tmpfile);
1638*45916cd2Sjpk 		fcount++;
1639*45916cd2Sjpk 		if ((zpath->path = (char **)realloc(zpath->path,
1640*45916cd2Sjpk 		    (fcount * sizeof (char *)))) == NULL)
1641*45916cd2Sjpk 			return (1);
1642*45916cd2Sjpk 		zpath->path[zpath->count] = strdup(zonepath);
1643*45916cd2Sjpk 		zpath->count = fcount;
1644*45916cd2Sjpk 		if (mknod(zonepath, statb.st_mode, statb.st_rdev) == -1) {
1645*45916cd2Sjpk 			switch (errno) {
1646*45916cd2Sjpk 			case EEXIST:
1647*45916cd2Sjpk 				break;
1648*45916cd2Sjpk 			default:
1649*45916cd2Sjpk 				dprintf("mknod error: %s\n",
1650*45916cd2Sjpk 				    strerror(errno));
1651*45916cd2Sjpk 				for (i = 0; i <= fcount; i++)
1652*45916cd2Sjpk 					free(zpath->path[i]);
1653*45916cd2Sjpk 				free(zpath->path);
1654*45916cd2Sjpk 				return (1);
1655*45916cd2Sjpk 			}
1656*45916cd2Sjpk 		}
1657*45916cd2Sjpk 		zonepath[len] = '\0';
1658*45916cd2Sjpk 	}
1659*45916cd2Sjpk 
1660*45916cd2Sjpk 	return (0);
1661*45916cd2Sjpk }
1662*45916cd2Sjpk 
1663*45916cd2Sjpk int
1664*45916cd2Sjpk remove_znode(char *zonename, devmap_t *dm)
1665*45916cd2Sjpk {
1666*45916cd2Sjpk 	int		len = 0;
1667*45916cd2Sjpk 	char		*zoneroot;
1668*45916cd2Sjpk 	char		**file;
1669*45916cd2Sjpk 	char		zonepath[MAXPATHLEN];
1670*45916cd2Sjpk 
1671*45916cd2Sjpk 	file = dm->dmap_devarray;
1672*45916cd2Sjpk 	if (file == NULL)
1673*45916cd2Sjpk 		return (NODMAPERR);
1674*45916cd2Sjpk 	if ((zoneroot = getzonerootbyname(zonename)) == NULL) {
1675*45916cd2Sjpk 		(void) snprintf(zonepath, MAXPATHLEN, "/zone/%s", zonename);
1676*45916cd2Sjpk 	} else {
1677*45916cd2Sjpk 		char *p;
1678*45916cd2Sjpk 
1679*45916cd2Sjpk 		if ((p = strstr(zoneroot, "/root")) == NULL)
1680*45916cd2Sjpk 			return (1);
1681*45916cd2Sjpk 		*p = '\0';
1682*45916cd2Sjpk 		(void)  strcpy(zonepath, zoneroot);
1683*45916cd2Sjpk 		free(zoneroot);
1684*45916cd2Sjpk 	}
1685*45916cd2Sjpk 	/*
1686*45916cd2Sjpk 	 * To support SunRay we will just deal with the
1687*45916cd2Sjpk 	 * file in /dev, not the symlinks.
1688*45916cd2Sjpk 	 */
1689*45916cd2Sjpk 	(void) strncat(zonepath, "/dev", MAXPATHLEN);
1690*45916cd2Sjpk 	len = strlen(zonepath);
1691*45916cd2Sjpk 	for (; *file != NULL; file++) {
1692*45916cd2Sjpk 		char *devrelpath;
1693*45916cd2Sjpk 
1694*45916cd2Sjpk 		/*
1695*45916cd2Sjpk 		 * remove device node from zone.
1696*45916cd2Sjpk 		 *
1697*45916cd2Sjpk 		 * SunRay devices don't start with /dev
1698*45916cd2Sjpk 		 * so skip over first directory to make
1699*45916cd2Sjpk 		 * sure it is /dev. SunRay devices in zones
1700*45916cd2Sjpk 		 * will have a symlink into /dev but
1701*45916cd2Sjpk 		 * we don't ever delete it.
1702*45916cd2Sjpk 		 */
1703*45916cd2Sjpk 		devrelpath = strchr(*file + 1, '/');
1704*45916cd2Sjpk 
1705*45916cd2Sjpk 		if (strlcat(zonepath, devrelpath, MAXPATHLEN) >= MAXPATHLEN) {
1706*45916cd2Sjpk 			dprintf("Buffer overflow in remove_znode for %s\n",
1707*45916cd2Sjpk 			    *file);
1708*45916cd2Sjpk 			return (1);
1709*45916cd2Sjpk 		}
1710*45916cd2Sjpk 		errno = 0;
1711*45916cd2Sjpk 		if ((unlink(zonepath) == -1) && (errno != ENOENT)) {
1712*45916cd2Sjpk 			perror(zonepath);
1713*45916cd2Sjpk 			return (1);
1714*45916cd2Sjpk 		}
1715*45916cd2Sjpk 		zonepath[len] = '\0';
1716*45916cd2Sjpk 	}
1717*45916cd2Sjpk 
1718*45916cd2Sjpk 	return (0);
1719*45916cd2Sjpk }
1720*45916cd2Sjpk 
1721*45916cd2Sjpk int
1722*45916cd2Sjpk update_device(char **devnames, char *zonename, int flag)
1723*45916cd2Sjpk {
1724*45916cd2Sjpk 	int		len, rc;
1725*45916cd2Sjpk 	char		*optstr = NULL;
1726*45916cd2Sjpk 	da_args		dargs;
1727*45916cd2Sjpk 	devinfo_t	devinfo;
1728*45916cd2Sjpk 
1729*45916cd2Sjpk 	dargs.optflag = flag;
1730*45916cd2Sjpk 	dargs.optflag |= DA_UPDATE|DA_ALLOC_ONLY;
1731*45916cd2Sjpk 	dargs.rootdir = NULL;
1732*45916cd2Sjpk 	dargs.devnames = devnames;
1733*45916cd2Sjpk 	devinfo.devname = devinfo.devtype = devinfo.devauths = devinfo.devexec =
1734*45916cd2Sjpk 	    devinfo.devlist = NULL;
1735*45916cd2Sjpk 	if (dargs.optflag & DA_ADD_ZONE) {
1736*45916cd2Sjpk 		len = strlen(DAOPT_ZONE) + strlen(zonename) + 3;
1737*45916cd2Sjpk 		if ((optstr = (char *)malloc(len)) == NULL)
1738*45916cd2Sjpk 			return (-1);
1739*45916cd2Sjpk 		(void) snprintf(optstr, len, "%s%s%s", DAOPT_ZONE, KV_ASSIGN,
1740*45916cd2Sjpk 		    zonename);
1741*45916cd2Sjpk 		devinfo.devopts = optstr;
1742*45916cd2Sjpk 	}
1743*45916cd2Sjpk 	dargs.devinfo = &devinfo;
1744*45916cd2Sjpk 
1745*45916cd2Sjpk 	rc = da_update_device(&dargs);
1746*45916cd2Sjpk 
1747*45916cd2Sjpk 	if (optstr)
1748*45916cd2Sjpk 		free(optstr);
1749*45916cd2Sjpk 
1750*45916cd2Sjpk 	return (rc);
1751*45916cd2Sjpk }
1752