/* $NetBSD: policy.c,v 1.7.4.1 2020/08/28 18:17:13 martin Exp $ */ /*- * Copyright (c) 2009 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Andrew Doran. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /*- * Copyright (c) 2007 Pawel Jakub Dawidek * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright 2012, Joyent, Inc. All rights reserved. */ #include #include #include #include #include int secpolicy_nfs(cred_t *cr) { return kauth_authorize_generic(cr, KAUTH_GENERIC_ISSUSER, NULL); } int secpolicy_zfs(cred_t *cred) { return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL); } int secpolicy_sys_config(cred_t *cred, int checkonly __unused) { return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL); } int secpolicy_zinject(cred_t *cred) { return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL); } int secpolicy_fs_mount(cred_t *cred, vnode_t *mvp, struct mount *vfsp) { return kauth_authorize_system(cred, KAUTH_SYSTEM_MOUNT, KAUTH_REQ_SYSTEM_MOUNT_NEW, mvp, KAUTH_ARG(vfsp->mnt_flag), NULL); } int secpolicy_fs_unmount(cred_t *cred, struct mount *vfsp) { return kauth_authorize_system(cred, KAUTH_SYSTEM_MOUNT, KAUTH_REQ_SYSTEM_MOUNT_UNMOUNT, vfsp, NULL, NULL); } int secpolicy_fs_owner(struct mount *mp, cred_t *cr) { return (EPERM); } /* * This check is done in kern_link(), so we could just return 0 here. */ int secpolicy_basic_link(vnode_t *vp, cred_t *cred) { return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL); } int secpolicy_vnode_stky_modify(cred_t *cred) { return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL); } int secpolicy_vnode_remove(vnode_t *vp, cred_t *cred) { return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL); } int secpolicy_vnode_owner(vnode_t *vp, cred_t *cred, uid_t owner) { if (owner == kauth_cred_getuid(cred)) return (0); if (secpolicy_fs_owner(vp->v_mount, cred) == 0) return (0); return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL); } int secpolicy_vnode_access(cred_t *cred, vnode_t *vp, uid_t owner, int mode) { return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL); } /* * Like secpolicy_vnode_access() but we get the actual wanted mode and the * current mode of the file, not the missing bits. */ int secpolicy_vnode_access2(cred_t *cr, vnode_t *vp, uid_t owner, accmode_t curmode, accmode_t wantmode) { accmode_t mode; mode = ~curmode & wantmode; if (mode == 0) return (0); return (secpolicy_vnode_access(cr, vp, owner, mode)); } int secpolicy_vnode_any_access(cred_t *cr, vnode_t *vp, uid_t owner) { return kauth_authorize_generic(cr, KAUTH_GENERIC_ISSUSER, NULL); } int secpolicy_xvattr(vnode_t *vp, xvattr_t *xvap, uid_t owner, cred_t *cred, vtype_t vtype) { return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL); } int secpolicy_vnode_setid_retain(vnode_t *vp, cred_t *cred, boolean_t issuidroot __unused) { return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL); } int secpolicy_vnode_setids_setgids(vnode_t *vp, cred_t *cred, gid_t gid) { if (groupmember(gid, cred)) return (0); return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL); } int secpolicy_vnode_chown(vnode_t *vp, cred_t *cred, uid_t owner) { return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL); } int secpolicy_vnode_create_gid(cred_t *cred) { return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL); } int secpolicy_vnode_utime_modify(cred_t *cred) { return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL); } int secpolicy_vnode_setdac(vnode_t *vp, cred_t *cred, uid_t owner) { if (owner == kauth_cred_getuid(cred)) return (0); return kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL); } int secpolicy_setid_setsticky_clear(vnode_t *vp, struct vattr *vap, const struct vattr *ovap, cred_t *cred) { /* * Privileged processes may set the sticky bit on non-directories, * as well as set the setgid bit on a file with a group that the process * is not a member of. Both of these are allowed in jail(8). */ if (vp->v_type != VDIR && (vap->va_mode & S_ISTXT)) { if (kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL)) return (EFTYPE); } /* * Check for privilege if attempting to set the * group-id bit. */ if ((vap->va_mode & S_ISGID) != 0) return (secpolicy_vnode_setids_setgids(vp, cred, ovap->va_gid)); return (0); } /* * XXX Copied from illumos. Should not be here; should be under * external/cddl/osnet/dist. Not sure why it is even in illumos's * policy.c rather than somewhere in vnode.c or something. */ int secpolicy_vnode_setattr(cred_t *cred, vnode_t *vp, struct vattr *vap, const struct vattr *ovap, int flags, int unlocked_access(void *, int, cred_t *), void *node) { int mask = vap->va_mask; int error = 0; boolean_t skipaclchk = (flags & ATTR_NOACLCHECK) ? B_TRUE : B_FALSE; if (mask & AT_SIZE) { if (vp->v_type == VDIR) { error = EISDIR; goto out; } /* * If ATTR_NOACLCHECK is set in the flags, then we don't * perform the secondary unlocked_access() call since the * ACL (if any) is being checked there. */ if (skipaclchk == B_FALSE) { error = unlocked_access(node, VWRITE, cred); if (error) goto out; } } if (mask & AT_MODE) { /* * If not the owner of the file then check privilege * for two things: the privilege to set the mode at all * and, if we're setting setuid, we also need permissions * to add the set-uid bit, if we're not the owner. * In the specific case of creating a set-uid root * file, we need even more permissions. */ if ((error = secpolicy_vnode_setdac(vp, cred, ovap->va_uid)) != 0) goto out; if ((error = secpolicy_setid_setsticky_clear(vp, vap, ovap, cred)) != 0) goto out; } else vap->va_mode = ovap->va_mode; if (mask & (AT_UID|AT_GID)) { boolean_t checkpriv = B_FALSE; /* * Chowning files. * * If you are the file owner: * chown to other uid FILE_CHOWN_SELF * chown to gid (non-member) FILE_CHOWN_SELF * chown to gid (member) * * Instead of PRIV_FILE_CHOWN_SELF, FILE_CHOWN is also * acceptable but the first one is reported when debugging. * * If you are not the file owner: * chown from root PRIV_FILE_CHOWN + zone * chown from other to any PRIV_FILE_CHOWN * */ if (kauth_cred_getuid(cred) != ovap->va_uid) { checkpriv = B_TRUE; } else { if (((mask & AT_UID) && vap->va_uid != ovap->va_uid) || ((mask & AT_GID) && vap->va_gid != ovap->va_gid && !groupmember(vap->va_gid, cred))) { checkpriv = B_TRUE; } } /* * If necessary, check privilege to see if update can be done. */ if (checkpriv && (error = secpolicy_vnode_chown(vp, cred, ovap->va_uid)) != 0) { goto out; } /* * If the file has either the set UID or set GID bits * set and the caller can set the bits, then leave them. */ secpolicy_setid_clear(vap, vp, cred); } if (mask & (AT_ATIME|AT_MTIME)) { /* * If not the file owner and not otherwise privileged, * always return an error when setting the * time other than the current (ATTR_UTIME flag set). * If setting the current time (ATTR_UTIME not set) then * unlocked_access will check permissions according to policy. */ if (kauth_cred_getuid(cred) != ovap->va_uid) { if (flags & ATTR_UTIME) error = secpolicy_vnode_utime_modify(cred); else if (skipaclchk == B_FALSE) { error = unlocked_access(node, VWRITE, cred); if (error == EACCES && secpolicy_vnode_utime_modify(cred) == 0) error = 0; } if (error) goto out; } } /* * Check for optional attributes here by checking the following: */ if (mask & AT_XVATTR) error = secpolicy_xvattr(vp, (xvattr_t *)vap, ovap->va_uid, cred, vp->v_type); out: return (error); } void secpolicy_setid_clear(struct vattr *vap, vnode_t *vp, cred_t *cred) { if (kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL) != 0) return; if ((vap->va_mode & (S_ISUID | S_ISGID)) != 0) { vap->va_mask |= AT_MODE; vap->va_mode &= ~(S_ISUID|S_ISGID); } return; } int secpolicy_smb(cred_t *cr) { return kauth_authorize_generic(cr, KAUTH_GENERIC_ISSUSER, NULL); } void secpolicy_fs_mount_clearopts(cred_t *cr, struct mount *vfsp) { printf("%s writeme\n", __func__); }