dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / allocate / allocate3.c
blob7f08a35639f16ed8a5de301f7c80cf74589c2566
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
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 <syslog.h>
43 #include <limits.h>
44 #include <user_attr.h>
45 #include <secdb.h>
46 #include <sys/mkdev.h>
47 #include <sys/acl.h>
48 #include <sys/file.h>
49 #include <sys/procfs.h>
50 #include <sys/param.h>
51 #include <sys/resource.h>
52 #include <sys/stat.h>
53 #include <sys/time.h>
54 #include <sys/types.h>
55 #include <sys/wait.h>
56 #include <utime.h>
57 #include <libgen.h>
58 #include <zone.h>
59 #include <nss_dbdefs.h>
60 #include <bsm/devalloc.h>
61 #include <libdevinfo.h>
62 #include "allocate.h"
64 extern void print_error(int, char *);
66 #if defined(DEBUG) || defined(lint)
67 #define dprintf(s, a) (void) fprintf(stderr, s, a)
68 #define dperror(s) perror(s)
69 #else /* !DEBUG */
70 #define dprintf(s, a) 0
71 #define dperror(s) 0
72 #endif /* DEBUG */
74 #define DEV_ERRORED(sbuf) (((sbuf).st_mode & ~S_IFMT) == ALLOC_ERR_MODE)
75 #define DEV_ALLOCATED(sbuf) ((sbuf).st_uid != DA_UID || \
76 !(((sbuf).st_mode & ~S_IFMT) == DEALLOC_MODE || \
77 DEV_ERRORED(sbuf)))
79 #define ALLOC_CLEAN "-A"
80 #define DEALLOC_CLEAN "-D"
81 #define DAC_DIR "/etc/security/dev"
82 #define DEVICE_AUTH_SEPARATOR ","
83 #define LOCALDEVICE "/dev/console"
84 #define PROCFS "/proc/"
85 #define SFF_NO_ERROR 0x1
87 #define ALLOC_BY_NONE -1
88 #define CHECK_DRANGE 1
89 #define CHECK_URANGE 2
90 #define CHECK_ZLABEL 3
92 extern void audit_allocate_list(char *);
93 extern void audit_allocate_device(char *);
95 extern char *newenv[];
97 struct state_file {
98 int sf_flags;
99 char sf_path[MAXPATHLEN];
102 struct file_info {
103 struct stat fi_stat;
104 char *fi_message;
107 static int lock_dev(char *, struct stat *);
110 * checks if the invoking user is local to the device
112 /*ARGSUSED*/
114 _is_local(uid_t uid)
116 struct stat statbuf;
118 if (stat(LOCALDEVICE, &statbuf) == 0 &&
119 statbuf.st_uid == uid)
120 return (1);
122 return (0);
126 * Checks if the user with the specified uid has the specified authorization
129 _is_authorized(char *auths, uid_t uid)
131 char *dcp, *authlist, *lasts;
132 char pw_buf[NSS_BUFLEN_PASSWD];
133 struct passwd pw_ent;
134 struct passwd *result;
137 * first, the easy cases
139 if (strcmp(auths, "@") == 0)
140 return (1);
141 if (strcmp(auths, "*") == 0)
142 return (ALLOC_BY_NONE);
143 getpwuid_r(uid, &pw_ent, pw_buf, sizeof (pw_buf), &result);
144 if (!result)
145 return (0);
146 if (strpbrk(auths, DEVICE_AUTH_SEPARATOR) == NULL)
147 return (chkauthattr(auths, pw_ent.pw_name));
148 authlist = strdup(auths);
149 if (authlist == NULL)
150 return (0);
151 for (dcp = authlist;
152 (dcp = strtok_r(dcp, DEVICE_AUTH_SEPARATOR, &lasts)) != NULL;
153 dcp = NULL) {
154 if (chkauthattr(dcp, pw_ent.pw_name))
155 break;
157 free(authlist);
159 return (dcp != NULL);
163 * Checks if the specified user has authorization for the device
166 _is_dev_authorized(devalloc_t *da, uid_t uid)
168 int ares;
169 char *auth_list, *dcp, *subauth = NULL;
171 auth_list = da->da_devauth;
172 if (auth_list == NULL)
173 return (0);
174 dcp = strpbrk(auth_list, KV_TOKEN_DELIMIT);
175 if (dcp == NULL)
176 return (_is_authorized(auth_list, uid));
177 if (_is_local(uid)) {
178 /* the local authorization is before the separator */
179 ares = dcp - auth_list;
180 subauth = malloc(ares + 1);
181 if (subauth == NULL)
182 return (0);
183 (void) strlcpy(subauth, auth_list, (ares + 1));
184 auth_list = subauth;
185 } else
186 auth_list = dcp + 1;
187 ares = _is_authorized(auth_list, uid);
188 free(subauth);
190 return (ares);
194 check_devs(devmap_t *dm)
196 int status = 0;
197 char **file;
199 if (dm->dmap_devarray == NULL)
200 return (NODMAPERR);
201 for (file = dm->dmap_devarray; *file != NULL; file++) {
202 if ((status = access(*file, F_OK)) == -1) {
203 dprintf("Unable to access file %s\n", *file);
204 break;
208 return (status);
211 void
212 print_dev_attrs(int optflag, devalloc_t *da, devmap_t *dm,
213 struct file_info *fip)
215 char *p = NULL;
216 char optbuf[BUFSIZ];
218 (void) printf("device=%s%s", dm->dmap_devname, KV_DELIMITER);
219 (void) printf("type=%s%s", dm->dmap_devtype, KV_DELIMITER);
220 (void) printf("auths=%s%s",
221 (da->da_devauth ? da->da_devauth : ""), KV_DELIMITER);
222 (void) printf("clean=%s%s",
223 (da->da_devexec ? da->da_devexec : ""), KV_DELIMITER);
224 if (da->da_devopts != NULL) {
225 if (_kva2str(da->da_devopts, optbuf, sizeof (optbuf),
226 KV_ASSIGN, KV_TOKEN_DELIMIT) == 0) {
227 if (p = rindex(optbuf, ':'))
228 *p = '\0';
229 (void) printf("%s", optbuf);
232 (void) printf("%s", KV_DELIMITER);
233 if (optflag & WINDOWING) {
234 if ((fip->fi_message != NULL) &&
235 (strcmp(fip->fi_message, DAOPT_CLASS) == 0))
236 (void) printf("owner=/FREE%s", KV_DELIMITER);
237 else if (DEV_ERRORED(fip->fi_stat))
238 (void) printf("owner=/ERROR%s", KV_DELIMITER);
239 else if (!DEV_ALLOCATED(fip->fi_stat))
240 (void) printf("owner=/FREE%s", KV_DELIMITER);
241 else
242 (void) printf("owner=%u%s", fip->fi_stat.st_uid,
243 KV_DELIMITER);
245 (void) printf("files=%s", dm->dmap_devlist);
246 (void) printf("\n");
249 void
250 print_dev(devmap_t *dm)
252 char **file;
254 (void) printf(gettext("device: %s "), dm->dmap_devname);
255 (void) printf(gettext("type: %s "), dm->dmap_devtype);
256 (void) printf(gettext("files:"));
257 file = dm->dmap_devarray;
258 if (file != NULL) {
259 for (; *file != NULL; file++)
260 (void) printf(" %s", *file);
262 (void) printf("\n");
265 /* ARGSUSED */
267 _list_device(int optflag, uid_t uid, devalloc_t *da, char *zonename)
269 int bytes = 0;
270 int error = 0;
271 int is_authorized = 0;
272 char *fname = NULL;
273 char file_name[MAXPATHLEN];
274 devmap_t *dm;
275 struct file_info fi;
277 fi.fi_message = NULL;
278 setdmapent();
279 if ((dm = getdmapnam(da->da_devname)) == NULL) {
280 enddmapent();
281 dprintf("Unable to find %s in the maps database\n",
282 da->da_devname);
283 return (NODMAPERR);
285 enddmapent();
287 if ((optflag & CLASS) &&
288 (!(optflag & (LISTALL | LISTFREE | LISTALLOC)))) {
289 fi.fi_message = DAOPT_CLASS;
290 if (optflag & LISTATTRS)
291 print_dev_attrs(optflag, da, dm, &fi);
292 else
293 print_dev(dm);
294 goto out;
297 bytes = snprintf(file_name, MAXPATHLEN, "%s/%s", DAC_DIR,
298 da->da_devname);
299 if (bytes <= 0) {
300 error = DEVNAMEERR;
301 goto out;
302 } else if (bytes >= MAXPATHLEN) {
303 dprintf("device name %s is too long.\n",
304 da->da_devname);
305 error = DEVLONGERR;
306 goto out;
308 fname = file_name;
309 if (stat(fname, &fi.fi_stat) != 0) {
310 dprintf("Unable to stat %s\n", fname);
311 dperror("Error:");
312 error = DACACCERR;
313 goto out;
315 is_authorized = _is_dev_authorized(da, uid);
316 if (optflag & LISTFREE) { /* list_devices -n */
318 * list all free devices
320 if (DEV_ALLOCATED(fi.fi_stat)) {
321 error = PREALLOCERR;
322 goto out;
324 } else if (optflag & LISTALLOC) { /* list_devices -u */
326 * list all allocated devices
328 if (!DEV_ALLOCATED(fi.fi_stat)) {
329 error = DEVNALLOCERR;
330 goto out;
332 if (fi.fi_stat.st_uid != uid) {
333 error = DEVSTATEERR;
334 goto out;
336 } else if (optflag & LISTALL) { /* list_devices -l */
338 * list all devices - free and allocated - available
340 if (DEV_ALLOCATED(fi.fi_stat)) {
341 if (optflag & WINDOWING &&
342 (is_authorized == ALLOC_BY_NONE)) {
344 * don't complain if we're here for the GUI.
346 error = 0;
347 } else if (fi.fi_stat.st_uid != uid) {
348 if (!(optflag & WINDOWING)) {
349 error = ALLOCUERR;
350 goto out;
355 if (check_devs(dm) == -1) {
356 error = DSPMISSERR;
357 goto out;
359 if (optflag & LISTATTRS)
360 print_dev_attrs(optflag, da, dm, &fi);
361 else
362 print_dev(dm);
364 error = 0;
366 out:
367 freedmapent(dm);
368 return (error);
371 /* ARGSUSED */
373 list_devices(int optflag, uid_t uid, char *device, char *zonename)
375 int error = 0;
376 char *class = NULL;
377 devalloc_t *da;
379 if (optflag & USERID) {
381 * we need device.revoke to list someone else's devices
383 if (!_is_authorized(DEVICE_REVOKE_AUTH, getuid()))
384 return (UAUTHERR);
387 * Lock the database to make sure no body writes to it while we are
388 * reading.
390 (void) lock_dev(NULL, NULL);
391 setdaent();
392 if (device) {
393 if (optflag & CLASS) {
395 * list all devices of this class.
397 while ((da = getdaent()) != NULL) {
398 class = kva_match(da->da_devopts, DAOPT_CLASS);
399 if (class && (strcmp(class, device) == 0)) {
400 (void) _list_device(optflag, uid, da,
401 zonename);
403 freedaent(da);
405 } else {
407 * list this device
409 if ((da = getdanam(device)) == NULL) {
410 enddaent();
411 return (NODAERR);
413 error = _list_device(optflag, uid, da, zonename);
414 freedaent(da);
416 } else {
418 * list all devices
420 while ((da = getdaent()) != NULL) {
421 (void) _list_device(optflag, uid, da, zonename);
422 freedaent(da);
425 enddaent();
427 return (error);
431 * Set the DAC characteristics of the file.
432 * This uses a fancy chmod() by setting a minimal ACL which sets the mode
433 * and discards any existing ACL.
436 _newdac(char *file, uid_t owner, gid_t group, o_mode_t mode)
438 int err = 0;
440 if (mode == ALLOC_MODE) {
441 if (chown(file, owner, group) == -1) {
442 dperror("newdac: unable to chown");
443 err = CHOWNERR;
445 } else do {
446 if (chown(file, owner, group) == -1) {
447 dperror("newdac: unable to chown");
448 err = CHOWNERR;
450 } while (fdetach(file) == 0);
452 if (err)
453 return (err);
455 if (strncmp(file, "/dev/", strlen("/dev/")) != 0) {
457 * This could be a SunRay device that is in /tmp.
459 if (chmod(file, mode) == -1) {
460 dperror("newdac: unable to chmod");
461 err = SETACLERR;
463 } else {
464 err = acl_strip(file, owner, group, (mode_t)mode);
467 if (err != 0) {
468 dperror("newdac: unable to setacl");
469 err = SETACLERR;
472 return (err);
476 * lock_dev -
477 * locks a section of DA_DB_LOCK.
478 * returns lock fd if successful, else -1 on error.
480 static int
481 lock_dev(char *file, struct stat *statbuf)
483 static int lockfd = -1;
484 int ret;
485 int count = 0;
486 int retry = 10;
487 off_t size = 0;
488 off_t offset;
489 char *lockfile;
491 lockfile = file;
493 if (statbuf) {
494 offset = statbuf->st_rdev;
495 dprintf("locking %s\n", file);
496 } else {
497 offset = 0;
498 dprintf("locking %s\n", lockfile);
500 if ((lockfd == -1) &&
501 (lockfd = open(lockfile, O_RDWR | O_CREAT, 0600)) == -1) {
502 dperror("lock_dev: cannot open lock file");
503 return (-1);
505 errno = 0;
506 while (retry) {
507 count++;
508 ret = lockf(lockfd, F_TLOCK, size);
509 if (ret == 0)
510 return (lockfd);
511 if ((errno != EACCES) && (errno != EAGAIN)) {
512 dperror("lock_dev: cannot set lock");
513 return (-1);
515 retry--;
516 (void) sleep(count);
517 errno = 0;
520 return (-1);
524 mk_alloc(devmap_t *list, uid_t uid)
526 int error = 0;
527 char **file;
528 gid_t gid = getgid();
529 mode_t mode = ALLOC_MODE;
531 file = list->dmap_devarray;
532 if (file == NULL)
533 return (NODMAPERR);
534 for (; *file != NULL; file++) {
535 dprintf("Allocating %s\n", *file);
536 if ((error = _newdac(*file, uid, gid, mode)) != 0) {
537 (void) _newdac(*file, ALLOC_ERRID, DA_GID,
538 ALLOC_ERR_MODE);
539 break;
543 return (error);
547 * mk_revoke() is used instead of system("/usr/sbin/fuser -k file")
548 * because "/usr/sbin/fuser -k file" kills all processes
549 * working with the file, even "vold" (bug #4095152).
552 mk_revoke(int optflag, char *file)
554 int r = 0, p[2], fp, lock;
555 int fuserpid;
556 char buf[MAXPATHLEN];
557 FILE *ptr;
558 pid_t c_pid;
559 prpsinfo_t info;
561 (void) strcpy(buf, PROCFS);
563 * vfork() and execl() just to make the same output
564 * as before fixing of bug #4095152.
565 * The problem is that the "fuser" command prints
566 * one part of output into stderr and another into stdout,
567 * but user sees them mixed. Of course, better to change "fuser"
568 * or to intercept and not to print its output.
570 if (!(optflag & SILENT)) {
571 c_pid = vfork();
572 if (c_pid == -1)
573 return (-1);
574 if (c_pid == 0) {
575 dprintf("first exec fuser %s\n", file);
576 (void) execl("/usr/sbin/fuser", "fuser", file, NULL);
577 dperror("first exec fuser");
578 _exit(1);
581 (void) waitpid(c_pid, &lock, 0);
582 dprintf("exit status %x\n", lock);
583 if (WEXITSTATUS(lock) != 0)
584 return (-1);
586 dprintf("first continuing c_pid=%d\n", (int)c_pid);
587 if (pipe(p)) {
588 dperror("pipe");
589 return (-1);
591 /* vfork() and execl() to catch output and to process it */
592 c_pid = vfork();
593 if (c_pid == -1) {
594 dperror("second vfork");
595 return (-1);
597 dprintf("second continuing c_pid=%d\n", (int)c_pid);
598 if (c_pid == 0) {
599 (void) close(p[0]);
600 (void) close(1);
601 (void) fcntl(p[1], F_DUPFD, 1);
602 (void) close(p[1]);
603 (void) close(2);
604 dprintf("second exec fuser %s\n", file);
605 (void) execl("/usr/sbin/fuser", "fuser", file, NULL);
606 dperror("second exec fuser");
607 _exit(1);
609 (void) close(p[1]);
610 if ((ptr = fdopen(p[0], "r")) != NULL) {
611 while (!feof(ptr)) {
612 if (fscanf(ptr, "%d", &fuserpid) > 0) {
613 (void) sprintf(buf + strlen(PROCFS), "%d",
614 fuserpid);
615 if ((fp = open(buf, O_RDONLY)) == -1) {
616 dperror(buf);
617 continue;
619 if (ioctl(fp, PIOCPSINFO,
620 (char *)&info) == -1) {
621 dprintf("%d psinfo failed", fuserpid);
622 dperror("");
623 (void) close(fp);
624 continue;
626 (void) close(fp);
627 if (strcmp(info.pr_fname, "vold") == 0) {
628 dprintf("%d matched vold name\n",
629 fuserpid);
630 continue;
632 if (strcmp(info.pr_fname, "deallocate")
633 == 0) {
634 dprintf("%d matched deallocate name\n",
635 fuserpid);
636 continue;
638 dprintf("killing %s", info.pr_fname);
639 dprintf("(%d)\n", fuserpid);
640 if ((r =
641 kill((pid_t)fuserpid, SIGKILL)) == -1) {
642 dprintf("kill %d", fuserpid);
643 dperror("");
644 break;
648 } else {
649 dperror("fdopen(p[0], r)");
650 r = -1;
652 (void) fclose(ptr);
654 return (r);
658 mk_unalloc(int optflag, devmap_t *list)
660 int error = 0;
661 int status;
662 char **file;
664 audit_allocate_list(list->dmap_devlist);
665 file = list->dmap_devarray;
666 if (file == NULL)
667 return (NODMAPERR);
668 for (; *file != NULL; file++) {
669 dprintf("Deallocating %s\n", *file);
670 if (mk_revoke(optflag, *file) < 0) {
671 dprintf("mk_unalloc: unable to revoke %s\n", *file);
672 dperror("");
673 error = CNTFRCERR;
675 status = _newdac(*file, DA_UID, DA_GID, DEALLOC_MODE);
676 if (error == 0)
677 error = status;
681 return (error);
685 mk_error(devmap_t *list)
687 int status = 0;
688 char **file;
690 audit_allocate_list(list->dmap_devlist);
691 file = list->dmap_devarray;
692 if (file == NULL)
693 return (NODMAPERR);
694 for (; *file != NULL; file++) {
695 dprintf("Putting %s in error state\n", *file);
696 status = _newdac(*file, ALLOC_ERRID, DA_GID, ALLOC_ERR_MODE);
699 return (status);
703 exec_clean(int optflag, char *devname, char *path, uid_t uid, char *zonename,
704 char *clean_arg)
706 int c;
707 int status = 0, exit_status;
708 char *mode, *cmd;
709 char zonepath[MAXPATHLEN];
710 char pw_buf[NSS_BUFLEN_PASSWD];
711 struct passwd pw_ent;
712 struct passwd *result;
714 zonepath[0] = '\0';
715 getpwuid_r(uid, &pw_ent, pw_buf, sizeof (pw_buf), &result);
716 if (!result)
717 return (-1);
718 if (optflag & FORCE_ALL)
719 mode = "-I";
720 else if (optflag & FORCE)
721 mode = "-f";
722 else
723 mode = "-s";
724 if (path == NULL)
725 return (0);
726 if ((cmd = strrchr(path, '/')) == NULL)
727 cmd = path;
728 else
729 cmd++; /* skip leading '/' */
730 c = vfork();
731 switch (c) {
732 case -1:
733 return (-1);
734 case 0:
735 (void) setuid(0);
736 dprintf("clean script: %s, ", path);
737 dprintf("cmd=%s, ", cmd);
738 dprintf("mode=%s, ", mode);
739 dprintf("devname=%s\n", devname);
740 (void) execle(path, cmd, mode, devname, NULL, newenv);
741 dprintf("Unable to execute clean up script %s\n", path);
742 dperror("");
743 exit(CNTDEXECERR);
744 default:
745 (void) waitpid(c, &status, 0);
746 dprintf("Child %d", c);
747 if (WIFEXITED(status)) {
748 exit_status = WEXITSTATUS(status);
749 dprintf(" exited, status: %d\n", exit_status);
750 return (exit_status);
751 } else if (WIFSIGNALED(status)) {
752 dprintf(" killed, signal %d\n", WTERMSIG(status));
753 } else {
754 dprintf(": exit status %d\n", status);
756 return (-1);
761 _deallocate_dev(int optflag, devalloc_t *da, devmap_t *dm_in, uid_t uid,
762 char *zonename, int *lock_fd)
764 int bytes = 0;
765 int error = 0;
766 int is_authorized = 0;
767 uid_t nuid;
768 char *fname = NULL;
769 char file_name[MAXPATHLEN];
770 char *devzone = NULL;
771 devmap_t *dm = NULL, *dm_new = NULL;
772 struct stat stat_buf;
774 if (dm_in == NULL) {
775 setdmapent();
776 if ((dm_new = getdmapnam(da->da_devname)) == NULL) {
777 enddmapent();
778 dprintf("Unable to find %s in device map database\n",
779 da->da_devname);
780 return (NODMAPERR);
782 enddmapent();
783 dm = dm_new;
784 } else {
785 dm = dm_in;
787 bytes = snprintf(file_name, MAXPATHLEN, "%s/%s", DAC_DIR,
788 da->da_devname);
789 if (bytes <= 0) {
790 error = DEVNAMEERR;
791 goto out;
792 } else if (bytes >= MAXPATHLEN) {
793 dprintf("device name %s is too long.\n",
794 da->da_devname);
795 error = DEVLONGERR;
796 goto out;
798 fname = file_name;
800 audit_allocate_device(fname);
802 if (stat(fname, &stat_buf) != 0) {
803 dprintf("Unable to stat %s\n", fname);
804 error = DACACCERR;
805 goto out;
807 is_authorized = _is_dev_authorized(da, uid);
808 if (is_authorized == ALLOC_BY_NONE) {
809 dprintf("Not deallocating %s, not allocatable\n",
810 da->da_devname);
811 goto out;
813 if (!(optflag & (FORCE | FORCE_ALL)) && !is_authorized) {
814 dprintf("User %d is unauthorized to deallocate\n", (int)uid);
815 error = UAUTHERR;
816 goto out;
818 if (!(optflag & FORCE) && stat_buf.st_uid != uid &&
819 DEV_ALLOCATED(stat_buf)) {
820 error = ALLOCUERR;
821 goto out;
823 if (!DEV_ALLOCATED(stat_buf)) {
824 if (DEV_ERRORED(stat_buf)) {
825 if (!(optflag & FORCE)) {
826 error = DEVSTATEERR;
827 goto out;
829 } else {
830 error = DEVNALLOCERR;
831 goto out;
834 /* All checks passed, time to lock and deallocate */
835 if ((*lock_fd = lock_dev(fname, &stat_buf)) == -1) {
836 error = DEVLKERR;
837 goto out;
839 if ((error = mk_unalloc(optflag, dm)) != 0) {
840 if (!(optflag & FORCE))
841 goto out;
843 if ((error = _newdac(fname, DA_UID, DA_GID,
844 DEALLOC_MODE)) != 0) {
845 (void) _newdac(file_name, DA_UID, DA_GID,
846 ALLOC_ERR_MODE);
847 goto out;
850 * if we are deallocating device owned by someone else,
851 * pass the owner's uid to the cleaning script.
853 nuid = (stat_buf.st_uid == uid) ? uid : stat_buf.st_uid;
854 error = exec_clean(optflag, da->da_devname, da->da_devexec, nuid,
855 devzone, DEALLOC_CLEAN);
856 if (error != 0) {
857 if (!(optflag & (FORCE | FORCE_ALL))) {
858 error = CLEANERR;
859 (void) mk_error(dm);
860 } else {
861 error = 0;
865 out:
866 if (dm_new)
867 freedmapent(dm_new);
868 return (error);
872 _allocate_dev(int optflag, uid_t uid, devalloc_t *da, char *zonename,
873 int *lock_fd)
875 int bytes = 0;
876 int error = 0;
877 int is_authorized = 0;
878 int dealloc_optflag = 0;
879 char *fname = NULL;
880 char file_name[MAXPATHLEN];
881 devmap_t *dm;
882 struct stat stat_buf;
884 setdmapent();
885 if ((dm = getdmapnam(da->da_devname)) == NULL) {
886 enddmapent();
887 dprintf("Unable to find %s in device map database\n",
888 da->da_devname);
889 return (NODMAPERR);
891 enddmapent();
892 bytes = snprintf(file_name, MAXPATHLEN, "%s/%s", DAC_DIR,
893 da->da_devname);
894 if (bytes <= 0) {
895 error = DEVNAMEERR;
896 goto out;
897 } else if (bytes >= MAXPATHLEN) {
898 dprintf("device name %s is too long.\n",
899 da->da_devname);
900 error = DEVLONGERR;
901 goto out;
903 fname = file_name;
905 (void) audit_allocate_device(fname);
907 if (stat(fname, &stat_buf) != 0) {
908 dprintf("Unable to stat %s\n", fname);
909 dperror("Error:");
910 error = DACACCERR;
911 goto out;
913 if (DEV_ERRORED(stat_buf)) {
914 error = DEVSTATEERR;
915 goto out;
917 is_authorized = _is_dev_authorized(da, uid);
918 if (is_authorized == ALLOC_BY_NONE) {
919 dprintf("Device %s is not allocatable\n", da->da_devname);
920 error = UAUTHERR;
921 goto out;
922 } else if (!is_authorized && !(optflag & USERNAME)) {
923 dprintf("User %d is unauthorized to allocate\n", (int)uid);
924 error = UAUTHERR;
925 goto out;
927 if (check_devs(dm) == -1) {
928 error = DSPMISSERR;
929 goto out;
931 if (DEV_ALLOCATED(stat_buf)) {
932 if (optflag & FORCE) {
933 if (optflag & SILENT)
934 dealloc_optflag = FORCE|SILENT;
935 else
936 dealloc_optflag = FORCE;
937 if (_deallocate_dev(dealloc_optflag, da, dm, uid,
938 zonename, lock_fd)) {
939 dprintf("Couldn't force deallocate device %s\n",
940 da->da_devname);
941 error = CNTFRCERR;
942 goto out;
944 } else if (stat_buf.st_uid == uid) {
945 error = PREALLOCERR;
946 goto out;
947 } else {
948 error = ALLOCUERR;
949 goto out;
952 /* All checks passed, time to lock and allocate */
953 if ((*lock_fd = lock_dev(fname, &stat_buf)) == -1) {
954 error = DEVLKERR;
955 goto out;
958 (void) audit_allocate_list(dm->dmap_devlist);
960 if ((error = mk_alloc(dm, uid)) != 0) {
961 (void) mk_unalloc(optflag, dm);
962 goto out;
965 if ((error = _newdac(file_name, uid, getgid(),
966 ALLOC_MODE)) != 0) {
967 (void) _newdac(file_name, DA_UID, DA_GID,
968 ALLOC_ERR_MODE);
969 goto out;
971 error = 0;
972 out:
973 freedmapent(dm);
974 return (error);
978 allocate(int optflag, uid_t uid, char *device, char *zonename)
980 int error = 0;
981 int lock_fd = -1;
982 devalloc_t *da;
984 if (optflag & (FORCE | USERID | USERNAME)) {
985 if (!_is_authorized(DEVICE_REVOKE_AUTH, getuid()))
986 return (UAUTHERR);
988 setdaent();
989 if (optflag & TYPE) {
991 * allocate devices of this type
993 while ((da = getdatype(device)) != NULL) {
994 dprintf("trying to allocate %s\n", da->da_devname);
995 error = _allocate_dev(optflag, uid, da, zonename,
996 &lock_fd);
997 freedaent(da);
998 error = 0;
1000 } else {
1002 * allocate this device
1004 if ((da = getdanam(device)) == NULL) {
1005 enddaent();
1006 return (NODAERR);
1008 dprintf("trying to allocate %s\n", da->da_devname);
1009 error = _allocate_dev(optflag, uid, da, zonename, &lock_fd);
1010 freedaent(da);
1011 if (error == DEVCLEAN_BADMOUNT)
1012 error = 0;
1014 enddaent();
1015 if (lock_fd != -1)
1016 (void) close(lock_fd);
1018 return (error);
1021 /* ARGSUSED */
1023 deallocate(int optflag, uid_t uid, char *device, char *zonename)
1025 int error = 0;
1026 int lock_fd = -1;
1027 devalloc_t *da;
1029 if (optflag & (FORCE | FORCE_ALL)) {
1030 if (!_is_authorized(DEVICE_REVOKE_AUTH, getuid()))
1031 return (UAUTHERR);
1033 if (optflag & FORCE_ALL)
1034 optflag |= FORCE;
1035 setdaent();
1036 if (optflag & FORCE_ALL) {
1038 * deallocate all devices
1040 while ((da = getdaent()) != NULL) {
1041 dprintf("trying to deallocate %s\n", da->da_devname);
1042 error = _deallocate_dev(optflag, da, NULL, uid,
1043 zonename, &lock_fd);
1044 freedaent(da);
1045 error = 0;
1047 } else if (!(optflag & TYPE)) {
1049 * deallocate this device
1051 if ((da = getdanam(device)) == NULL) {
1052 enddaent();
1053 return (NODAERR);
1055 dprintf("trying to deallocate %s\n", da->da_devname);
1056 error = _deallocate_dev(optflag, da, NULL, uid, zonename,
1057 &lock_fd);
1058 freedaent(da);
1059 if (error == DEVCLEAN_BADMOUNT)
1060 error = 0;
1062 enddaent();
1063 if (lock_fd != -1)
1064 (void) close(lock_fd);
1066 return (error);