#include <sys/types.h>
#include <sys/param.h>
#include <sys/proc.h>
#include <sys/module.h>
#include <sys/sysent.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/linker.h>
#include <sys/sysproto.h>
#include <sys/sysent.h>
#include <sys/proc.h>
#include <sys/syscall.h>
#include <sys/sysctl.h>

/* variables for sysctl */
static struct sysctl_ctx_list clist;
static struct sysctl_oid *a_root;

/* The default gid */
gid_t gid = 1001;

/*The hacked system call*/
static int
hacked_bind (struct thread *td, struct bind_args *ua)
{      
  struct proc *p = td->td_proc;
  struct ucred *cred;

  cred = p->p_ucred;

  if ( cred->cr_rgid == gid ) return EPERM;
  
  printf("pixie[bind]: (%d/%d)\n", cred->cr_ruid, cred->cr_rgid);
  return bind(td, ua);
}

static struct sysent
hacked_bind_bind_sysent = {        
       3,
       (void*)hacked_bind         /* sy_call */
};

static int
dummy_handler (struct module *module, int cmd, void *arg)
{
  int error = 0;

  switch (cmd) {
    case MOD_LOAD:
      sysctl_ctx_init(&clist);
      a_root = SYSCTL_ADD_NODE(&clist,
      SYSCTL_STATIC_CHILDREN( /* */ ),
      OID_AUTO, "pixie", CTLFLAG_RW, 0,
      "pixie root node");

      SYSCTL_ADD_INT(&clist, SYSCTL_CHILDREN(a_root),
      OID_AUTO, "gid", CTLFLAG_RW, 
      &gid,0,
      "gid denied sockets");

      sysent[SYS_bind]=hacked_bind_bind_sysent;
      break;
    case MOD_UNLOAD :
      sysent[SYS_bind].sy_call=(sy_call_t*)bind;
      
      sysctl_ctx_free(&clist);
      break;
    default :
      error = EINVAL;
      break;
  }
  return error;
}

static moduledata_t syscall_mod = {
 "Intercept", 
 dummy_handler,
 NULL
};

DECLARE_MODULE(syscall, syscall_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
  

