diff -ur src.virgin/sys/kern/kern_fork.c src.dirty/sys/kern/kern_fork.c
--- src.virgin/sys/kern/kern_fork.c	Mon Dec  9 19:33:44 2002
+++ src.dirty/sys/kern/kern_fork.c	Thu Feb 27 17:38:32 2003
@@ -120,6 +120,11 @@
 	int error;
 	struct proc *p2;
 
+	error = jail_check_resources(td);
+	if (error) {
+		return error;
+	}
+		
 	mtx_lock(&Giant);
 	error = fork1(td, RFFDG | RFPROC, 0, &p2);
 	if (error == 0) {
@@ -142,6 +147,11 @@
 	int error;
 	struct proc *p2;
 
+	error = jail_check_resources(td);
+	if (error) {
+		return error;
+	}
+
 	mtx_lock(&Giant);
 	error = fork1(td, RFFDG | RFPROC | RFPPWAIT | RFMEM, 0, &p2);
 	if (error == 0) {
@@ -162,6 +172,11 @@
 {
 	int error;
 	struct proc *p2;
+
+	error = jail_check_resources(td);
+	if (error) {
+		return error;
+	}
 
 	/* Don't allow kernel only flags. */
 	if ((uap->flags & RFKERNELONLY) != 0)
diff -ur src.virgin/sys/kern/kern_jail.c src.dirty/sys/kern/kern_jail.c
--- src.virgin/sys/kern/kern_jail.c	Thu Dec 19 02:40:10 2002
+++ src.dirty/sys/kern/kern_jail.c	Sat Mar 22 13:25:39 2003
@@ -18,6 +18,11 @@
 #include <sys/sysproto.h>
 #include <sys/malloc.h>
 #include <sys/proc.h>
+#include <vm/vm.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_page.h>
+#include <vm/vm_object.h>
+#include <vm/vm_map.h>
 #include <sys/jail.h>
 #include <sys/lock.h>
 #include <sys/mutex.h>
@@ -25,6 +30,10 @@
 #include <sys/sysctl.h>
 #include <net/if.h>
 #include <netinet/in.h>
+#include <sys/sbuf.h>
+#include <sys/sched.h>
+#include <sys/vnode.h>
+#include <sys/mount.h>
 
 MALLOC_DEFINE(M_PRISON, "prison", "Prison structures");
 
@@ -49,6 +58,118 @@
     &jail_sysvipc_allowed, 0,
     "Processes in jail can use System V IPC primitives");
 
+int jail_quotas_allowed = 0;
+SYSCTL_INT(_security_jail, OID_AUTO, quotas_allowed, CTLFLAG_RW, &jail_quotas_allowed, 0,
+    "Processes have access to the quota system.");
+
+int	jail_hide_processes = 0;
+SYSCTL_INT(_security_jail, OID_AUTO, hide_processes, CTLFLAG_RW,
+    &jail_hide_processes, 0,
+    "Processes in jail are not visible outside the jail (except to root)");
+
+int	jail_hide_files = 0;
+SYSCTL_INT(_security_jail, OID_AUTO, hide_files, CTLFLAG_RW,
+    &jail_hide_files, 0,
+    "Files in jail are not visible outside the jail (except to root)");
+
+struct jails firstjail = LIST_HEAD_INITIALIZER(jails);
+
+SYSCTL_NODE(, OID_AUTO, jail, CTLFLAG_RD, 0, "jail parameters");
+SYSCTL_NODE(_jail, OID_AUTO, jails, CTLFLAG_RD, 0, "per-jail settings");
+
+int jail_ipv4addr_sysctl(SYSCTL_HANDLER_ARGS);
+
+int
+jail_ipv4addr_sysctl(SYSCTL_HANDLER_ARGS)
+{
+	int error, i = 0, j = 0, k, ipmode;
+	char buf[1024], *tmpptr, *tmpbuf, *tmpbuf2;
+	struct prison *pr = (struct prison*)(oidp->oid_arg1);
+	u_int32_t *ips_new;
+	in_addr_t addr;
+	struct sbuf *sb;
+	struct in_addr inaddr;
+	unsigned long ipelement[4];
+
+	/* Spit out all IP addresses in jail. */
+	sb = sbuf_new(NULL, NULL, 1024, SBUF_AUTOEXTEND);
+	for (i = 0; i < pr->pr_nips; i++) {
+		inaddr.s_addr = ntohl(pr->pr_ips[i]);
+		sbuf_printf(sb, "%s", inet_ntoa(inaddr));
+		if (i != pr->pr_nips - 1) {
+			sbuf_printf(sb, ",");
+		}
+	}
+	sbuf_finish(sb);
+	strlcpy(buf, sbuf_data(sb), sizeof(buf));
+	error = sysctl_handle_string(oidp, &buf[0], sizeof(buf), req);
+	sbuf_delete(sb);
+
+	if (error == 0 && req->newptr != NULL) {
+		if (buf[0] == '+' || (buf[0] >= 48 && buf[0] <= 57)) {
+			ipmode = 0;
+			MALLOC(ips_new, u_int32_t *, sizeof(u_int32_t) * (pr->pr_nips + 1), M_PRISON, M_WAITOK);
+			memcpy(ips_new, pr->pr_ips, sizeof(u_int32_t) * (pr->pr_nips));
+		} else if (buf[0] == '-') {
+			ipmode = 1;
+			if (pr->pr_nips == 1) {
+				return EINVAL;
+			}
+			MALLOC(ips_new, u_int32_t *, sizeof(u_int32_t) * (pr->pr_nips - 1), M_PRISON, M_WAITOK);
+		} else {
+			return EINVAL;
+		}
+
+		/* Simulate inet_aton *sigh*. */
+		tmpptr = (char*)&addr;
+		if (buf[0] == '+' || buf[0] == '-') {
+			tmpbuf2 = buf + 1;
+		} else {
+			tmpbuf2 = buf;
+		}
+		tmpbuf = tmpbuf2;
+		while(*tmpbuf) {
+			/* First pass: replace '.' with '\0'. */
+			if (*tmpbuf == '.') {
+				i++;
+				*tmpbuf = '\0';
+			}
+			tmpbuf++;
+		}
+		tmpbuf = tmpbuf2;
+		for(j = 0; j <= i; j++) {
+			/* Second pass: fill addr. */
+			ipelement[j] = strtoul(tmpbuf, NULL, 10);
+			k = strlen(tmpbuf);
+			tmpbuf += k + 1;
+		}
+		addr = ipelement[3];
+		addr |= (ipelement[0] << 24) | (ipelement[1] << 16) | (ipelement[2] << 8);
+
+		/* Perform add/delete */
+		mtx_lock(&pr->pr_mtx);
+		if (ipmode == 0) {
+			ips_new[pr->pr_nips] = addr;
+			pr->pr_nips++;
+		} else {
+			i = 0;
+			for (j = 0; j < pr->pr_nips; j++) {
+				if (addr != pr->pr_ips[j]) {
+					ips_new[i] = pr->pr_ips[j];
+					i++;
+				}
+			}
+			pr->pr_nips--;
+		}
+		FREE(pr->pr_ips, M_PRISON);
+		pr->pr_ips = ips_new;
+		mtx_unlock(&pr->pr_mtx);
+
+	}
+
+	return error;
+}
+
 /*
  * MPSAFE
  */
@@ -60,16 +181,18 @@
 	} */ *uap;
 {
 	struct proc *p = td->td_proc;
-	int error;
+	int error, size = 0;
 	struct prison *pr;
 	struct jail j;
 	struct chroot_args ca;
 	struct ucred *newcred = NULL, *oldcred;
+	struct jailelement *tmpelement;
+	char *tmpString;
 
 	error = copyin(uap->jail, &j, sizeof j);
 	if (error)
 		return (error);
-	if (j.version != 0)
+	if (j.version != 1)
 		return (EINVAL);
 
 	MALLOC(pr, struct prison *, sizeof *pr , M_PRISON, M_WAITOK | M_ZERO);
@@ -85,7 +208,16 @@
 	if (error)
 		goto bail;
 	newcred = crget();
-	pr->pr_ip = j.ip_number;
+
+	MALLOC(pr->pr_ips, u_int32_t *, sizeof(u_int32_t) * j.nips, M_PRISON,
+	    M_WAITOK);
+	error = copyin(j.ips, pr->pr_ips, sizeof(u_int32_t) * j.nips);
+	if (error) {
+		FREE(pr->pr_ips, M_PRISON);
+		goto bail;
+	}
+	pr->pr_nips = j.nips;
+
 	PROC_LOCK(p);
 	/* Implicitly fail if already in jail.  */
 	error = suser_cred(p->p_ucred, 0);
@@ -96,6 +228,48 @@
 	p->p_ucred = newcred;
 	p->p_ucred->cr_prison = pr;
 	pr->pr_ref = 1;
+
+	/* Add jail to list. */
+	MALLOC(tmpelement, struct jailelement*, sizeof(struct jailelement), M_PRISON, M_WAITOK | M_ZERO);
+	tmpelement->pr = pr;
+	MALLOC(tmpelement->chroot_path, char *, strlen(j.path) + 1, M_PRISON, M_WAITOK);
+	copyinstr(j.path, tmpelement->chroot_path, strlen(j.path) + 1, &size);
+	LIST_INSERT_HEAD(&firstjail, tmpelement, pointers);
+
+	/* Add sysctls. */
+	strcpy(pr->pr_host_oid, pr->pr_host);
+	tmpString = pr->pr_host_oid;
+	while(*tmpString) {
+		if (*tmpString == '.') {
+			*tmpString = '_';
+		}
+		tmpString++;
+	}
+	
+	sysctl_ctx_init(&pr->jd_sysctltree);
+	pr->jd_sysctltreetop = SYSCTL_ADD_NODE(&pr->jd_sysctltree,
+		SYSCTL_STATIC_CHILDREN(_jail_jails), OID_AUTO,
+		pr->pr_host_oid, CTLFLAG_RD, 0, "jail hostname");
+	SYSCTL_ADD_INT(&pr->jd_sysctltree, SYSCTL_CHILDREN(pr->jd_sysctltreetop), OID_AUTO, "allow_raw_sockets", 
+		CTLFLAG_RW, &pr->jail_settings.allow_raw_sockets, 0, "Allow raw sockets in jail?");
+	SYSCTL_ADD_INT(&pr->jd_sysctltree, SYSCTL_CHILDREN(pr->jd_sysctltreetop), OID_AUTO, "allow_ipfw", 
+		CTLFLAG_RW, &pr->jail_settings.allow_ipfw, 0, "Allow ipfw use?");
+	SYSCTL_ADD_INT(&pr->jd_sysctltree, SYSCTL_CHILDREN(pr->jd_sysctltreetop), OID_AUTO, "max_ram", 
+		CTLFLAG_RW, &pr->jail_settings.max_ram, 0, "Maximum RAM allowed for jail (0 = unlimited)");
+	SYSCTL_ADD_INT(&pr->jd_sysctltree, SYSCTL_CHILDREN(pr->jd_sysctltreetop), OID_AUTO, "max_cpu", 
+		CTLFLAG_RW, &pr->jail_settings.max_cpu, 0, "Maximum CPU allowed for jail (0 = unlimited)");
+	SYSCTL_ADD_INT(&pr->jd_sysctltree, SYSCTL_CHILDREN(pr->jd_sysctltreetop), OID_AUTO, "max_procs", 
+		CTLFLAG_RW, &pr->jail_settings.max_procs, 0, "Maximum number of processes allowed for jail (0 = unlimited)");
+	SYSCTL_ADD_INT(&pr->jd_sysctltree, SYSCTL_CHILDREN(pr->jd_sysctltreetop), OID_AUTO, "procs_used", 
+		CTLFLAG_RD, &pr->jail_settings.procs_used, 0, "Number of processes running");
+	SYSCTL_ADD_INT(&pr->jd_sysctltree, SYSCTL_CHILDREN(pr->jd_sysctltreetop), OID_AUTO, "ram_used", 
+		CTLFLAG_RD, &pr->jail_settings.ram_used, 0, "Amount of RAM used");
+	SYSCTL_ADD_INT(&pr->jd_sysctltree, SYSCTL_CHILDREN(pr->jd_sysctltreetop), OID_AUTO, "cpu_used", 
+		CTLFLAG_RD, &pr->jail_settings.cpu_used, 0, "Amount of CPU used");
+	SYSCTL_ADD_PROC(&pr->jd_sysctltree, SYSCTL_CHILDREN(pr->jd_sysctltreetop), OID_AUTO, 
+		"ipv4addr", CTLTYPE_STRING | CTLFLAG_RW, pr, sizeof (struct prison), jail_ipv4addr_sysctl,
+		"A", "List of IPv4 addresses in jail.");
+
 	PROC_UNLOCK(p);
 	crfree(oldcred);
 	return (0);
@@ -107,17 +281,157 @@
 	return (error);
 }
 
+int
+jail_calctotalused(pr)
+	struct prison *pr;
+{
+	struct proc *process;
+	u_int totalram = 0;
+	u_int numprocs = 0;
+
+	/* Go through every process in the system and calculate 
+	   the amount of CPU and RAM used. */
+	FOREACH_PROC_IN_SYSTEM(process) {
+		if (!jailed(process->p_ucred)) {
+			continue;
+		}
+
+		if (process->p_ucred->cr_prison != pr) {
+			continue;
+		}
+
+		numprocs++;
+		totalram += process->p_vmspace->vm_tsize + process->p_vmspace->vm_dsize
+		    + process->p_vmspace->vm_ssize;
+	}
+
+	mtx_lock(&pr->pr_mtx);
+	pr->jail_settings.ram_used = totalram * PAGE_SIZE;
+	pr->jail_settings.procs_used = numprocs;
+	mtx_unlock(&pr->pr_mtx);
+
+	return 0;
+}
+
+/* This is from print.c in /usr/src/bin/ps. */
+#define fxtofl(fixpt)   ((double)(fixpt) / FSCALE)
+
+void
+jail_update_cpu(void)
+{
+	struct proc *p;
+	struct jailelement *element;
+	struct thread *td;
+
+	/* If no jails exist, exit function. */
+	if (!firstjail.lh_first) {
+		return;
+	}
+
+	/* Clear jail CPU counters. */
+	LIST_FOREACH(element, &firstjail, pointers) {
+		element->pr->jail_settings.cpu_used = 0;
+	}
+
+	/* Check all processes for CPU usage. */
+	FOREACH_PROC_IN_SYSTEM(p) {
+		FOREACH_THREAD_IN_PROC(p, td) {
+			if (td->td_kse && td->td_ucred->cr_prison) {
+				td->td_ucred->cr_prison->jail_settings.cpu_used += 
+				    fxtofl(sched_pctcpu(td->td_kse)) * 100.0;
+			}
+		}
+	}
+
+	/* Exit function. */
+	return;
+}
+
+int
+jail_check_cpu(uc)
+	struct ucred *uc;
+{
+	if (uc->cr_prison && uc->cr_prison->jail_settings.cpu_used >= 
+	    uc->cr_prison->jail_settings.max_cpu && uc->cr_prison->jail_settings.max_cpu > 0) {
+		return 1;
+	} else {
+		return 0;
+	}
+}
+
+int
+jail_check_resources(td)
+	struct thread *td;
+{
+	struct prison *pr = td->td_proc->p_ucred->cr_prison;
+        
+	if (pr) {
+		/* Ensure jail isn't using more than it is allocated. */ 
+		jail_calctotalused(pr);
+		if (pr->jail_settings.max_ram > 0 && 
+		    pr->jail_settings.ram_used > pr->jail_settings.max_ram) {
+			return ENOMEM;
+		} else if (pr->jail_settings.max_procs > 0 &&
+		    pr->jail_settings.procs_used > pr->jail_settings.max_procs) {
+			return EAGAIN;
+		} else if (pr->jail_settings.max_cpu > 0 &&  
+		    pr->jail_settings.cpu_used > pr->jail_settings.max_cpu) {    
+			return EAGAIN;
+		}
+	}
+
+	return 0;
+}
+
+int
+jail_check_fileperm(vp, cred, td)
+	struct vnode *vp;
+	struct ucred *cred;
+	struct thread *td;
+{
+	struct jailelement *element;
+
+	/* If file is in a running jail, and jail_hide_files = 1, deny permission
+	   to all but root. */
+	if (jail_hide_files && !cred->cr_prison && cred->cr_uid > 0) {
+		LIST_FOREACH(element, &firstjail, pointers) {
+			if (!strncmp(vp->v_mount->mnt_stat.f_mntonname, element->chroot_path,
+			    strlen(element->chroot_path))) {
+				return EACCES;
+			}
+		} 
+	}
+
+	return 0;
+}
+
 void
 prison_free(struct prison *pr)
 {
+	struct jailelement *element;
 
 	mtx_lock(&pr->pr_mtx);
 	pr->pr_ref--;
 	if (pr->pr_ref == 0) {
 		mtx_unlock(&pr->pr_mtx);
 		mtx_destroy(&pr->pr_mtx);
+
+		/* Remove jail from list. */
+		LIST_FOREACH(element, &firstjail, pointers) {
+			if (element->pr == pr) {
+				LIST_REMOVE(element, pointers);
+				break;
+			}
+		}
+
 		if (pr->pr_linux != NULL)
 			FREE(pr->pr_linux, M_PRISON);
+		FREE(pr->pr_ips, M_PRISON);
+
+		/* Remove sysctls. */
+		pr->jd_sysctltreetop = NULL;
+		sysctl_ctx_free(&pr->jd_sysctltree);
+
 		FREE(pr, M_PRISON);
 		return;
 	}
@@ -137,7 +451,7 @@
 prison_getip(struct ucred *cred)
 {
 
-	return (cred->cr_prison->pr_ip);
+	return (cred->cr_prison->pr_ips[0]);
 }
 
 int
@@ -152,20 +466,16 @@
 	else
 		tmp = ntohl(*ip);
 	if (tmp == INADDR_ANY) {
-		if (flag) 
-			*ip = cred->cr_prison->pr_ip;
-		else
-			*ip = htonl(cred->cr_prison->pr_ip);
 		return (0);
 	}
 	if (tmp == INADDR_LOOPBACK) {
 		if (flag)
-			*ip = cred->cr_prison->pr_ip;
+			*ip = cred->cr_prison->pr_ips[0];
 		else
-			*ip = htonl(cred->cr_prison->pr_ip);
+			*ip = htonl(cred->cr_prison->pr_ips[0]);
 		return (0);
 	}
-	if (cred->cr_prison->pr_ip != tmp)
+	if (!prison_check_ip(cred->cr_prison, tmp))
 		return (1);
 	return (0);
 }
@@ -183,9 +493,9 @@
 		tmp = ntohl(*ip);
 	if (tmp == INADDR_LOOPBACK) {
 		if (flag)
-			*ip = cred->cr_prison->pr_ip;
+			*ip = cred->cr_prison->pr_ips[0];
 		else
-			*ip = htonl(cred->cr_prison->pr_ip);
+			*ip = htonl(cred->cr_prison->pr_ips[0]);
 		return;
 	}
 	return;
@@ -201,7 +511,7 @@
 		ok = 1;
 	else if (sai->sin_family != AF_INET)
 		ok = 0;
-	else if (cred->cr_prison->pr_ip != ntohl(sai->sin_addr.s_addr))
+	else if (!prison_check_ip(cred->cr_prison, ntohl(sai->sin_addr.s_addr)))
 		ok = 1;
 	else
 		ok = 0;
@@ -221,6 +531,12 @@
 			return (ESRCH);
 		if (cred2->cr_prison != cred1->cr_prison)
 			return (ESRCH);
+	} else {
+		/* This is necessary because it appears if a process is running in
+		   a jail and the process is running under the same UID as the user,
+		   kill() will actually kill it. */
+		if (jailed(cred2) && cred1->cr_ruid != 0 && jail_hide_processes)
+			return (ESRCH);
 	}
 
 	return (0);
@@ -254,4 +570,20 @@
 	}
 	else
 		strlcpy(buf, hostname, size);
+}
+
+/*
+ * Returns 1 if the IP exists in the jail.
+ */
+int
+prison_check_ip(struct prison *pr, u_int32_t ip)
+{
+	register u_int i;
+
+	for (i = 0; i < pr->pr_nips; ++i) {
+		if (pr->pr_ips[i] == ip)
+			return (1);
+	}
+
+	return (0);
 }
diff -ur src.virgin/sys/kern/kern_switch.c src.dirty/sys/kern/kern_switch.c
--- src.virgin/sys/kern/kern_switch.c	Mon Oct 14 14:43:02 2002
+++ src.dirty/sys/kern/kern_switch.c	Thu Feb 27 17:38:32 2003
@@ -98,6 +98,7 @@
 #include <sys/proc.h>
 #include <sys/queue.h>
 #include <sys/sched.h>
+#include <sys/jail.h>
 #include <machine/critical.h>
 
 CTASSERT((RQB_BPW * RQB_LEN) == RQ_NQS);
@@ -241,6 +242,10 @@
 			original->td_kse = NULL;
 		original = owner;
 
+		if (TD_IS_JSLEEP(owner) && jail_check_cpu(owner->td_ucred) == 0) {
+			/* Wake it up. */
+			TD_CLR_JSLEEP(owner);
+		}
 		if (TD_CAN_RUN(owner)) {
 			/*
 			 * If the owner thread is now runnable,  run it..
@@ -379,6 +384,13 @@
 	struct ksegrp *kg;
 	struct thread *td2;
 	struct thread *tda;
+
+	if (td->td_ucred && jail_check_cpu(td->td_ucred) == 1) {
+		/* Don't add to run queue. Put it to sleep. Exit function. */
+		TD_SET_JSLEEP(td);
+		td->td_ucred->cr_prison->resched = 1;
+		return;
+	}
 
 	CTR1(KTR_RUNQ, "setrunqueue: td%p", td);
 	mtx_assert(&sched_lock, MA_OWNED);
diff -ur src.virgin/sys/kern/sched_4bsd.c src.dirty/sys/kern/sched_4bsd.c
--- src.virgin/sys/kern/sched_4bsd.c	Thu Nov 21 02:30:55 2002
+++ src.dirty/sys/kern/sched_4bsd.c	Thu Feb 27 17:38:32 2003
@@ -42,6 +42,7 @@
 #include <sys/systm.h>
 #include <sys/kernel.h>
 #include <sys/ktr.h>
+#include <sys/jail.h>
 #include <sys/lock.h>
 #include <sys/mutex.h>
 #include <sys/proc.h>
@@ -116,7 +117,7 @@
 {
 
 	mtx_assert(&sched_lock, MA_OWNED);
-	if (td->td_priority < curthread->td_priority)
+	if (td->td_priority < curthread->td_priority || td->td_ucred->cr_prison)
 		curthread->td_kse->ke_flags |= KEF_NEEDRESCHED;
 }
 
@@ -241,12 +242,29 @@
 	struct kse *ke;
 	struct ksegrp *kg;
 	int realstathz;
-	int awake;
+	int awake, checked_status = 0;
 
 	realstathz = stathz ? stathz : hz;
 	sx_slock(&allproc_lock);
 	FOREACH_PROC_IN_SYSTEM(p) {
 		mtx_lock_spin(&sched_lock);
+		if (p->p_ucred->cr_prison) {
+			if (!jail_check_cpu(p->p_ucred)) {
+				mtx_unlock_spin(&sched_lock);
+				FOREACH_THREAD_IN_PROC(p, td) {
+					if (TD_IS_JSLEEP(td)) {
+						TD_CLR_JSLEEP(td);
+						setrunqueue(td);
+					}
+				}
+				mtx_lock_spin(&sched_lock);
+			}
+			if (checked_status == 0) {
+				jail_update_cpu();
+				checked_status = 1;
+			}
+		}
+
 		p->p_swtime++;
 		FOREACH_KSEGRP_IN_PROC(p, kg) { 
 			awake = 0;
diff -ur src.virgin/sys/kern/sysv_ipc.c src.dirty/sys/kern/sysv_ipc.c
--- src.virgin/sys/kern/sysv_ipc.c	Mon Apr  1 14:31:00 2002
+++ src.dirty/sys/kern/sysv_ipc.c	Thu Feb 27 17:38:32 2003
@@ -78,6 +78,11 @@
 {
 	struct ucred *cred = td->td_ucred;
 
+	/* Check for jail match. */
+	if (cred->cr_prison != perm->pr) {
+		return EACCES;
+	}
+
 	/* Check for user match. */
 	if (cred->cr_uid != perm->cuid && cred->cr_uid != perm->uid) {
 		if (mode & IPC_M)
diff -ur src.virgin/sys/kern/sysv_msg.c src.dirty/sys/kern/sysv_msg.c
--- src.virgin/sys/kern/sysv_msg.c	Sun Dec 15 06:54:55 2002
+++ src.dirty/sys/kern/sysv_msg.c	Thu Feb 27 17:38:32 2003
@@ -435,6 +435,7 @@
 		msqptr->msg_perm.gid = msqbuf.msg_perm.gid;	/* change the owner */
 		msqptr->msg_perm.mode = (msqptr->msg_perm.mode & ~0777) |
 		    (msqbuf.msg_perm.mode & 0777);
+		msqptr->msg_perm.pr = td->td_ucred->cr_prison;
 		msqptr->msg_qbytes = msqbuf.msg_qbytes;
 		msqptr->msg_ctime = time_second;
 		break;
@@ -539,6 +540,7 @@
 		msqptr->msg_perm.mode = (msgflg & 0777);
 		/* Make sure that the returned msqid is unique */
 		msqptr->msg_perm.seq = (msqptr->msg_perm.seq + 1) & 0x7fff;
+		msqptr->msg_perm.pr = td->td_ucred->cr_prison;
 		msqptr->msg_first = NULL;
 		msqptr->msg_last = NULL;
 		msqptr->msg_cbytes = 0;
diff -ur src.virgin/sys/kern/sysv_sem.c src.dirty/sys/kern/sysv_sem.c
--- src.virgin/sys/kern/sysv_sem.c	Fri Oct 18 20:07:35 2002
+++ src.dirty/sys/kern/sysv_sem.c	Thu Feb 27 17:38:32 2003
@@ -585,6 +585,7 @@
 		semaptr->sem_perm.mode = (semaptr->sem_perm.mode & ~0777) |
 		    (sbuf.sem_perm.mode & 0777);
 		semaptr->sem_ctime = time_second;
+		semaptr->sem_perm.pr = td->td_ucred->cr_prison;
 		break;
 
 	case IPC_STAT:
@@ -832,6 +833,7 @@
 		sema[semid].sem_perm.mode = (semflg & 0777) | SEM_ALLOC;
 		sema[semid].sem_perm.seq =
 		    (sema[semid].sem_perm.seq + 1) & 0x7fff;
+		sema[semid].sem_perm.pr = cred->cr_prison;
 		sema[semid].sem_nsems = nsems;
 		sema[semid].sem_otime = 0;
 		sema[semid].sem_ctime = time_second;
diff -ur src.virgin/sys/kern/sysv_shm.c src.dirty/sys/kern/sysv_shm.c
--- src.virgin/sys/kern/sysv_shm.c	Wed Aug 14 20:10:12 2002
+++ src.dirty/sys/kern/sysv_shm.c	Thu Feb 27 17:38:32 2003
@@ -226,6 +226,11 @@
 
 	segnum = IPCID_TO_IX(shmmap_s->shmid);
 	shmseg = &shmsegs[segnum];
+	/* Check jail permissions. */
+	if (p->p_ucred->cr_prison != shmseg->shm_perm.pr) {
+		return(EACCES);
+	}
+
 	size = round_page(shmseg->shm_segsz);
 	result = vm_map_remove(&p->p_vmspace->vm_map, shmmap_s->va,
 	    shmmap_s->va + size);
@@ -538,6 +543,7 @@
 		    (shmseg->shm_perm.mode & ~ACCESSPERMS) |
 		    (inbuf.shm_perm.mode & ACCESSPERMS);
 		shmseg->shm_ctime = time_second;
+		shmseg->shm_perm.pr = td->td_ucred->cr_prison;
 		break;
 	case IPC_RMID:
 		error = ipcperm(td, &shmseg->shm_perm, IPC_M);
@@ -645,6 +651,7 @@
 	shmseg->shm_perm.mode = SHMSEG_ALLOCATED | SHMSEG_REMOVED;
 	shmseg->shm_perm.key = uap->key;
 	shmseg->shm_perm.seq = (shmseg->shm_perm.seq + 1) & 0x7fff;
+	shmseg->shm_perm.pr = td->td_ucred->cr_prison;
 	shm_handle = (struct shm_handle *)
 	    malloc(sizeof(struct shm_handle), M_SHM, M_WAITOK);
 	shmid = IXSEQ_TO_IPCID(segnum, shmseg->shm_perm);
@@ -673,6 +680,7 @@
 	shmseg->shm_lpid = shmseg->shm_nattch = 0;
 	shmseg->shm_atime = shmseg->shm_dtime = 0;
 	shmseg->shm_ctime = time_second;
+	shmseg->shm_perm.pr = td->td_ucred->cr_prison;
 	shm_committed += btoc(size);
 	shm_nused++;
 	if (shmseg->shm_perm.mode & SHMSEG_WANTED) {
diff -ur src.virgin/sys/kern/vfs_syscalls.c src.dirty/sys/kern/vfs_syscalls.c
--- src.virgin/sys/kern/vfs_syscalls.c	Mon Jan  6 14:20:54 2003
+++ src.dirty/sys/kern/vfs_syscalls.c	Mon Mar  3 07:53:27 2003
@@ -158,7 +158,8 @@
 }
 
 /* XXX PRISON: could be per prison flag */
-static int prison_quotas;
+/*static int prison_quotas;*/
+extern int jail_quotas_allowed;
 #if 0
 SYSCTL_INT(_kern_prison, OID_AUTO, quotas, CTLFLAG_RW, &prison_quotas, 0, "");
 #endif
@@ -189,7 +190,7 @@
 	int error;
 	struct nameidata nd;
 
-	if (jailed(td->td_ucred) && !prison_quotas)
+	if (jailed(td->td_ucred) && !jail_quotas_allowed)
 		return (EPERM);
 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, td);
 	if ((error = namei(&nd)) != 0)
@@ -311,6 +312,8 @@
 	int flags;
 };
 #endif
+extern struct jails firstjail;
+
 int
 getfsstat(td, uap)
 	struct thread *td;
@@ -324,6 +327,7 @@
 	register struct statfs *sp;
 	caddr_t sfsp;
 	long count, maxcount, error;
+	struct statfs *tmpsp;
 
 	maxcount = uap->bufsize / sizeof(struct statfs);
 	sfsp = (caddr_t)uap->buf;
@@ -356,7 +360,35 @@
 				continue;
 			}
 			sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
-			error = copyout(sp, sfsp, sizeof(*sp));
+
+			/* If jailed, only return the mountpoints that are in the jail. */
+			if (td->td_proc->p_ucred->cr_prison) {
+				struct jailelement *element;
+				LIST_FOREACH(element, &firstjail, pointers) {
+					if (element->pr == td->td_proc->p_ucred->cr_prison) {
+						break;
+					}
+				}
+				if (!strncmp(element->chroot_path, sp->f_mntonname, 
+				  strlen(element->chroot_path))) {
+					MALLOC(tmpsp, struct statfs *, sizeof(struct statfs), M_PRISON, M_WAITOK);
+					memcpy(tmpsp, sp, sizeof(struct statfs));
+					strcpy(tmpsp->f_mntonname, sp->f_mntonname + strlen(element->chroot_path));
+					if (strlen(tmpsp->f_mntonname) == 0) {
+						/* Root mount. */
+						strcpy(tmpsp->f_mntonname, "/");
+					}
+					error = copyout(tmpsp, sfsp, sizeof(*tmpsp));
+					FREE(tmpsp, M_PRISON);
+				} else {
+					mtx_lock(&mountlist_mtx);
+					nmp = TAILQ_NEXT(mp, mnt_list);
+					vfs_unbusy(mp, td);
+					continue;
+				}
+			} else {
+				error = copyout(sp, sfsp, sizeof(*sp));
+			}
 			if (error) {
 				vfs_unbusy(mp, td);
 				return (error);
@@ -1423,6 +1455,7 @@
 			flags |= VWRITE;
 		if (user_flags & X_OK)
 			flags |= VEXEC;
+
 #ifdef MAC
 		error = mac_check_vnode_access(cred, vp, flags);
 		if (error)
diff -ur src.virgin/sys/netinet/in_pcb.c src.dirty/sys/netinet/in_pcb.c
--- src.virgin/sys/netinet/in_pcb.c	Fri Nov  8 16:50:32 2002
+++ src.dirty/sys/netinet/in_pcb.c	Sun Mar  2 19:57:40 2003
@@ -296,7 +296,7 @@
 			    !IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) {
 				t = in_pcblookup_local(inp->inp_pcbinfo,
 				    sin->sin_addr, lport,
-				    prison ? 0 :  INPLOOKUP_WILDCARD);
+				    prison ? 0 :  INPLOOKUP_WILDCARD, prison ? td : NULL);
 				if (t &&
 				    (ntohl(sin->sin_addr.s_addr) != INADDR_ANY ||
 				     ntohl(t->inp_laddr.s_addr) != INADDR_ANY ||
@@ -319,7 +319,7 @@
 			    prison_ip(td->td_ucred, 0, &sin->sin_addr.s_addr))
 				return (EADDRNOTAVAIL);
 			t = in_pcblookup_local(pcbinfo, sin->sin_addr,
-			    lport, prison ? 0 : wild);
+			    lport, prison ? 0 : wild, prison ? td : NULL);
 			if (t &&
 			    (reuseport & t->inp_socket->so_options) == 0) {
 #if defined(INET6)
@@ -340,6 +340,9 @@
 		ushort first, last;
 		int count;
 
+		if (laddr.s_addr == INADDR_ANY && td->td_ucred->cr_prison)
+			laddr.s_addr = htonl(prison_getip(td->td_ucred));
+
 		if (laddr.s_addr != INADDR_ANY)
 			if (prison_ip(td->td_ucred, 0, &laddr.s_addr))
 				return (EINVAL);
@@ -381,7 +384,7 @@
 					*lastport = first;
 				lport = htons(*lastport);
 			} while (in_pcblookup_local(pcbinfo, laddr, lport,
-			    wild));
+			    wild, wild ? NULL : td));
 		} else {
 			/*
 			 * counting up
@@ -396,7 +399,7 @@
 					*lastport = first;
 				lport = htons(*lastport);
 			} while (in_pcblookup_local(pcbinfo, laddr, lport,
-			    wild));
+			    wild, wild ? NULL : td));
 		}
 	}
 	if (prison_ip(td->td_ucred, 0, &laddr.s_addr))
@@ -519,9 +522,13 @@
 		 * and the primary interface supports broadcast,
 		 * choose the broadcast address for that interface.
 		 */
-		if (faddr.s_addr == INADDR_ANY)
-			faddr = IA_SIN(TAILQ_FIRST(&in_ifaddrhead))->sin_addr;
-		else if (faddr.s_addr == (u_long)INADDR_BROADCAST &&
+		if (faddr.s_addr == INADDR_ANY) {
+			if (jailed(cred)) {
+				faddr.s_addr = htonl(prison_getip(cred));
+			} else {
+				faddr = IA_SIN(TAILQ_FIRST(&in_ifaddrhead))->sin_addr;
+			}
+		} else if (faddr.s_addr == (u_long)INADDR_BROADCAST &&
 		    (TAILQ_FIRST(&in_ifaddrhead)->ia_ifp->if_flags &
 		    IFF_BROADCAST))
 			faddr = satosin(&TAILQ_FIRST(
@@ -876,11 +883,12 @@
  * Lookup a PCB based on the local address and port.
  */
 struct inpcb *
-in_pcblookup_local(pcbinfo, laddr, lport_arg, wild_okay)
+in_pcblookup_local(pcbinfo, laddr, lport_arg, wild_okay, td)
 	struct inpcbinfo *pcbinfo;
 	struct in_addr laddr;
 	u_int lport_arg;
 	int wild_okay;
+	struct thread *td;
 {
 	register struct inpcb *inp;
 	int matchwild = 3, wildcard;
@@ -900,11 +908,18 @@
 #endif
 			if (inp->inp_faddr.s_addr == INADDR_ANY &&
 			    inp->inp_laddr.s_addr == laddr.s_addr &&
-			    inp->inp_lport == lport) {
+			    inp->inp_lport == lport && 
+			    (laddr.s_addr != INADDR_ANY || !td->td_ucred->cr_prison)) {
 				/*
 				 * Found.
 				 */
 				return (inp);
+			} else if (td->td_ucred->cr_prison &&
+			    td->td_ucred->cr_prison == inp->inp_socket->so_cred->cr_prison &&
+			    inp->inp_faddr.s_addr == INADDR_ANY &&
+			    inp->inp_laddr.s_addr == laddr.s_addr &&
+			    inp->inp_lport == lport) {
+				return (inp);
 			}
 		}
 		/*
@@ -1005,12 +1020,24 @@
 
 		head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0, pcbinfo->hashmask)];
 		LIST_FOREACH(inp, head, inp_hash) {
+			if (inp->inp_socket->so_cred->cr_prison &&
+			    inp->inp_lport == lport &&
+			    inp->inp_laddr.s_addr == INADDR_ANY) {
+				if (prison_check_ip(inp->inp_socket->so_cred->cr_prison, ntohl(laddr.s_addr))) {
+					return (inp);
+				}
+			}
+		}
+
+		head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0, pcbinfo->hashmask)];
+		LIST_FOREACH(inp, head, inp_hash) {
 #ifdef INET6
 			if ((inp->inp_vflag & INP_IPV4) == 0)
 				continue;
 #endif
 			if (inp->inp_faddr.s_addr == INADDR_ANY &&
-			    inp->inp_lport == lport) {
+			    inp->inp_lport == lport &&
+			    !inp->inp_socket->so_cred->cr_prison) {
 				if (ifp && ifp->if_type == IFT_FAITH &&
 				    (inp->inp_flags & INP_FAITH) == 0)
 					continue;
@@ -1019,11 +1046,14 @@
 				else if (inp->inp_laddr.s_addr == INADDR_ANY) {
 #if defined(INET6)
 					if (INP_CHECK_SOCKAF(inp->inp_socket,
-							     AF_INET6))
+							     AF_INET6)) {
 						local_wild_mapped = inp;
-					else
+					} else {
+#endif /* defined(INET6) */
+						local_wild = inp;
+#if defined(INET6)
+					}
 #endif /* defined(INET6) */
-					local_wild = inp;
 				}
 			}
 		}
@@ -1145,7 +1175,7 @@
 {
 	if (!jailed(td->td_ucred))
 		return (0);
-	if (ntohl(inp->inp_laddr.s_addr) == prison_getip(td->td_ucred))
+	if (prison_check_ip(td->td_ucred->cr_prison, ntohl(inp->inp_laddr.s_addr)))
 		return (0);
 	return (1);
 }
diff -ur src.virgin/sys/netinet/in_pcb.h src.dirty/sys/netinet/in_pcb.h
--- src.virgin/sys/netinet/in_pcb.h	Tue Nov 12 13:44:38 2002
+++ src.dirty/sys/netinet/in_pcb.h	Thu Feb 27 17:38:33 2003
@@ -339,7 +339,7 @@
 int	in_pcbinshash(struct inpcb *);
 struct inpcb *
 	in_pcblookup_local(struct inpcbinfo *,
-	    struct in_addr, u_int, int);
+	    struct in_addr, u_int, int, struct thread *);
 struct inpcb *
 	in_pcblookup_hash(struct inpcbinfo *, struct in_addr, u_int,
 	    struct in_addr, u_int, int, struct ifnet *);
diff -ur src.virgin/sys/netinet/ip_fw.c src.dirty/sys/netinet/ip_fw.c
--- src.virgin/sys/netinet/ip_fw.c	Sat Jun 22 05:51:02 2002
+++ src.dirty/sys/netinet/ip_fw.c	Sat Mar 22 13:36:09 2003
@@ -64,6 +64,8 @@
 
 #include <netinet/if_ether.h> /* XXX ethertype_ip */
 
+#include <sys/jail.h>
+
 static int fw_debug = 1;
 #ifdef IPFIREWALL_VERBOSE
 static int fw_verbose = 1;
@@ -2010,6 +2012,11 @@
 	}
 
 	error = 0;
+
+	/* If allow_ipfw is not enabled, return an error. */
+	if (sopt->sopt_td->td_ucred->cr_prison && !sopt->sopt_td->td_ucred->cr_prison->jail_settings.allow_ipfw) {
+		return EPERM;
+	}
 
 	switch (sopt->sopt_name) {
 	case IP_FW_GET:
diff -ur src.virgin/sys/netinet/ip_fw2.c src.dirty/sys/netinet/ip_fw2.c
--- src.virgin/sys/netinet/ip_fw2.c	Sun Dec 15 06:57:43 2002
+++ src.dirty/sys/netinet/ip_fw2.c	Sun Mar 23 10:05:37 2003
@@ -77,6 +77,8 @@
 
 #include <machine/in_cksum.h>	/* XXX for in_cksum */
 
+#include <sys/jail.h>
+
 /*
  * XXX This one should go in sys/mbuf.h. It is used to avoid that
  * a firewall-generated packet loops forever through the firewall.
@@ -2440,6 +2442,34 @@
 	return EINVAL;
 }
 
+static int
+check_ipfw_jail(struct thread *td, struct ip_fw *rule)
+{
+	ipfw_insn_ip *ip_cmd;
+	ipfw_insn *cmd;
+
+	/* Jailed? */
+	if (!td->td_ucred->cr_prison) {
+		return 0;
+	}
+
+	/* Default rule? */
+	if (rule->rulenum == IPFW_DEFAULT_RULE) {
+		return 0;
+	}
+
+	/* Check all IP addresses in opcode list. */
+	for (cmd = rule->cmd; cmd != ACTION_PTR(rule); cmd++) {
+		if (cmd->opcode == O_IP_DST || cmd->opcode == O_IP_SRC) {
+			ip_cmd = (ipfw_insn_ip*)(cmd);
+			if (prison_check_ip(td->td_ucred->cr_prison, htonl(ip_cmd->addr.s_addr))) {
+				return 0;
+			}
+		}
+	}
+
+	return EPERM;
+}
 
 /**
  * {set|get}sockopt parser.
@@ -2471,6 +2501,11 @@
 
 	error = 0;
 
+        /* If allow_ipfw is not enabled, return an error. */
+	if (sopt->sopt_td->td_ucred->cr_prison && !sopt->sopt_td->td_ucred->cr_prison->jail_settings.allow_ipfw) {
+		return EPERM;
+	}
+
 	switch (sopt->sopt_name) {
 	case IP_FW_GET:
 		/*
@@ -2498,10 +2533,12 @@
 
 		bp = buf;
 		for (rule = layer3_chain; rule ; rule = rule->next) {
-			int i = RULESIZE(rule);
-			bcopy(rule, bp, i);
-			((struct ip_fw *)bp)->set_disable = set_disable;
-			bp = (struct ip_fw *)((char *)bp + i);
+			if (!check_ipfw_jail(sopt->sopt_td, rule)) {
+				int i = RULESIZE(rule);
+				bcopy(rule, bp, i);
+				((struct ip_fw *)bp)->set_disable = set_disable;
+				bp = (struct ip_fw *)((char *)bp + i);
+			}
 		}
 		if (ipfw_dyn_v) {
 			int i;
@@ -2547,7 +2584,10 @@
 		 * the list to point to the default rule, and then freeing
 		 * the old list without the need for a lock.
 		 */
-
+		if (sopt->sopt_td->td_ucred->cr_prison) {
+			error = EPERM;
+			break;
+		}
 		s = splimp();
 		free_chain(&layer3_chain, 0 /* keep default rule */);
 		splx(s);
@@ -2561,6 +2601,10 @@
 		if (error || (error = check_ipfw_struct(rule, size)))
 			break;
 
+		/* Check and make sure IP addresses are valid (if jailed). */
+		error = check_ipfw_jail(sopt->sopt_td, rule);
+		if (error) break;
+
 		error = add_rule(&layer3_chain, rule);
 		size = RULESIZE(rule);
 		if (!error && sopt->sopt_dir == SOPT_GET)
@@ -2584,6 +2628,9 @@
 			2*sizeof(u_int32_t), sizeof(u_int32_t));
 		if (error)
 			break;
+		error = check_ipfw_jail(sopt->sopt_td, (struct ip_fw*)rule_buf);
+		if (error)
+			break;
 		size = sopt->sopt_valsize;
 		if (size == sizeof(u_int32_t))	/* delete or reassign */
 			error = del_entry(&layer3_chain, rule_buf[0]);
@@ -2605,7 +2652,22 @@
 		    if (error)
 			break;
 		}
-		error = zero_entry(rulenum, sopt->sopt_name == IP_FW_RESETLOG);
+
+		if (sopt->sopt_td->td_ucred->cr_prison) {
+			/* We have to do this slightly differently. rulenum can't be
+			   a rule that's outside the jail. */
+			for (rule = layer3_chain; rule ; rule = rule->next) {
+				if (rule->rulenum == rulenum || rulenum == 0) {
+					if (!check_ipfw_jail(sopt->sopt_td, rule)) {
+						zero_entry(rule->rulenum, sopt->sopt_name == IP_FW_RESETLOG);
+					} else {
+						continue;
+					}
+				}
+			}
+		} else {
+			error = zero_entry(rulenum, sopt->sopt_name == IP_FW_RESETLOG);
+		}
 		break;
 
 	default:
diff -ur src.virgin/sys/netinet/raw_ip.c src.dirty/sys/netinet/raw_ip.c
--- src.virgin/sys/netinet/raw_ip.c	Wed Nov 20 12:00:54 2002
+++ src.dirty/sys/netinet/raw_ip.c	Sat Mar 22 12:19:46 2003
@@ -78,6 +78,8 @@
 #include <netinet6/ipsec.h>
 #endif /*IPSEC*/
 
+#include <sys/jail.h>
+
 struct	inpcbhead ripcb;
 struct	inpcbinfo ripcbinfo;
 
@@ -528,12 +530,20 @@
 {
 	struct inpcb *inp;
 	int error, s;
+	struct prison *saved = NULL;
 
 	inp = sotoinpcb(so);
 	if (inp)
 		panic("rip_attach");
-	if (td && (error = suser(td)) != 0)
+	if (td && td->td_ucred->cr_prison && td->td_ucred->cr_prison->jail_settings.allow_raw_sockets) {
+		saved = td->td_ucred->cr_prison;
+		td->td_ucred->cr_prison = NULL;
+	}
+	if (td && (error = suser(td)) != 0) {
+		td->td_ucred->cr_prison = saved;
 		return error;
+	}
+	td->td_ucred->cr_prison = saved;
 
 	if (proto >= IPPROTO_MAX || proto < 0)
 		return EPROTONOSUPPORT;
diff -ur src.virgin/sys/netinet6/in6_pcb.c src.dirty/sys/netinet6/in6_pcb.c
--- src.virgin/sys/netinet6/in6_pcb.c	Tue Oct 15 20:25:05 2002
+++ src.dirty/sys/netinet6/in6_pcb.c	Thu Feb 27 17:38:33 2003
@@ -213,7 +213,7 @@
 					in6_sin6_2_sin(&sin, sin6);
 					t = in_pcblookup_local(pcbinfo,
 						sin.sin_addr, lport,
-						INPLOOKUP_WILDCARD);
+						INPLOOKUP_WILDCARD, NULL);
 					if (t &&
 					    (so->so_cred->cr_uid !=
 					     t->inp_socket->so_cred->cr_uid) &&
@@ -234,7 +234,7 @@
 
 				in6_sin6_2_sin(&sin, sin6);
 				t = in_pcblookup_local(pcbinfo, sin.sin_addr,
-						       lport, wild);
+						       lport, wild, wild ? NULL : td);
 				if (t &&
 				    (reuseport & t->inp_socket->so_options)
 				    == 0 &&
diff -ur src.virgin/sys/sys/ipc.h src.dirty/sys/sys/ipc.h
--- src.virgin/sys/sys/ipc.h	Mon Oct 14 14:50:41 2002
+++ src.dirty/sys/sys/ipc.h	Thu Feb 27 17:38:33 2003
@@ -84,6 +84,7 @@
 	ushort	mode;	/* r/w permission */
 	ushort	seq;	/* sequence # (to generate unique msg/sem/shm id) */
 	key_t	key;	/* user specified msg/sem/shm key */
+	struct prison *pr;	/* For jail control. */
 };
 
 #if __BSD_VISIBLE
diff -ur src.virgin/sys/sys/jail.h src.dirty/sys/sys/jail.h
--- src.virgin/sys/sys/jail.h	Sun May  5 21:13:08 2002
+++ src.dirty/sys/sys/jail.h	Sat Mar 22 13:34:12 2003
@@ -17,7 +17,8 @@
 	u_int32_t	version;
 	char		*path;
 	char		*hostname;
-	u_int32_t	ip_number;
+	u_int32_t	*ips;
+	u_int		nips;
 };
 
 #ifndef _KERNEL
@@ -29,6 +30,9 @@
 #include <sys/queue.h>
 #include <sys/_lock.h>
 #include <sys/_mutex.h>
+#include <sys/sysctl.h>
+
+struct vnode;
 
 #ifdef MALLOC_DECLARE
 MALLOC_DECLARE(M_PRISON);
@@ -48,10 +52,26 @@
 struct prison {
 	int		 pr_ref;			/* (p) refcount */
 	char 		 pr_host[MAXHOSTNAMELEN];	/* (p) jail hostname */
-	u_int32_t	 pr_ip;				/* (c) ip addr host */
+	u_int32_t	 *pr_ips;			/* (c) ip addr host */
+	u_int		pr_nips;
 	void		*pr_linux;			/* (p) linux abi */
 	int		 pr_securelevel;		/* (p) securelevel */
 	struct mtx	 pr_mtx;
+	u_int		pr_numprocs;
+	struct {
+		u_int max_ram;
+		u_int max_cpu;
+		u_int max_procs;
+		u_int ram_used;
+		u_int procs_used;
+		u_int cpu_used;
+		u_int allow_raw_sockets;
+		u_int allow_ipfw;
+	} jail_settings;
+	char pr_host_oid[MAXHOSTNAMELEN];
+	struct sysctl_ctx_list jd_sysctltree;
+	struct sysctl_oid *jd_sysctltreetop;
+	int resched;
 };
 
 /*
@@ -64,6 +84,17 @@
 extern int	jail_sysvipc_allowed;
 
 /*
+ * List of jails (for jail_attach(), et. al.)
+ */
+struct jailelement {
+	struct prison *pr;				/* Prison element */
+	char *chroot_path;				/* Path to chroot to. */
+	LIST_ENTRY(jailelement) pointers;
+};
+
+LIST_HEAD(jails, jailelement);
+
+/*
  * Kernel support functions for jail().
  */
 struct ucred;
@@ -77,6 +108,12 @@
 int prison_if(struct ucred *cred, struct sockaddr *sa);
 int prison_ip(struct ucred *cred, int flag, u_int32_t *ip);
 void prison_remote_ip(struct ucred *cred, int flags, u_int32_t *ip);
+int prison_check_ip(struct prison *pr, u_int32_t ip);
+int jail_calctotalused(struct prison *pr);
+int jail_check_resources(struct thread *td);
+int jail_check_cpu(struct ucred *uc);
+void jail_update_cpu(void);
+int jail_check_fileperm(struct vnode *vp, struct ucred *cred, struct thread *td);
 
 #endif /* !_KERNEL */
 #endif /* !_SYS_JAIL_H_ */
diff -ur src.virgin/sys/sys/proc.h src.dirty/sys/sys/proc.h
--- src.virgin/sys/sys/proc.h	Mon Dec  9 19:33:45 2002
+++ src.dirty/sys/sys/proc.h	Thu Feb 27 17:38:33 2003
@@ -347,6 +347,7 @@
 #define	TDI_LOCK	0x08	/* Stopped on a lock. */
 #define	TDI_IWAIT	0x10	/* Awaiting interrupt. */
 #define	TDI_LOAN	0x20	/* bound thread's KSE is lent */
+#define TDI_JSLEEP	0x40	/* Jail suspension due to high CPU. */
 
 #define	TD_IS_SLEEPING(td)	((td)->td_inhibitors & TDI_SLEEPING)
 #define	TD_ON_SLEEPQ(td)	((td)->td_wchan != NULL)
@@ -355,6 +356,7 @@
 #define	TD_ON_LOCK(td)		((td)->td_inhibitors & TDI_LOCK)
 #define	TD_LENT(td)		((td)->td_inhibitors & TDI_LOAN)
 #define	TD_AWAITING_INTR(td)	((td)->td_inhibitors & TDI_IWAIT)
+#define TD_IS_JSLEEP(td)	((td)->td_inhibitors & TDI_JSLEEP)
 #define	TD_IS_RUNNING(td)	((td)->td_state == TDS_RUNNING)
 #define	TD_ON_RUNQ(td)		((td)->td_state == TDS_RUNQ)
 #define	TD_CAN_RUN(td)		((td)->td_state == TDS_CAN_RUN)
@@ -377,6 +379,7 @@
 #define	TD_SET_SUSPENDED(td)	TD_SET_INHIB((td), TDI_SUSPENDED)
 #define	TD_SET_IWAIT(td)	TD_SET_INHIB((td), TDI_IWAIT)
 #define	TD_SET_LOAN(td)		TD_SET_INHIB((td), TDI_LOAN)
+#define TD_SET_JSLEEP(td)	TD_SET_INHIB((td), TDI_JSLEEP)
 
 #define	TD_CLR_SLEEPING(td)	TD_CLR_INHIB((td), TDI_SLEEPING)
 #define	TD_CLR_SWAPPED(td)	TD_CLR_INHIB((td), TDI_SWAPPED)
@@ -384,6 +387,7 @@
 #define	TD_CLR_SUSPENDED(td)	TD_CLR_INHIB((td), TDI_SUSPENDED)
 #define	TD_CLR_IWAIT(td)	TD_CLR_INHIB((td), TDI_IWAIT)
 #define	TD_CLR_LOAN(td)		TD_CLR_INHIB((td), TDI_LOAN)
+#define TD_CLR_JSLEEP(td)	TD_CLR_INHIB((td), TDI_JSLEEP)
 
 #define	TD_SET_RUNNING(td)	do {(td)->td_state = TDS_RUNNING; } while (0)
 #define	TD_SET_RUNQ(td)		do {(td)->td_state = TDS_RUNQ; } while (0)
diff -ur src.virgin/sys/ufs/ufs/ufs_vnops.c src.dirty/sys/ufs/ufs/ufs_vnops.c
--- src.virgin/sys/ufs/ufs/ufs_vnops.c	Sun Oct 27 11:09:49 2002
+++ src.dirty/sys/ufs/ufs/ufs_vnops.c	Mon Mar  3 07:57:17 2003
@@ -62,6 +62,7 @@
 #include <sys/conf.h>
 #include <sys/acl.h>
 #include <sys/mac.h>
+#include <sys/jail.h>
 
 #include <machine/mutex.h>
 
@@ -339,6 +340,12 @@
 	struct acl *acl;
 	size_t len;
 #endif
+
+	/* Do special jail checking, if necessary. */
+	error = jail_check_fileperm(vp, ap->a_cred, ap->a_td);
+	if (error) {
+		return error;
+	}
 
 	/*
 	 * Disallow write attempts on read-only filesystems;
diff -ur src.virgin/usr.sbin/jail/jail.c src.dirty/usr.sbin/jail/jail.c
--- src.virgin/usr.sbin/jail/jail.c	Mon Apr 22 07:44:43 2002
+++ src.dirty/usr.sbin/jail/jail.c	Thu Feb 27 17:38:33 2003
@@ -26,28 +26,68 @@
 main(int argc, char **argv)
 {
 	struct jail j;
-	int i;
+	int i, k, m, c = 1;
 	struct in_addr in;
+	char *tempstring, ipstring[16];
 
-	if (argc < 5) 
-		errx(1, "usage: %s path hostname ip-number command ...\n",
+	if (argc < 5) {
+		errx(1, "Usage: %s path hostname ip1[,ip2[...]] command ...\n",
 		    argv[0]);
+	}
+
 	i = chdir(argv[1]);
 	if (i)
 		err(1, "chdir %s", argv[1]);
 	memset(&j, 0, sizeof(j));
-	j.version = 0;
+	j.version = 1;
 	j.path = argv[1];
 	j.hostname = argv[2];
-	i = inet_aton(argv[3], &in);
-	if (!i)
-		errx(1, "Couldn't make sense of ip-number\n");
-	j.ip_number = ntohl(in.s_addr);
+
+	/* Feb. 1, 2003 (MS): Determine how many IP addresses user passed to jail. This
+	   is important later for filling in j.nips and for allocating the proper amount
+	   of memory. */
+	tempstring = argv[3];
+	while(*tempstring) {
+		if (*tempstring == ',') c++;
+		tempstring++;
+	}
+	j.nips = c;
+
+	/* Allocate RAM, depending on number of IP addresses passed. */
+	j.ips = (u_int32_t *)malloc(sizeof(u_int32_t) * c);
+	if (j.ips == NULL) {
+		errx(1, "malloc() issue, line 56 (/usr/src/usr.sbin/jail/jail.c). Possible lack of RAM or software bug.");
+	}
+
+	/* Copy each IP into the array.
+	   Note (MS, 02/01/2003): 4.x version used strtok(), a dangerous programming construct. */
+	tempstring = argv[3];
+	m = 0;
+	while (*tempstring) {
+		k = 0;
+		while (1) {
+			if (*(tempstring+k) == ',' || *(tempstring+k) == '\0') {
+				strncpy(ipstring, tempstring, k);
+				ipstring[k] = '\0';
+				i = inet_aton(ipstring, &in);
+				if (!i) {
+					free(j.ips);
+					errx(1, "Couldn't make sense of IP address %s", ipstring);
+				}
+				j.ips[m++] = ntohl(in.s_addr);
+				break;
+			}
+			k++;
+		}
+		tempstring = tempstring + k;
+		if (*tempstring == ',') tempstring++;
+	}
+		
 	i = jail(&j);
 	if (i)
-		err(1, "Imprisonment failed");
+		errx(1, "Imprisonment failed");
 	i = execv(argv[4], argv + 4);
 	if (i)
-		err(1, "execv(%s)", argv[4]);
+		errx(1, "execv(%s)", argv[4]);
 	exit (0);
 }
