/*
    ettercap -- dissector mountd (NFS) -- RPC

    Copyright (C) 2001  ALoR <alor@users.sourceforge.net>, NaGA <crwm@freemail.it>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

    $Id: ec_dissector_mountd.c,v 1.3 2002/04/12 15:59:15 alor Exp $
*/

#include "include/ec_main.h"

#include "include/ec_dissector.h"
#include "include/ec_inet_structures.h"

#define XID_LEN 1024

int SID_MAP_TCP[XID_LEN];
int versions_tcp[XID_LEN];
char *REM_DIRS_TCP[XID_LEN];

int SID_MAP_UDP[XID_LEN];
int versions_udp[XID_LEN];
char *REM_DIRS_UDP[XID_LEN];

// protos....

FUNC_DISSECTOR(Dissector_mountdUDP);
FUNC_DISSECTOR(Dissector_mountdTCP);

// ==========================================================


FUNC_DISSECTOR(Dissector_mountdTCP)
{
   TCP_header *tcp;
   u_char *buf;
   int XID,type;

   tcp = (TCP_header *) data;
   buf = (char *)((int)tcp + tcp->doff * 4);

   if (data_to_ettercap->datalen==0) return (0);

   type    = *(int *)(buf+8);
   XID     = *(int *)(buf+4);

   sprintf(data_to_ettercap->type, "mountd");

   if (ntohs(tcp->source) != SERV_PORT)
   {
      int program,proc,version;

      program = *(int *)(buf + 16);
      proc    = *(int *)(buf + 24);
      version = *(int *)(buf + 20);

      // CALL
      if (type == 0 && ntohl(program) == 100005 && ntohl(proc) == 1 )
      {
         int len, i, cred;

         DEBUG_MSG("\tDissector_mountd TCP - CALL");

         for (i=0; i<XID_LEN; i++)
            if (!SID_MAP_TCP[i]) break;

         if (i==XID_LEN) return (0);

         SID_MAP_TCP[i] = XID;
         cred = *(int *)(buf + 32);
         cred = ntohl(cred);
         len = *(int *)(buf+44+cred);
         if (ntohl(len)>100)
         {
            SID_MAP_TCP[i] = 0;
            return 0;
         }
         REM_DIRS_TCP[i] = calloc(1, ntohl(len)+1);
         memcpy(REM_DIRS_TCP[i], buf+48+cred, ntohl(len));
         versions_tcp[i]=version;
      }
      return (0);
   }

   // REPLY
   if ( ntohl(type) == 1 )
   {
      int i, len,result,offs;
      char *outstr;

      DEBUG_MSG("\tDissector_mountd TCP - REPLY");

      for (i=0; i<XID_LEN; i++)
         if (SID_MAP_TCP[i]==XID) break;

      if (i==XID_LEN) return (0);

      SID_MAP_TCP[i]=0;

      result = *(int *)(buf+28);
      if (result)
      {
         free(REM_DIRS_TCP[i]);
         return (0); //Unautorized
      }

      outstr = data_to_ettercap->info;
      snprintf(outstr, sizeof(data_to_ettercap->info), "NFS SERVER: %s  FHANDLE: %s [", data_to_ettercap->source_ip, REM_DIRS_TCP[i]);

      free(REM_DIRS_TCP[i]);

      if (ntohl(versions_tcp[i])==3)
      {
         len = *(int *)(buf+32);
         len = ntohl(len);
         if (len>64) len=64;
         offs=36;
      }
      else
      {
         len = 32;
         offs= 32;
      }

      for (i=0; i<len-1; i++)
         snprintf(outstr, sizeof(data_to_ettercap->info), "%s%.2x ", outstr, buf[i+offs]);

      snprintf(outstr, sizeof(data_to_ettercap->info), "%s%.2x]\n", outstr, buf[i+offs]);

      sprintf(data_to_ettercap->user, "\n");
      sprintf(data_to_ettercap->pass, "\n");
   }
   return 0;
}



FUNC_DISSECTOR(Dissector_mountdUDP)
{
   UDP_header *udp;
   u_char *buf;
   int XID,type;

   udp = (UDP_header *) data;
   buf = data + UDP_HEADER;

   type    = *(int *)(buf+4);
   XID     = *(int *)(buf);

   sprintf(data_to_ettercap->type,"mountd");

   if (ntohs(udp->source) != SERV_PORT)
   {
      int program,proc,version;

      program = *(int *)(buf+12);
      proc    = *(int *)(buf+20);
      version = *(int *)(buf+16);

      // CALL
      if (type == 0 && ntohl(program) == 100005 && ntohl(proc) == 1 )
      {
         int len, i, cred;

         DEBUG_MSG("\tDissector_mountd UDP - CALL");

         for (i=0; i<XID_LEN; i++)
            if (!SID_MAP_UDP[i]) break;

         if (i==XID_LEN) return (0);

         SID_MAP_UDP[i] = XID;
         cred = *(int *)(buf+28);
         cred = ntohl(cred);
         len = *(int *)(buf+40+cred);
         if (ntohl(len)>100)
         {
            SID_MAP_UDP[i] = 0;
            return 0;
         }
         REM_DIRS_UDP[i] = calloc(1, ntohl(len)+1);
         memcpy(REM_DIRS_UDP[i], buf+44+cred, ntohl(len));
         versions_udp[i] = version;
      }
      return (0);
   }

   // REPLY
   if ( ntohl(type) == 1 )
   {
      int i, len, offs,result;
      char *outstr;

      DEBUG_MSG("\tDissector_mountd UCP - REPLY");

      for (i=0; i<XID_LEN; i++)
         if (SID_MAP_UDP[i]==XID) break;

      if (i==XID_LEN) return (0);

      SID_MAP_UDP[i]=0;

      result = *(int *)(buf+24);
      if (result)
      {
         free(REM_DIRS_UDP[i]);
         return (0); //Unautorized
      }

      outstr = data_to_ettercap->info;
      snprintf(outstr, sizeof(data_to_ettercap->info), "NFS SERVER: %s  FHANDLE: %s [", data_to_ettercap->source_ip, REM_DIRS_UDP[i]);

      free(REM_DIRS_UDP[i]);

      if (ntohl(versions_udp[i]) == 3)
      {
         len = *(int *)(buf+28);
         len = ntohl(len);
         if (len>64) len = 64;
         offs = 32;
      }
      else
      {
         len = 32;
         offs = 28;
      }

      for (i=0; i<len-1; i++)
         snprintf(outstr, sizeof(data_to_ettercap->info), "%s%.2x ", outstr, buf[i+offs]);

      snprintf(outstr, sizeof(data_to_ettercap->info), "%s%.2x]\n", outstr, buf[i+offs]);

      sprintf(data_to_ettercap->user, "\n");
      sprintf(data_to_ettercap->pass, "\n");
   }
   return 0;
}

// vim:ts=3:expandtab

