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