Index: contrib/amd/include/am_defs.h
===================================================================
RCS file: /home/ncvs/src/contrib/amd/include/am_defs.h,v
retrieving revision 1.8
diff -u -r1.8 am_defs.h
--- contrib/amd/include/am_defs.h	1999/11/05 11:58:03	1.8
+++ contrib/amd/include/am_defs.h	2000/04/12 17:04:20
@@ -445,6 +445,7 @@
  * Actions to take if <sys/ucred.h> exists.
  */
 #ifdef HAVE_SYS_UCRED_H
+#include <sys/capability.h>
 # include <sys/ucred.h>
 #endif /* HAVE_SYS_UCRED_H */
 
Index: include/rpcsvc/bootparam_prot.x
===================================================================
RCS file: /home/ncvs/src/include/rpcsvc/bootparam_prot.x,v
retrieving revision 1.5
diff -u -r1.5 bootparam_prot.x
--- include/rpcsvc/bootparam_prot.x	1999/08/27 23:45:07	1.5
+++ include/rpcsvc/bootparam_prot.x	2000/04/12 18:00:22
@@ -43,6 +43,7 @@
 %#include <sys/errno.h>
 %#include <sys/param.h>
 %#include <sys/syslimits.h>
+%#include <sys/capability.h>
 %#include <sys/ucred.h>
 #else
 %#ifndef lint
Index: lib/libc/gen/getmntinfo.c
===================================================================
RCS file: /home/ncvs/src/lib/libc/gen/getmntinfo.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 getmntinfo.c
--- lib/libc/gen/getmntinfo.c	1994/05/27 04:56:40	1.1.1.1
+++ lib/libc/gen/getmntinfo.c	2000/01/09 07:19:44
@@ -36,6 +36,7 @@
 #endif /* LIBC_SCCS and not lint */
 
 #include <sys/param.h>
+#include <sys/capability.h>
 #include <sys/ucred.h>
 #include <sys/mount.h>
 #include <stdlib.h>
Index: lib/libkvm/kvm_getswapinfo.c
===================================================================
RCS file: /home/ncvs/src/lib/libkvm/kvm_getswapinfo.c,v
retrieving revision 1.12
diff -u -r1.12 kvm_getswapinfo.c
--- lib/libkvm/kvm_getswapinfo.c	2000/04/16 17:36:48	1.12
+++ lib/libkvm/kvm_getswapinfo.c	2000/04/16 22:47:54
@@ -19,6 +19,7 @@
 
 #include <sys/param.h>
 #include <sys/time.h>
+#include <sys/capability.h>
 #include <sys/ucred.h>
 #include <sys/stat.h>
 #include <sys/conf.h>
Index: sys/coda/coda_namecache.c
===================================================================
RCS file: /home/ncvs/src/sys/coda/coda_namecache.c,v
retrieving revision 1.10
diff -u -r1.10 coda_namecache.c
--- sys/coda/coda_namecache.c	1999/08/28 00:40:53	1.10
+++ sys/coda/coda_namecache.c	2000/04/12 04:43:28
@@ -79,6 +79,7 @@
 #include <sys/param.h>
 #include <sys/errno.h>
 #include <sys/malloc.h>
+#include <sys/capability.h>
 #include <sys/ucred.h>
 #include <sys/select.h>
 
Index: sys/i386/conf/CAP
===================================================================
RCS file: CAP
diff -N CAP
--- /dev/null	Fri Sep  1 08:50:50 2000
+++ CAP	Mon Aug  7 18:37:51 2000
@@ -0,0 +1,234 @@
+#
+# GENERIC -- Generic kernel configuration file for FreeBSD/i386
+#
+# For more information on this file, please read the handbook section on
+# Kernel Configuration Files:
+#
+#    http://www.FreeBSD.org/handbook/kernelconfig-config.html
+#
+# The handbook is also available locally in /usr/share/doc/handbook
+# if you've installed the doc distribution, otherwise always see the
+# FreeBSD World Wide Web server (http://www.FreeBSD.org/) for the
+# latest information.
+#
+# An exhaustive list of options and more detailed explanations of the
+# device lines is also present in the NOTES configuration file. If you are
+# in doubt as to the purpose or necessity of a line, check first in NOTES.
+#
+# $FreeBSD: src/sys/i386/conf/GENERIC,v 1.269 2000/07/29 02:12:44 obrien Exp $
+
+machine		i386
+cpu		I386_CPU
+cpu		I486_CPU
+cpu		I586_CPU
+cpu		I686_CPU
+ident		GENERIC
+maxusers	32
+
+hints		"GENERIC.hints"		#Default places to look for devices.
+
+makeoptions	DEBUG=-g		#Build kernel with gdb(1) debug symbols
+options		DDB
+
+options 	MATH_EMULATE		#Support for x87 emulation
+options 	INET			#InterNETworking
+options 	INET6			#IPv6 communications protocols
+options 	FFS			#Berkeley Fast Filesystem
+options 	FFS_ROOT		#FFS usable as root device [keep this!]
+options		FFS_EXTATTR		#FFS extended attributes
+options 	SOFTUPDATES		#Enable FFS soft updates support
+options 	MFS			#Memory Filesystem
+options 	MD_ROOT			#MD is a potential root device
+options 	NFS			#Network Filesystem
+options 	NFS_ROOT		#NFS usable as root device, NFS required
+options 	MSDOSFS			#MSDOS Filesystem
+options 	CD9660			#ISO 9660 Filesystem
+options 	CD9660_ROOT		#CD-ROM usable as root, CD9660 required
+options 	PROCFS			#Process filesystem
+options 	COMPAT_43		#Compatible with BSD 4.3 [KEEP THIS!]
+options 	SCSI_DELAY=15000	#Delay (in ms) before probing SCSI
+options 	UCONSOLE		#Allow users to grab the console
+options 	USERCONFIG		#boot -c editor
+options 	VISUAL_USERCONFIG	#visual boot -c editor
+options 	KTRACE			#ktrace(1) support
+options 	SYSVSHM			#SYSV-style shared memory
+options 	SYSVMSG			#SYSV-style message queues
+options 	SYSVSEM			#SYSV-style semaphores
+options 	P1003_1B		#Posix P1003_1B real-time extensions
+options 	_KPOSIX_PRIORITY_SCHEDULING
+options 	KBD_INSTALL_CDEV	# install a CDEV entry in /dev
+options 	RANDOMDEV		#entropy device
+options		CAPABILITIES
+
+# To make an SMP kernel, the next two are needed
+#options 	SMP			# Symmetric MultiProcessor Kernel
+#options 	APIC_IO			# Symmetric (APIC) I/O
+# Optionally these may need tweaked, (defaults shown):
+#options 	NCPU=2			# number of CPUs
+#options 	NBUS=8			# number of busses
+#options 	NAPIC=1			# number of IO APICs
+#options 	NINTR=24		# number of INTs
+
+device		isa
+device		eisa
+device		pci
+options 	COMPAT_OLDISA		# compatability shims for lnc, fe, le
+options 	COMPAT_OLDPCI		# compatability shims for lnc, vx
+
+# Floppy drives
+device		fdc
+
+# ATA and ATAPI devices
+device		ata
+device		atadisk			# ATA disk drives
+device		atapicd			# ATAPI CDROM drives
+device		atapifd			# ATAPI floppy drives
+device		atapist			# ATAPI tape drives
+options 	ATA_STATIC_ID		#Static device numbering
+#options 	ATA_ENABLE_ATAPI_DMA	#Enable DMA on ATAPI devices
+
+# SCSI Controllers
+device		ahb		# EISA AHA1742 family
+device		ahc		# AHA2940 and onboard AIC7xxx devices
+device		amd		# AMD 53C974 (Teckram DC-390(T))
+device		dpt		# DPT Smartcache - See NOTES for options!
+device		isp		# Qlogic family
+#device		ncr		# NCR/Symbios Logic
+device		sym		# NCR/Symbios Logic (newer chipsets + those of `ncr')
+
+device		adv
+device		adw
+device		bt
+device		aha	1
+device		aic
+
+# SCSI peripherals
+device		scbus		# SCSI bus (required)
+device		da		# Direct Access (disks)
+device		sa		# Sequential Access (tape etc)
+device		cd		# CD
+device		pass		# Passthrough device (direct SCSI access)
+
+# RAID controllers
+device		ida		# Compaq Smart RAID
+device		amr		# AMI MegaRAID
+device		mlx		# Mylex DAC960 family
+
+# atkbdc0 controls both the keyboard and the PS/2 mouse
+device		atkbdc	1
+device		atkbd
+device		psm
+
+device		vga
+
+# splash screen/screen saver
+device		splash
+
+# syscons is the default console driver, resembling an SCO console
+device		sc	1
+
+# Enable this for the pcvt (VT220 compatible) console driver
+#device		vt
+#options 	XSERVER			# support for X server on a vt console
+#options 	FAT_CURSOR		# start with block cursor
+# If you have a ThinkPAD, uncomment this along with the rest of the PCVT lines
+#options 	PCVT_SCANSET=2		# IBM keyboards are non-std
+
+# Floating point support - do not disable.
+device		npx
+
+# Power management support (see NOTES for more options)
+device		apm
+
+# PCCARD (PCMCIA) support
+device		card
+device		pcic
+
+# Serial (COM) ports
+device		sio
+
+# Parallel port
+device		ppc
+device		ppbus		# Parallel port bus (required)
+device		lpt		# Printer
+device		plip		# TCP/IP over parallel
+device		ppi		# Parallel port interface device
+#device		vpo		# Requires scbus and da
+
+
+# PCI Ethernet NICs.
+device		de		# DEC/Intel DC21x4x (``Tulip'')
+device		fxp		# Intel EtherExpress PRO/100B (82557, 82558)
+device		tx		# SMC 9432TX (83c170 ``EPIC'')
+device		vx		# 3Com 3c590, 3c595 (``Vortex'')
+device		wx		# Intel Gigabit Ethernet Card (``Wiseman'')
+
+# PCI Ethernet NICs that use the common MII bus controller code.
+device		miibus		# MII bus support
+device		dc		# DEC/Intel 21143 and various workalikes
+device		rl		# RealTek 8129/8139
+device		sf		# Adaptec AIC-6915 (``Starfire'')
+device		sis		# Silicon Integrated Systems SiS 900/SiS 7016
+device		ste		# Sundance ST201 (D-Link DFE-550TX)
+device		tl		# Texas Instruments ThunderLAN
+device		vr		# VIA Rhine, Rhine II
+device		wb		# Winbond W89C840F
+device		xl		# 3Com 3c90x (``Boomerang'', ``Cyclone'')
+
+# ISA Ethernet NICs.
+device		ed
+device		ex
+device		ep
+device		cs
+device		sn
+# WaveLAN/IEEE 802.11 wireless NICs. Note: the WaveLAN/IEEE really
+# exists only as a PCMCIA device, so there is no ISA attatement needed
+# and resources will always be dynamically assigned by the pccard code.
+device		wi
+# Aironet 4500/4800 802.11 wireless NICs. Note: the declaration below will
+# work for PCMCIA and PCI cards, as well as ISA cards set to ISA PnP
+# mode (the factory default). If you set the switches on your ISA
+# card for a manually chosen I/O address and IRQ, you must specify
+# those paremeters here.
+device		an
+# BayStack 660 and others
+device		awi
+# Xircom pccard ethernet
+device		xe
+# The probe order of these is presently determined by i386/isa/isa_compat.c.
+device		ie
+device		fe
+device		le
+device		lnc
+
+# Pseudo devices - the number indicates how many units to allocated.
+device		loop		# Network loopback
+device		ether		# Ethernet support
+device		sl		# Kernel SLIP
+device		ppp	1	# Kernel PPP
+device		tun		# Packet tunnel.
+device		pty		# Pseudo-ttys (telnet etc)
+device		md		# Memory "disks"
+device		gif	4	# IPv6 and IPv4 tunneling
+device		faith	1	# IPv6-to-IPv4 relaying (translation)
+
+# The `bpf' device enables the Berkeley Packet Filter.
+# Be aware of the administrative consequences of enabling this!
+device		bpf		# Berkeley packet filter
+
+# USB support
+device		uhci		# UHCI PCI->USB interface
+device		ohci		# OHCI PCI->USB interface
+device		usb		# USB Bus (required)
+#device		udbp		# USB Double Bulk Pipe devices
+device		ugen		# Generic
+device		uhid		# "Human Interface Devices"
+device		ukbd		# Keyboard
+device		ulpt		# Printer
+device		umass		# Disks/Mass storage - Requires scbus and da
+device		ums		# Mouse
+device		urio		# Diamond Rio 500 MP3 player
+# USB Ethernet, requires mii
+device		aue		# ADMtek USB ethernet
+device		cue		# CATC USB ethernet
+device		kue		# Kawasaki LSI USB ethernet
Index: sys/kern/init_main.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/init_main.c,v
retrieving revision 1.139
diff -u -r1.139 init_main.c
--- sys/kern/init_main.c	2000/08/20 21:34:33	1.139
+++ sys/kern/init_main.c	2000/08/24 02:19:10
@@ -72,6 +72,7 @@
 #include <vm/vm_map.h>
 #include <sys/user.h>
 #include <sys/copyright.h>
+#include <sys/capability.h>
 
 extern struct linker_set	sysinit_set;	/* XXX */
 
@@ -306,6 +307,9 @@
 	p->p_ucred = crget();
 	p->p_ucred->cr_ngroups = 1;	/* group 0 */
 
+	/* Give all kernel processes many capabilities */
+	cap_init_proc0(&p->p_ucred->cr_cap);
+
 	/* Don't jail it */
 	p->p_prison = 0;
 
@@ -568,6 +572,13 @@
 	initproc->p_flag |= P_INMEM | P_SYSTEM;
 	cpu_set_fork_handler(initproc, start_init, NULL);
 	remrunqueue(initproc);
+
+	/*
+	 * Give init necessary capabilities to shut the system down and
+	 * avoid a panic when done.
+	 */
+	cap_init_proc1(&initproc->p_ucred->cr_cap);
+
 	splx(s);
 }
 SYSINIT(init,SI_SUB_CREATE_INIT, SI_ORDER_FIRST, create_init, NULL)
Index: sys/kern/kern_acct.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/kern_acct.c,v
retrieving revision 1.26
diff -u -r1.26 kern_acct.c
--- sys/kern/kern_acct.c	2000/07/04 03:34:06	1.26
+++ sys/kern/kern_acct.c	2000/08/09 01:08:58
@@ -120,9 +120,10 @@
 	int error, flags;
 
 	/* Make sure that the caller is root. */
-	error = suser(p);
-	if (error)
+	if (((error = suser(p)) != 0) &&
+	    ((error = cap_check(p, CAP_SYS_PACCT)) != 0))
 		return (error);
+	suser_used(p);
 
 	/*
 	 * If accounting is to be started to a file, open that file for
Index: sys/kern/kern_cap.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/kern_cap.c,v
retrieving revision 1.3
diff -u -r1.3 kern_cap.c
--- sys/kern/kern_cap.c	2000/07/25 03:37:36	1.3
+++ sys/kern/kern_cap.c	2000/08/28 12:34:53
@@ -26,13 +26,11 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- *       $FreeBSD: src/sys/kern/kern_cap.c,v 1.3 2000/07/25 03:37:36 rwatson Exp $
+ * $FreeBSD: src/sys/kern/kern_cap.c,v 1.3 2000/07/25 03:37:36 rwatson Exp $
  */
 /*
  * Developed by the TrustedBSD Project.
  * Support for POSIX.1e process capabilities.
- *
- * XXX Currently just syscall stubs
  */
 
 #include <sys/types.h>
@@ -43,15 +41,298 @@
 #include <sys/sysent.h>
 #include <sys/capability.h>
 #include <sys/acct.h>
+#include <sys/namei.h>
+#include <sys/vnode.h>
+
+#include "opt_cap.h"
+
+static void	cap_zero(struct cap *cap_p);
+static int	cap_valid(struct cap *cap_p);
+static int	cap_subset(struct cap *cap1, struct cap *cap2);
+static int	cap_get_vp(struct vnode *vp, int ioflg, struct cap *cap_p,
+			struct proc *p);
+static int	cap_set_vp(struct vnode *vp, int ioflg, struct cap *cap_p,
+			struct proc *p);
+
+/*
+ * Return a capability set to a state where it has no flags enabled.
+ */
+static void
+cap_zero(struct cap *cap_p)
+{
+
+	bzero(cap_p, sizeof(*cap_p));
+}
+
+/*
+ * Check the validity of a capability set -- 0 on success, EINVAL otherwise
+ */
+static int
+cap_valid(struct cap *cap_p)
+{
+
+	/*
+	 * effective and inheritable cannot contain anything not in
+	 * permitted
+	 */
+	if ((cap_p->c_permitted[0] | cap_p->c_effective[0] |
+	    cap_p->c_inheritable[0]) != cap_p->c_permitted[0])
+		return (EINVAL);
+
+	if ((cap_p->c_permitted[1] | cap_p->c_effective[1] |
+	    cap_p->c_inheritable[1]) != cap_p->c_permitted[1])
+		return (EINVAL);
+
+	/*
+	 * None of the masks should contain mask indexing information
+	 */
+	if (cap_p->c_permitted[0] & CAP_TYPE_MASK)
+		return (EINVAL);
+	if (cap_p->c_permitted[1] & CAP_TYPE_MASK)
+		return (EINVAL);
+
+	return (0);
+}
+
+/*
+ * Check whether cap2 is a strict subset of cap1
+ * This only checks that cap2's permitted mask is a subset of cap1's permitted
+ * mask.  cap_valid() can be used to check that the inheritable and effective
+ * masks are valid for the new capability set.
+ */
+static int
+cap_subset(struct cap *cap1, struct cap *cap2)
+{
+
+	if ((cap1->c_permitted[0] | cap2->c_permitted[0]) !=
+	    cap1->c_permitted[0])
+		return (EPERM);
+
+	if ((cap1->c_permitted[1] | cap2->c_permitted[1]) !=
+	    cap1->c_permitted[1])
+		return (EPERM);
 
+	return (0);
+}
+
 /*
+ * cap_proc0: initialize capabilities for kernel processes
+ *
+ * XXX for now, give them all capabilities, as kernel processes may
+ * need to do all kinds of things.
+ */
+void
+cap_init_proc0(struct cap *cap_p)
+{
+	int	i;
+
+	/* all effective rights */
+	for (i = 0; i < __CAP_MASK_LEN; i++)
+		cap_p->c_effective[i] = 0xffffffff;
+	for (i = 0; i < __CAP_MASK_LEN; i++)
+		cap_p->c_permitted[i] = 0xffffffff;
+	for (i = 0; i < __CAP_MASK_LEN; i++)
+		cap_p->c_inheritable[i] = 0xffffffff;
+}
+
+/*
+ * cap_init: initialize capabilities for init
+ * 
+ * XXX init requires CAP_KILL in order to shut the system
+ * down successfully, as well as CAP_SYS_BOOT.
+ */
+void
+cap_init_proc1(struct cap *cap_p)
+{
+
+	bzero(cap_p, sizeof(struct cap));
+
+	/*
+	 * Give init the ability to kill processes later to shut
+	 * down.  Set as not-inheritable so those processes don't
+	 * get extra rights.
+	 *
+	 * XXX we may need to setsugid() init, so would require
+	 * a proc pointer, not just the cap pointer here.
+	 */
+	SET_CAPABILITY(cap_p->c_permitted, CAP_KILL);
+	SET_CAPABILITY(cap_p->c_effective, CAP_KILL);
+	SET_CAPABILITY(cap_p->c_permitted, CAP_SYS_BOOT);
+	SET_CAPABILITY(cap_p->c_effective, CAP_SYS_BOOT);
+}
+
+/*
+ * Perform capability inheritence on p, with optional vnode for a file
+ * from which to gain/mask new capabilities.  To not use a vnode, set
+ * vp to NULL.
+ *
+ * POSIX.1e defines the following inheritence:
+ *   pI` = pI
+ *   pP` = (fP` & X) | (fI & pI)
+ *   pE` = fE & pP
+ */
+void
+cap_inherit(struct vnode *vp, struct proc *p)
+{
+	struct cap	cap_file;
+	struct cap	*cap_p_proc;
+	int	len, error;
+
+#ifndef CAPABILITIES
+	return;
+#else /* CAPABILITIES */
+
+	/*
+	 * XXX have to do this, since we don't know if capabilities will
+	 * change.  This should be fixed to not crcopy if the capabilities
+	 * have not changed.
+	 */
+	p->p_ucred = crcopy(p->p_ucred);
+	cap_p_proc = &p->p_ucred->cr_cap;
+
+	len = sizeof(cap_file);
+	error =	cap_get_vp(vp, 0, &cap_file, p);
+	if (error) {
+		printf("cap_inherit: error retrieving capability\n");
+		printf("error: %d\n", error);
+	}
+
+	/* no change to cap_p_proc->c_inheritable[0,1] */
+	/* changes to permitted */
+	if (error == 0) {
+		cap_p_proc->c_permitted[0] = cap_file.c_permitted[0] |
+		    (cap_file.c_inheritable[0] &
+		    cap_p_proc->c_inheritable[0]);
+		cap_p_proc->c_permitted[1] = cap_file.c_permitted[1] |
+		    (cap_file.c_inheritable[1] &
+		    cap_p_proc->c_inheritable[1]);
+	} else {
+		cap_p_proc->c_permitted[0] = 0;
+		cap_p_proc->c_permitted[1] = 0;
+	}
+	/* changes to effective: */
+	if (error == 0) {
+		cap_p_proc->c_effective[0] = cap_file.c_effective[0] &
+		    cap_p_proc->c_permitted[0];
+		cap_p_proc->c_effective[1] = cap_file.c_effective[1] &
+		    cap_p_proc->c_permitted[1];
+	} else {
+		cap_p_proc->c_effective[0] = 0;
+		cap_p_proc->c_effective[1] = 0;
+	}
+ 
+	/*
+	 * Currently, we protect a process only if some of its capability
+	 * bits end up being turned on.  Is this correct?
+	 */
+	if ((cap_p_proc->c_permitted[0] || cap_p_proc->c_permitted[1]) ||
+	    (cap_p_proc->c_effective[0] || cap_p_proc->c_effective[1]) ||
+	    (cap_p_proc->c_inheritable[0] || cap_p_proc->c_inheritable[1]))
+		setsugid(p);
+#endif /* CAPABILITIES */
+}
+
+/*
+ * cap_check_xxx, cap_check: perform an authorization check to see if
+ * the given process has the specified capability, optionally with flags
+ * in the style of suser_xxx/suser.
+ */
+int
+cap_check_xxx(struct ucred *cred, struct proc *proc, cap_value_t cap, int flags)
+{
+
+#ifndef CAPABILITIES
+	return (EPERM);
+#else /* CAPABILITIES */
+
+	if (!cred && !proc) {
+		printf("cap_check_xxx(): THINK!\n");
+		return (EPERM);
+	}
+	if (!cred)
+		cred = proc->p_ucred;
+	if (!(cred->cr_cap.c_effective[CAP_TYPE_MASK & cap] &
+	    (cap & ~CAP_TYPE_MASK)))
+		return (EPERM);
+	if (proc && proc->p_prison && !(flags & PRISON_ROOT))
+		return (EPERM);
+	if (proc)
+		proc->p_acflag |= ASU;
+	return (0);
+
+#endif /* CAPABILITIES */
+}
+
+int
+cap_check(struct proc *p, cap_value_t cap)
+{
+
+	return (cap_check_xxx(NULL, p, cap, 0));
+}
+
+/*
+ * Internal function to retrieve the capability block from a
+ * vnode.  Will always fill in the cap set, possibly by zero'ing it
+ * if the file doesn't have a capability, or if it is invalid.
+ */
+static int
+cap_get_vp(struct vnode *vp, int ioflg, struct cap *cap_p, struct proc *p)
+{
+	int	len, error;
+
+	len = sizeof(*cap_p);
+	error = vn_extattr_get(vp, ioflg, POSIX1E_CAPABILITY_EXTATTR_NAME,
+	    &len, (char *) cap_p, p);
+        /*
+         * XXX should check for ENOATTR and convert to null capability it
+         * received, not ENOENT
+         */
+	if (error == ENOENT || error == EOPNOTSUPP) {
+		/*
+		 * Coerce no capability attribute to a null capability set
+		 */
+		error = 0;
+		cap_zero(cap_p);
+	} else if (error == 0 && len != sizeof(*cap_p)) {
+		printf("__cap_get_file: invalid capability on file\n");
+		cap_zero(cap_p);
+	}
+	return (error);
+}
+
+/*
+ * Internal function to set the capability set for a vnode.
+ * Partial writes of extended attributes may be a problem if the
+ * underlying implementation doesn't properly return failure
+ * information.  A partial write *should* result in an invalid
+ * capability, which cap_get_vp will convert into a NULL capability
+ * set.
+ */
+static int cap_set_vp(struct vnode *vp, int ioflg, struct cap *cap_p,
+    struct proc *p)
+{
+	int	len, error;
+
+	if ((error = cap_check_xxx(NULL, p, CAP_SETFCAP, PRISON_ROOT)) &&
+	    (error = suser_xxx(NULL, p, PRISON_ROOT)))
+		return (error);
+	/* audit privilege here */
+
+	len = sizeof(*cap_p);
+	error = vn_extattr_set(vp, ioflg, POSIX1E_CAPABILITY_EXTATTR_NAME,
+	    len, (char *) cap_p, p);
+	return (error);
+}
+
+/*
  * Syscall to allow a process to get it's currently capability set
  */
 int
 __cap_get_proc(struct proc *p, struct __cap_get_proc_args *uap)
 {
 
-	return (ENOSYS);
+	return (copyout(&p->p_ucred->cr_cap, (caddr_t)uap->cap_p,
+	    sizeof (struct cap)));
 }
 
 /*
@@ -61,10 +342,42 @@
 int
 __cap_set_proc(struct proc *p, struct __cap_set_proc_args *uap)
 {
+	struct cap	capability;
+	int	error, ok = 0, requires_privilege;
 
-	return (ENOSYS);
+	error = copyin(SCARG(uap, cap_p), &capability, sizeof(struct cap));
+	if (error)
+		return (error);
+
+	if ((error = cap_valid(&capability)))
+		return (error);
+
+	requires_privilege = 1;
+
+	if (suser_xxx(NULL, p, PRISON_ROOT) == 0)
+		ok = 1;
+
+	if (cap_check_xxx(NULL, p, CAP_SETPCAP, PRISON_ROOT) == 0)
+		ok = 1;
+
+	if (cap_subset(&p->p_ucred->cr_cap, &capability) == 0) {
+		ok = 1;
+		requires_privilege = 0;
+	}
+
+	if (!ok)
+		return (EPERM);
+
+	if (requires_privilege)
+		suser_used(p);
+
+	p->p_ucred = crcopy(p->p_ucred);
+	p->p_ucred->cr_cap = capability;
+
+	return (0);
 }
 
+
 /*
  * Syscalls to allow a process to retrieve capabilities associated with
  * files, if permitted.
@@ -72,6 +385,8 @@
 int
 __cap_get_fd(struct proc *p, struct __cap_get_fd_args *uap)
 {
+	struct cap	cap;
+	int	error;
 
 	return (ENOSYS);
 }
@@ -79,8 +394,21 @@
 int
 __cap_get_file(struct proc *p, struct __cap_get_file_args *uap)
 {
+	struct nameidata	nd;
+	struct cap	cap;
+	int	error;
+
+	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
+	    SCARG(uap, path_p), p);
+	if ((error = namei(&nd)) != 0)
+		return (error);
+
+	error = cap_get_vp(nd.ni_vp, IO_NODELOCKED, &cap, p);
+	if (error == 0)
+		error = copyout(&cap, SCARG(uap, cap_p), sizeof(cap));
 
-	return (ENOSYS);
+	NDFREE(&nd, 0);
+	return (error);
 }
 
 /*
@@ -90,6 +418,8 @@
 int
 __cap_set_fd(struct proc *p, struct __cap_set_fd_args *uap)
 {
+	struct cap	cap;
+	int	error;
 
 	return (ENOSYS);
 }
@@ -97,6 +427,21 @@
 int
 __cap_set_file(struct proc *p, struct __cap_set_file_args *uap)
 {
+	struct nameidata	nd;
+	struct cap	cap;
+	int	error;
+
+	error = copyin(SCARG(uap, cap_p), &cap, sizeof(cap));
+	if (error)
+		return (error);
+
+	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
+	    SCARG(uap, path_p), p);
+	if ((error = namei(&nd)) != 0)
+		return (error);
 
-	return (ENOSYS);
+	error = cap_set_vp(nd.ni_vp, IO_NODELOCKED, &cap, p);
+
+	NDFREE(&nd, 0);
+	return (error);
 }
Index: sys/kern/kern_exec.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/kern_exec.c,v
retrieving revision 1.112
diff -u -r1.112 kern_exec.c
--- sys/kern/kern_exec.c	2000/07/05 07:46:40	1.112
+++ sys/kern/kern_exec.c	2000/08/09 00:57:53
@@ -47,6 +47,7 @@
 #include <sys/shm.h>
 #include <sys/sysctl.h>
 #include <sys/vnode.h>
+#include <sys/capability.h>
 
 #include <vm/vm.h>
 #include <vm/vm_param.h>
@@ -275,6 +276,8 @@
 	 *
 	 * Don't honor setuid/setgid if the filesystem prohibits it or if
 	 * the process is being traced.
+	 *
+	 * Do CAP execution stuff here, in style of setuid/setgid
 	 */
 	if ((((attr.va_mode & VSUID) && p->p_ucred->cr_uid != attr.va_uid) ||
 	     ((attr.va_mode & VSGID) && p->p_ucred->cr_gid != attr.va_gid)) &&
@@ -284,11 +287,13 @@
 		 * Turn off syscall tracing for set-id programs, except for
 		 * root.
 		 */
-		if (p->p_tracep && suser(p)) {
+		if (p->p_tracep && suser(p) && cap_check(p, CAP_SYS_PTRACE)) {
 			p->p_traceflag = 0;
 			vrele(p->p_tracep);
 			p->p_tracep = NULL;
 		}
+		if (p->p_tracep)
+			suser_used(p);
 		/*
 		 * Set the new credentials.
 		 */
@@ -310,6 +315,14 @@
 	 */
 	p->p_cred->p_svuid = p->p_ucred->cr_uid;
 	p->p_cred->p_svgid = p->p_ucred->cr_gid;
+
+	/*
+	 * CAP inheritence, et al.
+	 * XXX should this be above the file CAP stuff?
+	 * XXX is this the right vp?  could be the vp from the interpreter.
+	 * XXX vp is now unlocked?
+	 */
+	cap_inherit(ndp->ni_vp, p);
 
 	/*
 	 * Store the vp for use in procfs
Index: sys/kern/kern_jail.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/kern_jail.c,v
retrieving revision 1.7
diff -u -r1.7 kern_jail.c
--- sys/kern/kern_jail.c	2000/06/04 04:28:31	1.7
+++ sys/kern/kern_jail.c	2000/08/09 01:09:40
@@ -51,9 +51,11 @@
 	struct jail j;
 	struct chroot_args ca;
 
-	error = suser(p);
-	if (error)
+	if (((error = suser(p)) != 0) &&
+	    ((error = cap_check(p, CAP_SYS_CHROOT)) != 0))
 		return (error);
+	suser_used(p);
+
 	error = copyin(uap->jail, &j, sizeof j);
 	if (error)
 		return (error);
Index: sys/kern/kern_linker.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/kern_linker.c,v
retrieving revision 1.50
diff -u -r1.50 kern_linker.c
--- sys/kern/kern_linker.c	2000/08/02 21:08:53	1.50
+++ sys/kern/kern_linker.c	2000/08/09 01:10:25
@@ -689,8 +689,10 @@
     if (securelevel > 0)	/* redundant, but that's OK */
 	return EPERM;
 
-    if ((error = suser(p)) != 0)
+    if (((error = suser(p)) != 0) &&
+        ((error = cap_check(p, CAP_SYS_MODULE)) != 0))
 	return error;
+    suser_used(p);
 
     realpath = NULL;
     pathname = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
@@ -732,8 +734,10 @@
     if (securelevel > 0)	/* redundant, but that's OK */
 	return EPERM;
 
-    if ((error = suser(p)) != 0)
+    if (((error = suser(p)) != 0) &&
+        ((error = cap_check(p, CAP_SYS_MODULE)) != 0))
 	return error;
+    suser_used(p);
 
     lf = linker_find_file_by_id(SCARG(uap, fileid));
     if (lf) {
Index: sys/kern/kern_ntptime.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/kern_ntptime.c,v
retrieving revision 1.35
diff -u -r1.35 kern_ntptime.c
--- sys/kern/kern_ntptime.c	2000/07/04 11:25:22	1.35
+++ sys/kern/kern_ntptime.c	2000/08/09 01:13:28
@@ -285,10 +285,12 @@
 	 * the assumption the superuser should know what it is doing.
 	 */
 	modes = ntv.modes;
-	if (modes)
-		error = suser(p);
-	if (error)
-		return (error);
+	if (modes) {
+		if ((error = suser(p)) &&
+		    (error = cap_check(p, CAP_SYS_TIME)));
+			return (error);
+		suser_used(p);
+	}
 	s = splclock();
 	if (modes & MOD_FREQUENCY) {
 		freq = (ntv.freq * 1000LL) >> 16;
Index: sys/kern/kern_prot.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/kern_prot.c,v
retrieving revision 1.62
diff -u -r1.62 kern_prot.c
--- sys/kern/kern_prot.c	2000/08/31 15:55:17	1.62
+++ sys/kern/kern_prot.c	2000/09/01 04:18:06
@@ -411,6 +411,7 @@
 #ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
 	    uid != pc->pc_ucred->cr_uid &&	/* allow setuid(geteuid()) */
 #endif
+	    (error = cap_check_xxx(0, p, CAP_SETUID, PRISON_ROOT)) &&
 	    (error = suser_xxx(0, p, PRISON_ROOT)))
 		return (error);
 
@@ -423,7 +424,8 @@
 #ifdef POSIX_APPENDIX_B_4_2_2	/* Use the clause from B.4.2.2 */
 	    uid == pc->pc_ucred->cr_uid ||
 #endif
-	    suser_xxx(0, p, PRISON_ROOT) == 0) /* we are using privs */
+	    suser_xxx(0, p, PRISON_ROOT) == 0 || /* we are using privs */
+	    cap_check_xxx(0, p, CAP_SETUID, PRISON_ROOT) == 0)
 #endif
 	{
 		/*
@@ -483,7 +485,8 @@
 	euid = uap->euid;
 	if (euid != pc->p_ruid &&		/* allow seteuid(getuid()) */
 	    euid != pc->p_svuid &&		/* allow seteuid(saved uid) */
-	    (error = suser_xxx(0, p, PRISON_ROOT)))
+	    (error = suser_xxx(0, p, PRISON_ROOT)) &&
+	    (error = cap_check_xxx(0, p, CAP_SETUID, PRISON_ROOT)))
 		return (error);
 	/*
 	 * Everything's okay, do it.  Copy credentials so other references do
@@ -531,7 +534,8 @@
 #ifdef POSIX_APPENDIX_B_4_2_2	/* Use BSD-compat clause from B.4.2.2 */
 	    gid != pc->pc_ucred->cr_groups[0] && /* allow setgid(getegid()) */
 #endif
-	    (error = suser_xxx(0, p, PRISON_ROOT)))
+	    (error = suser_xxx(0, p, PRISON_ROOT)) &&
+	    (error = cap_check_xxx(0, p, CAP_SETGID, PRISON_ROOT)))
 		return (error);
 
 #ifdef _POSIX_SAVED_IDS
@@ -543,7 +547,8 @@
 #ifdef POSIX_APPENDIX_B_4_2_2	/* use the clause from B.4.2.2 */
 	    gid == pc->pc_ucred->cr_groups[0] ||
 #endif
-	    suser_xxx(0, p, PRISON_ROOT) == 0) /* we are using privs */
+	    suser_xxx(0, p, PRISON_ROOT) == 0 || /* we are using privs */
+	    cap_check_xxx(0, p, CAP_SETGID, PRISON_ROOT) == 0)
 #endif
 	{
 		/*
@@ -595,7 +600,8 @@
 	egid = uap->egid;
 	if (egid != pc->p_rgid &&		/* allow setegid(getgid()) */
 	    egid != pc->p_svgid &&		/* allow setegid(saved gid) */
-	    (error = suser_xxx(0, p, PRISON_ROOT)))
+	    (error = suser_xxx(0, p, PRISON_ROOT)) &&
+	    (error = cap_check_xxx(0, p, CAP_SETGID, PRISON_ROOT)))
 		return (error);
 	if (pc->pc_ucred->cr_groups[0] != egid) {
 		pc->pc_ucred = crcopy(pc->pc_ucred);
@@ -621,7 +627,8 @@
 	register u_int ngrp;
 	int error;
 
-	if ((error = suser_xxx(0, p, PRISON_ROOT)))
+	if ((error = suser_xxx(0, p, PRISON_ROOT)) &&
+	    (error = cap_check_xxx(0, p, CAP_SETGID, PRISON_ROOT)))
 		return (error);
 	ngrp = uap->gidsetsize;
 	if (ngrp > NGROUPS)
@@ -670,7 +677,8 @@
 	if (((ruid != (uid_t)-1 && ruid != pc->p_ruid && ruid != pc->p_svuid) ||
 	     (euid != (uid_t)-1 && euid != pc->pc_ucred->cr_uid &&
 	     euid != pc->p_ruid && euid != pc->p_svuid)) &&
-	    (error = suser_xxx(0, p, PRISON_ROOT)) != 0)
+	    (error = suser_xxx(0, p, PRISON_ROOT)) != 0 &&
+	    (error = cap_check_xxx(0, p, CAP_SETUID, PRISON_ROOT)) != 0)
 		return (error);
 
 	if (euid != (uid_t)-1 && pc->pc_ucred->cr_uid != euid) {
@@ -713,7 +721,8 @@
 	if (((rgid != (gid_t)-1 && rgid != pc->p_rgid && rgid != pc->p_svgid) ||
 	     (egid != (gid_t)-1 && egid != pc->pc_ucred->cr_groups[0] &&
 	     egid != pc->p_rgid && egid != pc->p_svgid)) &&
-	    (error = suser_xxx(0, p, PRISON_ROOT)) != 0)
+	    (error = suser_xxx(0, p, PRISON_ROOT)) != 0 &&
+	    (error = cap_check_xxx(0, p, CAP_SETGID, PRISON_ROOT)) != 0)
 		return (error);
 
 	if (egid != (gid_t)-1 && pc->pc_ucred->cr_groups[0] != egid) {
@@ -815,7 +824,8 @@
 	      egid != pc->pc_ucred->cr_groups[0]) ||
 	     (sgid != (gid_t)-1 && sgid != pc->p_rgid && sgid != pc->p_svgid &&
 	      sgid != pc->pc_ucred->cr_groups[0])) &&
-	    (error = suser_xxx(0, p, PRISON_ROOT)) != 0)
+	    (error = suser_xxx(0, p, PRISON_ROOT)) != 0 &&
+	    (error = cap_check_xxx(0, p, CAP_SETGID, PRISON_ROOT)))
 		return (error);
 
 	if (egid != (gid_t)-1 && pc->pc_ucred->cr_groups[0] != egid) {
@@ -932,6 +942,23 @@
 	return (0);
 }
 
+/*
+ * For accounting purposes, flag a process as having used super-user
+ * privileges.  Right now this is not called much, as most code still
+ * assumes that suser() will do the dirty work.  But this is incorrect
+ * behavior.  Use of suser_used() is difficult in current code due to
+ * abuse of short-circuit boolean evaluation to call or not call
+ * suser(), rather than isolating use of privilege.
+ */
+void
+suser_used(proc)
+	struct proc *proc;
+{
+
+	if (proc)
+		proc->p_acflag |= ASU;
+}
+
 static int suser_permitted = 1;
 
 SYSCTL_INT(_kern, OID_AUTO, suser_permitted, CTLFLAG_RW, &suser_permitted, 0,
@@ -939,8 +966,9 @@
 
 /*
  * Test whether the specified credentials imply "super-user"
- * privilege; if so, and we have accounting info, set the flag
- * indicating use of super-powers.
+ * privilege.  This used to also set the appropriate accounting flag,
+ * but now ``suser_used(p)'' must be called explicitely, as not all
+ * invocations of suser() result in the privilege being excercised.
  * Returns 0 or error.
  */
 int
@@ -1134,7 +1162,6 @@
 	}
 }
 
-
 /*
  * Allocate a zeroed cred structure.
  */
@@ -1233,7 +1260,8 @@
 	int error;
 	char logintmp[MAXLOGNAME];
 
-	if ((error = suser_xxx(0, p, PRISON_ROOT)))
+	if ((error = suser_xxx(0, p, PRISON_ROOT)) &&
+	    (error = cap_check_xxx(0, p, CAP_SETUID, PRISON_ROOT)))
 		return (error);
 	error = copyinstr((caddr_t) uap->namebuf, (caddr_t) logintmp,
 	    sizeof(logintmp), (size_t *)0);
Index: sys/kern/kern_resource.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/kern_resource.c,v
retrieving revision 1.60
diff -u -r1.60 kern_resource.c
--- sys/kern/kern_resource.c	2000/08/30 04:49:07	1.60
+++ sys/kern/kern_resource.c	2000/09/01 15:29:32
@@ -78,6 +78,8 @@
 {
 	register struct proc *p;
 	register int low = PRIO_MAX + 1;
+	int privused = 0, cumulative_privused = 0;
+	int	error;
 
 	switch (uap->which) {
 
@@ -101,8 +103,11 @@
 		else if ((pg = pgfind(uap->who)) == NULL)
 			break;
 		LIST_FOREACH(p, &pg->pg_members, p_pglist) {
-			if (!p_can(curp, p, P_CAN_SEE, NULL) && p->p_nice < low)
+			if (!p_can(curp, p, P_CAN_SEE, &privused) &&
+			    p->p_nice < low)
 				low = p->p_nice;
+			if (privused)
+				cumulative_privused = 1;
 		}
 		break;
 	}
@@ -111,10 +116,13 @@
 		if (uap->who == 0)
 			uap->who = curp->p_ucred->cr_uid;
 		LIST_FOREACH(p, &allproc, p_list)
-			if (!p_can(curp, p, P_CAN_SEE, NULL) &&
+			if (!p_can(curp, p, P_CAN_SEE, NULL)  &&
 			    p->p_ucred->cr_uid == uap->who &&
-			    p->p_nice < low)
+			    p->p_nice < low) {
 				low = p->p_nice;
+				if (privused)
+					cumulative_privused = 1;
+			}
 		break;
 
 	default:
@@ -122,6 +130,10 @@
 	}
 	if (low == PRIO_MAX + 1)
 		return (ESRCH);
+
+	if (cumulative_privused)
+		suser_used(curp);
+
 	curp->p_retval[0] = low;
 	return (0);
 }
@@ -205,8 +217,11 @@
 		n = PRIO_MAX;
 	if (n < PRIO_MIN)
 		n = PRIO_MIN;
-	if (n < chgp->p_nice && suser(curp))
-		return (EACCES);
+	if (n < chgp->p_nice) {
+		if (suser(curp) && cap_check(curp, CAP_SYS_NICE))
+			return (EACCES);
+		suser_used(curp);
+	}
 	chgp->p_nice = n;
 	(void)resetpriority(chgp);
 	return (0);
@@ -254,7 +269,7 @@
 		if ((error = p_can(curp, p, P_CAN_SCHED, NULL)))
 		        return (error);
 		/* disallow setting rtprio in most cases if not superuser */
-		if (suser(curp) != 0) {
+		if (suser(NULL) && cap_check(curp, CAP_SYS_NICE)) {
 			/* can't set someone else's */
 			if (uap->pid)
 				return (EPERM);
@@ -272,6 +287,7 @@
 			if (rtp.type != RTP_PRIO_NORMAL)
 				return (EPERM);
 		}
+		suser_used(curp);
 		switch (rtp.type) {
 #ifdef RTP_PRIO_FIFO
 		case RTP_PRIO_FIFO:
@@ -386,9 +402,12 @@
 		limp->rlim_max = RLIM_INFINITY;
 
 	if (limp->rlim_cur > alimp->rlim_max ||
-	    limp->rlim_max > alimp->rlim_max)
-		if ((error = suser_xxx(0, p, PRISON_ROOT)))
+	    limp->rlim_max > alimp->rlim_max) {
+		if ((error = suser_xxx(0, p, PRISON_ROOT)) &&
+		    (error = cap_check_xxx(0, p, CAP_SYS_NICE, PRISON_ROOT)))
 			return (error);
+		suser_used(p);
+	}
 	if (limp->rlim_cur > limp->rlim_max)
 		limp->rlim_cur = limp->rlim_max;
 	if (p->p_limit->p_refcnt > 1 &&
Index: sys/kern/kern_shutdown.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/kern_shutdown.c,v
retrieving revision 1.77
diff -u -r1.77 kern_shutdown.c
--- sys/kern/kern_shutdown.c	2000/08/31 00:08:49	1.77
+++ sys/kern/kern_shutdown.c	2000/08/31 04:09:32
@@ -140,8 +140,9 @@
 {
 	int error;
 
-	if ((error = suser(p)))
+	if ((error = suser(p)) && (error = cap_check(p, CAP_SYS_BOOT)))
 		return (error);
+	suser_used(p);
 
 	boot(uap->opt);
 	return (0);
Index: sys/kern/kern_sig.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/kern_sig.c,v
retrieving revision 1.84
diff -u -r1.84 kern_sig.c
--- sys/kern/kern_sig.c	2000/08/30 04:49:07	1.84
+++ sys/kern/kern_sig.c	2000/08/31 04:26:12
@@ -62,6 +62,7 @@
 #include <sys/sysent.h>
 #include <sys/sysctl.h>
 #include <sys/malloc.h>
+#include <sys/capability.h>
 
 
 #include <machine/ipl.h>
@@ -95,6 +96,11 @@
 
 /*
  * Can process p, with pcred pc, send the signal sig to process q?
+ * XXX should p be able to signal q outside the same prison if CAP_KILL
+ * is present?
+ *
+ * XXX This should propagate the privused flag up the stack but
+ * doesn't.
  */
 #define CANSIGNAL(p, q, sig) \
 	(!p_can(p, q, P_CAN_KILL, NULL) || \
Index: sys/kern/kern_sysctl.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/kern_sysctl.c,v
retrieving revision 1.100
diff -u -r1.100 kern_sysctl.c
--- sys/kern/kern_sysctl.c	2000/07/28 22:40:04	1.100
+++ sys/kern/kern_sysctl.c	2000/08/09 04:54:08
@@ -1016,11 +1016,26 @@
 		return (EPERM);
 
 	/* Most likely only root can write */
+	/*
+	 * XXX What about capabilities?  Ought to map into many different
+	 * capabilities, which doesn't fit will in this scheme.
+	 * CAP_SYS_ADMIN is closest, but wrong.
+	 */
 	if (!(oid->oid_kind & CTLFLAG_ANYBODY) &&
-	    req->newptr && req->p &&
-	    (error = suser_xxx(0, req->p, 
-	    (oid->oid_kind & CTLFLAG_PRISON) ? PRISON_ROOT : 0)))
-		return (error);
+	    req->newptr && req->p) {
+		int	error_suser, error_cap, flag_prison;
+
+		flag_prison = ((oid->oid_kind & CTLFLAG_PRISON) ?
+		    PRISON_ROOT : 0);
+
+		error_suser = suser_xxx(0, req->p, flag_prison);
+		error_cap = cap_check_xxx(0, req->p, CAP_SYS_ADMIN,
+		    flag_prison);
+		if (error_suser && error_cap)
+			return (error_suser);
+
+		suser_used(req->p);
+	}
 
 	if (!oid->oid_handler)
 		return EINVAL;
Index: sys/kern/kern_time.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/kern_time.c,v
retrieving revision 1.70
diff -u -r1.70 kern_time.c
--- sys/kern/kern_time.c	2000/04/18 15:15:20	1.70
+++ sys/kern/kern_time.c	2000/08/09 01:16:22
@@ -174,8 +174,9 @@
 	struct timespec ats;
 	int error;
 
-	if ((error = suser(p)) != 0)
+	if (((error = suser(p)) != 0) && (error = cap_check(p, CAP_SYS_TIME)))
 		return (error);
+	suser_used(p);
 	if (SCARG(uap, clock_id) != CLOCK_REALTIME)
 		return (EINVAL);
 	if ((error = copyin(SCARG(uap, tp), &ats, sizeof(ats))) != 0)
@@ -331,8 +332,9 @@
 	struct timezone atz;
 	int error;
 
-	if ((error = suser(p)))
+	if (((error = suser(p))) && (error = cap_check(p, CAP_SYS_TIME)))
 		return (error);
+	suser_used(p);
 	/* Verify all parameters before changing time. */
 	if (uap->tv) {
 		if ((error = copyin((caddr_t)uap->tv, (caddr_t)&atv,
@@ -371,8 +373,11 @@
 	register long ndelta, ntickdelta, odelta;
 	int s, error;
 
-	if ((error = suser(p)))
+	if ((error = suser(p)) &&
+	    (error = cap_check(p, CAP_SYS_TIME)))
 		return (error);
+	suser_used(p);
+
 	if ((error =
 	    copyin((caddr_t)uap->delta, (caddr_t)&atv, sizeof(struct timeval))))
 		return (error);
Index: sys/kern/kern_xxx.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/kern_xxx.c,v
retrieving revision 1.31
diff -u -r1.31 kern_xxx.c
--- sys/kern/kern_xxx.c	1999/08/28 00:46:15	1.31
+++ sys/kern/kern_xxx.c	2000/08/09 01:50:45
@@ -85,8 +85,11 @@
 
 	name[0] = CTL_KERN;
 	name[1] = KERN_HOSTNAME;
-	if ((error = suser_xxx(0, p, PRISON_ROOT)))
+	if ((error = suser_xxx(0, p, PRISON_ROOT)) &&
+	    (error = cap_check_xxx(0, p, CAP_SYS_ADMIN, PRISON_ROOT)))
 		return (error);
+	suser_used(p);
+
 	return (userland_sysctl(p, name, 2, 0, 0, 0,
 		uap->hostname, uap->len, 0));
 }
@@ -122,8 +125,11 @@
 {
 	int error;
 
-	if ((error = suser(p)))
+	if ((error = suser(p)) &&
+	    (error = cap_check(p, CAP_SYS_ADMIN)))
 		return (error);
+	suser_used(p);
+
 	hostid = uap->hostid;
 	return (0);
 }
@@ -244,8 +250,11 @@
 {
         int error, domainnamelen;
 
-        if ((error = suser(p)))
+        if ((error = suser(p)) &&
+	    (error = cap_check(p, CAP_SYS_ADMIN)))
                 return (error);
+	suser_used(p);
+
         if ((u_int)uap->len > sizeof (domainname) - 1)
                 return EINVAL;
         domainnamelen = uap->len;
Index: sys/kern/makesyscalls.sh
===================================================================
RCS file: /home/ncvs/src/sys/kern/makesyscalls.sh,v
retrieving revision 1.42
diff -u -r1.42 makesyscalls.sh
--- sys/kern/makesyscalls.sh	2000/07/29 00:16:26	1.42
+++ sys/kern/makesyscalls.sh	2000/08/07 00:51:53
@@ -111,8 +111,9 @@
 		printf " * created from%s\n */\n\n", $0 > sysarg
 		printf "#ifndef %s\n", sysproto_h > sysarg
 		printf "#define\t%s\n\n", sysproto_h > sysarg
-		printf "#include <sys/signal.h>\n\n" > sysarg
-		printf "#include <sys/acl.h>\n\n" > sysarg
+		printf "#include <sys/signal.h>\n" > sysarg
+		printf "#include <sys/acl.h>\n" > sysarg
+		printf "#include <sys/capability.h>\n\n" > sysarg
 		printf "struct proc;\n\n" > sysarg
 		printf "#define\tPAD_(t)\t(sizeof(register_t) <= sizeof(t) ? \\\n" > sysarg
 		printf "\t\t0 : sizeof(register_t) - sizeof(t))\n\n" > sysarg
Index: sys/kern/sys_process.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/sys_process.c,v
retrieving revision 1.52
diff -u -r1.52 sys_process.c
--- sys/kern/sys_process.c	2000/08/30 04:49:07	1.52
+++ sys/kern/sys_process.c	2000/08/31 04:27:19
@@ -206,6 +206,7 @@
 	struct proc *p;
 	struct iovec iov;
 	struct uio uio;
+	int privused = 0;
 	int error = 0;
 	int write;
 	int s;
@@ -237,8 +238,10 @@
 		if (p->p_flag & P_TRACED)
 			return EBUSY;
 
-		if ((error = p_can(curp, p, P_CAN_DEBUG, NULL)))
+		if ((error = p_can(curp, p, P_CAN_DEBUG, &privused)))
 			return error;
+		if (privused)
+			suser_used(curp);
 
 		/* OK */
 		break;
Index: sys/kern/sys_socket.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/sys_socket.c,v
retrieving revision 1.32
diff -u -r1.32 sys_socket.c
--- sys/kern/sys_socket.c	2000/07/03 00:05:40	1.32
+++ sys/kern/sys_socket.c	2000/08/07 18:44:28
@@ -45,6 +45,7 @@
 #include <sys/stat.h>
 #include <sys/uio.h>
 #include <sys/filedesc.h>
+#include <sys/capability.h>
 #include <sys/ucred.h>
 
 #include <net/if.h>
Index: sys/kern/sysv_ipc.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/sysv_ipc.c,v
retrieving revision 1.15
diff -u -r1.15 sysv_ipc.c
--- sys/kern/sysv_ipc.c	2000/05/01 11:13:40	1.15
+++ sys/kern/sysv_ipc.c	2000/08/09 04:54:38
@@ -54,8 +54,14 @@
 
 	/* Check for user match. */
 	if (cred->cr_uid != perm->cuid && cred->cr_uid != perm->uid) {
-		if (mode & IPC_M)
-			return (suser(p) == 0 ? 0 : EPERM);
+		if (mode & IPC_M) {
+			if (suser(p) && cap_check(p, CAP_SYS_ADMIN))
+				return (EPERM);
+			else {
+				suser_used(p);
+				return (0);
+			}
+		}
 		/* Check for group match. */
 		mode >>= 3;
 		if (!groupmember(perm->gid, cred) &&
@@ -66,7 +72,14 @@
 
 	if (mode & IPC_M)
 		return (0);
-	return ((mode & perm->mode) == mode || suser(p) == 0 ? 0 : EACCES);
+
+	if ((mode & perm->mode) == mode)
+		return (0);
+	if (suser(p) == 0 || cap_check(p, CAP_IPC_OWNER) == 0) {
+		suser_used(p);
+		return (0);
+	}
+	return (EACCES);
 }
 
 #endif /* defined(SYSVSEM) || defined(SYSVSHM) || defined(SYSVMSG) */
Index: sys/kern/sysv_msg.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/sysv_msg.c,v
retrieving revision 1.24
diff -u -r1.24 sysv_msg.c
--- sys/kern/sysv_msg.c	2000/05/01 13:33:53	1.24
+++ sys/kern/sysv_msg.c	2000/08/09 02:32:30
@@ -329,8 +329,11 @@
 			return(eval);
 		if (msqbuf.msg_qbytes > msqptr->msg_qbytes) {
 			eval = suser(p);
+			if (eval != 0)
+				eval = cap_check(p, CAP_SYS_RESOURCE);
 			if (eval)
 				return(eval);
+			suser_used(p);
 		}
 		if (msqbuf.msg_qbytes > msginfo.msgmnb) {
 #ifdef MSG_DEBUG_OK
Index: sys/kern/tty.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/tty.c,v
retrieving revision 1.138
diff -u -r1.138 tty.c
--- sys/kern/tty.c	2000/07/04 11:25:23	1.138
+++ sys/kern/tty.c	2000/08/09 04:55:05
@@ -816,8 +816,10 @@
 			    ISSET(constty->t_state, TS_CONNECTED))
 				return (EBUSY);
 #ifndef	UCONSOLE
-			if ((error = suser(p)) != 0)
+			if (((error = suser(p)) != 0) &&
+			    (error = cap_check(p, CAP_SYS_TTY_CONFIG)) != 0)
 				return (error);
+			suser_used(p);
 #endif
 			constty = tp;
 		} else if (tp == constty)
@@ -988,10 +990,18 @@
 		splx(s);
 		break;
 	case TIOCSTI:			/* simulate terminal input */
-		if ((flag & FREAD) == 0 && suser(p))
-			return (EPERM);
-		if (!isctty(p, tp) && suser(p))
-			return (EACCES);
+		if ((flag & FREAD) == 0) {
+			if (suser(p) && cap_check(p, CAP_SYS_TTY_CONFIG))
+				return (EPERM);
+			else
+				suser_used(p);
+		}
+		if (!isctty(p, tp)) {
+			if (suser(p) && cap_check(p, CAP_SYS_TTY_CONFIG))
+				return (EACCES);
+			else
+				suser_used(p);
+		}
 		s = spltty();
 		(*linesw[tp->t_line].l_rint)(*(u_char *)data, tp);
 		splx(s);
@@ -1038,9 +1048,11 @@
 		}
 		break;
 	case TIOCSDRAINWAIT:
-		error = suser(p);
-		if (error)
+		if (((error = suser(p)) != 0) &&
+		    ((error = cap_check(p, CAP_SYS_TTY_CONFIG)) != 0))
 			return (error);
+		suser_used(p);
+
 		tp->t_timeout = *(int *)data * hz;
 		wakeup(TSA_OCOMPLETE(tp));
 		wakeup(TSA_OLOWAT(tp));
Index: sys/kern/tty_cons.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/tty_cons.c,v
retrieving revision 1.83
diff -u -r1.83 tty_cons.c
--- sys/kern/tty_cons.c	2000/07/04 11:25:23	1.83
+++ sys/kern/tty_cons.c	2000/08/09 02:45:21
@@ -373,9 +373,11 @@
 	 * output from the "virtual" console.
 	 */
 	if (cmd == TIOCCONS && constty) {
-		error = suser(p);
-		if (error)
+		if (((error = suser(p)) != 0) &&
+		    ((error = cap_check(p, CAP_SYS_TTY_CONFIG)) != 0))
 			return (error);
+		suser_used(p);
+
 		constty = NULL;
 		return (0);
 	}
Index: sys/kern/tty_pty.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/tty_pty.c,v
retrieving revision 1.78
diff -u -r1.78 tty_pty.c
--- sys/kern/tty_pty.c	2000/08/20 21:34:34	1.78
+++ sys/kern/tty_pty.c	2000/08/24 01:46:58
@@ -205,7 +205,11 @@
 		tp->t_lflag = TTYDEF_LFLAG;
 		tp->t_cflag = TTYDEF_CFLAG;
 		tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
-	} else if (tp->t_state & TS_XCLUDE && suser(p)) {
+	} else if (tp->t_state & TS_XCLUDE) {
+		/*
+		 * XXX used to be && suser(p) with, why could suser override
+		 * TS_XCLUDE?
+		 */
 		return (EBUSY);
 	} else if (pti->pt_prison != p->p_prison) {
 		return (EBUSY);
Index: sys/kern/tty_snoop.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/tty_snoop.c,v
retrieving revision 1.47
diff -u -r1.47 tty_snoop.c
--- sys/kern/tty_snoop.c	2000/04/02 07:02:41	1.47
+++ sys/kern/tty_snoop.c	2000/08/09 02:52:57
@@ -286,7 +286,8 @@
 	struct snoop   *snp;
 	int error;
 
-	if ((error = suser(p)) != 0)
+	if (((error = suser(p)) != 0) &&
+	    ((error = cap_check(p, CAP_SYS_ADMIN)))
 		return (error);
 
 	if (dev->si_drv1 == NULL) {
Index: sys/kern/vfs_syscalls.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/vfs_syscalls.c,v
retrieving revision 1.163
diff -u -r1.163 vfs_syscalls.c
--- sys/kern/vfs_syscalls.c	2000/08/09 01:57:11	1.163
+++ sys/kern/vfs_syscalls.c	2000/08/10 18:51:31
@@ -123,21 +123,31 @@
 	struct nameidata nd;
 	char fstypename[MFSNAMELEN];
 
-	if (usermount == 0 && (error = suser(p)))
-		return (error);
+	if (usermount == 0) {
+		if ((error = suser(p)) &&
+		    (error = cap_check(p, CAP_SYS_ADMIN)))
+			return (error);
+		suser_used(p);
+	}
 	/*
 	 * Do not allow NFS export by non-root users.
 	 */
 	if (SCARG(uap, flags) & MNT_EXPORTED) {
-		error = suser(p);
-		if (error)
+		if ((error = suser(p)) &&
+		    (error = cap_check(p, CAP_SYS_ADMIN)))
 			return (error);
+		suser_used(p);
 	}
 	/*
 	 * Silently enforce MNT_NOSUID and MNT_NODEV for non-root users
 	 */
-	if (suser_xxx(p->p_ucred, 0, 0)) 
+	if (suser_xxx(p->p_ucred, 0, 0) &&
+	    cap_check_xxx(p->p_ucred, NULL, CAP_SYS_ADMIN, 0))
 		SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV;
+	else if ((SCARG(uap, flags) & (MNT_NOSUID | MNT_NODEV)) !=
+	    (MNT_NOSUID | MNT_NODEV))
+		suser_used(p);
+	
 	/*
 	 * Get vnode to be covered
 	 */
@@ -168,10 +178,14 @@
 		 * Only root, or the user that did the original mount is
 		 * permitted to update it.
 		 */
-		if (mp->mnt_stat.f_owner != p->p_ucred->cr_uid &&
-		    (error = suser(p))) {
-			vput(vp);
-			return (error);
+		if (mp->mnt_stat.f_owner != p->p_ucred->cr_uid) {
+			if ((error = suser(p)) &&
+			    (error = cap_check(p, CAP_SYS_ADMIN)))
+				suser_used(p);
+			else {
+				vput(vp);
+				return (error);
+			}
 		}
 		if (vfs_busy(mp, LK_NOWAIT, 0, p)) {
 			vput(vp);
@@ -197,10 +211,14 @@
 	 * onto which we are attempting to mount.
 	 */
 	if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) ||
-	    (va.va_uid != p->p_ucred->cr_uid &&
-	     (error = suser(p)))) {
-		vput(vp);
-		return (error);
+	    (va.va_uid != p->p_ucred->cr_uid)) {
+		if ((error = suser(p)) &&
+		    (error = cap_check(p, CAP_SYS_ADMIN)))
+			suser_used(p);
+		else {
+			vput(vp);
+			return (error);
+		}
 	}
 	if ((error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, 0)) != 0) {
 		vput(vp);
@@ -239,10 +257,12 @@
 		linker_file_t lf;
 
 		/* Only load modules for root (very important!) */
-		if ((error = suser(p)) != 0) {
+		if ((error = suser(p)) &&
+		    (error = cap_check(p, CAP_SYS_MODULE))) {
 			vput(vp);
 			return error;
 		}
+		suser_used(p);
 		error = linker_load_file(fstypename, &lf);
 		if (error || lf == NULL) {
 			vput(vp);
@@ -444,10 +464,13 @@
 	 * Only root, or the user that did the original mount is
 	 * permitted to unmount this filesystem.
 	 */
-	if ((mp->mnt_stat.f_owner != p->p_ucred->cr_uid) &&
-	    (error = suser(p))) {
-		vput(vp);
-		return (error);
+	if ((mp->mnt_stat.f_owner != p->p_ucred->cr_uid)) {
+		if ((error = suser(p)) &&
+		    (error = cap_check(p, CAP_SYS_ADMIN))) {
+			vput(vp);
+			return (error);
+		}
+		suser_used(p);
 	}
 
 	/*
@@ -669,11 +692,13 @@
 	if (error)
 		return (error);
 	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
-	if (suser_xxx(p->p_ucred, 0, 0)) {
+	if (suser_xxx(p->p_ucred, 0, 0) &&
+	    cap_check_xxx(p->p_ucred, NULL, CAP_SYS_ADMIN, 0)) {
 		bcopy((caddr_t)sp, (caddr_t)&sb, sizeof(sb));
 		sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0;
 		sp = &sb;
-	}
+	} else
+		suser_used(p);
 	return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp)));
 }
 
@@ -709,11 +734,13 @@
 	if (error)
 		return (error);
 	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
-	if (suser_xxx(p->p_ucred, 0, 0)) {
+	if (suser_xxx(p->p_ucred, 0, 0) &&
+	    cap_check_xxx(p->p_ucred, NULL, CAP_SYS_ADMIN, 0)) {
 		bcopy((caddr_t)sp, (caddr_t)&sb, sizeof(sb));
 		sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0;
 		sp = &sb;
-	}
+	} else
+		suser_used(p);
 	return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp)));
 }
 
@@ -925,9 +952,11 @@
 	int error;
 	struct nameidata nd;
 
-	error = suser_xxx(0, p, PRISON_ROOT);
-	if (error)
+	if ((error = suser_xxx(NULL, p, PRISON_ROOT)) &&
+	    (error = cap_check_xxx(NULL, p, CAP_SYS_CHROOT, PRISON_ROOT)))
 		return (error);
+	suser_used(p);
+
 	if (chroot_allow_open_directories == 0 ||
 	    (chroot_allow_open_directories == 1 && fdp->fd_rdir != rootvnode))
 		error = chroot_refuse_vdir_fds(fdp);
@@ -1141,9 +1170,13 @@
 	case S_IFCHR:
 	case S_IFBLK:
 		error = suser(p);
+		if (error != 0)
+			error = cap_check(p, CAP_MKNOD);
 		break;
 	default:
 		error = suser_xxx(0, p, PRISON_ROOT);
+		if (error != 0)
+			error = cap_check_xxx(NULL, p, CAP_MKNOD, PRISON_ROOT);
 		break;
 	}
 	if (error)
@@ -2002,9 +2035,13 @@
 	 * if they are allowed to set flags and programs assume that
 	 * chown can't fail when done as root.
 	 */
-	if ((vp->v_type == VCHR || vp->v_type == VBLK) && 
-	    ((error = suser_xxx(p->p_ucred, p, PRISON_ROOT)) != 0))
-		return (error);
+	if (vp->v_type == VCHR || vp->v_type == VBLK) {
+		if ((error = suser_xxx(p->p_ucred, p, PRISON_ROOT)) &&
+		    (error = cap_check_xxx(p->p_ucred, p, CAP_SYS_SETFFLAG,
+		    PRISON_ROOT)))
+			return (error);
+		suser_used(p);
+	}
 
 	if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
 		return (error);
@@ -3181,8 +3218,13 @@
 	}
 	if ((error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) != 0)
 		goto out;
-	if (p->p_ucred->cr_uid != vattr.va_uid &&
-	    (error = suser_xxx(0, p, PRISON_ROOT)))
+	if (p->p_ucred->cr_uid != vattr.va_uid) {
+		if ((error = suser_xxx(NULL, p, PRISON_ROOT)) &&
+		    (error = cap_check_xxx(NULL, p, CAP_SYS_ADMIN,
+		    PRISON_ROOT)))
+			goto out;
+		suser_used(p);
+	}
 		goto out;
 	if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
 		goto out;
@@ -3235,9 +3277,11 @@
 	/*
 	 * Must be super user
 	 */
-	error = suser(p);
-	if (error)
+	if ((error = suser(p)) &&
+	    (error = cap_check(p, CAP_SYS_ADMIN)))
 		return (error);
+	suser_used(p);
+
 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
 	error = namei(&nd);
 	if (error)
@@ -3290,9 +3334,10 @@
 	/*
 	 * Must be super user
 	 */
-	error = suser(p);
-	if (error)
+	if ((error = suser(p)) &&
+	    (error = cap_check(p, CAP_SYS_ADMIN)))
 		return (error);
+	suser_used(p);
 
 	fmode = FFLAGS(SCARG(uap, flags));
 	/* why not allow a non-read/write open for our lockd? */
@@ -3440,9 +3485,10 @@
 	/*
 	 * Must be super user
 	 */
-	error = suser(p);
-	if (error)
+	if ((error = suser(p)) &&
+	    (error = cap_check(p, CAP_SYS_ADMIN)))
 		return (error);
+	suser_used(p);
 	
 	error = copyin(SCARG(uap, u_fhp), &fh, sizeof(fhandle_t));
 	if (error)
@@ -3484,8 +3530,10 @@
 	/*
 	 * Must be super user
 	 */
-	if ((error = suser(p)))
+	if ((error = suser(p)) &&
+	    (error = cap_check(p, CAP_SYS_ADMIN)))
 		return (error);
+	suser_used(p);
 
 	if ((error = copyin(SCARG(uap, u_fhp), &fh, sizeof(fhandle_t))) != 0)
 		return (error);
@@ -3500,11 +3548,14 @@
 	if ((error = VFS_STATFS(mp, sp, p)) != 0)
 		return (error);
 	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
-	if (suser_xxx(p->p_ucred, 0, 0)) {
+	if (suser_xxx(p->p_ucred, 0, 0) &&
+	    cap_check_xxx(p->p_ucred, NULL, CAP_SYS_ADMIN, 0)) {
 		bcopy((caddr_t)sp, (caddr_t)&sb, sizeof(sb));
 		sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0;
 		sp = &sb;
-	}
+	} else
+		suser_used(p);
+
 	return (copyout(sp, SCARG(uap, buf), sizeof(*sp)));
 }
 
Index: sys/kern/vfs_vnops.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/vfs_vnops.c,v
retrieving revision 1.100
diff -u -r1.100 vfs_vnops.c
--- sys/kern/vfs_vnops.c	2000/08/08 17:15:32	1.100
+++ sys/kern/vfs_vnops.c	2000/08/09 03:45:28
@@ -530,7 +530,8 @@
 	}
 	
 	sb->st_flags = vap->va_flags;
-	if (suser_xxx(p->p_ucred, 0, 0))
+	if (suser_xxx(p->p_ucred, 0, 0) &&
+	    cap_check_xxx(p->p_ucred, NULL, CAP_SYS_ADMIN, 0))
 		sb->st_gen = 0;
 	else
 		sb->st_gen = vap->va_gen;
Index: sys/net/if.c
===================================================================
RCS file: /home/ncvs/src/sys/net/if.c,v
retrieving revision 1.92
diff -u -r1.92 if.c
--- sys/net/if.c	2000/08/15 00:48:38	1.92
+++ sys/net/if.c	2000/08/24 01:47:52
@@ -764,7 +764,7 @@
 	register struct ifnet *ifp;
 	register struct ifreq *ifr;
 	struct ifstat *ifs;
-	int error;
+	int error, privilege_used = 0;
 	short oif_flags;
 
 	switch (cmd) {
@@ -796,9 +796,10 @@
 		break;
 
 	case SIOCSIFFLAGS:
-		error = suser(p);
-		if (error)
+		if ((error = suser(p)) && (error = cap_check(p, CAP_NET_ADMIN)))
 			return (error);
+		suser_used(p);
+
 		ifr->ifr_prevflags = ifp->if_flags;
 		if (ifp->if_flags & IFF_SMART) {
 			/* Smart drivers twiddle their own routes */
@@ -821,31 +822,37 @@
 		break;
 
 	case SIOCSIFMETRIC:
-		error = suser(p);
-		if (error)
+		if ((error = suser(p)) && (error = cap_check(p, CAP_NET_ADMIN)))
 			return (error);
+		suser_used(p);
+
 		ifp->if_metric = ifr->ifr_metric;
 		getmicrotime(&ifp->if_lastchange);
 		break;
 
 	case SIOCSIFPHYS:
-		error = suser(p);
-		if (error)
+		if ((error = suser(p)) && (error = cap_check(p, CAP_NET_ADMIN)))
 			return error;
+		privilege_used = 1;
+
 		if (!ifp->if_ioctl)
 		        return EOPNOTSUPP;
 		error = (*ifp->if_ioctl)(ifp, cmd, data);
 		if (error == 0)
 			getmicrotime(&ifp->if_lastchange);
+
+		if (error == 0 && privilege_used)
+			suser_used(p);
 		return(error);
 
 	case SIOCSIFMTU:
 	{
 		u_long oldmtu = ifp->if_mtu;
 
-		error = suser(p);
-		if (error)
+		if ((error = suser(p)) && (error = cap_check(p, CAP_NET_ADMIN)))
 			return (error);
+		privilege_used = 1;
+
 		if (ifp->if_ioctl == NULL)
 			return (EOPNOTSUPP);
 		if (ifr->ifr_mtu < IF_MINMTU || ifr->ifr_mtu > IF_MAXMTU)
@@ -863,14 +870,16 @@
 			nd6_setmtu(ifp);
 #endif
 		}
+		if (error == 0 && privilege_used)
+			suser_used(p);
 		return (error);
 	}
 
 	case SIOCADDMULTI:
 	case SIOCDELMULTI:
-		error = suser(p);
-		if (error)
+		if ((error = suser(p)) && (error = cap_check(p, CAP_NET_ADMIN)))
 			return (error);
+		privilege_used = 1;
 
 		/* Don't allow group membership on non-multicast interfaces. */
 		if ((ifp->if_flags & IFF_MULTICAST) == 0)
@@ -888,18 +897,23 @@
 		}
 		if (error == 0)
 			getmicrotime(&ifp->if_lastchange);
+		if (error == 0 && privilege_used)
+			suser_used(p);
 		return error;
 
         case SIOCSIFMEDIA:
 	case SIOCSIFGENERIC:
-		error = suser(p);
-		if (error)
+		if ((error = suser(p)) && (error = cap_check(p, CAP_NET_ADMIN)))
 			return (error);
+		privilege_used = 1;
+
 		if (ifp->if_ioctl == 0)
 			return (EOPNOTSUPP);
 		error = (*ifp->if_ioctl)(ifp, cmd, data);
 		if (error == 0)
 			getmicrotime(&ifp->if_lastchange);
+		if (error == 0 && privilege_used)
+			suser_used(p);
 		return error;
 
 	case SIOCGIFSTATUS:
Index: sys/netinet/in_pcb.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/in_pcb.c,v
retrieving revision 1.67
diff -u -r1.67 in_pcb.c
--- sys/netinet/in_pcb.c	2000/07/21 23:26:37	1.67
+++ sys/netinet/in_pcb.c	2000/08/07 00:55:25
@@ -49,6 +49,7 @@
 #include <sys/jail.h>
 #include <sys/kernel.h>
 #include <sys/sysctl.h>
+#include <sys/capability.h>
 
 #include <machine/limits.h>
 
@@ -219,7 +220,9 @@
 
 			/* GROSS */
 			if (ntohs(lport) < IPPORT_RESERVED && p &&
-			    suser_xxx(0, p, PRISON_ROOT))
+			    suser_xxx(0, p, PRISON_ROOT) &&
+			    cap_check_xxx(0, p, CAP_NET_BIND_SERVICE,
+			    PRISON_ROOT))
 				return (EACCES);
 			if (p && p->p_prison)
 				prison = 1;
@@ -279,7 +282,9 @@
 			last  = ipport_hilastauto;
 			lastport = &pcbinfo->lasthi;
 		} else if (inp->inp_flags & INP_LOWPORT) {
-			if (p && (error = suser_xxx(0, p, PRISON_ROOT)))
+			if (p && (error = suser_xxx(0, p, PRISON_ROOT)) &&
+			    (error = cap_check_xxx(0, p, CAP_NET_BIND_SERVICE,
+			    PRISON_ROOT)))
 				return error;
 			first = ipport_lowfirstauto;	/* 1023 */
 			last  = ipport_lowlastauto;	/* 600 */
Index: sys/netinet/raw_ip.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/raw_ip.c,v
retrieving revision 1.68
diff -u -r1.68 raw_ip.c
--- sys/netinet/raw_ip.c	2000/09/01 12:33:03	1.68
+++ sys/netinet/raw_ip.c	2000/09/01 13:47:49
@@ -47,6 +47,7 @@
 #include <sys/socket.h>
 #include <sys/socketvar.h>
 #include <sys/sysctl.h>
+#include <sys/capability.h>
 
 #include <vm/vm_zone.h>
 
@@ -444,7 +445,8 @@
 	inp = sotoinpcb(so);
 	if (inp)
 		panic("rip_attach");
-	if (p && (error = suser(p)) != 0)
+	if (p && (error = suser(p)) != 0 &&
+	    (error = cap_check(p, CAP_NET_RAW)) != 0)
 		return error;
 
 	error = soreserve(so, rip_sendspace, rip_recvspace);
Index: sys/netinet6/in6_pcb.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet6/in6_pcb.c,v
retrieving revision 1.13
diff -u -r1.13 in6_pcb.c
--- sys/netinet6/in6_pcb.c	2000/07/04 16:35:09	1.13
+++ sys/netinet6/in6_pcb.c	2000/08/10 02:06:52
@@ -178,7 +178,9 @@
 
 			/* GROSS */
 			if (ntohs(lport) < IPV6PORT_RESERVED && p &&
-			    suser_xxx(0, p, PRISON_ROOT))
+			    suser_xxx(0, p, PRISON_ROOT) &&
+			    cap_check_xxx(NULL, p, CAP_NET_BIND_SERVICE,
+			    PRISON_ROOT))
 				return(EACCES);
 			if (so->so_cred->cr_uid != 0 &&
 			    !IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
Index: sys/netinet6/in6_src.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet6/in6_src.c,v
retrieving revision 1.1
diff -u -r1.1 in6_src.c
--- sys/netinet6/in6_src.c	2000/07/04 16:35:09	1.1
+++ sys/netinet6/in6_src.c	2000/08/10 04:18:04
@@ -346,7 +346,8 @@
 		last  = ipport_hilastauto;
 		lastport = &pcbinfo->lasthi;
 	} else if (inp->inp_flags & INP_LOWPORT) {
-		if (p && (error = suser(p)))
+		if (p && (error = suser(p)) &&
+		    (error = cap_check(p, CAP_NET_BIND_SERVICE)))
 			return error;
 		first = ipport_lowfirstauto;	/* 1023 */
 		last  = ipport_lowlastauto;	/* 600 */
Index: sys/sys/capability.h
===================================================================
RCS file: /home/ncvs/src/sys/sys/capability.h,v
retrieving revision 1.3
diff -u -r1.3 capability.h
--- sys/sys/capability.h	2000/08/08 18:47:59	1.3
+++ sys/sys/capability.h	2000/08/09 05:03:03
@@ -129,7 +129,7 @@
  * in the BSD file environment
  * #define	CAP_LINUX_IMMUTABLE	(0x00000200 | SYSTEM_CAPABILITY)
  */
-#define	CAP_BSD_SETFFLAG	(0x00000200 | SYSTEM_CAPABILITY)
+#define	CAP_SYS_SETFFLAG	(0x00000200 | SYSTEM_CAPABILITY)
 #define	CAP_NET_BIND_SERVICE	(0x00000400 | SYSTEM_CAPABILITY)
 #define	CAP_NET_BROADCAST	(0x00000800 | SYSTEM_CAPABILITY)
 #define	CAP_NET_ADMIN		(0x00001000 | SYSTEM_CAPABILITY)
@@ -140,18 +140,22 @@
  * The following capabilities, borrowed from Linux, are unsafe in a
  * secure environment.
  *
- * #define	CAP_SYS_MODULE		(0x00010000 | SYSTEM_CAPABILITY)
- * #define	CAP_SYS_RAWIO		(0x00020000 | SYSTEM_CAPABILITY)
- * #define	CAP_SYS_CHROOT		(0x00040000 | SYSTEM_CAPABILITY)
- * #define	CAP_SYS_PTRACE		(0x00080000 | SYSTEM_CAPABILITY)
  */
+#define	CAP_SYS_MODULE		(0x00010000 | SYSTEM_CAPABILITY)
+#define	CAP_SYS_RAWIO		(0x00020000 | SYSTEM_CAPABILITY)
+#define	CAP_SYS_CHROOT		(0x00040000 | SYSTEM_CAPABILITY)
+#define	CAP_SYS_PTRACE		(0x00080000 | SYSTEM_CAPABILITY)
 #define	CAP_SYS_PACCT		(0x00100000 | SYSTEM_CAPABILITY)
 #define	CAP_SYS_ADMIN		(0x00200000 | SYSTEM_CAPABILITY)
+/*
+ * Back to the safe ones, again
+ */
 #define	CAP_SYS_BOOT		(0x00400000 | SYSTEM_CAPABILITY)
 #define	CAP_SYS_NICE		(0x00800000 | SYSTEM_CAPABILITY)
 #define	CAP_SYS_RESOURCE	(0x01000000 | SYSTEM_CAPABILITY)
 #define	CAP_SYS_TIME		(0x02000000 | SYSTEM_CAPABILITY)
 #define	CAP_SYS_TTY_CONFIG	(0x04000000 | SYSTEM_CAPABILITY)
+#define	CAP_MKNOD		(0x08000000 | SYSTEM_CAPABILITY)
 
 #ifdef _KERNEL
 
Index: sys/sys/mount.h
===================================================================
RCS file: /home/ncvs/src/sys/sys/mount.h,v
retrieving revision 1.95
diff -u -r1.95 mount.h
--- sys/sys/mount.h	2000/07/11 19:28:20	1.95
+++ sys/sys/mount.h	2000/07/12 18:29:21
@@ -37,6 +37,7 @@
 #ifndef _SYS_MOUNT_H_
 #define _SYS_MOUNT_H_
 
+#include <sys/capability.h>
 #include <sys/ucred.h>
 
 #ifndef _KERNEL
Index: sys/sys/proc.h
===================================================================
RCS file: /home/ncvs/src/sys/sys/proc.h,v
retrieving revision 1.109
diff -u -r1.109 proc.h
--- sys/sys/proc.h	2000/08/30 04:49:09	1.109
+++ sys/sys/proc.h	2000/08/31 04:29:28
@@ -51,6 +51,7 @@
 #ifndef _KERNEL
 #include <sys/time.h>			/* For structs itimerval, timeval. */
 #endif
+#include <sys/capability.h>
 #include <sys/ucred.h>
 #include <sys/event.h>			/* For struct klist */
 
@@ -311,6 +312,7 @@
 	uid_t	p_svuid;		/* Saved effective user id. */
 	gid_t	p_rgid;			/* Real group id. */
 	gid_t	p_svgid;		/* Saved effective group id. */
+	struct cap	p_cap;		/* Capabilities */
 	int	p_refcnt;		/* Number of references. */
 };
 
Index: sys/sys/sysctl.h
===================================================================
RCS file: /home/ncvs/src/sys/sys/sysctl.h,v
retrieving revision 1.87
diff -u -r1.87 sysctl.h
--- sys/sys/sysctl.h	2000/07/15 10:26:04	1.87
+++ sys/sys/sysctl.h	2000/08/07 00:55:43
@@ -328,7 +328,8 @@
 #define	KERN_PS_STRINGS		32	/* int: address of PS_STRINGS */
 #define	KERN_USRSTACK		33	/* int: address of USRSTACK */
 #define	KERN_LOGSIGEXIT		34	/* int: do we log sigexit procs? */
-#define KERN_MAXID		35      /* number of valid kern ids */
+#define KERN_SUSER_PERMITTED	35	/* int: suser_xxx() may succeed */
+#define KERN_MAXID		36      /* number of valid kern ids */
 
 #define CTL_KERN_NAMES { \
 	{ 0, 0 }, \
@@ -366,6 +367,7 @@
 	{ "ps_strings", CTLTYPE_INT }, \
 	{ "usrstack", CTLTYPE_INT }, \
 	{ "logsigexit", CTLTYPE_INT }, \
+	{ "suser_permitted", CTLTYPE_INT }, \
 }
 
 /*
Index: sys/sys/systm.h
===================================================================
RCS file: /home/ncvs/src/sys/sys/systm.h,v
retrieving revision 1.117
diff -u -r1.117 systm.h
--- sys/sys/systm.h	2000/08/31 00:08:50	1.117
+++ sys/sys/systm.h	2000/08/31 04:12:34
@@ -47,6 +47,7 @@
 #include <sys/callout.h>
 
 extern int securelevel;		/* system security level (see init(8)) */
+extern int suser_permitted;	/* suser_xxx() is permitted to return 0 */
 
 extern int cold;		/* nonzero if we are doing a cold boot */
 extern const char *panicstr;	/* panic message */
Index: sys/sys/ucred.h
===================================================================
RCS file: /home/ncvs/src/sys/sys/ucred.h,v
retrieving revision 1.14
diff -u -r1.14 ucred.h
--- sys/sys/ucred.h	1999/12/29 04:24:49	1.14
+++ sys/sys/ucred.h	2000/04/12 14:54:30
@@ -48,6 +48,7 @@
 	uid_t	cr_uid;			/* effective user id */
 	short	cr_ngroups;		/* number of groups */
 	gid_t	cr_groups[NGROUPS];	/* groups */
+	struct cap	cr_cap;		/* capabilities */
 };
 #define cr_gid cr_groups[0]
 #define NOCRED ((struct ucred *)0)	/* no credential available */
Index: sys/sys/user.h
===================================================================
RCS file: /home/ncvs/src/sys/sys/user.h,v
retrieving revision 1.24
diff -u -r1.24 user.h
--- sys/sys/user.h	1999/12/29 04:24:49	1.24
+++ sys/sys/user.h	2000/04/12 02:04:02
@@ -43,6 +43,7 @@
 #include <sys/errno.h>
 #include <sys/time.h>
 #include <sys/resource.h>
+#include <sys/capability.h>
 #include <sys/ucred.h>
 #include <sys/uio.h>
 #include <sys/proc.h>
Index: sys/sys/vnode.h
===================================================================
RCS file: /home/ncvs/src/sys/sys/vnode.h,v
retrieving revision 1.124
diff -u -r1.124 vnode.h
--- sys/sys/vnode.h	2000/08/29 14:45:45	1.124
+++ sys/sys/vnode.h	2000/08/29 16:37:03
@@ -528,6 +528,7 @@
 struct proc;
 struct stat;
 struct nstat;
+struct cap;
 struct ucred;
 struct uio;
 struct vattr;
Index: sys/ufs/ufs/ufs_extattr.c
===================================================================
RCS file: /home/ncvs/src/sys/ufs/ufs/ufs_extattr.c,v
retrieving revision 1.8
diff -u -r1.8 ufs_extattr.c
--- sys/ufs/ufs/ufs_extattr.c	2000/08/26 22:00:58	1.8
+++ sys/ufs/ufs/ufs_extattr.c	2000/08/27 03:48:35
@@ -309,18 +309,25 @@
 	char	*filename;
 	int	error, len, flags;
 
-	if ((error = suser_xxx(p->p_cred->pc_ucred, p, 0)))
+	if ((error = suser_xxx(p->p_cred->pc_ucred, p, 0)) &&
+	    (error = cap_check_xxx(p->p_cred->pc_ucred, p, CAP_SYS_ADMIN, 0)))
 		return (error);
 
 	switch(cmd) {
 	case UFS_EXTATTR_CMD_START:
 		error = ufs_extattr_start(mp, p);
 
+		if (error == 0)
+			suser_used(p);
 		return (error);
 		
 	case UFS_EXTATTR_CMD_STOP:
-		return (ufs_extattr_stop(mp, p));
+		error = ufs_extattr_stop(mp, p);
 
+		if (error == 0)
+			suser_used(p);
+		return (error);
+
 	case UFS_EXTATTR_CMD_ENABLE:
 		error = copyinstr(attrname, local_attrname,
 		    UFS_EXTATTR_MAXEXTATTRNAME, &len);
@@ -341,6 +348,8 @@
 		error = ufs_extattr_enable(ump, local_attrname, vp, p);
 		ufs_extattr_uepm_unlock(ump, p);
 
+		if (error == 0)
+			suser_used(p);
 		return (error);
 
 	case UFS_EXTATTR_CMD_DISABLE:
@@ -351,6 +360,8 @@
 		error = ufs_extattr_disable(ump, local_attrname, p);
 		ufs_extattr_uepm_unlock(ump, p);
 
+		if (error == 0)
+			suser_used(p);
 		return (error);
 
 	default:
@@ -364,7 +375,8 @@
  */
 static int
 ufs_extattr_credcheck(struct ufs_extattr_list_entry *uele, u_int32_t fowner,
-		      struct ucred *cred, struct proc *p, int access)
+		      struct ucred *cred, struct proc *p, int access,
+		      int *privilege_used)
 {
 	u_int	uef_perm;
 
@@ -386,8 +398,12 @@
 	/* XXX there might eventually be a capability check here */
 
 	/* If it's set to root-only, check for suser(p) */
-	if (uef_perm == UFS_EXTATTR_PERM_ROOT && !suser(p))
+	if (uef_perm == UFS_EXTATTR_PERM_ROOT && !suser(p) &&
+	    cap_check(p, CAP_SYS_ADMIN)) {
+		if (privilege_used)
+			*privilege_used = 1;
 		return (0);
+	}
 
 	/* Allow the owner if appropriate */
 	if (uef_perm == UFS_EXTATTR_PERM_OWNER && cred->cr_uid == fowner)
@@ -446,7 +462,7 @@
 	struct inode	*ip = VTOI(vp);
 	off_t	base_offset;
 	size_t	size, old_size;
-	int	error = 0;
+	int	error = 0, privilege_used = 0;
 
 	if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED))
 		return (EOPNOTSUPP);
@@ -456,7 +472,7 @@
 		return (ENOENT);
 
 	if ((error = ufs_extattr_credcheck(attribute, ip->i_uid, cred, p,
-	    IREAD)))
+	    IREAD, &privilege_used)))
 		return (error);
 
 	/*
@@ -555,6 +571,8 @@
 vopunlock_exit:
 	VOP_UNLOCK(attribute->uele_backing_vnode, 0, p);
 
+	if (error == 0 && privilege_used)
+		suser_used(p);
 	return (error);
 }
 
@@ -609,7 +627,7 @@
 	struct inode	*ip = VTOI(vp);
 	off_t	base_offset;
 
-	int	error = 0;
+	int	error = 0, privilege_used = 0;
 
 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
 		return (EROFS);
@@ -622,7 +640,7 @@
 		return (ENOENT);
 
 	if ((error = ufs_extattr_credcheck(attribute, ip->i_uid, cred,
-	    p, IWRITE)))
+	    p, IWRITE, &privilege_used)))
 		return (error);
 
 	/*
@@ -695,6 +713,8 @@
 	if (attribute->uele_backing_vnode != vp)
 		VOP_UNLOCK(attribute->uele_backing_vnode, 0, p);
 
+	if (error == 0 && privilege_used)
+		suser_used(p);
 	return (error);
 }
 
@@ -714,7 +734,7 @@
 	struct ufsmount	*ump = VFSTOUFS(mp);
 	struct inode	*ip = VTOI(vp);
 	off_t	base_offset;
-	int	error = 0;
+	int	error = 0, privilege_used = 0;
 
 	if (vp->v_mount->mnt_flag & MNT_RDONLY)  
 		return (EROFS);
@@ -727,7 +747,7 @@
 		return (ENOENT);
 
 	if ((error = ufs_extattr_credcheck(attribute, ip->i_uid, cred, p,
-	    IWRITE)))
+	    IWRITE, &privilege_used)))
 		return (error);
 
 	/*
@@ -788,6 +808,8 @@
 vopunlock_exit:
 	VOP_UNLOCK(attribute->uele_backing_vnode, 0, p);
 
+	if (error == 0 && privilege_used)
+		suser_used(p);
 	return (error);
 }
 
Index: sys/ufs/ufs/ufs_vfsops.c
===================================================================
RCS file: /home/ncvs/src/sys/ufs/ufs/ufs_vfsops.c,v
retrieving revision 1.18
diff -u -r1.18 ufs_vfsops.c
--- sys/ufs/ufs/ufs_vfsops.c	2000/04/15 03:34:26	1.18
+++ sys/ufs/ufs/ufs_vfsops.c	2000/08/09 18:41:17
@@ -102,7 +102,7 @@
 #ifndef QUOTA
 	return (EOPNOTSUPP);
 #else
-	int cmd, type, error;
+	int cmd, type, error, privilege_used = 0;
 
 	if (uid == -1)
 		uid = p->p_cred->p_ruid;
@@ -116,8 +116,11 @@
 			break;
 		/* fall through */
 	default:
-		if ((error = suser_xxx(0, p, PRISON_ROOT)) != 0)
+		if ((error = suser_xxx(0, p, PRISON_ROOT)) &&
+		    (error = cap_check_xxx(NULL, p, CAP_SYS_ADMIN,
+		    PRISON_ROOT)))
 			return (error);
+		privilege_used = 1;
 	}
 
 	type = cmds & SUBCMDMASK;
@@ -157,6 +160,8 @@
 		break;
 	}
 	vfs_unbusy(mp, p);
+	if (error == 0 && privilege_used)
+		suser_used(p);
 	return (error);
 #endif
 }
Index: sys/ufs/ufs/ufs_vnops.c
===================================================================
RCS file: /home/ncvs/src/sys/ufs/ufs/ufs_vnops.c,v
retrieving revision 1.143
diff -u -r1.143 ufs_vnops.c
--- sys/ufs/ufs/ufs_vnops.c	2000/08/29 14:45:49	1.143
+++ sys/ufs/ufs/ufs_vnops.c	2000/08/29 17:01:00
@@ -59,6 +59,7 @@
 #include <sys/lockf.h>
 #include <sys/event.h>
 #include <sys/conf.h>
+#include <sys/capability.h>
 
 #include <vm/vm.h>
 #include <vm/vm_extern.h>
@@ -300,10 +301,10 @@
 {
 	struct vnode *vp = ap->a_vp;
 	struct inode *ip = VTOI(vp);
-	mode_t mode = ap->a_mode;
-#ifdef QUOTA
-	int error;
-#endif
+	struct ucred *cred = ap->a_cred;
+	struct proc *p = ap->a_p;
+	register gid_t *gp;
+	int i, error, privused;
 
 	/*
 	 * Disallow write attempts on read-only file systems;
@@ -331,8 +332,15 @@
 	if ((mode & VWRITE) && (ip->i_flags & (IMMUTABLE | SF_SNAPSHOT)))
 		return (EPERM);
 
-	return (vaccess(vp->v_type, ip->i_mode, ip->i_uid, ip->i_gid,
-	    ap->a_mode, ap->a_cred, NULL));
+	privused = 0;
+	error = vaccess(vp->v_type, ip->i_mode, ip->i_uid, ip->i_gid,
+	    ap->a_mode, ap->a_cred, &privused);
+	if (error)
+		return (error);
+	if (privused)
+		suser_used(ap->a_p);
+
+	return (0);
 }
 
 /* ARGSUSED */
@@ -394,7 +402,7 @@
 	struct inode *ip = VTOI(vp);
 	struct ucred *cred = ap->a_cred;
 	struct proc *p = ap->a_p;
-	int error;
+	int error, privilege_used = 0;
 
 	/*
 	 * Check for unsettable attributes.
@@ -409,9 +417,12 @@
 		if (vp->v_mount->mnt_flag & MNT_RDONLY)
 			return (EROFS);
 		if (cred->cr_uid != ip->i_uid &&
-		    (error = suser_xxx(cred, p, PRISON_ROOT)))
+		    (error = suser_xxx(cred, p, PRISON_ROOT)) &&
+		    (error = cap_check_xxx(cred, p, CAP_SYS_SETFFLAG, 0)))
 			return (error);
-		if ((cred->cr_uid == 0) && (p->p_prison == NULL)) {
+		if (!suser_xxx(cred, p, 0) ||
+		    !cap_check_xxx(cred, p, CAP_SYS_SETFFLAG, 0)) {
+			privilege_used = 1;
 			if ((ip->i_flags
 			    & (SF_NOUNLINK | SF_IMMUTABLE | SF_APPEND)) &&
 			    securelevel > 0)
@@ -432,8 +443,11 @@
 			ip->i_flags |= (vap->va_flags & UF_SETTABLE);
 		}
 		ip->i_flag |= IN_CHANGE;
-		if (vap->va_flags & (IMMUTABLE | APPEND))
+		if (vap->va_flags & (IMMUTABLE | APPEND)) {
+			if (privilege_used)
+				suser_used(p);
 			return (0);
+		}
 	}
 	if (ip->i_flags & (IMMUTABLE | APPEND))
 		return (EPERM);
@@ -474,10 +488,14 @@
 		if ((ip->i_flags & SF_SNAPSHOT) != 0)
 			return (EPERM);
 		if (cred->cr_uid != ip->i_uid &&
-		    (error = suser_xxx(cred, p, PRISON_ROOT)) &&
 		    ((vap->va_vaflags & VA_UTIMES_NULL) == 0 ||
-		    (error = VOP_ACCESS(vp, VWRITE, cred, p))))
-			return (error);
+		    (error = VOP_ACCESS(vp, VWRITE, cred, p)))) {
+			if ((error = suser_xxx(cred, p, PRISON_ROOT)) &&
+			    (error = cap_check_xxx(cred, p, CAP_FOWNER,
+			    PRISON_ROOT)))
+				return (error);
+			privilege_used = 1;
+		}
 		if (vap->va_atime.tv_sec != VNOVAL)
 			ip->i_flag |= IN_ACCESS;
 		if (vap->va_mtime.tv_sec != VNOVAL)
@@ -505,6 +523,8 @@
 		error = ufs_chmod(vp, (int)vap->va_mode, cred, p);
 	}
 	VN_KNOTE(vp, NOTE_ATTRIB);
+	if (error == 0 && privilege_used)
+		suser_used(p);
 	return (error);
 }
 
@@ -520,22 +540,29 @@
 	struct proc *p;
 {
 	register struct inode *ip = VTOI(vp);
-	int error;
+	int error, privilege_used = 0;
 
 	if (cred->cr_uid != ip->i_uid) {
-	    error = suser_xxx(cred, p, PRISON_ROOT);
-	    if (error)
-		return (error);
+		if ((error = suser_xxx(cred, p, PRISON_ROOT)) &&
+		    (error = cap_check_xxx(cred, p, CAP_FOWNER, PRISON_ROOT)))
+			return (error);
+		privilege_used = 1;
 	}
-	if (cred->cr_uid) {
+	if (suser_xxx(cred, NULL, PRISON_ROOT)) {
 		if (vp->v_type != VDIR && (mode & S_ISTXT))
 			return (EFTYPE);
 		if (!groupmember(ip->i_gid, cred) && (mode & ISGID))
 			return (EPERM);
+	} else {
+		if ((vp->v_type != VDIR && (mode & S_ISTXT)) ||
+		    (!groupmember(ip->i_gid, cred) && (mode & ISGID)))
+			privilege_used = 1;
 	}
 	ip->i_mode &= ~ALLPERMS;
 	ip->i_mode |= (mode & ALLPERMS);
 	ip->i_flag |= IN_CHANGE;
+	if (privilege_used)
+		suser_used(p);
 	return (0);
 }
 
@@ -554,7 +581,7 @@
 	register struct inode *ip = VTOI(vp);
 	uid_t ouid;
 	gid_t ogid;
-	int error = 0;
+	int error = 0, privilege_used = 0;
 #ifdef QUOTA
 	register int i;
 	long change;
@@ -570,9 +597,12 @@
 	 * the caller must be superuser or the call fails.
 	 */
 	if ((cred->cr_uid != ip->i_uid || uid != ip->i_uid ||
-	    (gid != ip->i_gid && !groupmember((gid_t)gid, cred))) &&
-	    (error = suser_xxx(cred, p, PRISON_ROOT)))
-		return (error);
+	    (gid != ip->i_gid && !groupmember((gid_t)gid, cred)))) {
+		if ((error = suser_xxx(cred, p, PRISON_ROOT)) &&
+		    (error = cap_check_xxx(cred, p, CAP_CHOWN, PRISON_ROOT)))
+			return (error);
+		privilege_used = 1;
+	}
 	ogid = ip->i_gid;
 	ouid = ip->i_uid;
 #ifdef QUOTA
@@ -638,8 +668,15 @@
 		panic("ufs_chown: lost quota");
 #endif /* QUOTA */
 	ip->i_flag |= IN_CHANGE;
-	if (cred->cr_uid != 0 && (ouid != uid || ogid != gid))
-		ip->i_mode &= ~(ISUID | ISGID);
+	if (ouid != uid || ogid != gid) {
+		if (suser_xxx(cred, p, PRISON_ROOT) &&
+		    cap_check_xxx(cred, p, CAP_FSETID, PRISON_ROOT))
+			ip->i_mode &= ~(ISUID | ISGID);
+		else
+			privilege_used = 1;
+	}
+	if (privilege_used)
+		suser_used(p);
 	return (0);
 }
 
@@ -854,7 +891,7 @@
 	struct inode *ip, *xp, *dp;
 	struct direct newdir;
 	int doingdirectory = 0, oldparent = 0, newparent = 0;
-	int error = 0, ioflag;
+	int error = 0, ioflag, privilege_used = 0;
 
 #ifdef DIAGNOSTIC
 	if ((tcnp->cn_flags & HASBUF) == 0 ||
@@ -1092,12 +1129,19 @@
 		 * own the parent directory, or the destination of the rename,
 		 * otherwise the destination may not be changed (except by
 		 * root). This implements append-only directories.
+		 *
+		 * XXX should some sort of capability check be happening here?
 		 */
-		if ((dp->i_mode & S_ISTXT) && tcnp->cn_cred->cr_uid != 0 &&
+		if ((dp->i_mode & S_ISTXT) &&
 		    tcnp->cn_cred->cr_uid != dp->i_uid &&
 		    xp->i_uid != tcnp->cn_cred->cr_uid) {
-			error = EPERM;
-			goto bad;
+			if (suser_xxx(tcnp->cn_cred, NULL, 0) &&
+			    cap_check_xxx(tcnp->cn_cred, NULL, CAP_DAC_WRITE,
+			    0)) {
+				error = EPERM;
+				goto bad;
+			}
+			privilege_used = 1;
 		}
 		/*
 		 * Target must be empty if a directory and have no links
@@ -1185,6 +1229,8 @@
 		if (doingdirectory)
 			panic("ufs_rename: lost dir entry");
 		vrele(ap->a_fvp);
+		if (privilege_used)
+			suser_used(p);
 		return (0);
 	}
 	/*
@@ -1220,6 +1266,8 @@
 	if (xp)
 		vput(fvp);
 	vrele(ap->a_fvp);
+	if (error == 0 && privilege_used)
+		suser_used(p);
 	return (error);
 
 bad:
@@ -1239,6 +1287,8 @@
 		vput(fvp);
 	} else
 		vrele(fvp);
+	if (error == 0 && privilege_used)
+		suser_used(p);
 	return (error);
 }
 
@@ -2043,7 +2093,7 @@
 	register struct inode *ip, *pdir;
 	struct direct newdir;
 	struct vnode *tvp;
-	int error;
+	int error, privilege_used = 0;
 
 	pdir = VTOI(dvp);
 #ifdef DIAGNOSTIC
@@ -2121,9 +2171,13 @@
 	ip->i_nlink = 1;
 	if (DOINGSOFTDEP(tvp))
 		softdep_change_linkcnt(ip);
-	if ((ip->i_mode & ISGID) && !groupmember(ip->i_gid, cnp->cn_cred) &&
-	    suser_xxx(cnp->cn_cred, 0, 0))
-		ip->i_mode &= ~ISGID;
+	if ((ip->i_mode & ISGID) && !groupmember(ip->i_gid, cnp->cn_cred)) {
+		if (suser_xxx(cnp->cn_cred, 0, 0) &&
+		    cap_check_xxx(cnp->cn_cred, NULL, CAP_FSETID, 0))
+			ip->i_mode &= ~ISGID;
+		else
+			privilege_used = 1;
+	}
 
 	if (cnp->cn_flags & ISWHITEOUT)
 		ip->i_flags |= UF_OPAQUE;
@@ -2139,6 +2193,13 @@
 	if (error)
 		goto bad;
 	*vpp = tvp;
+/*
+	XXX struct proc is not passed in, so we can't mark as having used
+	    privilege
+
+	if (privilege_used)
+		suser_used(p);
+*/
 	return (0);
 
 bad:
Index: usr.bin/find/function.c
===================================================================
RCS file: /home/ncvs/src/usr.bin/find/function.c,v
retrieving revision 1.27
diff -u -r1.27 function.c
--- usr.bin/find/function.c	2000/07/28 20:02:42	1.27
+++ usr.bin/find/function.c	2000/08/07 00:56:16
@@ -44,6 +44,7 @@
 #endif /* not lint */
 
 #include <sys/param.h>
+#include <sys/capability.h>
 #include <sys/ucred.h>
 #include <sys/stat.h>
 #include <sys/wait.h>
Index: usr.bin/kdump/Makefile
===================================================================
RCS file: /home/ncvs/src/usr.bin/kdump/Makefile,v
retrieving revision 1.5
diff -u -r1.5 Makefile
--- usr.bin/kdump/Makefile	2000/08/01 10:21:12	1.5
+++ usr.bin/kdump/Makefile	2000/08/07 00:56:25
@@ -2,7 +2,7 @@
 # $FreeBSD: src/usr.bin/kdump/Makefile,v 1.5 2000/08/01 10:21:12 ru Exp $
 
 PROG=	kdump
-CFLAGS+=-I${.CURDIR}/../ktrace -I${.CURDIR}/../..
+CFLAGS+=-I${.CURDIR}/../ktrace -I${.CURDIR}/../.. -I${.CURDIR}/../../sys
 SRCS=	kdump.c ioctl.c subr.c
 .PATH:	${.CURDIR}/../ktrace
 CLEANFILES+=ioctl.c
Index: usr.sbin/inetd/builtins.c
===================================================================
RCS file: /home/ncvs/src/usr.sbin/inetd/builtins.c,v
retrieving revision 1.24
diff -u -r1.24 builtins.c
--- usr.sbin/inetd/builtins.c	2000/07/12 20:49:06	1.24
+++ usr.sbin/inetd/builtins.c	2000/07/14 05:48:31
@@ -33,6 +33,7 @@
 #include <sys/stat.h>
 #include <sys/socket.h>
 #include <sys/sysctl.h>
+#include <sys/capability.h>
 #include <sys/ucred.h>
 #include <sys/uio.h>
 #include <sys/utsname.h>
Index: usr.sbin/pstat/pstat.c
===================================================================
RCS file: /home/ncvs/src/usr.sbin/pstat/pstat.c,v
retrieving revision 1.49
diff -u -r1.49 pstat.c
--- usr.sbin/pstat/pstat.c	2000/01/29 16:45:28	1.49
+++ usr.sbin/pstat/pstat.c	2000/04/12 19:57:58
@@ -48,6 +48,7 @@
 #include <sys/param.h>
 #include <sys/time.h>
 #include <sys/vnode.h>
+#include <sys/capability.h>
 #include <sys/ucred.h>
 #define _KERNEL
 #include <sys/file.h>
Index: usr.sbin/rpc.umntall/rpc.umntall.c
===================================================================
RCS file: /home/ncvs/src/usr.sbin/rpc.umntall/rpc.umntall.c,v
retrieving revision 1.3
diff -u -r1.3 rpc.umntall.c
--- usr.sbin/rpc.umntall/rpc.umntall.c	2000/01/15 14:28:14	1.3
+++ usr.sbin/rpc.umntall/rpc.umntall.c	2000/04/12 20:10:46
@@ -31,6 +31,7 @@
 #endif /* not lint */
 
 #include <sys/param.h>
+#include <sys/capability.h>
 #include <sys/ucred.h>
 #include <sys/mount.h>
 
