xref: /illumos-gate/usr/src/cmd/allocate/allocate3.c (revision 7c478bd9)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 1999-2003 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 <unistd.h>
42 
43 #include <bsm/devices.h>
44 #include <bsm/audit_uevents.h>
45 
46 #include <sys/acl.h>
47 #include <sys/file.h>
48 #include <sys/procfs.h>
49 #include <sys/param.h>
50 #include <sys/resource.h>
51 #include <sys/stat.h>
52 #include <sys/time.h>
53 #include <sys/types.h>
54 #include <sys/wait.h>
55 
56 #include "allocate.h"
57 
58 #ifdef	DEBUG
59 #define	dprintf(s, a) (void) fprintf(stderr, s, a)
60 #define	dperror(s) perror(s)
61 #else	/* !DEBUG */
62 #define	dprintf(s, a)
63 #define	dperror(s)
64 #endif	/* DEBUG */
65 
66 #define	EXIT(number) { \
67 	if (optflg & FORCE) \
68 		error = number; \
69 	else \
70 		return (number); \
71 }
72 
73 #define	DEV_ALLOCATED(sbuf)	((sbuf).st_uid != ALLOC_UID || \
74 				((sbuf).st_mode & ~S_IFMT) == ALLOC_MODE)
75 
76 #define	DEVICE_AUTH_SEPARATOR	","
77 #define	PROCFS	"/proc/"
78 
79 extern void audit_allocate_list(char *);
80 extern void audit_allocate_device(char *);
81 
82 extern char	*newenv[];
83 
84 /*
85  * Checks if the specified user has any of the authorizations in the
86  * list of authorizations
87  */
88 
89 static int
90 is_authorized(char *auth_list, uid_t uid)
91 {
92 	char	*auth;
93 	struct passwd *pw;
94 
95 	pw = getpwuid(uid);
96 	if (pw == NULL) {
97 		dprintf("Can't get user info for uid=%d\n", (int)uid);
98 		return (0);
99 	}
100 
101 	auth = strtok(auth_list, DEVICE_AUTH_SEPARATOR);
102 	while (auth != NULL) {
103 		if (chkauthattr(auth, pw->pw_name))
104 			return (1);
105 		auth = strtok(NULL, DEVICE_AUTH_SEPARATOR);
106 	}
107 	return (0);
108 }
109 
110 static int
111 check_devs(char *list)
112 {
113 	char	*file;
114 
115 	file = strtok(list, " ");
116 	while (file != NULL) {
117 
118 		if (access(file, F_OK) == -1) {
119 			dprintf("Unable to access file %s\n", file);
120 			return (-1);
121 		}
122 		file = strtok(NULL, " ");
123 	}
124 	return (0);
125 }
126 
127 static void
128 print_dev(devmap_t *dev_list)
129 {
130 	char	*file;
131 
132 	(void) printf(gettext("device: %s "), dev_list->dmap_devname);
133 	(void) printf(gettext("type: %s "), dev_list->dmap_devtype);
134 	(void) printf(gettext("files: "));
135 
136 	file = strtok(dev_list->dmap_devlist, " ");
137 	while (file != NULL) {
138 		(void) printf("%s ", file);
139 		file = strtok(NULL, " ");
140 	}
141 	(void) printf("\n");
142 }
143 
144 static int
145 list_device(int optflg, uid_t uid, char *device)
146 {
147 	devalloc_t *dev_ent;
148 	devmap_t *dev_list;
149 	char	file_name[MAXPATHLEN];
150 	struct	stat stat_buf;
151 	char	*list;
152 	int	bytes_formated;
153 
154 	if ((dev_ent = getdanam(device)) == NULL) {
155 		if ((dev_list = getdmapdev(device)) == NULL) {
156 			dprintf("Unable to find %s in the allocate database\n",
157 			    device);
158 			return (NODMAPENT);
159 		} else if ((dev_ent = getdanam(dev_list->dmap_devname)) ==
160 		    NULL) {
161 			dprintf("Unable to find %s in the allocate database\n",
162 			    device);
163 			return (NODAENT);
164 		}
165 	} else if ((dev_list = getdmapnam(device)) == NULL) {
166 		dprintf("Unable to find %s in the allocate database\n", device);
167 		return (NODMAPENT);
168 	}
169 
170 	bytes_formated = snprintf(file_name, MAXPATHLEN, "%s/%s", DAC_DIR,
171 	    dev_ent->da_devname);
172 	if (bytes_formated <= 0) {
173 		return (DEVNAME_ERR);
174 	} else if (bytes_formated >= MAXPATHLEN) {
175 		dprintf("device name %s is too long.\n", dev_ent->da_devname);
176 		return (DEVNAME_TOOLONG);
177 	}
178 
179 	if (stat(file_name, &stat_buf)) {
180 		dprintf("Unable to stat %s\n", file_name);
181 		dperror("Error:");
182 		return (DACACC);
183 	}
184 
185 	if ((optflg & FREE) && DEV_ALLOCATED(stat_buf))
186 		return (ALLOC);
187 
188 	if ((optflg & LIST) && DEV_ALLOCATED(stat_buf) &&
189 	    (stat_buf.st_uid != uid))
190 		return (ALLOC_OTHER);
191 
192 	if ((optflg & CURRENT) && (stat_buf.st_uid != uid))
193 		return (NALLOC);
194 
195 	if ((stat_buf.st_mode & ~S_IFMT) == ALLOC_ERR_MODE)
196 		return (ALLOCERR);
197 
198 	if ((list = strdup(dev_list->dmap_devlist)) == NULL)
199 		return (SYSERROR);
200 
201 	if (check_devs(list) == -1) {
202 		free(list);
203 		return (DSPMISS);
204 	}
205 
206 	print_dev(dev_list);
207 
208 	free(list);
209 	return (0);
210 }
211 
212 int
213 list_devices(int optflg, uid_t uid, char *device)
214 {
215 	DIR   * dev_dir;
216 	struct dirent *dac_file;
217 	int	error = 0, ret_code = 1;
218 
219 	if (optflg & USERID) {
220 		if (!is_authorized(DEVICE_REVOKE_AUTH, getuid()))
221 			return (NOTAUTH);
222 	}
223 	setdaent();
224 
225 	if (device) {
226 		return (list_device(optflg, uid, device));
227 	}
228 
229 	if ((dev_dir = opendir(DAC_DIR)) == NULL) {
230 
231 		dperror("Can't open DAC_DIR");
232 		return (DACACC);
233 	}
234 
235 	while ((dac_file = readdir(dev_dir)) != NULL) {
236 		if ((strcmp(dac_file->d_name, ".") == 0) ||
237 		    (strcmp(dac_file->d_name, "..") == 0)) {
238 			continue;
239 		} else {
240 			error = list_device(optflg, uid, dac_file->d_name);
241 			ret_code = ret_code ? error : ret_code;
242 		}
243 	}
244 	(void) closedir(dev_dir);
245 	enddaent();
246 	return (ret_code);
247 }
248 
249 /*
250  * Set the DAC characteristics of the file.
251  * This uses a fancy chmod() by setting a minimal ACL which sets the mode
252  * and discards any existing ACL.
253  */
254 
255 static int
256 newdac(char *file, uid_t owner, gid_t group, o_mode_t mode)
257 {
258 	int	err = 0;
259 	aclent_t	min_acl[MIN_ACL_ENTRIES];
260 
261 	min_acl[0].a_type = USER_OBJ;
262 	min_acl[0].a_id   = owner;
263 	min_acl[0].a_perm = ((mode & 0700) >> 6);
264 
265 	min_acl[1].a_type = GROUP_OBJ;
266 	min_acl[1].a_id   = group;
267 	min_acl[1].a_perm = ((mode & 0070) >> 3);
268 
269 	min_acl[2].a_type = CLASS_OBJ;
270 	min_acl[2].a_id   = (uid_t)-1;
271 	min_acl[2].a_perm = ((mode & 0070) >> 3);
272 
273 	min_acl[3].a_type = OTHER_OBJ;
274 	min_acl[3].a_id   = (uid_t)-1;
275 	min_acl[3].a_perm = (mode & 0007);
276 
277 	do {
278 		if (chown(file, owner, group) == -1) {
279 			dperror("newdac, unable to chown");
280 			err = CHOWN_PERR;
281 		}
282 	} while (fdetach(file) == 0);
283 
284 	if (acl(file, SETACL, MIN_ACL_ENTRIES, min_acl) < 0) {
285 		dperror("newdac, unable to setacl");
286 		err = SETACL_PERR;
287 	}
288 
289 	return (err);
290 }
291 
292 static int
293 lock_dev(char *file)
294 {
295 	int	fd;
296 
297 	dprintf("locking %s\n", file);
298 	if ((fd = open(file, O_RDWR)) == -1) {
299 		dperror("lock_dev, cannot open DAC file");
300 		return (DACACC);
301 	}
302 
303 	if (lockf(fd, F_TLOCK, 0) == -1) {
304 		dperror("lock_dev, cannot set lock");
305 		return (DACLCK);
306 	}
307 
308 	return (0);
309 }
310 
311 static int
312 mk_alloc(char *list, uid_t uid)
313 {
314 	char	*file;
315 	int	err;
316 
317 	file = strtok(list, " ");
318 	while (file != NULL) {
319 
320 		dprintf("Allocating %s\n", file);
321 		if ((err = newdac(file, uid, getgid(), ALLOC_MODE)) != 0) {
322 			(void) newdac(file, ALLOC_UID, ALLOC_GID,
323 			    ALLOC_ERR_MODE);
324 			return (err);
325 		}
326 
327 		file = strtok(NULL, " ");
328 	}
329 	return (0);
330 }
331 
332 /*
333  * mk_revoke() is used instead of system("/usr/sbin/fuser -k file")
334  * because "/usr/sbin/fuser -k file" kills all processes
335  * working with the file, even "vold" (bug #4095152).
336  */
337 static int
338 mk_revoke(int optflg, char *file)
339 {
340 	char buf[MAXPATHLEN];
341 	int r = 0, p[2], fp, lock;
342 	FILE *ptr;
343 	prpsinfo_t info;
344 	pid_t pid, c_pid;
345 
346 	(void) strcpy(buf, PROCFS);
347 
348 	/*
349 	 * vfork() and execle() just to make the same output
350 	 * as before fixing of bug #4095152.
351 	 * The problem is that the "fuser" command prints
352 	 * one part of output into stderr and another into stdout,
353 	 * but user sees them mixed. Of course, better to change "fuser"
354 	 * or to intercept and not to print its output.
355 	 */
356 	if (!(optflg & SILENT)) {
357 		c_pid = vfork();
358 		if (c_pid == -1)
359 			return (-1);
360 		if (c_pid == 0) {
361 			dprintf("first exec fuser %s\n", file);
362 			(void) execle("/usr/sbin/fuser", "fuser", file, NULL,
363 			    newenv);
364 			dperror("first exec fuser");
365 			_exit(1);
366 		}
367 
368 		(void) waitpid(c_pid, &lock, 0);
369 		dprintf("exit status %x\n", lock);
370 		if (WEXITSTATUS(lock) != 0)
371 			return (-1);
372 	}
373 	dprintf("first continuing c_pid=%d\n", c_pid);
374 
375 	if (pipe(p)) {
376 		dperror("pipe");
377 		return (-1);
378 	}
379 
380 	/* vfork() and execle() to catch output and to process it */
381 	c_pid = vfork();
382 	if (c_pid == -1) {
383 		dperror("second vfork");
384 		return (-1);
385 	}
386 	dprintf("second continuing c_pid=%d\n", c_pid);
387 
388 	if (c_pid == 0) {
389 		(void) close(p[0]);
390 		(void) close(1);
391 		(void) fcntl(p[1], F_DUPFD, 1);
392 		(void) close(p[1]);
393 		(void) close(2);
394 		dprintf("second exec fuser %s\n", file);
395 		(void) execle("/usr/sbin/fuser", "fuser", file, NULL, newenv);
396 		dperror("second exec fuser");
397 		_exit(1);
398 	}
399 
400 	(void) close(p[1]);
401 	if ((ptr = fdopen(p[0], "r")) != NULL) {
402 		while (!feof(ptr)) {
403 			if (fscanf(ptr, "%d", &pid) > 0) {
404 				(void) sprintf(buf + strlen(PROCFS), "%d", pid);
405 				if ((fp = open(buf, O_RDONLY)) == -1) {
406 					dperror(buf);
407 					continue;
408 				}
409 				if (ioctl(fp, PIOCPSINFO, (char *)&info)
410 				    == -1) {
411 					dprintf("%d psinfo failed", pid);
412 					dperror("");
413 					(void) close(fp);
414 					continue;
415 				}
416 				(void) close(fp);
417 				if (strcmp(info.pr_fname, "vold") == NULL) {
418 					dprintf("%d matched vold name\n", pid);
419 					continue;
420 				}
421 				dprintf("killing %s", info.pr_fname);
422 				dprintf("(%d)\n", pid);
423 				if ((r = kill(pid, SIGKILL)) == -1) {
424 					dprintf("kill %d", pid);
425 					dperror("");
426 					break;
427 				}
428 			}
429 		}
430 		dprintf("eof reached %x\n", ptr);
431 	} else {
432 		dperror("fdopen(p[0])");
433 		r = -1;
434 	}
435 
436 	(void) fclose(ptr);
437 	return (r);
438 }
439 
440 static int
441 mk_unalloc(int optflg, char *list)
442 {
443 	char	*file;
444 	int	error = 0;
445 	int child, status;
446 
447 	audit_allocate_list(list);
448 
449 	child = vfork();
450 	switch (child) {
451 	case -1:
452 		return (-1);
453 	case 0:
454 		(void) setuid(0);
455 		file = strtok(list, " ");
456 		while (file != NULL) {
457 			dprintf("Deallocating %s\n", file);
458 			if (mk_revoke(optflg, file) < 0) {
459 				dprintf("mk_unalloc: unable to revoke %s\n",
460 				    file);
461 				dperror("");
462 				error = CNTFRC;
463 				break;
464 			}
465 			error = newdac(file, ALLOC_UID, ALLOC_GID,
466 			    DEALLOC_MODE);
467 			file = strtok(NULL, " ");
468 		}
469 		exit(error);
470 	default:
471 		while (wait(&status) != child);
472 		if (WIFEXITED(status)) {
473 			return (WEXITSTATUS(status));
474 		}
475 		return (-1);
476 	}
477 }
478 
479 static int
480 exec_clean(int optflg, char *name, char *path)
481 {
482 	char	*mode, *cmd;
483 	int	status;
484 	int	c;
485 
486 	if ((optflg & (FORCE_ALL | SILENT)) == (FORCE_ALL | SILENT))
487 		mode = "-I";
488 	else if (optflg & FORCE_ALL)
489 		mode = "-i";
490 	else if (optflg & FORCE)
491 		mode = "-f";
492 	else
493 		mode = "-s";
494 	if ((cmd = strrchr(path, '/')) == NULL)
495 		cmd = path;
496 	else
497 		cmd++;	/* skip leading '/' */
498 
499 	c = vfork();
500 	switch (c) {
501 	case -1:
502 		return (-1);
503 	case 0:
504 		(void) setuid(0);
505 		dprintf("clean script: %s, ", path);
506 		dprintf("cmd=%s, ", cmd);
507 		dprintf("mode=%s, ", mode);
508 		dprintf("name=%s\n", name);
509 		(void) execle(path, cmd, mode, name, NULL, newenv);
510 		dprintf("Unable to execute clean up script %s\n", path);
511 		dperror("");
512 		exit(CNTDEXEC);
513 	default:
514 		while (wait(&status) != c);
515 		if (WIFEXITED(status))
516 			return (WEXITSTATUS(status));
517 		dprintf("exit status %d\n", status);
518 		return (-1);
519 	}
520 }
521 
522 static int
523 deallocate_dev(int optflg, devalloc_t *dev_ent, uid_t uid)
524 {
525 	devmap_t *dev_list;
526 	char	file_name[MAXPATHLEN];
527 	struct stat stat_buf;
528 	char	*list;
529 	int	error = 0, err;
530 	int	bytes_formated;
531 
532 	bytes_formated = snprintf(file_name, MAXPATHLEN, "%s/%s", DAC_DIR,
533 	    dev_ent->da_devname);
534 	if (bytes_formated <= 0) {
535 		return (DEVNAME_ERR);
536 	} else if (bytes_formated >= MAXPATHLEN) {
537 		dprintf("device name %s is too long.\n", dev_ent->da_devname);
538 		return (DEVNAME_TOOLONG);
539 	}
540 
541 	audit_allocate_device(file_name);
542 
543 	if (stat(file_name, &stat_buf)) {
544 		dprintf("Unable to stat %s\n", file_name);
545 		dperror("Error:");
546 		return (DACACC);
547 	}
548 
549 	if (!(optflg & FORCE) && stat_buf.st_uid != uid &&
550 	    DEV_ALLOCATED(stat_buf)) {
551 		return (NALLOCU);
552 	}
553 
554 	if (!(optflg & FORCE_ALL) && !DEV_ALLOCATED(stat_buf)) {
555 		if ((stat_buf.st_mode & ~S_IFMT) == ALLOC_ERR_MODE) {
556 			if (!(optflg & FORCE))
557 				return (ALLOCERR);
558 		} else
559 			return (NALLOC);
560 	}
561 
562 	/* All checks passed, time to lock and deallocate */
563 	if ((error = lock_dev(file_name)) != 0)
564 		return (error);
565 
566 	if ((err = newdac(file_name, ALLOC_UID, ALLOC_GID, DEALLOC_MODE))
567 	    != 0) {
568 		(void) newdac(file_name, ALLOC_UID, ALLOC_GID, ALLOC_ERR_MODE);
569 		EXIT(err);
570 	}
571 
572 	if ((dev_list = getdmapnam(dev_ent->da_devname)) == NULL) {
573 		dprintf("Unable to find %s in the device map database\n",
574 		    dev_ent->da_devname);
575 		EXIT(NODMAPENT);
576 	} else {
577 		if ((list = strdup(dev_list->dmap_devlist)) == NULL) {
578 			EXIT(SYSERROR)
579 		} else {
580 			if (mk_unalloc(optflg, list) != 0) {
581 				(void) newdac(file_name, ALLOC_UID, ALLOC_GID,
582 				    ALLOC_ERR_MODE);
583 				free(list);
584 				list = NULL;
585 				EXIT(DEVLST);
586 			}
587 		}
588 	}
589 
590 	if (list != NULL)
591 		free(list);
592 	if (exec_clean(optflg, dev_ent->da_devname, dev_ent->da_devexec))
593 		EXIT(CLEAN_ERR);
594 	return (error);
595 }
596 
597 static int
598 allocate_dev(int optflg, uid_t uid, devalloc_t *dev_ent)
599 {
600 	devmap_t *dev_list;
601 	char	file_name[MAXPATHLEN];
602 	struct stat stat_buf;
603 	char	*list;
604 	int	error = 0;
605 	int	bytes_formated;
606 
607 	bytes_formated = snprintf(file_name, MAXPATHLEN, "%s/%s", DAC_DIR,
608 	    dev_ent->da_devname);
609 	if (bytes_formated <= 0) {
610 		return (DEVNAME_ERR);
611 	} else if (bytes_formated >= MAXPATHLEN) {
612 		dprintf("device name %s is too long.\n", dev_ent->da_devname);
613 		return (DEVNAME_TOOLONG);
614 	}
615 
616 	audit_allocate_device(file_name);
617 
618 	if (stat(file_name, &stat_buf)) {
619 		dprintf("Unable to stat %s\n", file_name);
620 		dperror("Error:");
621 		return (DACACC);
622 	}
623 
624 	if (DEV_ALLOCATED(stat_buf)) {
625 		if (optflg & FORCE) {
626 			if (deallocate_dev(FORCE, dev_ent, uid)) {
627 				dprintf("Couldn't force deallocate device %s\n",
628 				    dev_ent->da_devname);
629 				return (CNTFRC);
630 			}
631 		} else if (stat_buf.st_uid == uid) {
632 			return (ALLOC);
633 		} else
634 			return (ALLOC_OTHER);
635 	}
636 	if ((stat_buf.st_mode & ~S_IFMT) == ALLOC_ERR_MODE)
637 		return (ALLOCERR);
638 
639 	if (strcmp(dev_ent->da_devauth, "*") == 0) {
640 		dprintf("Device %s is not allocatable\n", dev_ent->da_devname);
641 		return (AUTHERR);
642 	}
643 
644 	if (strcmp(dev_ent->da_devauth, "@")) {
645 		if (!is_authorized(dev_ent->da_devauth, uid)) {
646 			dprintf("User %d is unauthorized to allocate\n",
647 			    (int)uid);
648 			return (IMPORT_ERR);
649 		}
650 	}
651 
652 	if ((dev_list = getdmapnam(dev_ent->da_devname)) == NULL) {
653 		dprintf("Unable to find %s in device map database\n",
654 		    dev_ent->da_devname);
655 		return (NODMAPENT);
656 	}
657 
658 	if ((list = strdup(dev_list->dmap_devlist)) == NULL)
659 		return (SYSERROR);
660 
661 	if (check_devs(list) == -1) {
662 		free(list);
663 		return (DSPMISS);
664 	}
665 
666 	/* All checks passed, time to lock and allocate */
667 	if ((error = lock_dev(file_name)) != 0) {
668 		free(list);
669 		return (error);
670 	}
671 
672 	if ((error = newdac(file_name, uid, getgid(), ALLOC_MODE)) != 0) {
673 		(void) newdac(file_name, ALLOC_UID, ALLOC_GID, ALLOC_ERR_MODE);
674 		free(list);
675 		return (error);
676 	}
677 
678 	/* refresh list from check_devs overwritting it */
679 	(void) strcpy(list, dev_list->dmap_devlist);
680 	audit_allocate_list(list);
681 
682 	if (mk_alloc(list, uid) != 0) {
683 		/* refresh list from mk_alloc overwritting it */
684 		(void) strcpy(list, dev_list->dmap_devlist);
685 		(void) mk_unalloc(optflg, list);
686 		free(list);
687 		return (DEVLST);
688 	}
689 
690 	free(list);
691 	return (0);
692 }
693 
694 int
695 allocate(int optflg, uid_t uid, char *device)
696 {
697 	devalloc_t	*dev_ent;
698 	devmap_t	*dev_list;
699 
700 	if (((optflg & FORCE) || uid != getuid()) &&
701 	    !is_authorized(DEVICE_REVOKE_AUTH, getuid()))
702 		return (NOTAUTH);
703 
704 	setdaent();
705 	setdmapent();
706 
707 	if (!(optflg & TYPE)) {
708 		if ((dev_ent = getdanam(device)) == NULL) {
709 			if ((dev_list = getdmapdev(device)) == NULL)
710 				return (NODMAPENT);
711 			else if ((dev_ent = getdanam(dev_list->dmap_devname))
712 			    == NULL)
713 				return (NODAENT);
714 		}
715 		return (allocate_dev(optflg, uid, dev_ent));
716 	}
717 
718 	while ((dev_ent = getdatype(device)) != NULL) {
719 		dprintf("trying to allocate %s\n", dev_ent->da_devname);
720 		if (!allocate_dev(optflg, uid, dev_ent)) {
721 			return (0);
722 		}
723 	}
724 	enddaent();
725 	return (NO_DEVICE);
726 }
727 
728 int
729 deallocate(int optflg, uid_t uid, char *device)
730 {
731 	DIR	*dev_dir;
732 	struct dirent	*dac_file;
733 	devalloc_t	*dev_ent;
734 	devmap_t	*dev_list;
735 	int	error = NODAENT;
736 
737 	if (optflg & (FORCE | FORCE_ALL) &&
738 	    !is_authorized(DEVICE_REVOKE_AUTH, getuid()))
739 		return (NOTAUTH);
740 	if (optflg & FORCE_ALL)
741 		optflg |= FORCE;
742 
743 	setdaent();
744 	setdmapent();
745 
746 	if (!(optflg & FORCE_ALL)) {
747 		if ((dev_ent = getdanam(device)) == NULL) {
748 			if ((dev_list = getdmapdev(device)) == NULL)
749 				return (NODMAPENT);
750 			else if ((dev_ent = getdanam(dev_list->dmap_devname))
751 			    == NULL)
752 				return (NODAENT);
753 		}
754 
755 		return (deallocate_dev(optflg, dev_ent, uid));
756 	}
757 
758 	if ((dev_dir = opendir(DAC_DIR)) == NULL) {
759 		dperror("Can't open DAC_DIR");
760 		return (DACACC);
761 	}
762 
763 	while ((dac_file = readdir(dev_dir)) != NULL) {
764 		if ((strcmp(dac_file->d_name, ".") == 0) ||
765 		    (strcmp(dac_file->d_name, "..") == 0)) {
766 			continue;
767 		} else {
768 			if ((dev_ent = getdanam(dac_file->d_name)) == NULL) {
769 				continue;
770 			}
771 			error = deallocate_dev(optflg, dev_ent, uid);
772 		}
773 	}
774 	(void) closedir(dev_dir);
775 	enddaent();
776 	return (error);
777 }
778