xref: /titanic_52/usr/src/cmd/allocate/allocate3.c (revision d444b03e85973a0566ba10d94e6f65ca1a6b21fa)
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