Home | History | Annotate | Download | only in allocate
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #include <auth_attr.h>
     28 #include <auth_list.h>
     29 #include <dirent.h>
     30 #include <errno.h>
     31 #include <fcntl.h>
     32 #include <libintl.h>
     33 #include <locale.h>
     34 #include <pwd.h>
     35 #include <signal.h>
     36 #include <stdio.h>
     37 #include <stdlib.h>
     38 #include <string.h>
     39 #include <strings.h>
     40 #include <unistd.h>
     41 #include <bsm/devices.h>
     42 #include <sys/acl.h>
     43 #include <tsol/label.h>
     44 #include <syslog.h>
     45 #include <limits.h>
     46 #include <user_attr.h>
     47 #include <secdb.h>
     48 #include <sys/mkdev.h>
     49 #include <sys/acl.h>
     50 #include <sys/file.h>
     51 #include <sys/procfs.h>
     52 #include <sys/param.h>
     53 #include <sys/resource.h>
     54 #include <sys/stat.h>
     55 #include <sys/time.h>
     56 #include <sys/types.h>
     57 #include <sys/wait.h>
     58 #include <utime.h>
     59 #include <libgen.h>
     60 #include <zone.h>
     61 #include <nss_dbdefs.h>
     62 #include <bsm/devalloc.h>
     63 #include <libdevinfo.h>
     64 #include "allocate.h"
     65 
     66 extern void print_error(int, char *);
     67 
     68 #if	defined(DEBUG) || defined(lint)
     69 #define	dprintf(s, a) (void) fprintf(stderr, s, a)
     70 #define	dperror(s) perror(s)
     71 #else	/* !DEBUG */
     72 #define	dprintf(s, a)	0
     73 #define	dperror(s)	0
     74 #endif	/* DEBUG */
     75 
     76 #define	DEV_ERRORED(sbuf)	(((sbuf).st_mode & ~S_IFMT) == ALLOC_ERR_MODE)
     77 #define	DEV_ALLOCATED(sbuf)	((sbuf).st_uid != DA_UID || \
     78 			!(((sbuf).st_mode & ~S_IFMT) == DEALLOC_MODE || \
     79 			DEV_ERRORED(sbuf)))
     80 
     81 #define	ALLOC_CLEAN		"-A"
     82 #define	DEALLOC_CLEAN		"-D"
     83 #define	DAC_DIR			"/etc/security/dev"
     84 #define	DEVICE_AUTH_SEPARATOR	","
     85 #define	LOCALDEVICE		"/dev/console"
     86 #define	PROCFS			"/proc/"
     87 #define	SFF_NO_ERROR		0x1
     88 
     89 #define	ALLOC_BY_NONE		-1
     90 #define	CHECK_DRANGE		1
     91 #define	CHECK_URANGE		2
     92 #define	CHECK_ZLABEL		3
     93 
     94 extern void audit_allocate_list(char *);
     95 extern void audit_allocate_device(char *);
     96 
     97 extern int	system_labeled;
     98 extern char	*newenv[];
     99 
    100 struct state_file {
    101 	int	sf_flags;
    102 	char	sf_path[MAXPATHLEN];
    103 };
    104 
    105 struct file_info {
    106 	struct stat	fi_stat;
    107 	char		*fi_message;
    108 };
    109 
    110 struct zone_path {
    111 	int	count;
    112 	char	**path;
    113 };
    114 
    115 struct dev_names {
    116 	char **dnames;
    117 };
    118 
    119 static int _dev_file_name(struct state_file *, devmap_t *);
    120 static int lock_dev(char *, struct stat *);
    121 static int _check_label(devalloc_t *, char *, uid_t, int);
    122 static int create_znode(char *, struct zone_path *, devmap_t *);
    123 static int remove_znode(char *, devmap_t *);
    124 static int update_device(char **, char *, int);
    125 
    126 /*
    127  * checks if the invoking user is local to the device
    128  */
    129 /*ARGSUSED*/
    130 int
    131 _is_local(uid_t uid)
    132 {
    133 	struct stat	statbuf;
    134 
    135 	if (stat(LOCALDEVICE, &statbuf) == 0 &&
    136 	    statbuf.st_uid == uid)
    137 		return (1);
    138 
    139 	return (0);
    140 }
    141 
    142 /*
    143  * Checks if the user with the specified uid has the specified authorization
    144  */
    145 int
    146 _is_authorized(char *auths, uid_t uid)
    147 {
    148 	char		*dcp, *authlist, *lasts;
    149 	char		pw_buf[NSS_BUFLEN_PASSWD];
    150 	struct passwd	pw_ent;
    151 
    152 	/*
    153 	 * first, the easy cases
    154 	 */
    155 	if (strcmp(auths, "@") == 0)
    156 		return (1);
    157 	if (strcmp(auths, "*") == 0)
    158 		return (ALLOC_BY_NONE);
    159 	if (getpwuid_r(uid, &pw_ent, pw_buf, sizeof (pw_buf)) == NULL)
    160 		return (0);
    161 	if (strpbrk(auths, DEVICE_AUTH_SEPARATOR) == NULL)
    162 		return (chkauthattr(auths, pw_ent.pw_name));
    163 	authlist = strdup(auths);
    164 	if (authlist == NULL)
    165 		return (0);
    166 	for (dcp = authlist;
    167 	    (dcp = strtok_r(dcp, DEVICE_AUTH_SEPARATOR, &lasts)) != NULL;
    168 	    dcp = NULL) {
    169 		if (chkauthattr(dcp, pw_ent.pw_name))
    170 			break;
    171 	}
    172 	free(authlist);
    173 
    174 	return (dcp != NULL);
    175 }
    176 
    177 /*
    178  * Checks if the specified user has authorization for the device
    179  */
    180 int
    181 _is_dev_authorized(devalloc_t *da, uid_t uid)
    182 {
    183 	int	ares;
    184 	char	*auth_list, *dcp, *subauth = NULL;
    185 
    186 	auth_list = da->da_devauth;
    187 	if (auth_list == NULL)
    188 		return (0);
    189 	dcp = strpbrk(auth_list, KV_TOKEN_DELIMIT);
    190 	if (dcp == NULL)
    191 		return (_is_authorized(auth_list, uid));
    192 	if (_is_local(uid)) {
    193 		/* the local authorization is before the separator */
    194 		ares = dcp - auth_list;
    195 		subauth = malloc(ares + 1);
    196 		if (subauth == NULL)
    197 			return (0);
    198 		(void) strlcpy(subauth, auth_list, (ares + 1));
    199 		auth_list = subauth;
    200 	} else
    201 		auth_list = dcp + 1;
    202 	ares = _is_authorized(auth_list, uid);
    203 	if (subauth != NULL)
    204 		free(subauth);
    205 
    206 	return (ares);
    207 }
    208 
    209 int
    210 check_devs(devmap_t *dm)
    211 {
    212 	int	status = 0;
    213 	char	**file;
    214 
    215 	if (dm->dmap_devarray == NULL)
    216 		return (NODMAPERR);
    217 	for (file = dm->dmap_devarray; *file != NULL; file++) {
    218 		if ((status = access(*file, F_OK)) == -1) {
    219 			dprintf("Unable to access file %s\n", *file);
    220 			break;
    221 		}
    222 	}
    223 
    224 	return (status);
    225 }
    226 
    227 int
    228 print_da_defs(da_defs_t *da_defs)
    229 {
    230 	char	optbuf[BUFSIZ];
    231 	char	*p = NULL;
    232 
    233 	if (da_defs->devopts == NULL) {
    234 		dprintf("No default attributes for %s\n", da_defs->devtype);
    235 		return (DEFATTRSERR);
    236 	}
    237 	(void) printf("dev_type=%s\n", da_defs->devtype);
    238 	if (_kva2str(da_defs->devopts, optbuf, sizeof (optbuf), KV_ASSIGN,
    239 	    KV_TOKEN_DELIMIT) == 0) {
    240 		if (p = rindex(optbuf, ':'))
    241 			*p = '\0';
    242 		(void) printf("\t%s\n", optbuf);
    243 	}
    244 
    245 	return (0);
    246 }
    247 
    248 void
    249 print_dev_attrs(int optflag, devalloc_t *da, devmap_t *dm,
    250     struct file_info *fip)
    251 {
    252 	char	*p = NULL;
    253 	char	optbuf[BUFSIZ];
    254 
    255 	(void) printf("device=%s%s", dm->dmap_devname, KV_DELIMITER);
    256 	(void) printf("type=%s%s", dm->dmap_devtype, KV_DELIMITER);
    257 	(void) printf("auths=%s%s",
    258 	    (da->da_devauth ? da->da_devauth : ""), KV_DELIMITER);
    259 	(void) printf("clean=%s%s",
    260 	    (da->da_devexec ? da->da_devexec : ""), KV_DELIMITER);
    261 	if (da->da_devopts != NULL) {
    262 		if (_kva2str(da->da_devopts, optbuf, sizeof (optbuf),
    263 		    KV_ASSIGN, KV_TOKEN_DELIMIT) == 0) {
    264 			if (p = rindex(optbuf, ':'))
    265 				*p = '\0';
    266 			(void) printf("%s", optbuf);
    267 		}
    268 	}
    269 	(void) printf("%s", KV_DELIMITER);
    270 	if (optflag & WINDOWING) {
    271 		if ((fip->fi_message != NULL) &&
    272 		    (strcmp(fip->fi_message, DAOPT_CLASS) == 0))
    273 			(void) printf("owner=/FREE%s", KV_DELIMITER);
    274 		else if (DEV_ERRORED(fip->fi_stat))
    275 			(void) printf("owner=/ERROR%s", KV_DELIMITER);
    276 		else if (!DEV_ALLOCATED(fip->fi_stat))
    277 			(void) printf("owner=/FREE%s", KV_DELIMITER);
    278 		else
    279 			(void) printf("owner=%u%s", fip->fi_stat.st_uid,
    280 			    KV_DELIMITER);
    281 	}
    282 	(void) printf("files=%s", dm->dmap_devlist);
    283 	(void) printf("\n");
    284 }
    285 
    286 void
    287 print_dev(devmap_t *dm)
    288 {
    289 	char	**file;
    290 
    291 	(void) printf(gettext("device: %s "), dm->dmap_devname);
    292 	(void) printf(gettext("type: %s "), dm->dmap_devtype);
    293 	(void) printf(gettext("files:"));
    294 	file = dm->dmap_devarray;
    295 	if (file != NULL) {
    296 		for (; *file != NULL; file++)
    297 			(void) printf(" %s", *file);
    298 	}
    299 	(void) printf("\n");
    300 }
    301 
    302 /* ARGSUSED */
    303 int
    304 _list_device(int optflag, uid_t uid, devalloc_t *da, char *zonename)
    305 {
    306 	int			bytes = 0;
    307 	int			error = 0;
    308 	int			is_authorized = 0;
    309 	char			*fname = NULL;
    310 	char			file_name[MAXPATHLEN];
    311 	devmap_t		*dm;
    312 	struct file_info	fi;
    313 	struct state_file	sf;
    314 
    315 	fi.fi_message = NULL;
    316 	setdmapent();
    317 	if ((dm = getdmapnam(da->da_devname)) == NULL) {
    318 		enddmapent();
    319 		dprintf("Unable to find %s in the maps database\n",
    320 		    da->da_devname);
    321 		return (NODMAPERR);
    322 	}
    323 	enddmapent();
    324 
    325 	if ((optflag & CLASS) &&
    326 	    (!(optflag & (LISTALL | LISTFREE | LISTALLOC)))) {
    327 		fi.fi_message = DAOPT_CLASS;
    328 		if (optflag & LISTATTRS)
    329 			print_dev_attrs(optflag, da, dm, &fi);
    330 		else
    331 			print_dev(dm);
    332 		goto out;
    333 	}
    334 
    335 	if (system_labeled) {
    336 		if ((error = _dev_file_name(&sf, dm)) != 0) {
    337 			freedmapent(dm);
    338 			dprintf("Unable to find %s device files\n",
    339 			    da->da_devname);
    340 			error = NODMAPERR;
    341 			goto out;
    342 		}
    343 		fname = sf.sf_path;
    344 	} else {
    345 		bytes = snprintf(file_name, MAXPATHLEN, "%s/%s", DAC_DIR,
    346 		    da->da_devname);
    347 		if (bytes <= 0) {
    348 			error = DEVNAMEERR;
    349 			goto out;
    350 		} else if (bytes >= MAXPATHLEN) {
    351 			dprintf("device name %s is too long.\n",
    352 			    da->da_devname);
    353 			error = DEVLONGERR;
    354 			goto out;
    355 		}
    356 		fname = file_name;
    357 	}
    358 	if (stat(fname, &fi.fi_stat) != 0) {
    359 		dprintf("Unable to stat %s\n", fname);
    360 		dperror("Error:");
    361 		error = DACACCERR;
    362 		goto out;
    363 	}
    364 	is_authorized = _is_dev_authorized(da, uid);
    365 	if (optflag & LISTFREE) {	/* list_devices -n */
    366 		/*
    367 		 * list all free devices
    368 		 */
    369 		if (DEV_ALLOCATED(fi.fi_stat)) {
    370 				error = PREALLOCERR;
    371 				goto out;
    372 		}
    373 		if (system_labeled) {
    374 			/*
    375 			 * for this free device, check if -
    376 			 * 1. user has authorization to allocate
    377 			 * 2. the zone label is within the label range of the
    378 			 *    device
    379 			 */
    380 			if (is_authorized == ALLOC_BY_NONE) {
    381 				error = DAUTHERR;
    382 				goto out;
    383 			} else if (is_authorized == 0) {
    384 				error = UAUTHERR;
    385 				goto out;
    386 			}
    387 			if (_check_label(da, zonename, uid,
    388 			    CHECK_DRANGE) != 0) {
    389 				error = LABELRNGERR;
    390 				goto out;
    391 			}
    392 		}
    393 	} else if (optflag & LISTALLOC) {	/*  list_devices -u */
    394 		/*
    395 		 * list all allocated devices
    396 		 */
    397 		if (!DEV_ALLOCATED(fi.fi_stat)) {
    398 			error = DEVNALLOCERR;
    399 			goto out;
    400 		}
    401 		if (fi.fi_stat.st_uid != uid) {
    402 			error = DEVSTATEERR;
    403 			goto out;
    404 		}
    405 		if (system_labeled) {
    406 			/*
    407 			 * check if the zone label equals the label at which
    408 			 * the device is allocated.
    409 			 */
    410 			if (_check_label(da, zonename, uid,
    411 			    CHECK_ZLABEL) != 0) {
    412 				error = LABELRNGERR;
    413 				goto out;
    414 			}
    415 		}
    416 	} else if (optflag & LISTALL) {		/* list_devices -l */
    417 		/*
    418 		 * list all devices - free and allocated - available
    419 		 */
    420 		if (DEV_ALLOCATED(fi.fi_stat)) {
    421 			if (optflag & WINDOWING &&
    422 			    (is_authorized == ALLOC_BY_NONE)) {
    423 				/*
    424 				 * don't complain if we're here for the GUI.
    425 				 */
    426 				error = 0;
    427 			} else if (fi.fi_stat.st_uid != uid) {
    428 				if (!(optflag & WINDOWING)) {
    429 					error = ALLOCUERR;
    430 					goto out;
    431 				}
    432 			}
    433 			if (system_labeled && !(optflag & WINDOWING)) {
    434 				/*
    435 				 * if we're not displaying in the GUI,
    436 				 * check if the zone label equals the label
    437 				 * at which the device is allocated.
    438 				 */
    439 				if (_check_label(da, zonename, uid,
    440 				    CHECK_ZLABEL) != 0) {
    441 					error = LABELRNGERR;
    442 					goto out;
    443 				}
    444 			}
    445 		} else if (system_labeled && !(optflag & WINDOWING)) {
    446 			/*
    447 			 * if we're not displaying in the GUI,
    448 			 * for this free device, check if -
    449 			 * 1. user has authorization to allocate
    450 			 * 2. the zone label is within the label range of the
    451 			 *    device
    452 			 */
    453 			if (is_authorized == ALLOC_BY_NONE) {
    454 				error = DAUTHERR;
    455 				goto out;
    456 			} else if (is_authorized == 0) {
    457 				error = UAUTHERR;
    458 				goto out;
    459 			}
    460 			if (_check_label(da, zonename, uid,
    461 			    CHECK_DRANGE) != 0) {
    462 				error = LABELRNGERR;
    463 				goto out;
    464 			}
    465 		}
    466 	}
    467 	if (system_labeled && DEV_ERRORED(fi.fi_stat) && !(optflag & LISTALL)) {
    468 		error = DEVSTATEERR;
    469 		goto out;
    470 	}
    471 	if (check_devs(dm) == -1) {
    472 		error = DSPMISSERR;
    473 		goto out;
    474 	}
    475 	if (optflag & LISTATTRS)
    476 		print_dev_attrs(optflag, da, dm, &fi);
    477 	else
    478 		print_dev(dm);
    479 
    480 	error = 0;
    481 
    482 out:
    483 	freedmapent(dm);
    484 	return (error);
    485 }
    486 
    487 /* ARGSUSED */
    488 int
    489 list_devices(int optflag, uid_t uid, char *device, char *zonename)
    490 {
    491 	int		error = 0;
    492 	char		*class = NULL;
    493 	da_defs_t	*da_defs;
    494 	devalloc_t	*da;
    495 
    496 	if (system_labeled && optflag & WINDOWING && !(optflag & LISTATTRS)) {
    497 		/*
    498 		 * Private interface for GUI.
    499 		 */
    500 		(void) puts(DA_DB_LOCK);
    501 		return (0);
    502 	}
    503 	if (optflag & USERID) {
    504 		/*
    505 		 * we need device.revoke to list someone else's devices
    506 		 */
    507 		if (!_is_authorized(DEVICE_REVOKE_AUTH, getuid()))
    508 			return (UAUTHERR);
    509 	}
    510 	if (system_labeled) {
    511 		if (!(optflag & USERID) &&
    512 		    !_is_authorized(DEFAULT_DEV_ALLOC_AUTH, uid))
    513 			/*
    514 			 * we need device.allocate to list our devices
    515 			 */
    516 			return (UAUTHERR);
    517 		if (optflag & LISTDEFS) {
    518 			/*
    519 			 * list default attrs from devalloc_defaults
    520 			 */
    521 			setdadefent();
    522 			if (device) {
    523 				/*
    524 				 * list default attrs for this device type
    525 				 */
    526 				da_defs = getdadeftype(device);
    527 				if (da_defs == NULL) {
    528 					enddadefent();
    529 					dprintf("No default attributes for "
    530 					    "%s\n", device);
    531 					return (DEFATTRSERR);
    532 				}
    533 				error = print_da_defs(da_defs);
    534 				freedadefent(da_defs);
    535 			} else {
    536 				/*
    537 				 * list everything in devalloc_defaults
    538 				 */
    539 				while ((da_defs = getdadefent()) != NULL) {
    540 					(void) print_da_defs(da_defs);
    541 					freedadefent(da_defs);
    542 				}
    543 			}
    544 			enddadefent();
    545 			return (error);
    546 		}
    547 	}
    548 	/*
    549 	 * Lock the database to make sure no body writes to it while we are
    550 	 * reading.
    551 	 */
    552 	(void) lock_dev(NULL, NULL);
    553 	setdaent();
    554 	if (device) {
    555 		if (optflag & CLASS) {
    556 			/*
    557 			 * list all devices of this class.
    558 			 */
    559 			while ((da = getdaent()) != NULL) {
    560 				class =	 kva_match(da->da_devopts, DAOPT_CLASS);
    561 				if (class && (strcmp(class, device) == 0)) {
    562 					(void) _list_device(optflag, uid, da,
    563 					    zonename);
    564 				}
    565 				freedaent(da);
    566 			}
    567 		} else {
    568 			/*
    569 			 * list this device
    570 			 */
    571 			if ((da = getdanam(device)) == NULL) {
    572 				enddaent();
    573 				return (NODAERR);
    574 			}
    575 			error = _list_device(optflag, uid, da, zonename);
    576 			freedaent(da);
    577 		}
    578 	} else {
    579 		/*
    580 		 * list all devices
    581 		 */
    582 		while ((da = getdaent()) != NULL) {
    583 			(void) _list_device(optflag, uid, da, zonename);
    584 			freedaent(da);
    585 		}
    586 	}
    587 	enddaent();
    588 
    589 	return (error);
    590 }
    591 
    592 /*
    593  * Set the DAC characteristics of the file.
    594  * This uses a fancy chmod() by setting a minimal ACL which sets the mode
    595  * and discards any existing ACL.
    596  */
    597 int
    598 _newdac(char *file, uid_t owner, gid_t group, o_mode_t mode)
    599 {
    600 	int	err = 0;
    601 
    602 	if (mode == ALLOC_MODE) {
    603 		if (chown(file, owner, group) == -1) {
    604 			dperror("newdac: unable to chown");
    605 			err = CHOWNERR;
    606 		}
    607 	} else do {
    608 		if (chown(file, owner, group) == -1) {
    609 			dperror("newdac: unable to chown");
    610 			err = CHOWNERR;
    611 		}
    612 	} while (fdetach(file) == 0);
    613 
    614 	if (err)
    615 		return (err);
    616 
    617 	if (strncmp(file, "/dev/", strlen("/dev/")) != 0) {
    618 		/*
    619 		 * This could be a SunRay device that is in /tmp.
    620 		 */
    621 		if (chmod(file, mode) == -1) {
    622 			dperror("newdac: unable to chmod");
    623 			err = SETACLERR;
    624 		}
    625 	} else {
    626 		err = acl_strip(file, owner, group, (mode_t)mode);
    627 	}
    628 
    629 	if (err != 0) {
    630 		dperror("newdac: unable to setacl");
    631 		err = SETACLERR;
    632 	}
    633 
    634 	return (err);
    635 }
    636 
    637 /*
    638  * lock_dev -
    639  *	locks a section of DA_DB_LOCK.
    640  *	returns lock fd if successful, else -1 on error.
    641  */
    642 static int
    643 lock_dev(char *file, struct stat *statbuf)
    644 {
    645 	static int	lockfd = -1;
    646 	int		ret;
    647 	int		count = 0;
    648 	int		retry = 10;
    649 	off_t		size = 0;
    650 	off_t		offset;
    651 	char		*lockfile;
    652 
    653 	if (system_labeled)
    654 		lockfile = DA_DB_LOCK;
    655 	else
    656 		lockfile = file;
    657 
    658 	if (statbuf) {
    659 		offset = statbuf->st_rdev;
    660 		dprintf("locking %s\n", file);
    661 	} else {
    662 		offset = 0;
    663 		dprintf("locking %s\n", lockfile);
    664 	}
    665 	if ((lockfd == -1) &&
    666 	    (lockfd = open(lockfile, O_RDWR | O_CREAT, 0600)) == -1) {
    667 		dperror("lock_dev: cannot open lock file");
    668 		return (-1);
    669 	}
    670 	if (system_labeled) {
    671 		(void) _newdac(lockfile, DA_UID, DA_GID, 0600);
    672 		if (lseek(lockfd, offset, SEEK_SET) == -1) {
    673 			dperror("lock_dev: cannot position lock file");
    674 			return (-1);
    675 		}
    676 		size = 1;
    677 	}
    678 	errno = 0;
    679 	while (retry) {
    680 		count++;
    681 		ret = lockf(lockfd, F_TLOCK, size);
    682 		if (ret == 0)
    683 			return (lockfd);
    684 		if ((errno != EACCES) && (errno != EAGAIN)) {
    685 			dperror("lock_dev: cannot set lock");
    686 			return (-1);
    687 		}
    688 		retry--;
    689 		(void) sleep(count);
    690 		errno = 0;
    691 	}
    692 
    693 	return (-1);
    694 }
    695 
    696 int
    697 mk_alloc(devmap_t *list, uid_t uid, struct zone_path *zpath)
    698 {
    699 	int	i;
    700 	int	error = 0;
    701 	char	**file;
    702 	gid_t	gid = getgid();
    703 	mode_t	mode = ALLOC_MODE;
    704 
    705 	file = list->dmap_devarray;
    706 	if (file == NULL)
    707 		return (NODMAPERR);
    708 	for (; *file != NULL; file++) {
    709 		dprintf("Allocating %s\n", *file);
    710 		if ((error = _newdac(*file, uid, gid, mode)) != 0) {
    711 			(void) _newdac(*file, ALLOC_ERRID, DA_GID,
    712 			    ALLOC_ERR_MODE);
    713 			break;
    714 		}
    715 	}
    716 	if (system_labeled && zpath->count && (error == 0)) {
    717 		/*
    718 		 * mark as allocated any new device nodes that we
    719 		 * created in local zone
    720 		 */
    721 		for (i = 0; i < zpath->count; i++) {
    722 			dprintf("Allocating %s\n", zpath->path[i]);
    723 			if ((error = _newdac(zpath->path[i], uid, gid,
    724 			    mode)) != 0) {
    725 				(void) _newdac(zpath->path[i], ALLOC_ERRID,
    726 				    DA_GID, ALLOC_ERR_MODE);
    727 				break;
    728 			}
    729 		}
    730 	}
    731 
    732 	return (error);
    733 }
    734 
    735 /*
    736  * mk_revoke() is used instead of system("/usr/sbin/fuser -k file")
    737  * because "/usr/sbin/fuser -k file" kills all processes
    738  * working with the file, even "vold" (bug #4095152).
    739  */
    740 int
    741 mk_revoke(int optflag, char *file)
    742 {
    743 	int		r = 0, p[2], fp, lock;
    744 	int		fuserpid;
    745 	char		buf[MAXPATHLEN];
    746 	FILE		*ptr;
    747 	pid_t		c_pid;
    748 	prpsinfo_t	info;
    749 
    750 	(void) strcpy(buf, PROCFS);
    751 	/*
    752 	 * vfork() and execl() just to make the same output
    753 	 * as before fixing of bug #4095152.
    754 	 * The problem is that the "fuser" command prints
    755 	 * one part of output into stderr and another into stdout,
    756 	 * but user sees them mixed. Of course, better to change "fuser"
    757 	 * or to intercept and not to print its output.
    758 	 */
    759 	if (!(optflag & SILENT)) {
    760 		c_pid = vfork();
    761 		if (c_pid == -1)
    762 			return (-1);
    763 		if (c_pid == 0) {
    764 			dprintf("first exec fuser %s\n", file);
    765 			(void) execl("/usr/sbin/fuser", "fuser", file, NULL);
    766 			dperror("first exec fuser");
    767 			_exit(1);
    768 		}
    769 
    770 		(void) waitpid(c_pid, &lock, 0);
    771 		dprintf("exit status %x\n", lock);
    772 		if (WEXITSTATUS(lock) != 0)
    773 			return (-1);
    774 	}
    775 	dprintf("first continuing c_pid=%d\n", (int)c_pid);
    776 	if (pipe(p)) {
    777 		dperror("pipe");
    778 		return (-1);
    779 	}
    780 	/* vfork() and execl() to catch output and to process it */
    781 	c_pid = vfork();
    782 	if (c_pid == -1) {
    783 		dperror("second vfork");
    784 		return (-1);
    785 	}
    786 	dprintf("second continuing c_pid=%d\n", (int)c_pid);
    787 	if (c_pid == 0) {
    788 		(void) close(p[0]);
    789 		(void) close(1);
    790 		(void) fcntl(p[1], F_DUPFD, 1);
    791 		(void) close(p[1]);
    792 		(void) close(2);
    793 		dprintf("second exec fuser %s\n", file);
    794 		(void) execl("/usr/sbin/fuser", "fuser", file, NULL);
    795 		dperror("second exec fuser");
    796 		_exit(1);
    797 	}
    798 	(void) close(p[1]);
    799 	if ((ptr = fdopen(p[0], "r")) != NULL) {
    800 		while (!feof(ptr)) {
    801 			if (fscanf(ptr, "%d", &fuserpid) > 0) {
    802 				(void) sprintf(buf + strlen(PROCFS), "%d",
    803 				    fuserpid);
    804 				if ((fp = open(buf, O_RDONLY)) == -1) {
    805 					dperror(buf);
    806 					continue;
    807 				}
    808 				if (ioctl(fp, PIOCPSINFO,
    809 				    (char *)&info) == -1) {
    810 					dprintf("%d psinfo failed", fuserpid);
    811 					dperror("");
    812 					(void) close(fp);
    813 					continue;
    814 				}
    815 				(void) close(fp);
    816 				if (strcmp(info.pr_fname, "vold") == NULL) {
    817 					dprintf("%d matched vold name\n",
    818 					    fuserpid);
    819 					continue;
    820 				}
    821 				dprintf("killing %s", info.pr_fname);
    822 				dprintf("(%d)\n", fuserpid);
    823 				if ((r =
    824 				    kill((pid_t)fuserpid, SIGKILL)) == -1) {
    825 					dprintf("kill %d", fuserpid);
    826 					dperror("");
    827 					break;
    828 				}
    829 			}
    830 		}
    831 	} else {
    832 		dperror("fdopen(p[0], r)");
    833 		r = -1;
    834 	}
    835 	(void) fclose(ptr);
    836 
    837 	return (r);
    838 }
    839 
    840 int
    841 mk_unalloc(int optflag, devmap_t *list)
    842 {
    843 	int	error = 0;
    844 	int	status;
    845 	char	**file;
    846 
    847 	audit_allocate_list(list->dmap_devlist);
    848 	file = list->dmap_devarray;
    849 	if (file == NULL)
    850 		return (NODMAPERR);
    851 	for (; *file != NULL; file++) {
    852 		dprintf("Deallocating %s\n", *file);
    853 		if (mk_revoke(optflag, *file) < 0) {
    854 			dprintf("mk_unalloc: unable to revoke %s\n", *file);
    855 			dperror("");
    856 			error = CNTFRCERR;
    857 		}
    858 		status = _newdac(*file, DA_UID, DA_GID, DEALLOC_MODE);
    859 		if (error == 0)
    860 			error = status;
    861 
    862 	}
    863 
    864 	return (error);
    865 }
    866 
    867 int
    868 mk_error(devmap_t *list)
    869 {
    870 	int	status = 0;
    871 	char	**file;
    872 
    873 	audit_allocate_list(list->dmap_devlist);
    874 	file = list->dmap_devarray;
    875 	if (file == NULL)
    876 		return (NODMAPERR);
    877 	for (; *file != NULL; file++) {
    878 		dprintf("Putting %s in error state\n", *file);
    879 		status = _newdac(*file, ALLOC_ERRID, DA_GID, ALLOC_ERR_MODE);
    880 	}
    881 
    882 	return (status);
    883 }
    884 
    885 int
    886 exec_clean(int optflag, char *devname, char *path, uid_t uid, char *zonename,
    887     char *clean_arg)
    888 {
    889 	int		c;
    890 	int		status = 0, exit_status;
    891 	char		*mode, *cmd, *wdwcmd, *zoneroot;
    892 	char		*devzone = zonename;
    893 	char		wdwpath[PATH_MAX];
    894 	char		zonepath[MAXPATHLEN];
    895 	char		title[100];
    896 	char		pw_buf[NSS_BUFLEN_PASSWD];
    897 	struct passwd	pw_ent;
    898 
    899 	zonepath[0] = '\0';
    900 	if (system_labeled) {
    901 		if ((zoneroot = getzonerootbyname(zonename)) == NULL) {
    902 			if (strcmp(clean_arg, ALLOC_CLEAN) == 0) {
    903 				return (-1);
    904 			} else if (optflag & FORCE) {
    905 				(void) strcpy(zonepath, "/");
    906 				devzone = GLOBAL_ZONENAME;
    907 			} else {
    908 				dprintf("unable to get label for %s zone\n",
    909 				    zonename);
    910 				return (-1);
    911 			}
    912 		} else {
    913 			(void) strcpy(zonepath, zoneroot);
    914 			free(zoneroot);
    915 		}
    916 	}
    917 	if (getpwuid_r(uid, &pw_ent, pw_buf, sizeof (pw_buf)) == NULL)
    918 		return (-1);
    919 	if (optflag & FORCE_ALL)
    920 		mode = "-I";
    921 	else if (optflag & FORCE)
    922 		mode = "-f";
    923 	else
    924 		mode = "-s";
    925 	if (path == NULL)
    926 		return (0);
    927 	if ((cmd = strrchr(path, '/')) == NULL)
    928 		cmd = path;
    929 	else
    930 		cmd++;	/* skip leading '/' */
    931 	c = vfork();
    932 	switch (c) {
    933 	case -1:
    934 		return (-1);
    935 	case 0:
    936 		(void) setuid(0);
    937 		if (system_labeled && (optflag & WINDOWING)) {
    938 			/* First try .windowing version of script */
    939 			(void) strncpy(wdwpath, path, PATH_MAX);
    940 			(void) strncat(wdwpath, ".windowing", PATH_MAX);
    941 			if ((wdwcmd = strrchr(wdwpath, '/')) == NULL)
    942 				wdwcmd = wdwpath;
    943 			(void) execl(wdwpath, wdwcmd, mode, devname, clean_arg,
    944 			    pw_ent.pw_name, devzone, zonepath, NULL);
    945 			/* If that failed, run regular version via dtterm */
    946 			(void) snprintf(title, sizeof (title),
    947 			    "Device %s for %s",
    948 			    strcmp(clean_arg, ALLOC_CLEAN) == 0 ?
    949 			    "allocation" : "deallocation", devname);
    950 			(void) execl("/usr/dt/bin/dtterm", "dtterm",
    951 			    "-title", title, "-geometry", "x10+100+400",
    952 			    "-e", "/etc/security/lib/wdwwrapper",
    953 			    path, mode, devname, clean_arg, pw_ent.pw_name,
    954 			    devzone, zonepath, NULL);
    955 			/*
    956 			 * And if that failed, continue on to try
    957 			 * running regular version directly.
    958 			 */
    959 		}
    960 		dprintf("clean script: %s, ", path);
    961 		dprintf("cmd=%s, ", cmd);
    962 		dprintf("mode=%s, ", mode);
    963 		if (system_labeled) {
    964 			dprintf("devname=%s ", devname);
    965 			dprintf("zonename=%s ", devzone);
    966 			dprintf("zonepath=%s ", zonepath);
    967 			dprintf("username=%s\n", pw_ent.pw_name);
    968 			(void) execl(path, cmd, mode, devname, clean_arg,
    969 			    pw_ent.pw_name, devzone, zonepath, NULL);
    970 		} else {
    971 			dprintf("devname=%s\n", devname);
    972 			(void) execle(path, cmd, mode, devname, NULL, newenv);
    973 		}
    974 		dprintf("Unable to execute clean up script %s\n", path);
    975 		dperror("");
    976 		exit(CNTDEXECERR);
    977 	default:
    978 		(void) waitpid(c, &status, 0);
    979 		dprintf("Child %d", c);
    980 		if (WIFEXITED(status)) {
    981 			exit_status = WEXITSTATUS(status);
    982 			dprintf(" exited, status: %d\n", exit_status);
    983 			return (exit_status);
    984 		} else if (WIFSIGNALED(status)) {
    985 			dprintf(" killed, signal %d\n", WTERMSIG(status));
    986 		} else {
    987 			dprintf(": exit status %d\n", status);
    988 		}
    989 		return (-1);
    990 	}
    991 }
    992 
    993 int
    994 _deallocate_dev(int optflag, devalloc_t *da, devmap_t *dm_in, uid_t uid,
    995     char *zonename, int *lock_fd)
    996 {
    997 	int			bytes = 0;
    998 	int			error = 0;
    999 	int			is_authorized = 0;
   1000 	uid_t			nuid;
   1001 	char			*fname = NULL;
   1002 	char			file_name[MAXPATHLEN];
   1003 	char			*devzone = NULL;
   1004 	devmap_t		*dm = NULL, *dm_new = NULL;
   1005 	struct stat		stat_buf;
   1006 	struct state_file	sf;
   1007 
   1008 	if (dm_in == NULL) {
   1009 		setdmapent();
   1010 		if ((dm_new = getdmapnam(da->da_devname)) == NULL) {
   1011 			enddmapent();
   1012 			dprintf("Unable to find %s in device map database\n",
   1013 			    da->da_devname);
   1014 			return (NODMAPERR);
   1015 		}
   1016 		enddmapent();
   1017 		dm = dm_new;
   1018 	} else {
   1019 		dm = dm_in;
   1020 	}
   1021 	if (system_labeled) {
   1022 		if (_dev_file_name(&sf, dm) != 0) {
   1023 			if (dm_new)
   1024 				freedmapent(dm_new);
   1025 			dprintf("Unable to find %s device files\n",
   1026 			    da->da_devname);
   1027 			error = NODMAPERR;
   1028 			goto out;
   1029 		}
   1030 		fname = sf.sf_path;
   1031 	} else {
   1032 		bytes = snprintf(file_name,  MAXPATHLEN, "%s/%s", DAC_DIR,
   1033 		    da->da_devname);
   1034 		if (bytes <= 0) {
   1035 			error = DEVNAMEERR;
   1036 			goto out;
   1037 		} else if (bytes >= MAXPATHLEN) {
   1038 			dprintf("device name %s is too long.\n",
   1039 			    da->da_devname);
   1040 			error = DEVLONGERR;
   1041 			goto out;
   1042 		}
   1043 		fname = file_name;
   1044 	}
   1045 
   1046 	audit_allocate_device(fname);
   1047 
   1048 	if (stat(fname, &stat_buf) != 0) {
   1049 		dprintf("Unable to stat %s\n", fname);
   1050 		error = DACACCERR;
   1051 		goto out;
   1052 	}
   1053 	is_authorized = _is_dev_authorized(da, uid);
   1054 	if (!(optflag & (FORCE | FORCE_ALL)) && !is_authorized) {
   1055 		dprintf("User %d is unauthorized to deallocate\n", (int)uid);
   1056 		error = UAUTHERR;
   1057 		goto out;
   1058 	}
   1059 	if (system_labeled) {
   1060 		/*
   1061 		 * unless we're here to deallocate by force, check if the
   1062 		 * label at which the device is currently allocated is
   1063 		 * within the user label range.
   1064 		 */
   1065 		if (!(optflag & FORCE) &&
   1066 		    _check_label(da, zonename, uid, CHECK_URANGE) != 0) {
   1067 			error = LABELRNGERR;
   1068 			goto out;
   1069 		}
   1070 	}
   1071 	if (!(optflag & FORCE) && stat_buf.st_uid != uid &&
   1072 	    DEV_ALLOCATED(stat_buf)) {
   1073 		error = ALLOCUERR;
   1074 		goto out;
   1075 	}
   1076 	if (!DEV_ALLOCATED(stat_buf)) {
   1077 		if (DEV_ERRORED(stat_buf)) {
   1078 			if (!(optflag & FORCE)) {
   1079 				error = DEVSTATEERR;
   1080 				goto out;
   1081 			}
   1082 		} else {
   1083 			error = DEVNALLOCERR;
   1084 			goto out;
   1085 		}
   1086 	}
   1087 	/* All checks passed, time to lock and deallocate */
   1088 	if ((*lock_fd = lock_dev(fname, &stat_buf)) == -1) {
   1089 		error = DEVLKERR;
   1090 		goto out;
   1091 	}
   1092 	if (system_labeled) {
   1093 		devzone = kva_match(da->da_devopts, DAOPT_ZONE);
   1094 		if (devzone == NULL) {
   1095 			devzone = GLOBAL_ZONENAME;
   1096 		} else if (strcmp(devzone, GLOBAL_ZONENAME) != 0) {
   1097 			if ((remove_znode(devzone, dm) != 0) &&
   1098 			    !(optflag & FORCE)) {
   1099 				error = ZONEERR;
   1100 				goto out;
   1101 			}
   1102 		}
   1103 	}
   1104 	if ((error = mk_unalloc(optflag, dm)) != 0) {
   1105 		if (!(optflag & FORCE))
   1106 			goto out;
   1107 	}
   1108 	if (system_labeled == 0) {
   1109 		if ((error = _newdac(fname, DA_UID, DA_GID,
   1110 		    DEALLOC_MODE)) != 0) {
   1111 			(void) _newdac(file_name, DA_UID, DA_GID,
   1112 			    ALLOC_ERR_MODE);
   1113 			goto out;
   1114 		}
   1115 	}
   1116 	/*
   1117 	 * if we are deallocating device owned by someone else,
   1118 	 * pass the owner's uid to the cleaning script.
   1119 	 */
   1120 	nuid = (stat_buf.st_uid == uid) ? uid : stat_buf.st_uid;
   1121 	error = exec_clean(optflag, da->da_devname, da->da_devexec, nuid,
   1122 	    devzone, DEALLOC_CLEAN);
   1123 	if (error != 0) {
   1124 		if (!(optflag & (FORCE | FORCE_ALL))) {
   1125 			error = CLEANERR;
   1126 			(void) mk_error(dm);
   1127 		} else {
   1128 			error = 0;
   1129 		}
   1130 	}
   1131 
   1132 out:
   1133 	if (dm_new)
   1134 		freedmapent(dm_new);
   1135 	return (error);
   1136 }
   1137 
   1138 int
   1139 _allocate_dev(int optflag, uid_t uid, devalloc_t *da, char *zonename,
   1140 	int *lock_fd)
   1141 {
   1142 	int			i;
   1143 	int			bytes = 0;
   1144 	int			error = 0;
   1145 	int			is_authorized = 0;
   1146 	int			dealloc_optflag = 0;
   1147 	char			*fname = NULL;
   1148 	char			file_name[MAXPATHLEN];
   1149 	devmap_t 		*dm;
   1150 	struct stat 		stat_buf;
   1151 	struct state_file	sf;
   1152 	struct zone_path	zpath;
   1153 
   1154 	zpath.count = 0;
   1155 	zpath.path = NULL;
   1156 	setdmapent();
   1157 	if ((dm = getdmapnam(da->da_devname)) == NULL) {
   1158 		enddmapent();
   1159 		dprintf("Unable to find %s in device map database\n",
   1160 		    da->da_devname);
   1161 		return (NODMAPERR);
   1162 	}
   1163 	enddmapent();
   1164 	if (system_labeled) {
   1165 		if (_dev_file_name(&sf, dm) != 0) {
   1166 			freedmapent(dm);
   1167 			dprintf("Unable to find %s device files\n",
   1168 			    da->da_devname);
   1169 			error = NODMAPERR;
   1170 			goto out;
   1171 		}
   1172 		fname = sf.sf_path;
   1173 	} else {
   1174 		bytes = snprintf(file_name,  MAXPATHLEN, "%s/%s", DAC_DIR,
   1175 		    da->da_devname);
   1176 		if (bytes <= 0) {
   1177 			error = DEVNAMEERR;
   1178 			goto out;
   1179 		} else if (bytes >= MAXPATHLEN) {
   1180 			dprintf("device name %s is too long.\n",
   1181 			    da->da_devname);
   1182 			error = DEVLONGERR;
   1183 			goto out;
   1184 		}
   1185 		fname = file_name;
   1186 	}
   1187 
   1188 	(void) audit_allocate_device(fname);
   1189 
   1190 	if (stat(fname, &stat_buf) != 0) {
   1191 		dprintf("Unable to stat %s\n", fname);
   1192 		dperror("Error:");
   1193 		error = DACACCERR;
   1194 		goto out;
   1195 	}
   1196 	if (DEV_ERRORED(stat_buf)) {
   1197 		error = DEVSTATEERR;
   1198 		goto out;
   1199 	}
   1200 	is_authorized = _is_dev_authorized(da, uid);
   1201 	if (is_authorized == ALLOC_BY_NONE) {
   1202 		dprintf("Device %s is not allocatable\n", da->da_devname);
   1203 		error = UAUTHERR;
   1204 		goto out;
   1205 	} else if (!is_authorized && !(optflag & USERNAME)) {
   1206 		dprintf("User %d is unauthorized to allocate\n", (int)uid);
   1207 		error = UAUTHERR;
   1208 		goto out;
   1209 	}
   1210 	if (system_labeled) {
   1211 		/*
   1212 		 * check if label of the zone to which the device is being
   1213 		 * allocated is within the device label range.
   1214 		 */
   1215 		if (_check_label(da, zonename, uid, CHECK_DRANGE) != 0) {
   1216 			error = LABELRNGERR;
   1217 			goto out;
   1218 		}
   1219 	}
   1220 	if (check_devs(dm) == -1) {
   1221 		error = DSPMISSERR;
   1222 		goto out;
   1223 	}
   1224 	if (DEV_ALLOCATED(stat_buf)) {
   1225 		if (optflag & FORCE) {
   1226 			if (optflag & SILENT)
   1227 				dealloc_optflag = FORCE|SILENT;
   1228 			else
   1229 				dealloc_optflag = FORCE;
   1230 			if (_deallocate_dev(dealloc_optflag, da, dm, uid,
   1231 			    zonename, lock_fd)) {
   1232 				dprintf("Couldn't force deallocate device %s\n",
   1233 				    da->da_devname);
   1234 				error = CNTFRCERR;
   1235 				goto out;
   1236 			}
   1237 		} else if (stat_buf.st_uid == uid) {
   1238 			error = PREALLOCERR;
   1239 			goto out;
   1240 		} else {
   1241 			error = ALLOCUERR;
   1242 			goto out;
   1243 		}
   1244 	}
   1245 	/* All checks passed, time to lock and allocate */
   1246 	if ((*lock_fd = lock_dev(fname, &stat_buf)) == -1) {
   1247 		error = DEVLKERR;
   1248 		goto out;
   1249 	}
   1250 	if (system_labeled) {
   1251 		/*
   1252 		 * Run the cleaning program; it also mounts allocated
   1253 		 * device if required.
   1254 		 */
   1255 		error = exec_clean(optflag, da->da_devname, da->da_devexec, uid,
   1256 		    zonename, ALLOC_CLEAN);
   1257 		if (error != DEVCLEAN_OK) {
   1258 			switch (error) {
   1259 			case DEVCLEAN_ERROR:
   1260 			case DEVCLEAN_SYSERR:
   1261 				dprintf("allocate: "
   1262 				    "Error in device clean program %s\n",
   1263 				    da->da_devexec);
   1264 				error = CLEANERR;
   1265 				(void) mk_error(dm);
   1266 				goto out;
   1267 			case DEVCLEAN_BADMOUNT:
   1268 				dprintf("allocate: Failed to mount device %s\n",
   1269 				    da->da_devexec);
   1270 				goto out;
   1271 			case DEVCLEAN_MOUNTOK:
   1272 				break;
   1273 			default:
   1274 				error = 0;
   1275 				goto out;
   1276 			}
   1277 		}
   1278 		/*
   1279 		 * If not mounted, create zonelinks, if this is not the
   1280 		 * global zone.
   1281 		 */
   1282 		if ((strcmp(zonename, GLOBAL_ZONENAME) != 0) &&
   1283 		    (error != DEVCLEAN_MOUNTOK)) {
   1284 			if (create_znode(zonename, &zpath, dm) != 0) {
   1285 				error = ZONEERR;
   1286 				goto out;
   1287 			}
   1288 		}
   1289 	}
   1290 
   1291 	(void) audit_allocate_list(dm->dmap_devlist);
   1292 
   1293 	if ((error = mk_alloc(dm, uid, &zpath)) != 0) {
   1294 		(void) mk_unalloc(optflag, dm);
   1295 		goto out;
   1296 	}
   1297 
   1298 	if (system_labeled == 0) {
   1299 		if ((error = _newdac(file_name, uid, getgid(),
   1300 		    ALLOC_MODE)) != 0) {
   1301 			(void) _newdac(file_name, DA_UID, DA_GID,
   1302 			    ALLOC_ERR_MODE);
   1303 			goto out;
   1304 		}
   1305 	}
   1306 	error = 0;
   1307 out:
   1308 	if (zpath.count) {
   1309 		for (i = 0; i < zpath.count; i++)
   1310 			free(zpath.path[i]);
   1311 		free(zpath.path);
   1312 	}
   1313 	freedmapent(dm);
   1314 	return (error);
   1315 }
   1316 
   1317 void
   1318 _store_devnames(int *count, struct dev_names *dnms, char *zonename,
   1319     devalloc_t *da, int flag)
   1320 {
   1321 	int i;
   1322 
   1323 	dnms->dnames = (char **)realloc(dnms->dnames,
   1324 	    (*count + 1) * sizeof (char *));
   1325 	if (da) {
   1326 		dnms->dnames[*count] = strdup(da->da_devname);
   1327 		(*count)++;
   1328 	} else {
   1329 		dnms->dnames[*count] = NULL;
   1330 		if (flag == DA_ADD_ZONE)
   1331 			(void) update_device(dnms->dnames, zonename,
   1332 			    DA_ADD_ZONE);
   1333 		else if (flag == DA_REMOVE_ZONE)
   1334 			(void) update_device(dnms->dnames, NULL,
   1335 			    DA_REMOVE_ZONE);
   1336 		for (i = 0; i < *count; i++)
   1337 			free(dnms->dnames[i]);
   1338 		free(dnms->dnames);
   1339 	}
   1340 }
   1341 
   1342 int
   1343 allocate(int optflag, uid_t uid, char *device, char *zonename)
   1344 {
   1345 	int		count = 0;
   1346 	int		error = 0;
   1347 	int		lock_fd = -1;
   1348 	devalloc_t	*da;
   1349 	struct dev_names dnms;
   1350 
   1351 	if (optflag & (FORCE | USERID | USERNAME)) {
   1352 		if (!_is_authorized(DEVICE_REVOKE_AUTH, getuid()))
   1353 			return (UAUTHERR);
   1354 	}
   1355 	dnms.dnames = NULL;
   1356 	setdaent();
   1357 	if (optflag & TYPE) {
   1358 		/*
   1359 		 * allocate devices of this type
   1360 		 */
   1361 		while ((da = getdatype(device)) != NULL) {
   1362 			if (system_labeled &&
   1363 			    da_check_logindevperm(da->da_devname)) {
   1364 				freedaent(da);
   1365 				continue;
   1366 			}
   1367 			dprintf("trying to allocate %s\n", da->da_devname);
   1368 			error = _allocate_dev(optflag, uid, da, zonename,
   1369 			    &lock_fd);
   1370 			if (system_labeled && (error == 0)) {
   1371 				/*
   1372 				 * we need to record in device_allocate the
   1373 				 * label (zone name) at which this device is
   1374 				 * being allocated. store this device entry.
   1375 				 */
   1376 				_store_devnames(&count, &dnms, zonename, da, 0);
   1377 			}
   1378 			freedaent(da);
   1379 			error = 0;
   1380 		}
   1381 	} else {
   1382 		/*
   1383 		 * allocate this device
   1384 		 */
   1385 		if ((da = getdanam(device)) == NULL) {
   1386 			enddaent();
   1387 			return (NODAERR);
   1388 		}
   1389 		if (system_labeled && da_check_logindevperm(device)) {
   1390 			freedaent(da);
   1391 			return (LOGINDEVPERMERR);
   1392 		}
   1393 		dprintf("trying to allocate %s\n", da->da_devname);
   1394 		error = _allocate_dev(optflag, uid, da, zonename, &lock_fd);
   1395 		/*
   1396 		 * we need to record in device_allocate the label (zone name)
   1397 		 * at which this device is being allocated. store this device
   1398 		 * entry.
   1399 		 */
   1400 		if (system_labeled && (error == 0))
   1401 			_store_devnames(&count, &dnms, zonename, da, 0);
   1402 		freedaent(da);
   1403 		if (error == DEVCLEAN_BADMOUNT)
   1404 			error = 0;
   1405 	}
   1406 	enddaent();
   1407 	if (lock_fd != -1)
   1408 		(void) close(lock_fd);
   1409 	/*
   1410 	 * add to device_allocate labels (zone names) for the devices we
   1411 	 * allocated.
   1412 	 */
   1413 	if (dnms.dnames)
   1414 		_store_devnames(&count, &dnms, zonename, NULL, DA_ADD_ZONE);
   1415 
   1416 	return (error);
   1417 }
   1418 
   1419 /* ARGSUSED */
   1420 int
   1421 deallocate(int optflag, uid_t uid, char *device, char *zonename)
   1422 {
   1423 	int		count = 0;
   1424 	int		error = 0;
   1425 	int		lock_fd = -1;
   1426 	char		*class = NULL;
   1427 	devalloc_t	*da;
   1428 	struct dev_names dnms;
   1429 
   1430 	if (optflag & (FORCE | FORCE_ALL)) {
   1431 		if (!_is_authorized(DEVICE_REVOKE_AUTH, getuid()))
   1432 		return (UAUTHERR);
   1433 	}
   1434 	if (optflag & FORCE_ALL)
   1435 		optflag |= FORCE;
   1436 	dnms.dnames = NULL;
   1437 	setdaent();
   1438 	if (optflag & FORCE_ALL) {
   1439 		/*
   1440 		 * deallocate all devices
   1441 		 */
   1442 		while ((da = getdaent()) != NULL) {
   1443 			if (system_labeled &&
   1444 			    da_check_logindevperm(da->da_devname)) {
   1445 				freedaent(da);
   1446 				continue;
   1447 			}
   1448 			dprintf("trying to deallocate %s\n", da->da_devname);
   1449 			error = _deallocate_dev(optflag, da, NULL, uid,
   1450 			    zonename, &lock_fd);
   1451 			if (system_labeled && (error == 0)) {
   1452 				/*
   1453 				 * we need to remove this device's allocation
   1454 				 * label (zone name) from device_allocate.
   1455 				 * store this device name.
   1456 				 */
   1457 				_store_devnames(&count, &dnms, zonename, da, 0);
   1458 			}
   1459 			freedaent(da);
   1460 			error = 0;
   1461 		}
   1462 	} else if (system_labeled && (optflag & TYPE)) {
   1463 		/*
   1464 		 * deallocate all devices of this type
   1465 		 */
   1466 		while ((da = getdatype(device)) != NULL) {
   1467 			if (da_check_logindevperm(da->da_devname)) {
   1468 				freedaent(da);
   1469 				continue;
   1470 			}
   1471 			dprintf("trying to deallocate %s\n", da->da_devname);
   1472 			error = _deallocate_dev(optflag, da, NULL, uid,
   1473 			    zonename, &lock_fd);
   1474 			if (error == 0) {
   1475 				/*
   1476 				 * we need to remove this device's allocation
   1477 				 * label (zone name) from device_allocate.
   1478 				 * store this device name.
   1479 				 */
   1480 				_store_devnames(&count, &dnms, zonename, da, 0);
   1481 			}
   1482 			freedaent(da);
   1483 			error = 0;
   1484 		}
   1485 	} else if (system_labeled && (optflag & CLASS)) {
   1486 		/*
   1487 		 * deallocate all devices of this class (for sunray)
   1488 		 */
   1489 		while ((da = getdaent()) != NULL) {
   1490 			class =  kva_match(da->da_devopts, DAOPT_CLASS);
   1491 			if (class && (strcmp(class, device) == 0)) {
   1492 				dprintf("trying to deallocate %s\n",
   1493 				    da->da_devname);
   1494 				error = _deallocate_dev(optflag, da, NULL, uid,
   1495 				    zonename, &lock_fd);
   1496 				if (error == 0) {
   1497 					/*
   1498 					 * we need to remove this device's
   1499 					 * allocation label (zone name) from
   1500 					 * device_allocate. store this device
   1501 					 * name.
   1502 					 */
   1503 					_store_devnames(&count, &dnms, zonename,
   1504 					    da, 0);
   1505 				}
   1506 				error = 0;
   1507 			}
   1508 			freedaent(da);
   1509 		}
   1510 	} else if (!(optflag & TYPE)) {
   1511 		/*
   1512 		 * deallocate this device
   1513 		 */
   1514 		if ((da = getdanam(device)) == NULL) {
   1515 			enddaent();
   1516 			return (NODAERR);
   1517 		}
   1518 		if (system_labeled && da_check_logindevperm(da->da_devname)) {
   1519 			freedaent(da);
   1520 			return (LOGINDEVPERMERR);
   1521 		}
   1522 		dprintf("trying to deallocate %s\n", da->da_devname);
   1523 		error = _deallocate_dev(optflag, da, NULL, uid, zonename,
   1524 		    &lock_fd);
   1525 		if (system_labeled && (error == 0)) {
   1526 			/*
   1527 			 * we need to remove this device's allocation label
   1528 			 * (zone name) from device_allocate. store this
   1529 			 * device name.
   1530 			 */
   1531 			_store_devnames(&count, &dnms, zonename, da, 0);
   1532 		}
   1533 		freedaent(da);
   1534 		if (error == DEVCLEAN_BADMOUNT)
   1535 			error = 0;
   1536 	}
   1537 	enddaent();
   1538 	if (lock_fd != -1)
   1539 		(void) close(lock_fd);
   1540 	/*
   1541 	 * remove from device_allocate labels (zone names) for the devices we
   1542 	 * deallocated.
   1543 	 */
   1544 	if (dnms.dnames)
   1545 		_store_devnames(&count, &dnms, zonename, NULL, DA_REMOVE_ZONE);
   1546 
   1547 	return (error);
   1548 }
   1549 
   1550 static int
   1551 _dev_file_name(struct state_file *sfp, devmap_t *dm)
   1552 {
   1553 	sfp->sf_flags = 0;
   1554 	/* if devlist is generated, never leave device in error state */
   1555 	if (dm->dmap_devlist[0] == '`')
   1556 		sfp->sf_flags |= SFF_NO_ERROR;
   1557 	if (dm->dmap_devarray == NULL ||
   1558 	    dm->dmap_devarray[0] == NULL)
   1559 		return (NODMAPERR);
   1560 	(void) strncpy(sfp->sf_path, dm->dmap_devarray[0],
   1561 	    sizeof (sfp->sf_path));
   1562 	sfp->sf_path[sizeof (sfp->sf_path) - 1] = '\0';
   1563 	if (sfp->sf_path[0] == '\0') {
   1564 		dprintf("dev_file_name: no device list for %s\n",
   1565 		    dm->dmap_devname);
   1566 		return (NODMAPERR);
   1567 	}
   1568 
   1569 	return (0);
   1570 }
   1571 
   1572 /*
   1573  * _check_label -
   1574  *	checks the device label range against zone label, which is also
   1575  *	user's current label.
   1576  *	returns 0 if in range, -1 for all other conditions.
   1577  *
   1578  */
   1579 
   1580 static int
   1581 _check_label(devalloc_t *da, char *zonename, uid_t uid, int flag)
   1582 {
   1583 	int		err;
   1584 	int		in_range = 0;
   1585 	char		*alloczone, *lstr;
   1586 	char		pw_buf[NSS_BUFLEN_PASSWD];
   1587 	blrange_t	*range;
   1588 	m_label_t	*zlabel;
   1589 	struct passwd	pw_ent;
   1590 
   1591 	if ((da == NULL) || (zonename == NULL))
   1592 		return (-1);
   1593 
   1594 	if ((zlabel = getzonelabelbyname(zonename)) == NULL) {
   1595 		dprintf("unable to get label for %s zone\n", zonename);
   1596 		return (-1);
   1597 	}
   1598 	if (flag == CHECK_DRANGE) {
   1599 		blrange_t	drange;
   1600 
   1601 		drange.lower_bound = blabel_alloc();
   1602 		lstr = kva_match(da->da_devopts, DAOPT_MINLABEL);
   1603 		if (lstr == NULL) {
   1604 			bsllow(drange.lower_bound);
   1605 		} else if (stobsl(lstr, drange.lower_bound, NO_CORRECTION,
   1606 		    &err) == 0) {
   1607 			dprintf("bad min_label for device %s\n",
   1608 			    da->da_devname);
   1609 			free(zlabel);
   1610 			blabel_free(drange.lower_bound);
   1611 			return (-1);
   1612 		}
   1613 		drange.upper_bound = blabel_alloc();
   1614 		lstr = kva_match(da->da_devopts, DAOPT_MAXLABEL);
   1615 		if (lstr == NULL) {
   1616 			bslhigh(drange.upper_bound);
   1617 		} else if (stobsl(lstr, drange.upper_bound, NO_CORRECTION,
   1618 		    &err) == 0) {
   1619 			dprintf("bad max_label for device %s\n",
   1620 			    da->da_devname);
   1621 			free(zlabel);
   1622 			blabel_free(drange.lower_bound);
   1623 			blabel_free(drange.upper_bound);
   1624 			return (-1);
   1625 		}
   1626 		if (blinrange(zlabel, &drange) == 0) {
   1627 			char	*zlbl = NULL, *min = NULL, *max = NULL;
   1628 
   1629 			(void) bsltos(zlabel, &zlbl, 0, 0);
   1630 			(void) bsltos(drange.lower_bound, &min, 0, 0);
   1631 			(void) bsltos(drange.upper_bound, &max, 0, 0);
   1632 			dprintf("%s zone label ", zonename);
   1633 			dprintf("%s outside device label range: ", zlbl);
   1634 			dprintf("min - %s, ", min);
   1635 			dprintf("max - %s\n", max);
   1636 			free(zlabel);
   1637 			blabel_free(drange.lower_bound);
   1638 			blabel_free(drange.upper_bound);
   1639 			return (-1);
   1640 		}
   1641 	} else if (flag == CHECK_URANGE) {
   1642 		if (getpwuid_r(uid, &pw_ent, pw_buf, sizeof (pw_buf)) == NULL) {
   1643 			dprintf("Unable to get passwd entry for userid %d\n",
   1644 			    (int)uid);
   1645 			free(zlabel);
   1646 			return (-1);
   1647 		}
   1648 		if ((range = getuserrange(pw_ent.pw_name)) == NULL) {
   1649 			dprintf("Unable to get label range for userid %d\n",
   1650 			    (int)uid);
   1651 			free(zlabel);
   1652 			return (-1);
   1653 		}
   1654 		in_range = blinrange(zlabel, range);
   1655 		free(zlabel);
   1656 		blabel_free(range->lower_bound);
   1657 		blabel_free(range->upper_bound);
   1658 		free(range);
   1659 		if (in_range == 0) {
   1660 			dprintf("%s device label ", da->da_devname);
   1661 			dprintf("out of user %d label range\n", (int)uid);
   1662 			return (-1);
   1663 		}
   1664 	} else if (flag == CHECK_ZLABEL) {
   1665 		alloczone = kva_match(da->da_devopts, DAOPT_ZONE);
   1666 		if (alloczone == NULL) {
   1667 			free(zlabel);
   1668 			return (-1);
   1669 		}
   1670 		if (strcmp(zonename, alloczone) != 0) {
   1671 			dprintf("%s zone is different than ", zonename);
   1672 			dprintf("%s zone to which the device ", alloczone);
   1673 			dprintf("%s is allocated\n", da->da_devname);
   1674 			free(zlabel);
   1675 			return (-1);
   1676 		}
   1677 	}
   1678 	free(zlabel);
   1679 
   1680 	return (0);
   1681 }
   1682 
   1683 int
   1684 create_znode(char *zonename, struct zone_path *zpath, devmap_t *list)
   1685 {
   1686 	int		size;
   1687 	int		len = 0;
   1688 	int		fcount = 0;
   1689 	char		*p, *tmpfile, *zoneroot;
   1690 	char		**file;
   1691 	char		zonepath[MAXPATHLEN];
   1692 	di_prof_t	prof = NULL;
   1693 
   1694 	file = list->dmap_devarray;
   1695 	if (file == NULL)
   1696 		return (NODMAPERR);
   1697 	if ((zoneroot = getzonerootbyname(zonename)) == NULL) {
   1698 		dprintf("unable to get label for %s zone\n", zonename);
   1699 		return (1);
   1700 	}
   1701 	(void) strcpy(zonepath, zoneroot);
   1702 	free(zoneroot);
   1703 	len = strlen(zonepath);
   1704 	size = sizeof (zonepath);
   1705 	(void) strlcat(zonepath, "/dev", size);
   1706 	if (di_prof_init(zonepath, &prof)) {
   1707 		dprintf("failed to initialize dev profile at %s\n", zonepath);
   1708 		return (1);
   1709 	}
   1710 	zonepath[len] = '\0';
   1711 	for (; *file != NULL; file++) {
   1712 		/*
   1713 		 * First time initialization
   1714 		 */
   1715 		tmpfile = strdup(*file);
   1716 
   1717 		/*
   1718 		 * Most devices have pathnames starting in /dev
   1719 		 * but SunRay devices do not. In SRRS 3.1 they use /tmp.
   1720 		 *
   1721 		 * If the device pathname is not in /dev then create
   1722 		 * a symbolic link to it and put the device in /dev
   1723 		 */
   1724 		if (strncmp(tmpfile, "/dev/", strlen("/dev/")) != 0) {
   1725 			char	*linkdir;
   1726 			char	srclinkdir[MAXPATHLEN];
   1727 			char	dstlinkdir[MAXPATHLEN];
   1728 
   1729 			linkdir = strchr(tmpfile + 1, '/');
   1730 			p = strchr(linkdir + 1, '/');
   1731 			*p = '\0';
   1732 			(void) strcpy(dstlinkdir, "/dev");
   1733 			(void) strncat(dstlinkdir, linkdir, MAXPATHLEN);
   1734 			(void) snprintf(srclinkdir, MAXPATHLEN, "%s/root%s",
   1735 			    zonepath, tmpfile);
   1736 			(void) symlink(dstlinkdir, srclinkdir);
   1737 			*p = '/';
   1738 			(void) strncat(dstlinkdir, p, MAXPATHLEN);
   1739 			free(tmpfile);
   1740 			tmpfile = strdup(dstlinkdir);
   1741 		}
   1742 		if (di_prof_add_dev(prof, tmpfile)) {
   1743 			dprintf("failed to add %s to profile\n", tmpfile);
   1744 			di_prof_fini(prof);
   1745 			return (1);
   1746 		}
   1747 		if (strlcat(zonepath, tmpfile, size) >= size) {
   1748 			dprintf("Buffer overflow in create_znode for %s\n",
   1749 			    *file);
   1750 			free(tmpfile);
   1751 			di_prof_fini(prof);
   1752 			return (1);
   1753 		}
   1754 		free(tmpfile);
   1755 		fcount++;
   1756 		if ((zpath->path = (char **)realloc(zpath->path,
   1757 		    (fcount * sizeof (char *)))) == NULL) {
   1758 			di_prof_fini(prof);
   1759 			return (1);
   1760 		}
   1761 		zpath->path[zpath->count] = strdup(zonepath);
   1762 		zpath->count = fcount;
   1763 		zonepath[len] = '\0';
   1764 	}
   1765 
   1766 	if (di_prof_commit(prof))
   1767 		dprintf("failed to add devices to zone %s\n", zonename);
   1768 	di_prof_fini(prof);
   1769 
   1770 	return (0);
   1771 }
   1772 
   1773 int
   1774 remove_znode(char *zonename, devmap_t *dm)
   1775 {
   1776 	int		len = 0;
   1777 	char		*zoneroot;
   1778 	char		**file;
   1779 	char		zonepath[MAXPATHLEN];
   1780 	di_prof_t	prof = NULL;
   1781 
   1782 	file = dm->dmap_devarray;
   1783 	if (file == NULL)
   1784 		return (NODMAPERR);
   1785 	if ((zoneroot = getzonerootbyname(zonename)) == NULL) {
   1786 		(void) snprintf(zonepath, MAXPATHLEN, "/zone/%s", zonename);
   1787 	} else {
   1788 		(void)  strcpy(zonepath, zoneroot);
   1789 		free(zoneroot);
   1790 	}
   1791 	/*
   1792 	 * To support SunRay we will just deal with the
   1793 	 * file in /dev, not the symlinks.
   1794 	 */
   1795 	(void) strncat(zonepath, "/dev", MAXPATHLEN);
   1796 	len = strlen(zonepath);
   1797 	if (di_prof_init(zonepath, &prof)) {
   1798 		dprintf("failed to initialize dev profile at %s\n", zonepath);
   1799 		return (1);
   1800 	}
   1801 	for (; *file != NULL; file++) {
   1802 		char *devrelpath;
   1803 
   1804 		/*
   1805 		 * remove device node from zone.
   1806 		 *
   1807 		 * SunRay devices don't start with /dev
   1808 		 * so skip over first directory to make
   1809 		 * sure it is /dev. SunRay devices in zones
   1810 		 * will have a symlink into /dev but
   1811 		 * we don't ever delete it.
   1812 		 */
   1813 		devrelpath = strchr(*file + 1, '/');
   1814 
   1815 		if (di_prof_add_exclude(prof, devrelpath + 1)) {
   1816 			dprintf("Failed exclude %s in dev profile\n", *file);
   1817 			di_prof_fini(prof);
   1818 			return (1);
   1819 		}
   1820 		zonepath[len] = '\0';
   1821 	}
   1822 
   1823 	if (di_prof_commit(prof))
   1824 		dprintf("failed to remove devices from zone %s\n", zonename);
   1825 	di_prof_fini(prof);
   1826 	return (0);
   1827 }
   1828 
   1829 int
   1830 update_device(char **devnames, char *zonename, int flag)
   1831 {
   1832 	int		len, rc;
   1833 	char		*optstr = NULL;
   1834 	da_args		dargs;
   1835 	devinfo_t	devinfo;
   1836 
   1837 	dargs.optflag = flag;
   1838 	dargs.optflag |= DA_UPDATE|DA_ALLOC_ONLY;
   1839 	dargs.rootdir = NULL;
   1840 	dargs.devnames = devnames;
   1841 	devinfo.devname = devinfo.devtype = devinfo.devauths = devinfo.devexec =
   1842 	    devinfo.devlist = NULL;
   1843 	if (dargs.optflag & DA_ADD_ZONE) {
   1844 		len = strlen(DAOPT_ZONE) + strlen(zonename) + 3;
   1845 		if ((optstr = (char *)malloc(len)) == NULL)
   1846 			return (-1);
   1847 		(void) snprintf(optstr, len, "%s%s%s", DAOPT_ZONE, KV_ASSIGN,
   1848 		    zonename);
   1849 		devinfo.devopts = optstr;
   1850 	}
   1851 	dargs.devinfo = &devinfo;
   1852 
   1853 	rc = da_update_device(&dargs);
   1854 
   1855 	if (optstr)
   1856 		free(optstr);
   1857 
   1858 	return (rc);
   1859 }
   1860