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