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