policy.c revision 1.10 1 1.10 christos /* $NetBSD: policy.c,v 1.10 2022/03/30 16:34:27 christos Exp $ */
2 1.1 haad
3 1.1 haad /*-
4 1.1 haad * Copyright (c) 2009 The NetBSD Foundation, Inc.
5 1.1 haad * All rights reserved.
6 1.1 haad *
7 1.1 haad * This code is derived from software contributed to The NetBSD Foundation
8 1.1 haad * by Andrew Doran.
9 1.1 haad *
10 1.1 haad * Redistribution and use in source and binary forms, with or without
11 1.1 haad * modification, are permitted provided that the following conditions
12 1.1 haad * are met:
13 1.1 haad * 1. Redistributions of source code must retain the above copyright
14 1.1 haad * notice, this list of conditions and the following disclaimer.
15 1.1 haad * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 haad * notice, this list of conditions and the following disclaimer in the
17 1.1 haad * documentation and/or other materials provided with the distribution.
18 1.1 haad *
19 1.1 haad * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 1.1 haad * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 1.1 haad * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 1.1 haad * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 1.1 haad * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 1.1 haad * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 1.1 haad * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 1.1 haad * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 1.1 haad * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 1.1 haad * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 1.1 haad * POSSIBILITY OF SUCH DAMAGE.
30 1.1 haad */
31 1.1 haad
32 1.1 haad /*-
33 1.1 haad * Copyright (c) 2007 Pawel Jakub Dawidek <pjd (at) FreeBSD.org>
34 1.1 haad * All rights reserved.
35 1.1 haad *
36 1.1 haad * Redistribution and use in source and binary forms, with or without
37 1.1 haad * modification, are permitted provided that the following conditions
38 1.1 haad * are met:
39 1.1 haad * 1. Redistributions of source code must retain the above copyright
40 1.1 haad * notice, this list of conditions and the following disclaimer.
41 1.1 haad * 2. Redistributions in binary form must reproduce the above copyright
42 1.1 haad * notice, this list of conditions and the following disclaimer in the
43 1.1 haad * documentation and/or other materials provided with the distribution.
44 1.1 haad *
45 1.1 haad * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
46 1.1 haad * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47 1.1 haad * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48 1.1 haad * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
49 1.1 haad * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50 1.1 haad * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51 1.1 haad * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52 1.1 haad * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53 1.1 haad * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54 1.1 haad * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55 1.1 haad * SUCH DAMAGE.
56 1.1 haad */
57 1.1 haad
58 1.4 riastrad /*
59 1.4 riastrad * CDDL HEADER START
60 1.4 riastrad *
61 1.4 riastrad * The contents of this file are subject to the terms of the
62 1.4 riastrad * Common Development and Distribution License (the "License").
63 1.4 riastrad * You may not use this file except in compliance with the License.
64 1.4 riastrad *
65 1.4 riastrad * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
66 1.4 riastrad * or http://www.opensolaris.org/os/licensing.
67 1.4 riastrad * See the License for the specific language governing permissions
68 1.4 riastrad * and limitations under the License.
69 1.4 riastrad *
70 1.4 riastrad * When distributing Covered Code, include this CDDL HEADER in each
71 1.4 riastrad * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
72 1.4 riastrad * If applicable, add the following below this CDDL HEADER, with the
73 1.4 riastrad * fields enclosed by brackets "[]" replaced with your own identifying
74 1.4 riastrad * information: Portions Copyright [yyyy] [name of copyright owner]
75 1.4 riastrad *
76 1.4 riastrad * CDDL HEADER END
77 1.4 riastrad */
78 1.4 riastrad /*
79 1.4 riastrad * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
80 1.4 riastrad * Copyright 2012, Joyent, Inc. All rights reserved.
81 1.4 riastrad */
82 1.4 riastrad
83 1.1 haad #include <sys/param.h>
84 1.1 haad #include <sys/vnode.h>
85 1.1 haad #include <sys/mount.h>
86 1.1 haad #include <sys/stat.h>
87 1.1 haad #include <sys/policy.h>
88 1.1 haad
89 1.1 haad int
90 1.7 chs secpolicy_nfs(cred_t *cr)
91 1.7 chs {
92 1.7 chs
93 1.7 chs return kauth_authorize_generic(cr, KAUTH_GENERIC_ISSUSER, NULL);
94 1.7 chs }
95 1.7 chs
96 1.7 chs int
97 1.7 chs secpolicy_zfs(cred_t *cred)
98 1.1 haad {
99 1.1 haad
100 1.1 haad return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL);
101 1.1 haad }
102 1.1 haad
103 1.1 haad int
104 1.7 chs secpolicy_sys_config(cred_t *cred, int checkonly __unused)
105 1.1 haad {
106 1.1 haad
107 1.1 haad return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL);
108 1.1 haad }
109 1.1 haad
110 1.1 haad int
111 1.7 chs secpolicy_zinject(cred_t *cred)
112 1.1 haad {
113 1.1 haad
114 1.1 haad return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL);
115 1.1 haad }
116 1.1 haad
117 1.1 haad int
118 1.7 chs secpolicy_fs_mount(cred_t *cred, vnode_t *mvp, struct mount *vfsp)
119 1.1 haad {
120 1.1 haad
121 1.1 haad return kauth_authorize_system(cred, KAUTH_SYSTEM_MOUNT,
122 1.9 hannken KAUTH_REQ_SYSTEM_MOUNT_NEW, mvp, KAUTH_ARG(vfsp->mnt_flag), NULL);
123 1.1 haad }
124 1.1 haad
125 1.1 haad int
126 1.7 chs secpolicy_fs_unmount(cred_t *cred, struct mount *vfsp)
127 1.1 haad {
128 1.1 haad
129 1.1 haad return kauth_authorize_system(cred, KAUTH_SYSTEM_MOUNT,
130 1.1 haad KAUTH_REQ_SYSTEM_MOUNT_UNMOUNT, vfsp, NULL, NULL);
131 1.1 haad }
132 1.1 haad
133 1.7 chs int
134 1.7 chs secpolicy_fs_owner(struct mount *mp, cred_t *cr)
135 1.7 chs {
136 1.7 chs
137 1.7 chs return (EPERM);
138 1.7 chs }
139 1.7 chs
140 1.1 haad /*
141 1.1 haad * This check is done in kern_link(), so we could just return 0 here.
142 1.1 haad */
143 1.1 haad int
144 1.7 chs secpolicy_basic_link(vnode_t *vp, cred_t *cred)
145 1.1 haad {
146 1.1 haad
147 1.10 christos return kauth_authorize_vnode(cred, KAUTH_VNODE_ADD_LINK, vp,
148 1.10 christos /* XXX dvp, currently unused */ NULL, 0);
149 1.1 haad }
150 1.1 haad
151 1.1 haad int
152 1.7 chs secpolicy_vnode_stky_modify(cred_t *cred)
153 1.1 haad {
154 1.1 haad
155 1.4 riastrad return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL);
156 1.1 haad }
157 1.1 haad
158 1.1 haad int
159 1.7 chs secpolicy_vnode_remove(vnode_t *vp, cred_t *cred)
160 1.1 haad {
161 1.1 haad
162 1.1 haad return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL);
163 1.1 haad }
164 1.1 haad
165 1.1 haad
166 1.1 haad int
167 1.7 chs secpolicy_vnode_owner(vnode_t *vp, cred_t *cred, uid_t owner)
168 1.1 haad {
169 1.1 haad
170 1.4 riastrad if (owner == kauth_cred_getuid(cred))
171 1.4 riastrad return (0);
172 1.1 haad
173 1.7 chs if (secpolicy_fs_owner(vp->v_mount, cred) == 0)
174 1.7 chs return (0);
175 1.7 chs
176 1.4 riastrad return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL);
177 1.1 haad }
178 1.1 haad
179 1.1 haad int
180 1.7 chs secpolicy_vnode_access(cred_t *cred, vnode_t *vp, uid_t owner,
181 1.8 christos accmode_t mode)
182 1.1 haad {
183 1.1 haad
184 1.4 riastrad return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL);
185 1.1 haad }
186 1.1 haad
187 1.7 chs /*
188 1.7 chs * Like secpolicy_vnode_access() but we get the actual wanted mode and the
189 1.7 chs * current mode of the file, not the missing bits.
190 1.7 chs */
191 1.1 haad int
192 1.7 chs secpolicy_vnode_access2(cred_t *cr, vnode_t *vp, uid_t owner,
193 1.7 chs accmode_t curmode, accmode_t wantmode)
194 1.7 chs {
195 1.7 chs accmode_t mode;
196 1.7 chs
197 1.7 chs mode = ~curmode & wantmode;
198 1.7 chs
199 1.7 chs if (mode == 0)
200 1.7 chs return (0);
201 1.7 chs
202 1.7 chs return (secpolicy_vnode_access(cr, vp, owner, mode));
203 1.7 chs }
204 1.7 chs
205 1.7 chs int
206 1.7 chs secpolicy_vnode_any_access(cred_t *cr, vnode_t *vp, uid_t owner)
207 1.7 chs {
208 1.7 chs
209 1.7 chs return kauth_authorize_generic(cr, KAUTH_GENERIC_ISSUSER, NULL);
210 1.7 chs }
211 1.7 chs
212 1.7 chs int
213 1.7 chs secpolicy_xvattr(vnode_t *vp, xvattr_t *xvap, uid_t owner, cred_t *cred, vtype_t vtype)
214 1.1 haad {
215 1.4 riastrad
216 1.4 riastrad return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL);
217 1.1 haad }
218 1.1 haad
219 1.1 haad int
220 1.7 chs secpolicy_vnode_setid_retain(vnode_t *vp, cred_t *cred, boolean_t issuidroot __unused)
221 1.1 haad {
222 1.1 haad
223 1.4 riastrad return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL);
224 1.1 haad }
225 1.1 haad
226 1.1 haad int
227 1.7 chs secpolicy_vnode_setids_setgids(vnode_t *vp, cred_t *cred, gid_t gid)
228 1.1 haad {
229 1.1 haad
230 1.4 riastrad if (groupmember(gid, cred))
231 1.4 riastrad return (0);
232 1.4 riastrad
233 1.4 riastrad return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL);
234 1.1 haad }
235 1.1 haad
236 1.1 haad int
237 1.7 chs secpolicy_vnode_chown(vnode_t *vp, cred_t *cred, uid_t owner)
238 1.1 haad {
239 1.1 haad
240 1.4 riastrad return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL);
241 1.1 haad }
242 1.1 haad
243 1.1 haad int
244 1.7 chs secpolicy_vnode_create_gid(cred_t *cred)
245 1.1 haad {
246 1.1 haad
247 1.4 riastrad return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL);
248 1.1 haad }
249 1.1 haad
250 1.6 riastrad int
251 1.7 chs secpolicy_vnode_utime_modify(cred_t *cred)
252 1.5 riastrad {
253 1.5 riastrad
254 1.5 riastrad return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL);
255 1.5 riastrad }
256 1.5 riastrad
257 1.1 haad int
258 1.7 chs secpolicy_vnode_setdac(vnode_t *vp, cred_t *cred, uid_t owner)
259 1.1 haad {
260 1.1 haad
261 1.4 riastrad if (owner == kauth_cred_getuid(cred))
262 1.4 riastrad return (0);
263 1.4 riastrad
264 1.4 riastrad return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL);
265 1.1 haad }
266 1.1 haad
267 1.1 haad int
268 1.7 chs secpolicy_setid_setsticky_clear(vnode_t *vp, struct vattr *vap,
269 1.7 chs const struct vattr *ovap, cred_t *cred)
270 1.1 haad {
271 1.1 haad /*
272 1.1 haad * Privileged processes may set the sticky bit on non-directories,
273 1.1 haad * as well as set the setgid bit on a file with a group that the process
274 1.1 haad * is not a member of. Both of these are allowed in jail(8).
275 1.1 haad */
276 1.1 haad if (vp->v_type != VDIR && (vap->va_mode & S_ISTXT)) {
277 1.4 riastrad if (kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL))
278 1.1 haad return (EFTYPE);
279 1.1 haad }
280 1.1 haad /*
281 1.1 haad * Check for privilege if attempting to set the
282 1.1 haad * group-id bit.
283 1.1 haad */
284 1.1 haad if ((vap->va_mode & S_ISGID) != 0)
285 1.7 chs return (secpolicy_vnode_setids_setgids(vp, cred, ovap->va_gid));
286 1.4 riastrad
287 1.1 haad return (0);
288 1.1 haad }
289 1.1 haad
290 1.4 riastrad /*
291 1.4 riastrad * XXX Copied from illumos. Should not be here; should be under
292 1.4 riastrad * external/cddl/osnet/dist. Not sure why it is even in illumos's
293 1.4 riastrad * policy.c rather than somewhere in vnode.c or something.
294 1.4 riastrad */
295 1.1 haad int
296 1.7 chs secpolicy_vnode_setattr(cred_t *cred, vnode_t *vp, struct vattr *vap,
297 1.1 haad const struct vattr *ovap, int flags,
298 1.7 chs int unlocked_access(void *, int, cred_t *), void *node)
299 1.1 haad {
300 1.4 riastrad int mask = vap->va_mask;
301 1.4 riastrad int error = 0;
302 1.4 riastrad boolean_t skipaclchk = (flags & ATTR_NOACLCHECK) ? B_TRUE : B_FALSE;
303 1.1 haad
304 1.4 riastrad if (mask & AT_SIZE) {
305 1.4 riastrad if (vp->v_type == VDIR) {
306 1.4 riastrad error = EISDIR;
307 1.4 riastrad goto out;
308 1.4 riastrad }
309 1.4 riastrad
310 1.4 riastrad /*
311 1.4 riastrad * If ATTR_NOACLCHECK is set in the flags, then we don't
312 1.4 riastrad * perform the secondary unlocked_access() call since the
313 1.4 riastrad * ACL (if any) is being checked there.
314 1.4 riastrad */
315 1.4 riastrad if (skipaclchk == B_FALSE) {
316 1.4 riastrad error = unlocked_access(node, VWRITE, cred);
317 1.4 riastrad if (error)
318 1.4 riastrad goto out;
319 1.4 riastrad }
320 1.4 riastrad }
321 1.4 riastrad if (mask & AT_MODE) {
322 1.4 riastrad /*
323 1.4 riastrad * If not the owner of the file then check privilege
324 1.4 riastrad * for two things: the privilege to set the mode at all
325 1.4 riastrad * and, if we're setting setuid, we also need permissions
326 1.4 riastrad * to add the set-uid bit, if we're not the owner.
327 1.4 riastrad * In the specific case of creating a set-uid root
328 1.4 riastrad * file, we need even more permissions.
329 1.4 riastrad */
330 1.7 chs if ((error = secpolicy_vnode_setdac(vp, cred, ovap->va_uid)) != 0)
331 1.4 riastrad goto out;
332 1.4 riastrad
333 1.4 riastrad if ((error = secpolicy_setid_setsticky_clear(vp, vap,
334 1.4 riastrad ovap, cred)) != 0)
335 1.4 riastrad goto out;
336 1.4 riastrad } else
337 1.4 riastrad vap->va_mode = ovap->va_mode;
338 1.4 riastrad
339 1.4 riastrad if (mask & (AT_UID|AT_GID)) {
340 1.4 riastrad boolean_t checkpriv = B_FALSE;
341 1.4 riastrad
342 1.4 riastrad /*
343 1.4 riastrad * Chowning files.
344 1.4 riastrad *
345 1.4 riastrad * If you are the file owner:
346 1.4 riastrad * chown to other uid FILE_CHOWN_SELF
347 1.4 riastrad * chown to gid (non-member) FILE_CHOWN_SELF
348 1.4 riastrad * chown to gid (member) <none>
349 1.4 riastrad *
350 1.4 riastrad * Instead of PRIV_FILE_CHOWN_SELF, FILE_CHOWN is also
351 1.4 riastrad * acceptable but the first one is reported when debugging.
352 1.4 riastrad *
353 1.4 riastrad * If you are not the file owner:
354 1.4 riastrad * chown from root PRIV_FILE_CHOWN + zone
355 1.4 riastrad * chown from other to any PRIV_FILE_CHOWN
356 1.4 riastrad *
357 1.4 riastrad */
358 1.4 riastrad if (kauth_cred_getuid(cred) != ovap->va_uid) {
359 1.4 riastrad checkpriv = B_TRUE;
360 1.4 riastrad } else {
361 1.4 riastrad if (((mask & AT_UID) && vap->va_uid != ovap->va_uid) ||
362 1.4 riastrad ((mask & AT_GID) && vap->va_gid != ovap->va_gid &&
363 1.4 riastrad !groupmember(vap->va_gid, cred))) {
364 1.4 riastrad checkpriv = B_TRUE;
365 1.4 riastrad }
366 1.4 riastrad }
367 1.4 riastrad /*
368 1.4 riastrad * If necessary, check privilege to see if update can be done.
369 1.4 riastrad */
370 1.4 riastrad if (checkpriv &&
371 1.7 chs (error = secpolicy_vnode_chown(vp, cred, ovap->va_uid)) != 0) {
372 1.4 riastrad goto out;
373 1.4 riastrad }
374 1.4 riastrad
375 1.4 riastrad /*
376 1.4 riastrad * If the file has either the set UID or set GID bits
377 1.4 riastrad * set and the caller can set the bits, then leave them.
378 1.4 riastrad */
379 1.7 chs secpolicy_setid_clear(vap, vp, cred);
380 1.4 riastrad }
381 1.4 riastrad if (mask & (AT_ATIME|AT_MTIME)) {
382 1.4 riastrad /*
383 1.4 riastrad * If not the file owner and not otherwise privileged,
384 1.4 riastrad * always return an error when setting the
385 1.4 riastrad * time other than the current (ATTR_UTIME flag set).
386 1.4 riastrad * If setting the current time (ATTR_UTIME not set) then
387 1.4 riastrad * unlocked_access will check permissions according to policy.
388 1.4 riastrad */
389 1.4 riastrad if (kauth_cred_getuid(cred) != ovap->va_uid) {
390 1.4 riastrad if (flags & ATTR_UTIME)
391 1.4 riastrad error = secpolicy_vnode_utime_modify(cred);
392 1.4 riastrad else if (skipaclchk == B_FALSE) {
393 1.4 riastrad error = unlocked_access(node, VWRITE, cred);
394 1.4 riastrad if (error == EACCES &&
395 1.4 riastrad secpolicy_vnode_utime_modify(cred) == 0)
396 1.4 riastrad error = 0;
397 1.4 riastrad }
398 1.4 riastrad if (error)
399 1.4 riastrad goto out;
400 1.4 riastrad }
401 1.4 riastrad }
402 1.4 riastrad
403 1.4 riastrad /*
404 1.4 riastrad * Check for optional attributes here by checking the following:
405 1.4 riastrad */
406 1.4 riastrad if (mask & AT_XVATTR)
407 1.7 chs error = secpolicy_xvattr(vp, (xvattr_t *)vap, ovap->va_uid,
408 1.7 chs cred, vp->v_type);
409 1.4 riastrad out:
410 1.4 riastrad return (error);
411 1.1 haad }
412 1.1 haad
413 1.1 haad void
414 1.7 chs secpolicy_setid_clear(struct vattr *vap, vnode_t *vp, cred_t *cred)
415 1.1 haad {
416 1.1 haad if (kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL) != 0)
417 1.1 haad return;
418 1.1 haad
419 1.1 haad if ((vap->va_mode & (S_ISUID | S_ISGID)) != 0) {
420 1.4 riastrad vap->va_mask |= AT_MODE;
421 1.4 riastrad vap->va_mode &= ~(S_ISUID|S_ISGID);
422 1.1 haad }
423 1.4 riastrad
424 1.1 haad return;
425 1.1 haad }
426 1.1 haad
427 1.1 haad int
428 1.7 chs secpolicy_smb(cred_t *cr)
429 1.1 haad {
430 1.1 haad
431 1.7 chs return kauth_authorize_generic(cr, KAUTH_GENERIC_ISSUSER, NULL);
432 1.1 haad }
433 1.1 haad
434 1.1 haad void
435 1.7 chs secpolicy_fs_mount_clearopts(cred_t *cr, struct mount *vfsp)
436 1.1 haad {
437 1.1 haad
438 1.7 chs printf("%s writeme\n", __func__);
439 1.1 haad }
440