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]
23 * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
26 #include <auth_attr.h>
27 #include <auth_list.h>
40 #include <bsm/devices.h>
44 #include <user_attr.h>
46 #include <sys/mkdev.h>
49 #include <sys/procfs.h>
50 #include <sys/param.h>
51 #include <sys/resource.h>
54 #include <sys/types.h>
59 #include <nss_dbdefs.h>
60 #include <bsm/devalloc.h>
61 #include <libdevinfo.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)
70 #define dprintf(s, a) 0
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 || \
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
[];
99 char sf_path
[MAXPATHLEN
];
107 static int lock_dev(char *, struct stat
*);
110 * checks if the invoking user is local to the device
118 if (stat(LOCALDEVICE
, &statbuf
) == 0 &&
119 statbuf
.st_uid
== uid
)
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)
141 if (strcmp(auths
, "*") == 0)
142 return (ALLOC_BY_NONE
);
143 getpwuid_r(uid
, &pw_ent
, pw_buf
, sizeof (pw_buf
), &result
);
146 if (strpbrk(auths
, DEVICE_AUTH_SEPARATOR
) == NULL
)
147 return (chkauthattr(auths
, pw_ent
.pw_name
));
148 authlist
= strdup(auths
);
149 if (authlist
== NULL
)
152 (dcp
= strtok_r(dcp
, DEVICE_AUTH_SEPARATOR
, &lasts
)) != NULL
;
154 if (chkauthattr(dcp
, pw_ent
.pw_name
))
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
)
169 char *auth_list
, *dcp
, *subauth
= NULL
;
171 auth_list
= da
->da_devauth
;
172 if (auth_list
== NULL
)
174 dcp
= strpbrk(auth_list
, KV_TOKEN_DELIMIT
);
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);
183 (void) strlcpy(subauth
, auth_list
, (ares
+ 1));
187 ares
= _is_authorized(auth_list
, uid
);
194 check_devs(devmap_t
*dm
)
199 if (dm
->dmap_devarray
== NULL
)
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
);
212 print_dev_attrs(int optflag
, devalloc_t
*da
, devmap_t
*dm
,
213 struct file_info
*fip
)
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
, ':'))
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
);
242 (void) printf("owner=%u%s", fip
->fi_stat
.st_uid
,
245 (void) printf("files=%s", dm
->dmap_devlist
);
250 print_dev(devmap_t
*dm
)
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
;
259 for (; *file
!= NULL
; file
++)
260 (void) printf(" %s", *file
);
267 _list_device(int optflag
, uid_t uid
, devalloc_t
*da
, char *zonename
)
271 int is_authorized
= 0;
273 char file_name
[MAXPATHLEN
];
277 fi
.fi_message
= NULL
;
279 if ((dm
= getdmapnam(da
->da_devname
)) == NULL
) {
281 dprintf("Unable to find %s in the maps database\n",
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
);
297 bytes
= snprintf(file_name
, MAXPATHLEN
, "%s/%s", DAC_DIR
,
302 } else if (bytes
>= MAXPATHLEN
) {
303 dprintf("device name %s is too long.\n",
309 if (stat(fname
, &fi
.fi_stat
) != 0) {
310 dprintf("Unable to stat %s\n", fname
);
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
)) {
324 } else if (optflag
& LISTALLOC
) { /* list_devices -u */
326 * list all allocated devices
328 if (!DEV_ALLOCATED(fi
.fi_stat
)) {
329 error
= DEVNALLOCERR
;
332 if (fi
.fi_stat
.st_uid
!= uid
) {
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.
347 } else if (fi
.fi_stat
.st_uid
!= uid
) {
348 if (!(optflag
& WINDOWING
)) {
355 if (check_devs(dm
) == -1) {
359 if (optflag
& LISTATTRS
)
360 print_dev_attrs(optflag
, da
, dm
, &fi
);
373 list_devices(int optflag
, uid_t uid
, char *device
, char *zonename
)
379 if (optflag
& USERID
) {
381 * we need device.revoke to list someone else's devices
383 if (!_is_authorized(DEVICE_REVOKE_AUTH
, getuid()))
387 * Lock the database to make sure no body writes to it while we are
390 (void) lock_dev(NULL
, NULL
);
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
,
409 if ((da
= getdanam(device
)) == NULL
) {
413 error
= _list_device(optflag
, uid
, da
, zonename
);
420 while ((da
= getdaent()) != NULL
) {
421 (void) _list_device(optflag
, uid
, da
, zonename
);
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
)
440 if (mode
== ALLOC_MODE
) {
441 if (chown(file
, owner
, group
) == -1) {
442 dperror("newdac: unable to chown");
446 if (chown(file
, owner
, group
) == -1) {
447 dperror("newdac: unable to chown");
450 } while (fdetach(file
) == 0);
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");
464 err
= acl_strip(file
, owner
, group
, (mode_t
)mode
);
468 dperror("newdac: unable to setacl");
477 * locks a section of DA_DB_LOCK.
478 * returns lock fd if successful, else -1 on error.
481 lock_dev(char *file
, struct stat
*statbuf
)
483 static int lockfd
= -1;
494 offset
= statbuf
->st_rdev
;
495 dprintf("locking %s\n", file
);
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");
508 ret
= lockf(lockfd
, F_TLOCK
, size
);
511 if ((errno
!= EACCES
) && (errno
!= EAGAIN
)) {
512 dperror("lock_dev: cannot set lock");
524 mk_alloc(devmap_t
*list
, uid_t uid
)
528 gid_t gid
= getgid();
529 mode_t mode
= ALLOC_MODE
;
531 file
= list
->dmap_devarray
;
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
,
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
;
556 char buf
[MAXPATHLEN
];
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
)) {
575 dprintf("first exec fuser %s\n", file
);
576 (void) execl("/usr/sbin/fuser", "fuser", file
, NULL
);
577 dperror("first exec fuser");
581 (void) waitpid(c_pid
, &lock
, 0);
582 dprintf("exit status %x\n", lock
);
583 if (WEXITSTATUS(lock
) != 0)
586 dprintf("first continuing c_pid=%d\n", (int)c_pid
);
591 /* vfork() and execl() to catch output and to process it */
594 dperror("second vfork");
597 dprintf("second continuing c_pid=%d\n", (int)c_pid
);
601 (void) fcntl(p
[1], F_DUPFD
, 1);
604 dprintf("second exec fuser %s\n", file
);
605 (void) execl("/usr/sbin/fuser", "fuser", file
, NULL
);
606 dperror("second exec fuser");
610 if ((ptr
= fdopen(p
[0], "r")) != NULL
) {
612 if (fscanf(ptr
, "%d", &fuserpid
) > 0) {
613 (void) sprintf(buf
+ strlen(PROCFS
), "%d",
615 if ((fp
= open(buf
, O_RDONLY
)) == -1) {
619 if (ioctl(fp
, PIOCPSINFO
,
620 (char *)&info
) == -1) {
621 dprintf("%d psinfo failed", fuserpid
);
627 if (strcmp(info
.pr_fname
, "vold") == 0) {
628 dprintf("%d matched vold name\n",
632 if (strcmp(info
.pr_fname
, "deallocate")
634 dprintf("%d matched deallocate name\n",
638 dprintf("killing %s", info
.pr_fname
);
639 dprintf("(%d)\n", fuserpid
);
641 kill((pid_t
)fuserpid
, SIGKILL
)) == -1) {
642 dprintf("kill %d", fuserpid
);
649 dperror("fdopen(p[0], r)");
658 mk_unalloc(int optflag
, devmap_t
*list
)
664 audit_allocate_list(list
->dmap_devlist
);
665 file
= list
->dmap_devarray
;
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
);
675 status
= _newdac(*file
, DA_UID
, DA_GID
, DEALLOC_MODE
);
685 mk_error(devmap_t
*list
)
690 audit_allocate_list(list
->dmap_devlist
);
691 file
= list
->dmap_devarray
;
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
);
703 exec_clean(int optflag
, char *devname
, char *path
, uid_t uid
, char *zonename
,
707 int status
= 0, exit_status
;
709 char zonepath
[MAXPATHLEN
];
710 char pw_buf
[NSS_BUFLEN_PASSWD
];
711 struct passwd pw_ent
;
712 struct passwd
*result
;
715 getpwuid_r(uid
, &pw_ent
, pw_buf
, sizeof (pw_buf
), &result
);
718 if (optflag
& FORCE_ALL
)
720 else if (optflag
& FORCE
)
726 if ((cmd
= strrchr(path
, '/')) == NULL
)
729 cmd
++; /* skip leading '/' */
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
);
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
));
754 dprintf(": exit status %d\n", status
);
761 _deallocate_dev(int optflag
, devalloc_t
*da
, devmap_t
*dm_in
, uid_t uid
,
762 char *zonename
, int *lock_fd
)
766 int is_authorized
= 0;
769 char file_name
[MAXPATHLEN
];
770 char *devzone
= NULL
;
771 devmap_t
*dm
= NULL
, *dm_new
= NULL
;
772 struct stat stat_buf
;
776 if ((dm_new
= getdmapnam(da
->da_devname
)) == NULL
) {
778 dprintf("Unable to find %s in device map database\n",
787 bytes
= snprintf(file_name
, MAXPATHLEN
, "%s/%s", DAC_DIR
,
792 } else if (bytes
>= MAXPATHLEN
) {
793 dprintf("device name %s is too long.\n",
800 audit_allocate_device(fname
);
802 if (stat(fname
, &stat_buf
) != 0) {
803 dprintf("Unable to stat %s\n", fname
);
807 is_authorized
= _is_dev_authorized(da
, uid
);
808 if (is_authorized
== ALLOC_BY_NONE
) {
809 dprintf("Not deallocating %s, not allocatable\n",
813 if (!(optflag
& (FORCE
| FORCE_ALL
)) && !is_authorized
) {
814 dprintf("User %d is unauthorized to deallocate\n", (int)uid
);
818 if (!(optflag
& FORCE
) && stat_buf
.st_uid
!= uid
&&
819 DEV_ALLOCATED(stat_buf
)) {
823 if (!DEV_ALLOCATED(stat_buf
)) {
824 if (DEV_ERRORED(stat_buf
)) {
825 if (!(optflag
& FORCE
)) {
830 error
= DEVNALLOCERR
;
834 /* All checks passed, time to lock and deallocate */
835 if ((*lock_fd
= lock_dev(fname
, &stat_buf
)) == -1) {
839 if ((error
= mk_unalloc(optflag
, dm
)) != 0) {
840 if (!(optflag
& FORCE
))
843 if ((error
= _newdac(fname
, DA_UID
, DA_GID
,
844 DEALLOC_MODE
)) != 0) {
845 (void) _newdac(file_name
, DA_UID
, DA_GID
,
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
);
857 if (!(optflag
& (FORCE
| FORCE_ALL
))) {
872 _allocate_dev(int optflag
, uid_t uid
, devalloc_t
*da
, char *zonename
,
877 int is_authorized
= 0;
878 int dealloc_optflag
= 0;
880 char file_name
[MAXPATHLEN
];
882 struct stat stat_buf
;
885 if ((dm
= getdmapnam(da
->da_devname
)) == NULL
) {
887 dprintf("Unable to find %s in device map database\n",
892 bytes
= snprintf(file_name
, MAXPATHLEN
, "%s/%s", DAC_DIR
,
897 } else if (bytes
>= MAXPATHLEN
) {
898 dprintf("device name %s is too long.\n",
905 (void) audit_allocate_device(fname
);
907 if (stat(fname
, &stat_buf
) != 0) {
908 dprintf("Unable to stat %s\n", fname
);
913 if (DEV_ERRORED(stat_buf
)) {
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
);
922 } else if (!is_authorized
&& !(optflag
& USERNAME
)) {
923 dprintf("User %d is unauthorized to allocate\n", (int)uid
);
927 if (check_devs(dm
) == -1) {
931 if (DEV_ALLOCATED(stat_buf
)) {
932 if (optflag
& FORCE
) {
933 if (optflag
& SILENT
)
934 dealloc_optflag
= FORCE
|SILENT
;
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",
944 } else if (stat_buf
.st_uid
== uid
) {
952 /* All checks passed, time to lock and allocate */
953 if ((*lock_fd
= lock_dev(fname
, &stat_buf
)) == -1) {
958 (void) audit_allocate_list(dm
->dmap_devlist
);
960 if ((error
= mk_alloc(dm
, uid
)) != 0) {
961 (void) mk_unalloc(optflag
, dm
);
965 if ((error
= _newdac(file_name
, uid
, getgid(),
967 (void) _newdac(file_name
, DA_UID
, DA_GID
,
978 allocate(int optflag
, uid_t uid
, char *device
, char *zonename
)
984 if (optflag
& (FORCE
| USERID
| USERNAME
)) {
985 if (!_is_authorized(DEVICE_REVOKE_AUTH
, getuid()))
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
,
1002 * allocate this device
1004 if ((da
= getdanam(device
)) == NULL
) {
1008 dprintf("trying to allocate %s\n", da
->da_devname
);
1009 error
= _allocate_dev(optflag
, uid
, da
, zonename
, &lock_fd
);
1011 if (error
== DEVCLEAN_BADMOUNT
)
1016 (void) close(lock_fd
);
1023 deallocate(int optflag
, uid_t uid
, char *device
, char *zonename
)
1029 if (optflag
& (FORCE
| FORCE_ALL
)) {
1030 if (!_is_authorized(DEVICE_REVOKE_AUTH
, getuid()))
1033 if (optflag
& FORCE_ALL
)
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
);
1047 } else if (!(optflag
& TYPE
)) {
1049 * deallocate this device
1051 if ((da
= getdanam(device
)) == NULL
) {
1055 dprintf("trying to deallocate %s\n", da
->da_devname
);
1056 error
= _deallocate_dev(optflag
, da
, NULL
, uid
, zonename
,
1059 if (error
== DEVCLEAN_BADMOUNT
)
1064 (void) close(lock_fd
);