Main Page | Modules | Class List | Directories | File List | Class Members | File Members | Related Pages

sp_rpc_check.c

Go to the documentation of this file.
00001 /*
00002 ** Copyright (C) 1998-2002 Martin Roesch <roesch@sourcefire.com>
00003 **
00004 ** This program is free software; you can redistribute it and/or modify
00005 ** it under the terms of the GNU General Public License as published by
00006 ** the Free Software Foundation; either version 2 of the License, or
00007 ** (at your option) any later version.
00008 **
00009 ** This program is distributed in the hope that it will be useful,
00010 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 ** GNU General Public License for more details.
00013 **
00014 ** You should have received a copy of the GNU General Public License
00015 ** along with this program; if not, write to the Free Software
00016 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017 */
00018 
00019 /* $Id$ */
00020 
00021 #ifdef HAVE_CONFIG_H
00022 #include "config.h"
00023 #endif
00024 
00025 #include <sys/types.h>
00026 #include <stdlib.h>
00027 #include <ctype.h>
00028 #ifndef WIN32
00029 #include <rpc/rpc.h>
00030 #endif /* !WIN32 */
00031 
00032 #include "rules.h"
00033 #include "decode.h"
00034 #include "plugbase.h"
00035 #include "parser.h"
00036 #include "debug.h"
00037 #include "util.h"
00038 #include "plugin_enum.h"
00039 
00040 /*
00041  * This is driven by 64-bit Solaris which doesn't
00042  * define _LONG
00043  * 
00044  */
00045 
00046 #ifndef IXDR_GET_LONG
00047     #define IXDR_GET_LONG IXDR_GET_INT32
00048 #endif
00049 
00050 typedef struct _RpcCheckData
00051 {
00052     u_long program; /* RPC program number */
00053     u_long vers; /* RPC program version */
00054     u_long proc; /* RPC procedure number */
00055     int flags; /* Which of the above fields have been specified */
00056 
00057 } RpcCheckData;
00058 
00059 #define RPC_CHECK_PROG 1
00060 #define RPC_CHECK_VERS 2
00061 #define RPC_CHECK_PROC 4
00062 
00063 void RpcCheckInit(char *, OptTreeNode *, int);
00064 void ParseRpc(char *, OptTreeNode *);
00065 int CheckRpc(Packet *, struct _OptTreeNode *, OptFpList *);
00066 
00067 
00068 
00069 /****************************************************************************
00070  * 
00071  * Function: SetupRpcCheck()
00072  *
00073  * Purpose: Register the rpc option keyword with its setup function
00074  *
00075  * Arguments: None.
00076  *
00077  * Returns: void function
00078  *
00079  ****************************************************************************/
00080 void SetupRpcCheck(void)
00081 {
00082     /* map the keyword to an initialization/processing function */
00083     RegisterPlugin("rpc", RpcCheckInit);
00084 
00085     DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "Plugin: RPCCheck Initialized\n"););
00086 }
00087 
00088 
00089 /****************************************************************************
00090  * 
00091  * Function: RpcCheckInit(char *, OptTreeNode *)
00092  *
00093  * Purpose: Parse the rpc keyword arguments and link the detection module
00094  *          into the function list
00095  *
00096  * Arguments: data => rule arguments/data
00097  *            otn => pointer to the current rule option list node
00098  *
00099  * Returns: void function
00100  *
00101  ****************************************************************************/
00102 void RpcCheckInit(char *data, OptTreeNode *otn, int protocol)
00103 {
00104     if(protocol != IPPROTO_TCP && protocol != IPPROTO_UDP)
00105     {
00106         FatalError("%s(%d) => Bad protocol in RPC Check rule...\n",
00107                    file_name, file_line);
00108     }
00109 
00110     /* multiple declaration check */ 
00111     if(otn->ds_list[PLUGIN_RPC_CHECK])
00112     {
00113         FatalError("%s(%d): Multiple rpc options in rule\n", file_name,
00114                 file_line);
00115     }
00116 
00117     /* allocate the data structure and attach it to the
00118        rule's data struct list */
00119     otn->ds_list[PLUGIN_RPC_CHECK] = (RpcCheckData *)
00120             SnortAlloc(sizeof(RpcCheckData));
00121 
00122     /* this is where the keyword arguments are processed and placed into the 
00123        rule option's data structure */
00124     ParseRpc(data, otn);
00125 
00126     /* finally, attach the option's detection function to the rule's 
00127        detect function pointer list */
00128     AddOptFuncToList(CheckRpc, otn);
00129 }
00130 
00131 
00132 
00133 /****************************************************************************
00134  * 
00135  * Function: ParseRpc(char *, OptTreeNode *)
00136  *
00137  * Purpose: Parse the RPC keyword's arguments
00138  *
00139  * Arguments: data => argument data
00140  *            otn => pointer to the current rule's OTN
00141  *
00142  * Returns: void function
00143  *
00144  ****************************************************************************/
00145 void ParseRpc(char *data, OptTreeNode *otn)
00146 {
00147     RpcCheckData *ds_ptr;  /* data struct pointer */
00148     char *tmp;
00149 
00150     /* set the ds pointer to make it easier to reference the option's
00151        particular data struct */
00152     ds_ptr = otn->ds_list[PLUGIN_RPC_CHECK];
00153     ds_ptr->flags=0;
00154 
00155     /* advance past whitespace */
00156     while(isspace((int)*data)) data++;
00157 
00158     if(*data != '*')
00159     {
00160         ds_ptr->program = strtoul(data,&tmp,0);
00161         ds_ptr->flags|=RPC_CHECK_PROG;
00162         DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "Set RPC program to %lu\n", ds_ptr->program););
00163     }
00164     if(*tmp == '\0') return;
00165     data=++tmp;
00166     if(*data != '*')
00167     {
00168         ds_ptr->vers = strtoul(data,&tmp,0);
00169         ds_ptr->flags|=RPC_CHECK_VERS;
00170         DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "Set RPC vers to %lu\n", ds_ptr->vers););
00171     }
00172     else
00173     {
00174         tmp++;
00175     }
00176     if(*tmp == '\0') return;
00177     data=++tmp;
00178     if(*data != '*')
00179     {
00180         ds_ptr->proc = strtoul(data,&tmp,0);
00181         ds_ptr->flags|=RPC_CHECK_PROC;
00182         DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,"Set RPC proc to %lu\n", ds_ptr->proc););
00183     }
00184 }
00185 
00186 
00187 /****************************************************************************
00188  * 
00189  * Function: CheckRpc(char *, OptTreeNode *)
00190  *
00191  * Purpose: Test if the packet RPC equals the rule option's rpc
00192  *
00193  * Arguments: data => argument data
00194  *            otn => pointer to the current rule's OTN
00195  *
00196  * Returns: 0 on failure, return value of next list function on success
00197  *
00198  ****************************************************************************/
00199 int CheckRpc(Packet *p, struct _OptTreeNode *otn, OptFpList *fp_list)
00200 {
00201     RpcCheckData *ds_ptr;  /* data struct pointer */
00202     unsigned char* c=(unsigned char*)p->data;
00203     u_long xid, rpcvers, prog, vers, proc;
00204     enum msg_type direction;
00205 #ifdef DEBUG
00206     int i;
00207 #endif
00208     if(!p->iph || (p->iph->ip_proto == IPPROTO_TCP && !p->tcph)
00209        || (p->iph->ip_proto == IPPROTO_UDP && !p->udph))
00210         return 0; /* if error occured while ip header
00211                    * was processed, return 0 automagically.
00212                */
00213 
00214     if(p->iph->ip_proto == IPPROTO_TCP)
00215     {
00216         /* offset to rpc_msg */
00217         c+=4;
00218         /* Fail if the packet is too short to match */
00219         if(p->dsize<28)
00220         {
00221             DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "RPC packet too small"););
00222             return 0;
00223         }
00224     }
00225     else
00226     { /* must be UDP */
00227         /* Fail if the packet is too short to match */
00228         if(p->dsize<24)
00229         {
00230             DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "RPC packet too small"););
00231             return 0;
00232         }
00233     }
00234 
00235 #ifdef DEBUG
00236     DebugMessage(DEBUG_PLUGIN,"<---xid---> <---dir---> <---rpc--->"
00237                  " <---prog--> <---vers--> <---proc-->\n");
00238     for(i=0; i<24; i++)
00239     {
00240         DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "%02X ",c[i]););
00241     }
00242     DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,"\n"););
00243 #endif
00244 
00245     /* Read xid */
00246     xid = IXDR_GET_LONG (c);
00247 
00248     /* Read direction : CALL or REPLY */
00249     direction = IXDR_GET_ENUM (c, enum msg_type);
00250 
00251     /* We only look at calls */
00252     if(direction != CALL)
00253     {
00254         DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "RPC packet not a call"););
00255         return 0;
00256     }
00257 
00258     /* Read the RPC message version */
00259     rpcvers = IXDR_GET_LONG (c);
00260 
00261     /* Fail if it is not right */
00262     if(rpcvers != RPC_MSG_VERSION)
00263     {
00264         DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,"RPC msg version invalid"););
00265         return 0;
00266     }
00267 
00268     /* Read the program number, version, and procedure */
00269     prog = IXDR_GET_LONG (c);
00270     vers = IXDR_GET_LONG (c);
00271     proc = IXDR_GET_LONG (c);
00272 
00273     DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,"RPC decoded to: %lu %lu %lu\n",
00274                             prog,vers,proc););
00275 
00276     ds_ptr=(RpcCheckData *)otn->ds_list[PLUGIN_RPC_CHECK];
00277 
00278     DEBUG_WRAP(
00279                DebugMessage(DEBUG_PLUGIN, "RPC matching on: %d %d %d\n",
00280                             ds_ptr->flags & RPC_CHECK_PROG,ds_ptr->flags & RPC_CHECK_VERS,
00281                             ds_ptr->flags & RPC_CHECK_PROC););
00282     if(!(ds_ptr->flags & RPC_CHECK_PROG) ||
00283        ds_ptr->program == prog)
00284     {
00285         DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,"RPC program matches"););
00286         if(!(ds_ptr->flags & RPC_CHECK_VERS) ||
00287            ds_ptr->vers == vers)
00288         {
00289             DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,"RPC version matches"););
00290             if(!(ds_ptr->flags & RPC_CHECK_PROC) ||
00291                ds_ptr->proc == proc)
00292             {
00293                 DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,"RPC proc matches"););
00294                 DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "Yippee! Found one!"););
00295                 /* call the next function in the function list recursively */
00296                 return fp_list->next->OptTestFunc(p, otn, fp_list->next);
00297             }
00298         }
00299     }
00300     else
00301     {
00302         /* you can put debug comments here or not */
00303         DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,"RPC not equal\n"););
00304     }
00305 
00306     /* if the test isn't successful, return 0 */
00307     return 0;
00308 }

Generated on Sun May 14 14:51:13 2006 by  doxygen 1.4.2