xref: /titanic_52/usr/src/cmd/allocate/allocate3.c (revision b2eb1770e05377d3b46c691c5721f32915d57f58)
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 2006 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 "allocate.h"
66 
67 extern void print_error(int, char *);
68 
69 #if	defined(DEBUG) || defined(lint)
70 #define	dprintf(s, a) (void) fprintf(stderr, s, a)
71 #define	dperror(s) perror(s)
72 #else	/* !DEBUG */
73 #define	dprintf(s, a)	0
74 #define	dperror(s)	0
75 #endif	/* DEBUG */
76 
77 #define	DEV_ERRORED(sbuf)	(((sbuf).st_mode & ~S_IFMT) == ALLOC_ERR_MODE)
78 #define	DEV_INVALID(sbuf)	(((sbuf).st_mode & ~S_IFMT) == ALLOC_INVALID)
79 #define	DEV_ALLOCATED(sbuf)	((sbuf).st_uid != ALLOC_UID || \
80 			!(((sbuf).st_mode & ~S_IFMT) == DEALLOC_MODE || \
81 			DEV_ERRORED(sbuf) || DEV_INVALID(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 devnames {
118 	char **dnames;
119 };
120 
121 static int _dev_file_name(struct state_file *, devmap_t *);
122 static int lock_dev(char *);
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 (DEV_INVALID(fip->fi_stat))
274 			(void) printf("owner=/INVALID:%s%s", fip->fi_message,
275 			    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=%ld%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 	setdmapent();
318 	if ((dm = getdmapnam(da->da_devname)) == NULL) {
319 		enddmapent();
320 		dprintf("Unable to find %s in the maps database\n",
321 		    da->da_devname);
322 		return (NODMAPERR);
323 	}
324 	enddmapent();
325 	if (system_labeled) {
326 		if ((error = _dev_file_name(&sf, dm)) != 0) {
327 			freedmapent(dm);
328 			dprintf("Unable to find %s device files\n",
329 			    da->da_devname);
330 			error = NODMAPERR;
331 			goto out;
332 		}
333 		fname = sf.sf_path;
334 	} else {
335 		bytes = snprintf(file_name, MAXPATHLEN, "%s/%s", DAC_DIR,
336 		    da->da_devname);
337 		if (bytes <= 0) {
338 			error = DEVNAMEERR;
339 			goto out;
340 		} else if (bytes >= MAXPATHLEN) {
341 			dprintf("device name %s is too long.\n",
342 			    da->da_devname);
343 			error = DEVLONGERR;
344 			goto out;
345 		}
346 		fname = file_name;
347 	}
348 	if (stat(fname, &fi.fi_stat) != 0) {
349 		dprintf("Unable to stat %s\n", fname);
350 		dperror("Error:");
351 		error = DACACCERR;
352 		goto out;
353 	}
354 	if (optflag & USERID)
355 		is_authorized = 1;
356 	else
357 		is_authorized = _is_dev_authorized(da, uid);
358 	if (optflag & LISTFREE) {	/* list_devices -n */
359 		/*
360 		 * list all free devices
361 		 */
362 		if (DEV_ALLOCATED(fi.fi_stat)) {
363 				error = PREALLOCERR;
364 				goto out;
365 		}
366 		if (system_labeled) {
367 			/*
368 			 * for this free device, check if -
369 			 * 1. user has authorization to allocate
370 			 * 2. the zone label is within the label range of the
371 			 *    device
372 			 */
373 			if (is_authorized == ALLOC_BY_NONE) {
374 				error = DAUTHERR;
375 				goto out;
376 			} else if (is_authorized == 0) {
377 				error = UAUTHERR;
378 				goto out;
379 			}
380 			if (_check_label(da, zonename, uid,
381 			    CHECK_DRANGE) != 0) {
382 				error = LABELRNGERR;
383 				goto out;
384 			}
385 		}
386 	} else if (optflag & LISTALLOC) {	/*  list_devices -u */
387 		/*
388 		 * list all allocated devices
389 		 */
390 		if (!DEV_ALLOCATED(fi.fi_stat)) {
391 			error = DEVNALLOCERR;
392 			goto out;
393 		}
394 		if (fi.fi_stat.st_uid != uid) {
395 			error = DEVSTATEERR;
396 			goto out;
397 		}
398 		if (system_labeled) {
399 			/*
400 			 * check if the zone label equals the label at which
401 			 * the device is allocated.
402 			 */
403 			if (_check_label(da, zonename, uid,
404 			    CHECK_ZLABEL) != 0) {
405 				error = LABELRNGERR;
406 				goto out;
407 			}
408 		}
409 	} else if (optflag & LISTALL) {		/* list_devices -l */
410 		/*
411 		 * list all devices - free and allocated - available
412 		 */
413 		if (DEV_ALLOCATED(fi.fi_stat)) {
414 			if (optflag & WINDOWING &&
415 			    (is_authorized == ALLOC_BY_NONE)) {
416 				/*
417 				 * don't complain if we're here for the GUI.
418 				 */
419 				error = 0;
420 			} else if (fi.fi_stat.st_uid != uid) {
421 				if (!(optflag & WINDOWING)) {
422 					error = ALLOCUERR;
423 					goto out;
424 				}
425 			}
426 			if (system_labeled && !(optflag & WINDOWING)) {
427 				/*
428 				 * if we're not displaying in the GUI,
429 				 * check if the zone label equals the label
430 				 * at which the device is allocated.
431 				 */
432 				if (_check_label(da, zonename, uid,
433 				    CHECK_ZLABEL) != 0) {
434 					error = LABELRNGERR;
435 					goto out;
436 				}
437 			}
438 		} else if (system_labeled && !(optflag & WINDOWING)) {
439 			/*
440 			 * if we're not displaying in the GUI,
441 			 * for this free device, check if -
442 			 * 1. user has authorization to allocate
443 			 * 2. the zone label is within the label range of the
444 			 *    device
445 			 */
446 			if (is_authorized == ALLOC_BY_NONE) {
447 				error = DAUTHERR;
448 				goto out;
449 			} else if (is_authorized == 0) {
450 				error = UAUTHERR;
451 				goto out;
452 			}
453 			if (_check_label(da, zonename, uid,
454 			    CHECK_DRANGE) != 0) {
455 				error = LABELRNGERR;
456 				goto out;
457 			}
458 		}
459 	}
460 	if (system_labeled && DEV_ERRORED(fi.fi_stat) && !(optflag & LISTALL)) {
461 		error = DEVSTATEERR;
462 		goto out;
463 	}
464 	if (check_devs(dm) == -1) {
465 		error = DSPMISSERR;
466 		goto out;
467 	}
468 	if (optflag & LISTATTRS)
469 		print_dev_attrs(optflag, da, dm, &fi);
470 	else
471 		print_dev(dm);
472 
473 	error = 0;
474 
475 out:
476 	freedmapent(dm);
477 	return (error);
478 }
479 
480 /* ARGSUSED */
481 int
482 list_devices(int optflag, uid_t uid, char *device, char *zonename)
483 {
484 	int		error = 0;
485 	da_defs_t	*da_defs;
486 	devalloc_t	*da;
487 
488 	if (system_labeled && optflag & WINDOWING && !(optflag & LISTATTRS)) {
489 		/*
490 		 * Private interface for GUI.
491 		 */
492 		(void) lock_dev(NULL);
493 		(void) puts(DA_DB_LOCK);
494 		return (0);
495 	}
496 	if (optflag & USERID) {
497 		/*
498 		 * we need device.revoke to list someone else's devices
499 		 */
500 		if (!_is_authorized(DEVICE_REVOKE_AUTH, getuid()))
501 			return (UAUTHERR);
502 	}
503 	if (system_labeled) {
504 		if (!(optflag & USERID) &&
505 		    !_is_authorized(DEFAULT_DEV_ALLOC_AUTH, uid))
506 			/*
507 			 * we need device.allocate to list our devices
508 			 */
509 			return (UAUTHERR);
510 		if (optflag & LISTDEFS) {
511 			/*
512 			 * list default attrs from devalloc_defaults
513 			 */
514 			setdadefent();
515 			if (device) {
516 				/*
517 				 * list default attrs for this device type
518 				 */
519 				da_defs = getdadeftype(device);
520 				if (da_defs == NULL) {
521 					enddadefent();
522 					dprintf("No default attributes for "
523 					    "%s\n", device);
524 					return (DEFATTRSERR);
525 				}
526 				error = print_da_defs(da_defs);
527 				freedadefent(da_defs);
528 			} else {
529 				/*
530 				 * list everything in devalloc_defaults
531 				 */
532 				while ((da_defs = getdadefent()) != NULL) {
533 					(void) print_da_defs(da_defs);
534 					freedadefent(da_defs);
535 				}
536 			}
537 			enddadefent();
538 			return (error);
539 		}
540 	}
541 	setdaent();
542 	if (device) {
543 		/*
544 		 * list this device
545 		 */
546 		if ((da = getdanam(device)) == NULL) {
547 			enddaent();
548 			return (NODAERR);
549 		}
550 		error = _list_device(optflag, uid, da, zonename);
551 		freedaent(da);
552 	} else {
553 		/*
554 		 * list all devices
555 		 */
556 		while ((da = getdaent()) != NULL) {
557 			(void) _list_device(optflag, uid, da, zonename);
558 			freedaent(da);
559 		}
560 	}
561 	enddaent();
562 
563 	return (error);
564 }
565 
566 /*
567  * Set the DAC characteristics of the file.
568  * This uses a fancy chmod() by setting a minimal ACL which sets the mode
569  * and discards any existing ACL.
570  */
571 int
572 _newdac(char *file, uid_t owner, gid_t group, o_mode_t mode)
573 {
574 	int	err = 0;
575 
576 	if (mode == ALLOC_MODE) {
577 		if (chown(file, owner, group) == -1) {
578 			dperror("newdac: unable to chown");
579 			err = CHOWNERR;
580 		}
581 	} else do {
582 		if (chown(file, owner, group) == -1) {
583 			dperror("newdac: unable to chown");
584 			err = CHOWNERR;
585 		}
586 	} while (fdetach(file) == 0);
587 
588 	if (err)
589 		return (err);
590 
591 	if (strncmp(file, "/dev/", strlen("/dev/")) != 0) {
592 		/*
593 		 * This could be a SunRay device that is in /tmp.
594 		 */
595 		if (chmod(file, mode) == -1) {
596 			dperror("newdac: unable to chmod");
597 			err = SETACLERR;
598 		}
599 	} else {
600 		err = acl_strip(file, owner, group, (mode_t)mode);
601 	}
602 
603 	if (err != 0) {
604 		dperror("newdac: unable to setacl");
605 		err = SETACLERR;
606 	}
607 
608 	return (err);
609 }
610 
611 static int
612 lock_dev(char *file)
613 {
614 	int	lockfd = -1;
615 
616 	if ((file == NULL) || system_labeled)
617 		file = DA_DEV_LOCK;
618 	dprintf("locking %s\n", file);
619 	if ((lockfd = open(file, O_RDWR | O_CREAT, 0600)) == -1) {
620 		dperror("lock_dev: cannot open lock file");
621 		return (DEVLKERR);
622 	}
623 	if (lockf(lockfd, F_TLOCK, 0) == -1) {
624 		dperror("lock_dev: cannot set lock");
625 		return (DEVLKERR);
626 	}
627 
628 	return (0);
629 }
630 
631 int
632 mk_alloc(devmap_t *list, uid_t uid, struct zone_path *zpath)
633 {
634 	int	i;
635 	int	error = 0;
636 	char	**file;
637 	gid_t	gid = getgid();
638 	mode_t	mode = ALLOC_MODE;
639 
640 	file = list->dmap_devarray;
641 	if (file == NULL)
642 		return (NODMAPERR);
643 	for (; *file != NULL; file++) {
644 		dprintf("Allocating %s\n", *file);
645 		if ((error = _newdac(*file, uid, gid, mode)) != 0) {
646 			(void) _newdac(*file, ALLOC_ERRID, ALLOC_GID,
647 			    ALLOC_ERR_MODE);
648 			break;
649 		}
650 	}
651 	if (system_labeled && zpath->count && (error == 0)) {
652 		/*
653 		 * mark as allocated any new device nodes that we
654 		 * created in local zone
655 		 */
656 		for (i = 0; i < zpath->count; i++) {
657 			dprintf("Allocating %s\n", zpath->path[i]);
658 			if ((error = _newdac(zpath->path[i], uid, gid,
659 			    mode)) != 0) {
660 				(void) _newdac(zpath->path[i], ALLOC_ERRID,
661 				    ALLOC_GID, ALLOC_ERR_MODE);
662 				break;
663 			}
664 		}
665 	}
666 
667 	return (error);
668 }
669 
670 /*
671  * mk_revoke() is used instead of system("/usr/sbin/fuser -k file")
672  * because "/usr/sbin/fuser -k file" kills all processes
673  * working with the file, even "vold" (bug #4095152).
674  */
675 int
676 mk_revoke(int optflag, char *file)
677 {
678 	int		r = 0, p[2], fp, lock;
679 	int		fuserpid;
680 	char		buf[MAXPATHLEN];
681 	FILE		*ptr;
682 	pid_t		c_pid;
683 	prpsinfo_t	info;
684 
685 	(void) strcpy(buf, PROCFS);
686 	/*
687 	 * vfork() and execl() just to make the same output
688 	 * as before fixing of bug #4095152.
689 	 * The problem is that the "fuser" command prints
690 	 * one part of output into stderr and another into stdout,
691 	 * but user sees them mixed. Of course, better to change "fuser"
692 	 * or to intercept and not to print its output.
693 	 */
694 	if (!(optflag & SILENT)) {
695 		c_pid = vfork();
696 		if (c_pid == -1)
697 			return (-1);
698 		if (c_pid == 0) {
699 			dprintf("first exec fuser %s\n", file);
700 			(void) execl("/usr/sbin/fuser", "fuser", file, NULL);
701 			dperror("first exec fuser");
702 			_exit(1);
703 		}
704 
705 		(void) waitpid(c_pid, &lock, 0);
706 		dprintf("exit status %x\n", lock);
707 		if (WEXITSTATUS(lock) != 0)
708 			return (-1);
709 	}
710 	dprintf("first continuing c_pid=%d\n", (int)c_pid);
711 	if (pipe(p)) {
712 		dperror("pipe");
713 		return (-1);
714 	}
715 	/* vfork() and execl() to catch output and to process it */
716 	c_pid = vfork();
717 	if (c_pid == -1) {
718 		dperror("second vfork");
719 		return (-1);
720 	}
721 	dprintf("second continuing c_pid=%d\n", (int)c_pid);
722 	if (c_pid == 0) {
723 		(void) close(p[0]);
724 		(void) close(1);
725 		(void) fcntl(p[1], F_DUPFD, 1);
726 		(void) close(p[1]);
727 		(void) close(2);
728 		dprintf("second exec fuser %s\n", file);
729 		(void) execl("/usr/sbin/fuser", "fuser", file, NULL);
730 		dperror("second exec fuser");
731 		_exit(1);
732 	}
733 	(void) close(p[1]);
734 	if ((ptr = fdopen(p[0], "r")) != NULL) {
735 		while (!feof(ptr)) {
736 			if (fscanf(ptr, "%d", &fuserpid) > 0) {
737 				(void) sprintf(buf + strlen(PROCFS), "%d",
738 				    fuserpid);
739 				if ((fp = open(buf, O_RDONLY)) == -1) {
740 					dperror(buf);
741 					continue;
742 				}
743 				if (ioctl(fp, PIOCPSINFO,
744 				    (char *)&info) == -1) {
745 					dprintf("%d psinfo failed", fuserpid);
746 					dperror("");
747 					(void) close(fp);
748 					continue;
749 				}
750 				(void) close(fp);
751 				if (strcmp(info.pr_fname, "vold") == NULL) {
752 					dprintf("%d matched vold name\n",
753 					    fuserpid);
754 					continue;
755 				}
756 				dprintf("killing %s", info.pr_fname);
757 				dprintf("(%d)\n", fuserpid);
758 				if ((r =
759 				    kill((pid_t)fuserpid, SIGKILL)) == -1) {
760 					dprintf("kill %d", fuserpid);
761 					dperror("");
762 					break;
763 				}
764 			}
765 		}
766 	} else {
767 		dperror("fdopen(p[0], r)");
768 		r = -1;
769 	}
770 	(void) fclose(ptr);
771 
772 	return (r);
773 }
774 
775 int
776 mk_unalloc(int optflag, devmap_t *list)
777 {
778 	int	error = 0;
779 	int	status;
780 	char	**file;
781 
782 	audit_allocate_list(list->dmap_devlist);
783 	file = list->dmap_devarray;
784 	if (file == NULL)
785 		return (NODMAPERR);
786 	for (; *file != NULL; file++) {
787 		dprintf("Deallocating %s\n", *file);
788 		if (mk_revoke(optflag, *file) < 0) {
789 			dprintf("mk_unalloc: unable to revoke %s\n", *file);
790 			dperror("");
791 			error = CNTFRCERR;
792 		}
793 		status = _newdac(*file, ALLOC_UID, ALLOC_GID, DEALLOC_MODE);
794 		if (error == 0)
795 			error = status;
796 
797 	}
798 
799 	return (error);
800 }
801 
802 int
803 mk_error(devmap_t *list)
804 {
805 	int	status = 0;
806 	char	**file;
807 
808 	audit_allocate_list(list->dmap_devlist);
809 	file = list->dmap_devarray;
810 	if (file == NULL)
811 		return (NODMAPERR);
812 	for (; *file != NULL; file++) {
813 		dprintf("Putting %s in error state\n", *file);
814 		status = _newdac(*file, ALLOC_ERRID, ALLOC_GID, ALLOC_ERR_MODE);
815 	}
816 
817 	return (status);
818 }
819 
820 int
821 exec_clean(int optflag, char *devname, char *path, uid_t uid, char *zonename,
822     char *clean_arg)
823 {
824 	int		c;
825 	int		status = 0, exit_status;
826 	char		*mode, *cmd, *wdwcmd, *zoneroot;
827 	char		*devzone = zonename;
828 	char		wdwpath[PATH_MAX];
829 	char		zonepath[MAXPATHLEN];
830 	char		title[100];
831 	char		pw_buf[NSS_BUFLEN_PASSWD];
832 	struct passwd	pw_ent;
833 
834 	zonepath[0] = '\0';
835 	if (system_labeled) {
836 		if ((zoneroot = getzonerootbyname(zonename)) == NULL) {
837 			if (strcmp(clean_arg, ALLOC_CLEAN) == 0) {
838 				return (-1);
839 			} else if (optflag & FORCE) {
840 				(void) strcpy(zonepath, "/");
841 				devzone = GLOBAL_ZONENAME;
842 			} else {
843 				dprintf("unable to get label for %s zone\n",
844 				    zonename);
845 				return (-1);
846 			}
847 		} else {
848 			(void) strcpy(zonepath, zoneroot);
849 			free(zoneroot);
850 		}
851 	}
852 	if (getpwuid_r(uid, &pw_ent, pw_buf, sizeof (pw_buf)) == NULL)
853 		return (-1);
854 	if (optflag & FORCE_ALL)
855 		mode = "-I";
856 	else if (optflag & FORCE)
857 		mode = "-f";
858 	else
859 		mode = "-s";
860 	if (path == NULL)
861 		return (0);
862 	if ((cmd = strrchr(path, '/')) == NULL)
863 		cmd = path;
864 	else
865 		cmd++;	/* skip leading '/' */
866 	c = vfork();
867 	switch (c) {
868 	case -1:
869 		return (-1);
870 	case 0:
871 		(void) setuid(0);
872 		if (system_labeled && (optflag & WINDOWING)) {
873 			/* First try .windowing version of script */
874 			(void) strncpy(wdwpath, path, PATH_MAX);
875 			(void) strncat(wdwpath, ".windowing", PATH_MAX);
876 			if ((wdwcmd = strrchr(wdwpath, '/')) == NULL)
877 				wdwcmd = wdwpath;
878 			(void) execl(wdwpath, wdwcmd, mode, devname, clean_arg,
879 			    pw_ent.pw_name, devzone, zonepath, NULL);
880 			/* If that failed, run regular version via dtterm */
881 			(void) snprintf(title, sizeof (title),
882 			    "Device %s for %s",
883 			    strcmp(clean_arg, ALLOC_CLEAN) == 0 ?
884 			    "allocation" : "deallocation", devname);
885 			(void) execl("/usr/dt/bin/dtterm", "dtterm",
886 			    "-title", title, "-geometry", "x10+100+400",
887 			    "-e", "/etc/security/lib/wdwwrapper",
888 			    path, mode, devname, clean_arg, pw_ent.pw_name,
889 			    devzone, zonepath, NULL);
890 			/*
891 			 * And if that failed, continue on to try
892 			 * running regular version directly.
893 			 */
894 		}
895 		dprintf("clean script: %s, ", path);
896 		dprintf("cmd=%s, ", cmd);
897 		dprintf("mode=%s, ", mode);
898 		if (system_labeled) {
899 			dprintf("devname=%s ", devname);
900 			dprintf("zonename=%s ", devzone);
901 			dprintf("zonepath=%s ", zonepath);
902 			dprintf("username=%s\n", pw_ent.pw_name);
903 			(void) execl(path, cmd, mode, devname, clean_arg,
904 			    pw_ent.pw_name, devzone, zonepath, NULL);
905 		} else {
906 			dprintf("devname=%s\n", devname);
907 			(void) execle(path, cmd, mode, devname, NULL, newenv);
908 		}
909 		dprintf("Unable to execute clean up script %s\n", path);
910 		dperror("");
911 		exit(CNTDEXECERR);
912 	default:
913 		(void) waitpid(c, &status, 0);
914 		dprintf("Child %d", c);
915 		if (WIFEXITED(status)) {
916 			exit_status = WEXITSTATUS(status);
917 			dprintf(" exited, status: %d\n", exit_status);
918 			return (exit_status);
919 		} else if (WIFSIGNALED(status)) {
920 			dprintf(" killed, signal %d\n", WTERMSIG(status));
921 		} else {
922 			dprintf(": exit status %d\n", status);
923 		}
924 		return (-1);
925 	}
926 }
927 
928 int
929 _deallocate_dev(int optflag, devalloc_t *da, devmap_t *dm_in, uid_t uid,
930     char *zonename)
931 {
932 	int			bytes = 0;
933 	int			error = 0;
934 	int			is_authorized = 0;
935 	uid_t			nuid;
936 	char			*fname = NULL;
937 	char			file_name[MAXPATHLEN];
938 	char			*devzone = NULL;
939 	devmap_t		*dm = NULL, *dm_new = NULL;
940 	struct stat		stat_buf;
941 	struct state_file	sf;
942 
943 	if (dm_in == NULL) {
944 		setdmapent();
945 		if ((dm_new = getdmapnam(da->da_devname)) == NULL) {
946 			enddmapent();
947 			dprintf("Unable to find %s in device map database\n",
948 			    da->da_devname);
949 			return (NODMAPERR);
950 		}
951 		enddmapent();
952 		dm = dm_new;
953 	} else {
954 		dm = dm_in;
955 	}
956 	if (system_labeled) {
957 		if (_dev_file_name(&sf, dm) != 0) {
958 			if (dm_new)
959 				freedmapent(dm_new);
960 			dprintf("Unable to find %s device files\n",
961 			    da->da_devname);
962 			error = NODMAPERR;
963 			goto out;
964 		}
965 		fname = sf.sf_path;
966 	} else {
967 		bytes = snprintf(file_name,  MAXPATHLEN, "%s/%s", DAC_DIR,
968 		    da->da_devname);
969 		if (bytes <= 0) {
970 			error = DEVNAMEERR;
971 			goto out;
972 		} else if (bytes >= MAXPATHLEN) {
973 			dprintf("device name %s is too long.\n",
974 			    da->da_devname);
975 			error = DEVLONGERR;
976 			goto out;
977 		}
978 		fname = file_name;
979 	}
980 
981 	audit_allocate_device(fname);
982 
983 	if (stat(fname, &stat_buf) != 0) {
984 		dprintf("Unable to stat %s\n", fname);
985 		error = DACACCERR;
986 		goto out;
987 	}
988 	is_authorized = _is_dev_authorized(da, uid);
989 	if (!(optflag & (FORCE | FORCE_ALL)) && !is_authorized) {
990 		dprintf("User %d is unauthorized to deallocate\n", (int)uid);
991 		error = UAUTHERR;
992 		goto out;
993 	}
994 	if (system_labeled) {
995 		/*
996 		 * unless we're here to deallocate by force, check if the
997 		 * label at which the device is currently allocated is
998 		 * within the user label range.
999 		 */
1000 		if (!(optflag & FORCE) &&
1001 		    _check_label(da, zonename, uid, CHECK_URANGE) != 0) {
1002 			error = LABELRNGERR;
1003 			goto out;
1004 		}
1005 	}
1006 	if (!(optflag & FORCE) && stat_buf.st_uid != uid &&
1007 	    DEV_ALLOCATED(stat_buf)) {
1008 		error = ALLOCUERR;
1009 		goto out;
1010 	}
1011 	if (!DEV_ALLOCATED(stat_buf)) {
1012 		if (DEV_ERRORED(stat_buf)) {
1013 			if (!(optflag & FORCE)) {
1014 				error = DEVSTATEERR;
1015 				goto out;
1016 			}
1017 		} else {
1018 			error = DEVNALLOCERR;
1019 			goto out;
1020 		}
1021 	}
1022 	/* All checks passed, time to lock and deallocate */
1023 	if ((error = lock_dev(fname)) != 0)
1024 		goto out;
1025 	if (system_labeled) {
1026 		devzone = kva_match(da->da_devopts, DAOPT_ZONE);
1027 		if (devzone && (strcmp(devzone, GLOBAL_ZONENAME) != 0)) {
1028 			if ((remove_znode(devzone, dm) != 0) &&
1029 			    !(optflag & FORCE)) {
1030 				error = ZONEERR;
1031 				goto out;
1032 			}
1033 		}
1034 	}
1035 	if ((error = mk_unalloc(optflag, dm)) != 0) {
1036 		if (!(optflag & FORCE))
1037 			goto out;
1038 	}
1039 	if (system_labeled == 0) {
1040 		if ((error = _newdac(fname, ALLOC_UID, ALLOC_GID,
1041 		    DEALLOC_MODE)) != 0) {
1042 			(void) _newdac(file_name, ALLOC_UID, ALLOC_GID,
1043 			    ALLOC_ERR_MODE);
1044 			goto out;
1045 		}
1046 	}
1047 	/*
1048 	 * if we are deallocating device owned by someone else,
1049 	 * pass the owner's uid to the cleaning script.
1050 	 */
1051 	nuid = (stat_buf.st_uid == uid) ? uid : stat_buf.st_uid;
1052 	error = exec_clean(optflag, da->da_devname, da->da_devexec, nuid,
1053 	    devzone, DEALLOC_CLEAN);
1054 	if (error != 0) {
1055 		if (!(optflag & (FORCE | FORCE_ALL))) {
1056 			error = CLEANERR;
1057 			(void) mk_error(dm);
1058 		} else {
1059 			error = 0;
1060 		}
1061 	}
1062 
1063 out:
1064 	if (dm_new)
1065 		freedmapent(dm_new);
1066 	return (error);
1067 }
1068 
1069 int
1070 _allocate_dev(int optflag, uid_t uid, devalloc_t *da, char *zonename)
1071 {
1072 	int			i;
1073 	int			bytes = 0;
1074 	int			error = 0;
1075 	int			is_authorized = 0;
1076 	int			dealloc_optflag = 0;
1077 	char			*fname = NULL;
1078 	char			file_name[MAXPATHLEN];
1079 	devmap_t 		*dm;
1080 	struct stat 		stat_buf;
1081 	struct state_file	sf;
1082 	struct zone_path	zpath;
1083 
1084 	zpath.count = 0;
1085 	zpath.path = NULL;
1086 	setdmapent();
1087 	if ((dm = getdmapnam(da->da_devname)) == NULL) {
1088 		enddmapent();
1089 		dprintf("Unable to find %s in device map database\n",
1090 		    da->da_devname);
1091 		return (NODMAPERR);
1092 	}
1093 	enddmapent();
1094 	if (system_labeled) {
1095 		if (_dev_file_name(&sf, dm) != 0) {
1096 			freedmapent(dm);
1097 			dprintf("Unable to find %s device files\n",
1098 			    da->da_devname);
1099 			error = NODMAPERR;
1100 			goto out;
1101 		}
1102 		fname = sf.sf_path;
1103 	} else {
1104 		bytes = snprintf(file_name,  MAXPATHLEN, "%s/%s", DAC_DIR,
1105 		    da->da_devname);
1106 		if (bytes <= 0) {
1107 			error = DEVNAMEERR;
1108 			goto out;
1109 		} else if (bytes >= MAXPATHLEN) {
1110 			dprintf("device name %s is too long.\n",
1111 			    da->da_devname);
1112 			error = DEVLONGERR;
1113 			goto out;
1114 		}
1115 		fname = file_name;
1116 	}
1117 
1118 	(void) audit_allocate_device(fname);
1119 
1120 	if (stat(fname, &stat_buf) != 0) {
1121 		dprintf("Unable to stat %s\n", fname);
1122 		dperror("Error:");
1123 		error = DACACCERR;
1124 		goto out;
1125 	}
1126 	if (DEV_ERRORED(stat_buf)) {
1127 		error = DEVSTATEERR;
1128 		goto out;
1129 	}
1130 	is_authorized = _is_dev_authorized(da, uid);
1131 	if (is_authorized == ALLOC_BY_NONE) {
1132 		dprintf("Device %s is not allocatable\n", da->da_devname);
1133 		error = UAUTHERR;
1134 		goto out;
1135 	} else if (!is_authorized && !(optflag & USERNAME)) {
1136 		dprintf("User %d is unauthorized to allocate\n", (int)uid);
1137 		error = UAUTHERR;
1138 		goto out;
1139 	}
1140 	if (system_labeled) {
1141 		/*
1142 		 * check if label of the zone to which the device is being
1143 		 * allocated is within the device label range.
1144 		 */
1145 		if (_check_label(da, zonename, uid, CHECK_DRANGE) != 0) {
1146 			error = LABELRNGERR;
1147 			goto out;
1148 		}
1149 	}
1150 	if (check_devs(dm) == -1) {
1151 		error = DSPMISSERR;
1152 		goto out;
1153 	}
1154 	if (DEV_ALLOCATED(stat_buf)) {
1155 		if (optflag & FORCE) {
1156 			if (optflag & SILENT)
1157 				dealloc_optflag = FORCE|SILENT;
1158 			else
1159 				dealloc_optflag = FORCE;
1160 			if (_deallocate_dev(dealloc_optflag, da, dm, uid,
1161 			    zonename)) {
1162 				dprintf("Couldn't force deallocate device %s\n",
1163 				    da->da_devname);
1164 				error = CNTFRCERR;
1165 				goto out;
1166 			}
1167 		} else if (stat_buf.st_uid == uid) {
1168 			error = PREALLOCERR;
1169 			goto out;
1170 		} else {
1171 			error = ALLOCUERR;
1172 			goto out;
1173 		}
1174 	}
1175 	/* All checks passed, time to lock and allocate */
1176 	if ((error = lock_dev(fname)) != 0)
1177 		goto out;
1178 	if (system_labeled) {
1179 		/*
1180 		 * Run the cleaning program; it also mounts allocated
1181 		 * device if required.
1182 		 */
1183 		error = exec_clean(optflag, da->da_devname, da->da_devexec, uid,
1184 		    zonename, ALLOC_CLEAN);
1185 		if ((error != 0) && (error != CLEAN_MOUNT)) {
1186 			error = CLEANERR;
1187 			(void) mk_error(dm);
1188 			goto out;
1189 		}
1190 		/*
1191 		 * If not mounted, create zonelinks, if this is not the
1192 		 * global zone.
1193 		 */
1194 		if ((strcmp(zonename, GLOBAL_ZONENAME) != 0) &&
1195 		    (error != CLEAN_MOUNT)) {
1196 			if (create_znode(zonename, &zpath, dm) != 0) {
1197 				error = ZONEERR;
1198 				goto out;
1199 			}
1200 		}
1201 	}
1202 
1203 	(void) audit_allocate_list(dm->dmap_devlist);
1204 
1205 	if ((error = mk_alloc(dm, uid, &zpath)) != 0) {
1206 		(void) mk_unalloc(optflag, dm);
1207 		goto out;
1208 	}
1209 
1210 	if (system_labeled == 0) {
1211 		if ((error = _newdac(file_name, uid, getgid(),
1212 		    ALLOC_MODE)) != 0) {
1213 			(void) _newdac(file_name, ALLOC_UID, ALLOC_GID,
1214 			    ALLOC_ERR_MODE);
1215 			goto out;
1216 		}
1217 	}
1218 	error = 0;
1219 out:
1220 	if (zpath.count) {
1221 		for (i = 0; i < zpath.count; i++)
1222 			free(zpath.path[i]);
1223 		free(zpath.path);
1224 	}
1225 	freedmapent(dm);
1226 	return (error);
1227 }
1228 
1229 void
1230 _store_devnames(int *count, struct devnames *dnms, char *zonename,
1231     devalloc_t *da, int flag)
1232 {
1233 	int i;
1234 
1235 	dnms->dnames = (char **)realloc(dnms->dnames,
1236 	    (*count + 1) * sizeof (char *));
1237 	if (da) {
1238 		dnms->dnames[*count] = strdup(da->da_devname);
1239 		(*count)++;
1240 	} else {
1241 		dnms->dnames[*count] = NULL;
1242 		if (flag == DA_ADD_ZONE)
1243 			(void) update_device(dnms->dnames, zonename,
1244 			    DA_ADD_ZONE);
1245 		else if (flag == DA_REMOVE_ZONE)
1246 			(void) update_device(dnms->dnames, NULL,
1247 			    DA_REMOVE_ZONE);
1248 		for (i = 0; i < *count; i++)
1249 			free(dnms->dnames[i]);
1250 		free(dnms->dnames);
1251 	}
1252 }
1253 
1254 int
1255 allocate(int optflag, uid_t uid, char *device, char *zonename)
1256 {
1257 	int		count = 0;
1258 	int		error = 0;
1259 	devalloc_t	*da;
1260 	struct devnames	dnms;
1261 
1262 	if (optflag & (FORCE | USERID | USERNAME)) {
1263 		if (!_is_authorized(DEVICE_REVOKE_AUTH, getuid()))
1264 			return (UAUTHERR);
1265 	}
1266 	dnms.dnames = NULL;
1267 	setdaent();
1268 	if (optflag & TYPE) {
1269 		/*
1270 		 * allocate devices of this type
1271 		 */
1272 		while ((da = getdatype(device)) != NULL) {
1273 			if (system_labeled &&
1274 			    da_check_logindevperm(da->da_devname)) {
1275 				freedaent(da);
1276 				continue;
1277 			}
1278 			dprintf("trying to allocate %s\n", da->da_devname);
1279 			error = _allocate_dev(optflag, uid, da, zonename);
1280 			if (system_labeled && (error == 0)) {
1281 				/*
1282 				 * we need to record in device_allocate the
1283 				 * label (zone name) at which this device is
1284 				 * being allocated. store this device entry.
1285 				 */
1286 				_store_devnames(&count, &dnms, zonename, da, 0);
1287 			}
1288 			freedaent(da);
1289 			error = 0;
1290 		}
1291 	} else {
1292 		/*
1293 		 * allocate this device
1294 		 */
1295 		if ((da = getdanam(device)) == NULL) {
1296 			enddaent();
1297 			return (NODAERR);
1298 		}
1299 		if (system_labeled && da_check_logindevperm(device)) {
1300 			freedaent(da);
1301 			return (LOGINDEVPERMERR);
1302 		}
1303 		dprintf("trying to allocate %s\n", da->da_devname);
1304 		error = _allocate_dev(optflag, uid, da, zonename);
1305 		/*
1306 		 * we need to record in device_allocate the label (zone name)
1307 		 * at which this device is being allocated. store this device
1308 		 * entry.
1309 		 */
1310 		if (system_labeled && (error == 0))
1311 			_store_devnames(&count, &dnms, zonename, da, 0);
1312 		freedaent(da);
1313 	}
1314 	enddaent();
1315 	/*
1316 	 * add to device_allocate labels (zone names) for the devices we
1317 	 * allocated.
1318 	 */
1319 	if (dnms.dnames)
1320 		_store_devnames(&count, &dnms, zonename, NULL, DA_ADD_ZONE);
1321 
1322 	return (error);
1323 }
1324 
1325 /* ARGSUSED */
1326 int
1327 deallocate(int optflag, uid_t uid, char *device, char *zonename)
1328 {
1329 	int		count = 0;
1330 	int		error = 0;
1331 	devalloc_t	*da;
1332 	struct devnames dnms;
1333 
1334 	if (optflag & (FORCE | FORCE_ALL)) {
1335 		if (!_is_authorized(DEVICE_REVOKE_AUTH, getuid()))
1336 		return (UAUTHERR);
1337 	}
1338 	if (optflag & FORCE_ALL)
1339 		optflag |= FORCE;
1340 	dnms.dnames = NULL;
1341 	setdaent();
1342 	if (optflag & FORCE_ALL) {
1343 		/*
1344 		 * deallocate all devices
1345 		 */
1346 		while ((da = getdaent()) != NULL) {
1347 			if (system_labeled &&
1348 			    da_check_logindevperm(da->da_devname)) {
1349 				freedaent(da);
1350 				continue;
1351 			}
1352 			dprintf("trying to deallocate %s\n", da->da_devname);
1353 			error = _deallocate_dev(optflag, da, NULL, uid,
1354 			    zonename);
1355 			if (system_labeled && (error == 0)) {
1356 				/*
1357 				 * we need to remove this device's allocation
1358 				 * label (zone name) from device_allocate.
1359 				 * store this device name.
1360 				 */
1361 				_store_devnames(&count, &dnms, zonename, da, 0);
1362 			}
1363 			freedaent(da);
1364 			error = 0;
1365 		}
1366 	} else if (system_labeled && optflag & TYPE) {
1367 		/*
1368 		 * deallocate all devices of this type
1369 		 */
1370 		while ((da = getdatype(device)) != NULL) {
1371 			if (da_check_logindevperm(da->da_devname)) {
1372 				freedaent(da);
1373 				continue;
1374 			}
1375 			dprintf("trying to deallocate %s\n", da->da_devname);
1376 			error = _deallocate_dev(optflag, da, NULL, uid,
1377 			    zonename);
1378 			if (error == 0) {
1379 				/*
1380 				 * we need to remove this device's allocation
1381 				 * label (zone name) from device_allocate.
1382 				 * store this device name.
1383 				 */
1384 				_store_devnames(&count, &dnms, zonename, da, 0);
1385 			}
1386 			freedaent(da);
1387 			error = 0;
1388 		}
1389 	} else if (!(optflag & TYPE)) {
1390 		/*
1391 		 * deallocate this device
1392 		 */
1393 		if ((da = getdanam(device)) == NULL) {
1394 			enddaent();
1395 			return (NODAERR);
1396 		}
1397 		if (system_labeled && da_check_logindevperm(da->da_devname)) {
1398 			freedaent(da);
1399 			return (LOGINDEVPERMERR);
1400 		}
1401 		dprintf("trying to deallocate %s\n", da->da_devname);
1402 		error = _deallocate_dev(optflag, da, NULL, uid, zonename);
1403 		if (system_labeled && (error == 0)) {
1404 			/*
1405 			 * we need to remove this device's allocation label
1406 			 * (zone name) from device_allocate. store this
1407 			 * device name.
1408 			 */
1409 			_store_devnames(&count, &dnms, zonename, da, 0);
1410 		}
1411 		freedaent(da);
1412 	}
1413 	enddaent();
1414 	/*
1415 	 * remove from device_allocate labels (zone names) for the devices we
1416 	 * deallocated.
1417 	 */
1418 	if (dnms.dnames)
1419 		_store_devnames(&count, &dnms, zonename, NULL, DA_REMOVE_ZONE);
1420 
1421 	return (error);
1422 }
1423 
1424 static int
1425 _dev_file_name(struct state_file *sfp, devmap_t *dm)
1426 {
1427 	sfp->sf_flags = 0;
1428 	/* if devlist is generated, never leave device in error state */
1429 	if (dm->dmap_devlist[0] == '`')
1430 		sfp->sf_flags |= SFF_NO_ERROR;
1431 	if (dm->dmap_devarray == NULL ||
1432 	    dm->dmap_devarray[0] == NULL)
1433 		return (NODMAPERR);
1434 	(void) strncpy(sfp->sf_path, dm->dmap_devarray[0],
1435 	    sizeof (sfp->sf_path));
1436 	sfp->sf_path[sizeof (sfp->sf_path) - 1] = '\0';
1437 	if (sfp->sf_path[0] == '\0') {
1438 		dprintf("dev_file_name: no device list for %s\n",
1439 		    dm->dmap_devname);
1440 		return (NODMAPERR);
1441 	}
1442 
1443 	return (0);
1444 }
1445 
1446 /*
1447  * _check_label -
1448  *	checks the device label range against zone label, which is also
1449  *	user's current label.
1450  *	returns 0 if in range, -1 for all other conditions.
1451  *
1452  */
1453 
1454 static int
1455 _check_label(devalloc_t *da, char *zonename, uid_t uid, int flag)
1456 {
1457 	int		err;
1458 	int		in_range = 0;
1459 	char		*alloczone, *lstr;
1460 	char		pw_buf[NSS_BUFLEN_PASSWD];
1461 	blrange_t	*range;
1462 	m_label_t	*zlabel;
1463 	struct passwd	pw_ent;
1464 
1465 	if ((da == NULL) || (zonename == NULL))
1466 		return (-1);
1467 
1468 	if ((zlabel = getzonelabelbyname(zonename)) == NULL) {
1469 		dprintf("unable to get label for %s zone\n", zonename);
1470 		return (-1);
1471 	}
1472 	if (flag == CHECK_DRANGE) {
1473 		blrange_t	drange;
1474 
1475 		drange.lower_bound = blabel_alloc();
1476 		lstr = kva_match(da->da_devopts, DAOPT_MINLABEL);
1477 		if (lstr == NULL) {
1478 			bsllow(drange.lower_bound);
1479 		} else if (stobsl(lstr, drange.lower_bound, NO_CORRECTION,
1480 		    &err) == 0) {
1481 			dprintf("bad min_label for device %s\n",
1482 			    da->da_devname);
1483 			free(zlabel);
1484 			blabel_free(drange.lower_bound);
1485 			return (-1);
1486 		}
1487 		drange.upper_bound = blabel_alloc();
1488 		lstr = kva_match(da->da_devopts, DAOPT_MAXLABEL);
1489 		if (lstr == NULL) {
1490 			bslhigh(drange.upper_bound);
1491 		} else if (stobsl(lstr, drange.upper_bound, NO_CORRECTION,
1492 		    &err) == 0) {
1493 			dprintf("bad max_label for device %s\n",
1494 			    da->da_devname);
1495 			free(zlabel);
1496 			blabel_free(drange.lower_bound);
1497 			blabel_free(drange.upper_bound);
1498 			return (-1);
1499 		}
1500 		if (blinrange(zlabel, &drange) == 0) {
1501 			char	*zlbl = NULL, *min = NULL, *max = NULL;
1502 
1503 			(void) bsltos(zlabel, &zlbl, 0, 0);
1504 			(void) bsltos(drange.lower_bound, &min, 0, 0);
1505 			(void) bsltos(drange.upper_bound, &max, 0, 0);
1506 			dprintf("%s zone label ", zonename);
1507 			dprintf("%s outside device label range: ", zlbl);
1508 			dprintf("min - %s, ", min);
1509 			dprintf("max - %s\n", max);
1510 			free(zlabel);
1511 			blabel_free(drange.lower_bound);
1512 			blabel_free(drange.upper_bound);
1513 			return (-1);
1514 		}
1515 	} else if (flag == CHECK_URANGE) {
1516 		if (getpwuid_r(uid, &pw_ent, pw_buf, sizeof (pw_buf)) == NULL) {
1517 			dprintf("Unable to get passwd entry for userid %d\n",
1518 			    (int)uid);
1519 			free(zlabel);
1520 			return (-1);
1521 		}
1522 		if ((range = getuserrange(pw_ent.pw_name)) == NULL) {
1523 			dprintf("Unable to get label range for userid %d\n",
1524 			    (int)uid);
1525 			free(zlabel);
1526 			return (-1);
1527 		}
1528 		in_range = blinrange(zlabel, range);
1529 		free(zlabel);
1530 		blabel_free(range->lower_bound);
1531 		blabel_free(range->upper_bound);
1532 		free(range);
1533 		if (in_range == 0) {
1534 			dprintf("%s device label ", da->da_devname);
1535 			dprintf("out of user %d label range\n", (int)uid);
1536 			return (-1);
1537 		}
1538 	} else if (flag == CHECK_ZLABEL) {
1539 		alloczone = kva_match(da->da_devopts, DAOPT_ZONE);
1540 		if (alloczone == NULL) {
1541 			free(zlabel);
1542 			return (-1);
1543 		}
1544 		if (strcmp(zonename, alloczone) != 0) {
1545 			dprintf("%s zone is different than ", zonename);
1546 			dprintf("%s zone to which the device ", alloczone);
1547 			dprintf("%s is allocated\n", da->da_devname);
1548 			free(zlabel);
1549 			return (-1);
1550 		}
1551 	}
1552 	free(zlabel);
1553 
1554 	return (0);
1555 }
1556 
1557 int
1558 create_znode(char *zonename, struct zone_path *zpath, devmap_t *list)
1559 {
1560 	int		i;
1561 	int		size;
1562 	int		len = 0;
1563 	int		fcount = 0;
1564 	char		*p, *tmpfile, *zoneroot;
1565 	char		**file;
1566 	char		zonepath[MAXPATHLEN];
1567 	struct stat	statb;
1568 
1569 	file = list->dmap_devarray;
1570 	if (file == NULL)
1571 		return (NODMAPERR);
1572 	if ((zoneroot = getzonerootbyname(zonename)) == NULL) {
1573 		dprintf("unable to get label for %s zone\n", zonename);
1574 		return (1);
1575 	}
1576 	(void) strcpy(zonepath, zoneroot);
1577 	free(zoneroot);
1578 	if ((p = strstr(zonepath, "/root")) == NULL)
1579 		return (1);
1580 	*p = '\0';
1581 	len = strlen(zonepath);
1582 	size = sizeof (zonepath);
1583 	for (; *file != NULL; file++) {
1584 		if (stat(*file, &statb) == -1) {
1585 			dprintf("Couldn't stat the file %s\n", *file);
1586 			return (1);
1587 		}
1588 		/*
1589 		 * First time initialization
1590 		 */
1591 		tmpfile = strdup(*file);
1592 
1593 		/*
1594 		 * Most devices have pathnames starting in /dev
1595 		 * but SunRay devices do not. In SRRS 3.1 they use /tmp.
1596 		 *
1597 		 * If the device pathname is not in /dev then create
1598 		 * a symbolic link to it and put the device in /dev
1599 		 */
1600 		if (strncmp(tmpfile, "/dev/", strlen("/dev/")) != 0) {
1601 			char	*linkdir;
1602 			char	srclinkdir[MAXPATHLEN];
1603 			char	dstlinkdir[MAXPATHLEN];
1604 
1605 			linkdir = strchr(tmpfile + 1, '/');
1606 			p = strchr(linkdir + 1, '/');
1607 			*p = '\0';
1608 			(void) strcpy(dstlinkdir, "/dev");
1609 			(void) strncat(dstlinkdir, linkdir, MAXPATHLEN);
1610 			(void) snprintf(srclinkdir, MAXPATHLEN, "%s/root%s",
1611 				zonepath, tmpfile);
1612 			(void) symlink(dstlinkdir, srclinkdir);
1613 			*p = '/';
1614 			(void) strncat(dstlinkdir, p, MAXPATHLEN);
1615 			free(tmpfile);
1616 			tmpfile = strdup(dstlinkdir);
1617 		}
1618 		if ((p = rindex(tmpfile, '/')) == NULL) {
1619 			dprintf("bad path in create_znode for %s\n",
1620 			    tmpfile);
1621 			return (1);
1622 		}
1623 		*p = '\0';
1624 		(void) strcat(zonepath, tmpfile);
1625 		*p = '/';
1626 		if ((mkdirp(zonepath, 0755) != 0) && (errno != EEXIST)) {
1627 			dprintf("Unable to create directory %s\n", zonepath);
1628 			return (1);
1629 		}
1630 		zonepath[len] = '\0';
1631 		if (strlcat(zonepath, tmpfile, size) >= size) {
1632 			dprintf("Buffer overflow in create_znode for %s\n",
1633 			    *file);
1634 			free(tmpfile);
1635 			return (1);
1636 		}
1637 		free(tmpfile);
1638 		fcount++;
1639 		if ((zpath->path = (char **)realloc(zpath->path,
1640 		    (fcount * sizeof (char *)))) == NULL)
1641 			return (1);
1642 		zpath->path[zpath->count] = strdup(zonepath);
1643 		zpath->count = fcount;
1644 		if (mknod(zonepath, statb.st_mode, statb.st_rdev) == -1) {
1645 			switch (errno) {
1646 			case EEXIST:
1647 				break;
1648 			default:
1649 				dprintf("mknod error: %s\n",
1650 				    strerror(errno));
1651 				for (i = 0; i <= fcount; i++)
1652 					free(zpath->path[i]);
1653 				free(zpath->path);
1654 				return (1);
1655 			}
1656 		}
1657 		zonepath[len] = '\0';
1658 	}
1659 
1660 	return (0);
1661 }
1662 
1663 int
1664 remove_znode(char *zonename, devmap_t *dm)
1665 {
1666 	int		len = 0;
1667 	char		*zoneroot;
1668 	char		**file;
1669 	char		zonepath[MAXPATHLEN];
1670 
1671 	file = dm->dmap_devarray;
1672 	if (file == NULL)
1673 		return (NODMAPERR);
1674 	if ((zoneroot = getzonerootbyname(zonename)) == NULL) {
1675 		(void) snprintf(zonepath, MAXPATHLEN, "/zone/%s", zonename);
1676 	} else {
1677 		char *p;
1678 
1679 		if ((p = strstr(zoneroot, "/root")) == NULL)
1680 			return (1);
1681 		*p = '\0';
1682 		(void)  strcpy(zonepath, zoneroot);
1683 		free(zoneroot);
1684 	}
1685 	/*
1686 	 * To support SunRay we will just deal with the
1687 	 * file in /dev, not the symlinks.
1688 	 */
1689 	(void) strncat(zonepath, "/dev", MAXPATHLEN);
1690 	len = strlen(zonepath);
1691 	for (; *file != NULL; file++) {
1692 		char *devrelpath;
1693 
1694 		/*
1695 		 * remove device node from zone.
1696 		 *
1697 		 * SunRay devices don't start with /dev
1698 		 * so skip over first directory to make
1699 		 * sure it is /dev. SunRay devices in zones
1700 		 * will have a symlink into /dev but
1701 		 * we don't ever delete it.
1702 		 */
1703 		devrelpath = strchr(*file + 1, '/');
1704 
1705 		if (strlcat(zonepath, devrelpath, MAXPATHLEN) >= MAXPATHLEN) {
1706 			dprintf("Buffer overflow in remove_znode for %s\n",
1707 			    *file);
1708 			return (1);
1709 		}
1710 		errno = 0;
1711 		if ((unlink(zonepath) == -1) && (errno != ENOENT)) {
1712 			perror(zonepath);
1713 			return (1);
1714 		}
1715 		zonepath[len] = '\0';
1716 	}
1717 
1718 	return (0);
1719 }
1720 
1721 int
1722 update_device(char **devnames, char *zonename, int flag)
1723 {
1724 	int		len, rc;
1725 	char		*optstr = NULL;
1726 	da_args		dargs;
1727 	devinfo_t	devinfo;
1728 
1729 	dargs.optflag = flag;
1730 	dargs.optflag |= DA_UPDATE|DA_ALLOC_ONLY;
1731 	dargs.rootdir = NULL;
1732 	dargs.devnames = devnames;
1733 	devinfo.devname = devinfo.devtype = devinfo.devauths = devinfo.devexec =
1734 	    devinfo.devlist = NULL;
1735 	if (dargs.optflag & DA_ADD_ZONE) {
1736 		len = strlen(DAOPT_ZONE) + strlen(zonename) + 3;
1737 		if ((optstr = (char *)malloc(len)) == NULL)
1738 			return (-1);
1739 		(void) snprintf(optstr, len, "%s%s%s", DAOPT_ZONE, KV_ASSIGN,
1740 		    zonename);
1741 		devinfo.devopts = optstr;
1742 	}
1743 	dargs.devinfo = &devinfo;
1744 
1745 	rc = da_update_device(&dargs);
1746 
1747 	if (optstr)
1748 		free(optstr);
1749 
1750 	return (rc);
1751 }
1752