# -*- Fundamental -*-
#
# (C) Tenable Network Security
#
#
# NFS functions
#

# mount(soc, share)    - Mounts an NFS share and returns a file handle
#              (soc is a socket opened to the mount daemon)
#
# readdir(soc, fid)    - Returns the content of the directory pointed by
#              <fid>. (soc is a socket opened to the NFS daemon)
#
# cwd(soc, fid, dir)    - Changes the working directory to <dir>. Returns
#              a new fid
#
# umount(soc, share)    - Tells the remote NFS server we don't need its services
#                  any more (soc is a socket opened to the mount daemon)
#
#
# $Id: nfs_func.inc,v 1.9 2006/04/10 18:37:22 renaud Exp $

function padsz(len)
{
 if(len % 4)
  return 4 - len % 4;
 else
  return 0;
}

function rpclong(val)
{
 local_var ret;
 
 ret = raw_string(val / (256*256*256),
           val / (256*256),
          val /  256,
          val % 256);
 return ret;          
}


function str2long(val, idx)
{
 local_var ret;
 if ( strlen(val) <= (idx + 3) )
    return NULL;

 ret = ord(val[idx]) * 256 * 256 * 256 + 
       ord(val[idx+1]) * 256 * 256 +
       ord(val[idx+2]) * 256 +
       ord(val[idx+3]);
       
  return int(ret);
}



function rpcpad(pad)
{
 return crap(length:pad, data:raw_string(0));
}




function mount(soc, share)
{
  local_var pad, req, len, r, ret, i;
  
  pad = padsz(len:strlen(this_host_name()));
  len = 52 + strlen(this_host_name()) + pad;
  
  req =        rpclong(val:rand()) +
             rpclong(val:0) +
           rpclong(val:2) +
           rpclong(val:100005) +
           rpclong(val:1) +
           rpclong(val:1) +
           rpclong(val:1) +
           rpclong(val:len) +
           rpclong(val:rand()) +
           rpclong(val:strlen(this_host_name())) +
           this_host_name() +
           rpcpad(pad:pad) +
           rpclong(val:0)  +    
           rpclong(val:0)  +    
           rpclong(val:7)  +    
           rpclong(val:0)  +    
           rpclong(val:2)  +     
           rpclong(val:3)  +    
           rpclong(val:4)  +
           rpclong(val:5)  +
           rpclong(val:20) +
           rpclong(val:31) +
           rpclong(val:0)  +    
           rpclong(val:0)  +
           rpclong(val:0)  +
                    
           rpclong(val:strlen(share)) +
           share +
           rpcpad(pad:padsz(len:strlen(share)));
           
  send(socket:soc, data:req);
  r = recv(socket:soc, length:4096);
  if(strlen(r) < 60)
   return NULL;
  else
   {
    if(str2long(val:r, idx:24) != 0)
      return NULL;
      
    ret = "";
    for(i=28;i<60;i++)ret += r[i];
    return ret;
   }
}

function readdir(soc, fid)
{
 local_var req, r, i, dir, ret;
 
 req =         rpclong(val:rand()) +
         rpclong(val:0)         +
        rpclong(val:2)      +
        rpclong(val:100003) +
        rpclong(val:2)      +
        rpclong(val:16)     +
        rpclong(val:1)      +
        rpclong(val:48)     +
        rpclong(val:0)          +
        rpclong(val:0)          +
        rpclong(val:0)          +
        rpclong(val:0)        +
        rpclong(val:7)        +
        rpclong(val:0)        +
        rpclong(val:2)        +
        rpclong(val:3)        +
        rpclong(val:4)        +
        rpclong(val:5)          +
        rpclong(val:20)         +
        rpclong(val:31)        +
        
        rpclong(val:0)        +
        rpclong(val:0)        +
        fid            +
        rpclong(val:0)        +
        rpclong(val:8192);
        
 send(socket:soc, data:req);
 r = recv(socket:soc, length:8192);    
 if(strlen(r) <= 24) return NULL;
 if(str2long(val:r, idx:24) != 0) return NULL; # Could not read dir
 
 i = 28;
 ret = make_list();
 while(str2long(val:r, idx:i) == 1)
 {
  if ( i > strlen(r)) break;
  i += 4;
  i += 4; # File ID - don't care
  len = str2long(val:r, idx:i);
  i+=4;
  dir = substr(r, i, i + len - 1);
  i += len;
  i += padsz(len:len);
  i += 4;
  ret = make_list(ret, dir);
 }
 return ret;    
}


function cwd(soc, dir, fid)
{
 local_var req, ret, i;
 
 
 req = rpclong(val:rand()) +
       rpclong(val:0)      +
       rpclong(val:2)      +
       rpclong(val:100003) +
       rpclong(val:2)      +
       rpclong(val:4)      +
       rpclong(val:1)      +
       rpclong(val:48)      +
       rpclong(val:0)       +
       rpclong(val:0)       +
       rpclong(val:0)       +
       rpclong(val:0)       +
       rpclong(val:7)       +
       rpclong(val:0)       +
       rpclong(val:2)       +
       rpclong(val:3)       +
       rpclong(val:4)       +
       rpclong(val:5)       +
       rpclong(val:20)       +
       rpclong(val:31)       +
       rpclong(val:0)      +
       rpclong(val:0)      +
       fid +
       rpclong(val:strlen(dir)) +
       dir +
       rpcpad(pad:padsz(len:strlen(dir)));
       
   send(socket:soc, data:req);
   r = recv(socket:soc, length:8192);
   if(strlen(r) < 24)
    return NULL;
   
  if(strlen(r) < 24)
    return NULL;
   else
   {
    if(str2long(val:r, idx:24) != 0)
      return NULL;
      
    ret = "";
    for(i=28;i<56;i++)ret += r[i];
    ret += rpclong(val:0);
    return ret;
   }
}






function open(soc, file, fid)
{
 local_var req, ret, i;
 
 
 req = rpclong(val:rand()) +
       rpclong(val:0)      +
       rpclong(val:2)      +
       rpclong(val:100003) +
       rpclong(val:2)      +
       rpclong(val:4)      +
       rpclong(val:1)      +
       rpclong(val:48)      +
       rpclong(val:0)       +
       rpclong(val:0)       +
       rpclong(val:0)       +
       rpclong(val:0)       +
       rpclong(val:7)       +
       rpclong(val:0)       +
       rpclong(val:2)       +
       rpclong(val:3)       +
       rpclong(val:3)       +
       rpclong(val:5)       +
       rpclong(val:20)       +
       rpclong(val:31)       +
       rpclong(val:0)      +
       rpclong(val:0)      +
       fid +
       rpclong(val:strlen(file)) +
       file +
       rpcpad(pad:padsz(len:strlen(file)));
       
   send(socket:soc, data:req);
   r = recv(socket:soc, length:8192);
   if(strlen(r) < 24)
    return NULL;
   
  if(strlen(r) < 24)
    return NULL;
   else
   {
    if(str2long(val:r, idx:24) != 0)
      return NULL;
      
    ret = "";
    for(i=28;i<56;i++)ret += r[i];
    ret += rpclong(val:0);
    return ret;
   }
}

function read(soc, fid, length, off)
{
 local_var req, ret, i, len;
 
 
 req = rpclong(val:rand()) +
       rpclong(val:0)      +
       rpclong(val:2)      +
       rpclong(val:100003) +
       rpclong(val:2)      +
       rpclong(val:6)      +
       rpclong(val:1)      +
       rpclong(val:48)      +
       rpclong(val:0)       +
       rpclong(val:0)       +
       rpclong(val:0)       +
       rpclong(val:0)       +
       rpclong(val:7)       +
       rpclong(val:0)       +
       rpclong(val:2)       +
       rpclong(val:3)       +
       rpclong(val:4)       +
       rpclong(val:5)       +
       rpclong(val:20)       +
       rpclong(val:31)       +
       rpclong(val:0)      +
       rpclong(val:0)      +
       fid +
       rpclong(val:off) +
       rpclong(val:length) + 
       rpclong(val:0);
       
   send(socket:soc, data:req);
   r = recv(socket:soc, length:length + 33);
   if(strlen(r) <= 32)
    return NULL;
   
   return substr(r, 32, strlen(r) - 1);
}


function umount(soc, share)
{
 local_var pad, req, len, r, ret, i;
  
  pad = padsz(len:strlen(this_host_name()));
  len = 52 + strlen(this_host_name()) + pad;
 
 req =  rpclong(val:rand()) +
             rpclong(val:0) +
           rpclong(val:2) +
           rpclong(val:100005) +
           rpclong(val:1) +
           rpclong(val:3) +
           rpclong(val:1) +
           rpclong(val:len) +
           rpclong(val:rand()) +
           rpclong(val:strlen(this_host_name())) +
           this_host_name() +
           rpcpad(pad:pad) +
           rpclong(val:0)  +    
           rpclong(val:0)  +    
           rpclong(val:7)  +    
           rpclong(val:0)  +    
           rpclong(val:2)  +     
           rpclong(val:3)  +    
           rpclong(val:4)  +
           rpclong(val:5)  +
           rpclong(val:20) +
           rpclong(val:31) +
           rpclong(val:0)  +    
           rpclong(val:0)  +
           rpclong(val:0)  +
                    
           rpclong(val:strlen(share)) +
           share +
           rpcpad(pad:padsz(len:strlen(share)));
           
  send(socket:soc, data:req);
  r = recv(socket:soc, length:8192);           
}