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