]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/cddl/compat/opensolaris/kern/opensolaris_policy.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / sys / cddl / compat / opensolaris / kern / opensolaris_policy.c
1 /*-
2  * Copyright (c) 2007 Pawel Jakub Dawidek <pjd@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
30 #include <sys/param.h>
31 #include <sys/priv.h>
32 #include <sys/vnode.h>
33 #include <sys/mount.h>
34 #include <sys/stat.h>
35 #include <sys/policy.h>
36
37 int
38 secpolicy_zfs(struct ucred *cred)
39 {
40
41         return (priv_check_cred(cred, PRIV_VFS_MOUNT, 0));
42 }
43
44 int
45 secpolicy_sys_config(struct ucred *cred, int checkonly __unused)
46 {
47
48         return (priv_check_cred(cred, PRIV_ZFS_POOL_CONFIG, 0));
49 }
50
51 int
52 secpolicy_zinject(struct ucred *cred)
53 {
54
55         return (priv_check_cred(cred, PRIV_ZFS_INJECT, 0));
56 }
57
58 int
59 secpolicy_fs_unmount(struct ucred *cred, struct mount *vfsp __unused)
60 {
61
62         return (priv_check_cred(cred, PRIV_VFS_UNMOUNT, 0));
63 }
64
65 /*
66  * This check is done in kern_link(), so we could just return 0 here.
67  */
68 extern int hardlink_check_uid;
69 int
70 secpolicy_basic_link(struct ucred *cred)
71 {
72
73         if (!hardlink_check_uid)
74                 return (0);
75         return (priv_check_cred(cred, PRIV_VFS_LINK, 0));
76 }
77
78 int
79 secpolicy_vnode_stky_modify(struct ucred *cred)
80 {
81
82         return (EPERM);
83 }
84
85 int
86 secpolicy_vnode_remove(struct ucred *cred)
87 {
88
89         return (priv_check_cred(cred, PRIV_VFS_ADMIN, 0));
90 }
91
92 int
93 secpolicy_vnode_access(struct ucred *cred, struct vnode *vp, uint64_t owner,
94     int mode)
95 {
96
97         if ((mode & VREAD) && priv_check_cred(cred, PRIV_VFS_READ, 0) != 0) {
98                 return (EACCES);
99         }
100         if ((mode & VWRITE) &&
101             priv_check_cred(cred, PRIV_VFS_WRITE, 0) != 0) {
102                 return (EACCES);
103         }
104         if (mode & VEXEC) {
105                 if (vp->v_type == VDIR) {
106                         if (priv_check_cred(cred, PRIV_VFS_LOOKUP, 0) != 0) {
107                                 return (EACCES);
108                         }
109                 } else {
110                         if (priv_check_cred(cred, PRIV_VFS_EXEC, 0) != 0) {
111                                 return (EACCES);
112                         }
113                 }
114         }
115         return (0);
116 }
117
118 int
119 secpolicy_vnode_setdac(struct ucred *cred, uid_t owner)
120 {
121
122         if (owner == cred->cr_uid)
123                 return (0);
124         return (priv_check_cred(cred, PRIV_VFS_ADMIN, 0));
125 }
126
127 int
128 secpolicy_vnode_setattr(struct ucred *cred, struct vnode *vp, struct vattr *vap,
129     const struct vattr *ovap, int flags,
130     int unlocked_access(void *, int, struct ucred *), void *node)
131 {
132         int mask = vap->va_mask;
133         int error;
134
135         if (mask & AT_SIZE) {
136                 if (vp->v_type == VDIR)
137                         return (EISDIR);
138                 error = unlocked_access(node, VWRITE, cred);
139                 if (error)
140                         return (error);
141         }
142         if (mask & AT_MODE) {
143                 /*
144                  * If not the owner of the file then check privilege
145                  * for two things: the privilege to set the mode at all
146                  * and, if we're setting setuid, we also need permissions
147                  * to add the set-uid bit, if we're not the owner.
148                  * In the specific case of creating a set-uid root
149                  * file, we need even more permissions.
150                  */
151                 error = secpolicy_vnode_setdac(cred, ovap->va_uid);
152                 if (error)
153                         return (error);
154                 error = secpolicy_setid_setsticky_clear(vp, vap, ovap, cred);
155                 if (error)
156                         return (error);
157         } else {
158                 vap->va_mode = ovap->va_mode;
159         }
160         if (mask & (AT_UID | AT_GID)) {
161                 error = secpolicy_vnode_setdac(cred, ovap->va_uid);
162                 if (error)
163                         return (error);
164
165                 /*
166                  * To change the owner of a file, or change the group of a file to a
167                  * group of which we are not a member, the caller must have
168                  * privilege.
169                  */
170                 if (((mask & AT_UID) && vap->va_uid != ovap->va_uid) ||
171                     ((mask & AT_GID) && vap->va_gid != ovap->va_gid &&
172                      !groupmember(vap->va_gid, cred))) {
173                         error = priv_check_cred(cred, PRIV_VFS_CHOWN, 0);
174                         if (error)
175                                 return (error);
176                 }
177
178                 if (((mask & AT_UID) && vap->va_uid != ovap->va_uid) ||
179                     ((mask & AT_GID) && vap->va_gid != ovap->va_gid)) {
180                         secpolicy_setid_clear(vap, cred);
181                 }
182         }
183         if (mask & (AT_ATIME | AT_MTIME)) {
184                 /*
185                  * From utimes(2):
186                  * If times is NULL, ... The caller must be the owner of
187                  * the file, have permission to write the file, or be the
188                  * super-user.
189                  * If times is non-NULL, ... The caller must be the owner of
190                  * the file or be the super-user.
191                  */
192                 error = secpolicy_vnode_setdac(cred, ovap->va_uid);
193                 if (error && (vap->va_vaflags & VA_UTIMES_NULL))
194                         error = unlocked_access(node, VWRITE, cred);
195                 if (error)
196                         return (error);
197         }
198         return (0);
199 }
200
201 int
202 secpolicy_vnode_create_gid(struct ucred *cred)
203 {
204
205         return (EPERM);
206 }
207
208 int
209 secpolicy_vnode_setids_setgids(struct ucred *cred, gid_t gid)
210 {
211
212         if (!groupmember(gid, cred))
213                 return (priv_check_cred(cred, PRIV_VFS_SETGID, 0));
214         return (0);
215 }
216
217 int
218 secpolicy_vnode_setid_retain(struct ucred *cred, boolean_t issuidroot __unused)
219 {
220
221         return (priv_check_cred(cred, PRIV_VFS_RETAINSUGID, 0));
222 }
223
224 void
225 secpolicy_setid_clear(struct vattr *vap, struct ucred *cred)
226 {
227
228         if ((vap->va_mode & (S_ISUID | S_ISGID)) != 0) {
229                 if (priv_check_cred(cred, PRIV_VFS_RETAINSUGID, 0)) {
230                         vap->va_mask |= AT_MODE;
231                         vap->va_mode &= ~(S_ISUID|S_ISGID);
232                 }
233         }
234 }
235
236 int
237 secpolicy_setid_setsticky_clear(struct vnode *vp, struct vattr *vap,
238     const struct vattr *ovap, struct ucred *cred)
239 {
240         int error;
241
242         /*
243          * Privileged processes may set the sticky bit on non-directories,
244          * as well as set the setgid bit on a file with a group that the process
245          * is not a member of. Both of these are allowed in jail(8).
246          */
247         if (vp->v_type != VDIR && (vap->va_mode & S_ISTXT)) {
248                 if (priv_check_cred(cred, PRIV_VFS_STICKYFILE, 0))
249                         return (EFTYPE);
250         }
251         /*
252          * Check for privilege if attempting to set the
253          * group-id bit.
254          */
255         if ((vap->va_mode & S_ISGID) != 0) {
256                 error = secpolicy_vnode_setids_setgids(cred, ovap->va_gid);
257                 if (error)
258                         return (error);
259         }
260         return (0);
261 }