/*
 * Copyright (c) 2023 The DragonFly Project.  All rights reserved.
 *
 * This code is derived from software contributed to The DragonFly Project
 * by Matthew Dillon <dillon@backplane.com>
 *
 * 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.
 * 3. Neither the name of The DragonFly Project nor the names of its
 *    contributors may be used to endorse or promote products derived
 *    from this software without specific, prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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
 * COPYRIGHT HOLDERS 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.
 */
#ifndef _SYS_CAPS_H_
#define	_SYS_CAPS_H_

#ifndef _MACHINE_STDINT_H_
#include <machine/stdint.h>
#endif

/*
 * NOTE: 2 bits per system capability.  System capabilities are negatives,
 *	 i.e. restrictions, rather than allowances.
 */
typedef __uint64_t		__syscapelm_t;

#define __SYSCAP_EXECMASK	((__syscapelm_t)0xAAAAAAAAAAAAAAAALLU)

#define __SYSCAP_COUNT		256
#define __SYSCAP_BITS_PER	2
#define __SYSCAP_BITS_MASK	((1 << __SYSCAP_BITS_PER) - 1)
#define __SYSCAP_PER_ELM	(sizeof(__syscapelm_t) * 8 / __SYSCAP_BITS_PER)
#define __SYSCAP_PER_ELM_MASK	(__SYSCAP_PER_ELM - 1)
#define __SYSCAP_NUMELMS	(__SYSCAP_COUNT / __SYSCAP_PER_ELM)

#define __SYSCAP_INDEX(cap)	((cap) / __SYSCAP_PER_ELM)
#define __SYSCAP_SHIFT(cap)	(((cap) & __SYSCAP_PER_ELM_MASK) *	\
				 __SYSCAP_BITS_PER)


typedef struct syscaps {
	__syscapelm_t	caps[__SYSCAP_NUMELMS];
} __syscaps_t;

/*
 * Resource data passed to/from userland
 */
typedef struct syscap_base {
	size_t		res;	/* resource type, EOF ends list */
	size_t		len;	/* total bytes including this header */
} syscap_base_t;

#define SYSCAP_RESOURCE_EOF	0x0000

#if 0
/* TODO / DISCUSS */
#define SYSCAP_RESOURCE_PATH	0x0001		/* allowed wildcard paths */
#endif

/*
 * Restriction application.  Restrictions applied to EXEC or ALL are inherited
 * by children recursively.  A restriction that only applies to SELF is not
 * inherited by children.
 *
 * Restrictions cannot be downgraded once applied (this is a feature).
 * The syscap_set() operation is a logical OR.
 */
#define __SYSCAP_NONE		0x00000000	/* no restriction */
#define __SYSCAP_SELF		0x00000001	/* restrict for us */
#define __SYSCAP_EXEC		0x00000002	/* restrict for execs */
#define __SYSCAP_ALL		0x00000003	/* restrict for us and fork */

#define __SYSCAP_XFLAGS		0x7FFF0000	/* extra flags (in 'cap') */
#define __SYSCAP_INPARENT	0x00010000	/* set in parent process */
#define __SYSCAP_NULLCRED	0x00020000	/* null cred ok */
#define __SYSCAP_NOROOTTEST	0x00040000	/* don't test uid */
#define __SYSCAP_WHEELOK	0x00080000	/* don't test uid if wheel */

#define __SYSCAP_GROUP_0	0x00000000
#define __SYSCAP_GROUP_1	0x00000010
#define __SYSCAP_GROUP_2	0x00000020
#define __SYSCAP_GROUP_3	0x00000030
#define __SYSCAP_GROUP_4	0x00000040
#define __SYSCAP_GROUP_5	0x00000050
#define __SYSCAP_GROUP_6	0x00000060
#define __SYSCAP_GROUP_7	0x00000070
#define __SYSCAP_GROUP_8	0x00000080
#define __SYSCAP_GROUP_9	0x00000090
#define __SYSCAP_GROUP_10	0x000000A0
#define __SYSCAP_GROUP_11	0x000000B0
#define __SYSCAP_GROUP_12	0x000000C0
#define __SYSCAP_GROUP_13	0x000000D0
#define __SYSCAP_GROUP_14	0x000000E0
#define __SYSCAP_GROUP_15	0x000000F0

#define __SYSCAP_GROUP_MASK	0x000000F0
#define __SYSCAP_GROUP_SHIFT	4

/*
 * Base capability restrictions.  Group 0 can be used to disable the whole
 * of any other group 1...15.
 *
 * RESTRICTEDROOT	- Catch-all for dangerous root interactions,
 *			  always disabled by jails and also automatically
 *			  disabled upon chroot.
 *
 * SENSITIVEROOT	- Catch-all for sensitive root operations such as
 *			  mount, umount, ifconfig, and so forth, some of
 *			  which might be enabled in jails.
 */
#define SYSCAP_ANY		(__SYSCAP_GROUP_0 | 0)
#define SYSCAP_RESTRICTEDROOT	(__SYSCAP_GROUP_0 | 1)
#define SYSCAP_SENSITIVEROOT	(__SYSCAP_GROUP_0 | 2)
#define SYSCAP_NOEXEC		(__SYSCAP_GROUP_0 | 3)
#define SYSCAP_NOCRED		(__SYSCAP_GROUP_0 | 4)
#define SYSCAP_NOJAIL		(__SYSCAP_GROUP_0 | 5)
#define SYSCAP_NONET		(__SYSCAP_GROUP_0 | 6)
#define SYSCAP_NONET_SENSITIVE	(__SYSCAP_GROUP_0 | 7)
#define SYSCAP_NOVFS		(__SYSCAP_GROUP_0 | 8)
#define SYSCAP_NOVFS_SENSITIVE	(__SYSCAP_GROUP_0 | 9)
#define SYSCAP_NOMOUNT		(__SYSCAP_GROUP_0 | 10)
#define SYSCAP_NO11		(__SYSCAP_GROUP_0 | 11)
#define SYSCAP_NO12		(__SYSCAP_GROUP_0 | 12)
#define SYSCAP_NO13		(__SYSCAP_GROUP_0 | 13)
#define SYSCAP_NO14		(__SYSCAP_GROUP_0 | 14)
#define SYSCAP_NO15		(__SYSCAP_GROUP_0 | 15)

/*
 * Automatic if SYSCAP_RESTRICTEDROOT is set
 *
 * reboot includes shutdown
 */
#define SYSCAP_NODRIVER		(__SYSCAP_GROUP_1 | 0)
#define SYSCAP_NOVM_MLOCK	(__SYSCAP_GROUP_1 | 1)
#define SYSCAP_NOVM_RESIDENT	(__SYSCAP_GROUP_1 | 2)
#define SYSCAP_NOCPUCTL_WRMSR	(__SYSCAP_GROUP_1 | 3)
#define SYSCAP_NOCPUCTL_UPDATE	(__SYSCAP_GROUP_1 | 4)
#define SYSCAP_NOACCT		(__SYSCAP_GROUP_1 | 5)
#define SYSCAP_NOKENV_WR	(__SYSCAP_GROUP_1 | 6)
#define SYSCAP_NOKLD		(__SYSCAP_GROUP_1 | 7)
#define SYSCAP_NOKERN_WR	(__SYSCAP_GROUP_1 | 8)
#define SYSCAP_NOREBOOT		(__SYSCAP_GROUP_1 | 9)

/*
 * Automatic if SYSCAP_SENSITIVEROOT is set
 */
#define SYSCAP_NOPROC_TRESPASS	(__SYSCAP_GROUP_2 | 0)
#define SYSCAP_NOPROC_SETLOGIN	(__SYSCAP_GROUP_2 | 1)
#define SYSCAP_NOPROC_SETRLIMIT	(__SYSCAP_GROUP_2 | 2)
#define SYSCAP_NOSYSCTL_WR	(__SYSCAP_GROUP_2 | 3)
#define SYSCAP_NOVARSYM_SYS	(__SYSCAP_GROUP_2 | 4)
#define SYSCAP_NOSETHOSTNAME	(__SYSCAP_GROUP_2 | 5)
#define SYSCAP_NOQUOTA_WR	(__SYSCAP_GROUP_2 | 6)
#define SYSCAP_NODEBUG_UNPRIV	(__SYSCAP_GROUP_2 | 7)
#define SYSCAP_NOSETTIME	(__SYSCAP_GROUP_2 | 8)
#define SYSCAP_NOSCHED		(__SYSCAP_GROUP_2 | 9)
#define SYSCAP_NOSCHED_CPUSET	(__SYSCAP_GROUP_2 | 10)

#define SYSCAP_NOEXEC_SUID	(__SYSCAP_GROUP_3 | 0)
#define SYSCAP_NOEXEC_SGID	(__SYSCAP_GROUP_3 | 1)

#define SYSCAP_NOCRED_SETUID	(__SYSCAP_GROUP_4 | 0)
#define SYSCAP_NOCRED_SETGID	(__SYSCAP_GROUP_4 | 1)
#define SYSCAP_NOCRED_SETEUID	(__SYSCAP_GROUP_4 | 2)
#define SYSCAP_NOCRED_SETEGID	(__SYSCAP_GROUP_4 | 3)
#define SYSCAP_NOCRED_SETREUID	(__SYSCAP_GROUP_4 | 4)
#define SYSCAP_NOCRED_SETREGID	(__SYSCAP_GROUP_4 | 5)
#define SYSCAP_NOCRED_SETRESUID	(__SYSCAP_GROUP_4 | 6)
#define SYSCAP_NOCRED_SETRESGID	(__SYSCAP_GROUP_4 | 7)
#define SYSCAP_NOCRED_SETGROUPS	(__SYSCAP_GROUP_4 | 8)

#define SYSCAP_NOJAIL_CREATE	(__SYSCAP_GROUP_5 | 0)
#define SYSCAP_NOJAIL_ATTACH	(__SYSCAP_GROUP_5 | 1)

#define SYSCAP_NONET_RESPORT	(__SYSCAP_GROUP_6 | 0)
#define SYSCAP_NONET_RAW	(__SYSCAP_GROUP_6 | 1)

#define SYSCAP_NONET_IFCONFIG	(__SYSCAP_GROUP_7 | 0)	/* sensitive NET */
#define SYSCAP_NONET_ROUTE	(__SYSCAP_GROUP_7 | 1)
#define SYSCAP_NONET_LAGG	(__SYSCAP_GROUP_7 | 2)
#define SYSCAP_NONET_NETGRAPH	(__SYSCAP_GROUP_7 | 3)
#define SYSCAP_NONET_BT_RAW	(__SYSCAP_GROUP_7 | 4)
#define SYSCAP_NONET_WIFI	(__SYSCAP_GROUP_7 | 5)

#define SYSCAP_NOVFS_SYSFLAGS	(__SYSCAP_GROUP_8 | 0)
#define SYSCAP_NOVFS_CHOWN	(__SYSCAP_GROUP_8 | 1)
#define SYSCAP_NOVFS_CHMOD	(__SYSCAP_GROUP_8 | 2)
#define SYSCAP_NOVFS_LINK	(__SYSCAP_GROUP_8 | 3)
#define SYSCAP_NOVFS_CHFLAGS_DEV (__SYSCAP_GROUP_8 | 4)
#define SYSCAP_NOVFS_SETATTR	(__SYSCAP_GROUP_8 | 5)
#define SYSCAP_NOVFS_SETGID	(__SYSCAP_GROUP_8 | 6)
#define SYSCAP_NOVFS_GENERATION	(__SYSCAP_GROUP_8 | 7)
#define SYSCAP_NOVFS_RETAINSUGID (__SYSCAP_GROUP_8 | 8)

#define SYSCAP_NOVFS_MKNOD_BAD	(__SYSCAP_GROUP_9 | 0)	/* sensitive VFS */
#define SYSCAP_NOVFS_MKNOD_WHT	(__SYSCAP_GROUP_9 | 1)
#define SYSCAP_NOVFS_MKNOD_DIR	(__SYSCAP_GROUP_9 | 2)
#define SYSCAP_NOVFS_MKNOD_DEV	(__SYSCAP_GROUP_9 | 3)
#define SYSCAP_NOVFS_IOCTL	(__SYSCAP_GROUP_9 | 4)	/* sensitive ioctls */
#define SYSCAP_NOVFS_CHROOT	(__SYSCAP_GROUP_9 | 5)
#define SYSCAP_NOVFS_REVOKE	(__SYSCAP_GROUP_9 | 6)

#define SYSCAP_NOMOUNT_NULLFS	(__SYSCAP_GROUP_10 | 0)
#define SYSCAP_NOMOUNT_DEVFS	(__SYSCAP_GROUP_10 | 1)
#define SYSCAP_NOMOUNT_TMPFS	(__SYSCAP_GROUP_10 | 2)
#define SYSCAP_NOMOUNT_UMOUNT	(__SYSCAP_GROUP_10 | 3)
#define SYSCAP_NOMOUNT_FUSE	(__SYSCAP_GROUP_10 | 4)
#define SYSCAP_NOMOUNT_PROCFS	(__SYSCAP_GROUP_10 | 5)

#if 0
/* TODO/DISCUSS */

#define SYSCAP_NOBIND		8
#define SYSCAP_NOLISTEN		9
#define SYSCAP_NOACCEPT		10
#define SYSCAP_NOCONNECT	11

#define SYSCAP_NOFILE_UIDR	16	/* restrict uid match to (list) */
#define SYSCAP_NOFILE_UIDW	17	/* restrict uid match to (list) */
#define SYSCAP_NOFILE_UIDX	18	/* restrict uid match to (list) */
#define SYSCAP_NOFILE_GIDR	19	/* restrict gid match to (list) */
#define SYSCAP_NOFILE_GIDW	20	/* restrict gid match to (list) */
#define SYSCAP_NOFILE_GIDX	21	/* restrict gid match to (list) */
#define SYSCAP_NOFILE_OIDR	22	/* restrict catch-all to (list) */
#define SYSCAP_NOFILE_OIDW	23	/* restrict catch-all to (list) */
#define SYSCAP_NOFILE_OIDX	24	/* restrict catch-all to (list) */
#endif

#define __SYSCAP_STRINGS_0		\
		"any",			\
		"restricted_root",	\
		"sensitive_root",	\
		"noexec",		\
		"nocred",		\
		"nojail",		\
		"nonet",		\
		"nonet_sensitive",	\
		"novfs",		\
		"novfs_sensitive",	\
		"nomount"

#define __SYSCAP_STRINGS_1		\
		"nodriver",		\
		"novm_mlock",		\
		"novm_resident",	\
		"nocpuctl_wrmsr",	\
		"nocpuctl_update",	\
		"noacct",		\
		"nokenv_wr",		\
		"nokld",		\
		"nokern_wr",		\
		"noreboot"

#define __SYSCAP_STRINGS_2		\
		"noproc_trespass",	\
		"noproc_setlogin",	\
		"noproc_setrlimit",	\
		"nosysctl_wr",		\
		"novarsym_sys",		\
		"nosethostname",	\
		"noquota_wr",		\
		"nodebug_unpriv",	\
		"nosettime",		\
		"nosched",		\
		"nosched_cpuset"

#define __SYSCAP_STRINGS_3		\
		"noexec_suid",		\
		"noexec_sgid"

#define __SYSCAP_STRINGS_4		\
		"nocred_setuid",	\
		"nocred_setgid",	\
		"nocred_seteuid",	\
		"nocred_setegid",	\
		"nocred_setreuid",	\
		"nocred_setregid",	\
		"nocred_setresuid",	\
		"nocred_setresgid",	\
		"nocred_setgroups"

#define __SYSCAP_STRINGS_5		\
		"nojail_create",	\
		"nojail_attach"

#define __SYSCAP_STRINGS_6		\
		"nonet_resport",	\
		"nonet_raw"

#define __SYSCAP_STRINGS_7		\
		"nonet_ifconfig",	\
		"nonet_route",		\
		"nonet_lagg",		\
		"nonet_netgraph",	\
		"nonet_bt_raw",		\
		"nonet_wifi"

#define __SYSCAP_STRINGS_8		\
		"novfs_sysflags",	\
		"novfs_chown",		\
		"novfs_chmod",		\
		"novfs_chroot",		\
		"novfs_link",		\
		"novfs_chflags_dev",	\
		"novfs_revoke",		\
		"novfs_setattr",	\
		"novfs_setgid",		\
		"novfs_generation",	\
		"novfs_retainsugid"

#define __SYSCAP_STRINGS_9		\
		"novfs_mknod_bad",	\
		"novfs_mknod_wht",	\
		"novfs_mknod_dir",	\
		"novfs_mknod_dev",	\
		"novfs_ioct"

#define __SYSCAP_STRINGS_10		\
		"nomount_nullfs",	\
		"nomount_devfs",	\
		"nomount_tmpfs",	\
		"nomount_umount",	\
		"nomount_fuse"

#define __SYSCAP_ALLSTRINGS					\
	const char *SyscapAllStrings[__SYSCAP_COUNT/16][16] = {	\
		{ __SYSCAP_STRINGS_0 },				\
		{ __SYSCAP_STRINGS_1 },				\
		{ __SYSCAP_STRINGS_2 },				\
		{ __SYSCAP_STRINGS_3 },				\
		{ __SYSCAP_STRINGS_4 },				\
		{ __SYSCAP_STRINGS_5 },				\
		{ __SYSCAP_STRINGS_6 },				\
		{ __SYSCAP_STRINGS_7 },				\
		{ __SYSCAP_STRINGS_8 },				\
		{ __SYSCAP_STRINGS_9 },				\
		{ __SYSCAP_STRINGS_10 }				\
	}

/*
 * userland prototypes
 */
__BEGIN_DECLS
int syscap_get(int cap, void *data, size_t bytes);
int syscap_set(int cap, int flags, const void *data, size_t bytes);
__END_DECLS

/*
 * kern_caps.c support functions
 */
#ifdef _KERNEL

struct proc;
struct thread;
struct ucred;

void caps_exec(struct proc *p);
int caps_get(struct ucred *cred, int cap);
void caps_set_locked(struct proc *p, int cap, int flags);
int caps_priv_check(struct ucred *cred, int cap);
int caps_priv_check_self(int cap);
int caps_priv_check_td(struct thread *td, int cap);

#endif
#endif
