"Fossies" - the Fresh Open Source Software Archive

Member "snort-2.9.17/src/dynamic-preprocessors/ftptelnet/ftpp_si.c" (16 Oct 2020, 36219 Bytes) of package /linux/misc/snort-2.9.17.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "ftpp_si.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.9.16.1_vs_2.9.17.

    1 /*
    2  * ftpp_si.c
    3  *
    4  * Copyright (C) 2014-2020 Cisco and/or its affiliates. All rights reserved.
    5  * Copyright (C) 2004-2013 Sourcefire, Inc.
    6  * Steven A. Sturges <ssturges@sourcefire.com>
    7  * Daniel J. Roelker <droelker@sourcefire.com>
    8  * Marc A. Norton <mnorton@sourcefire.com>
    9  * Kevin Liu <kliu@sourcefire.com>
   10  *
   11  * This program is free software; you can redistribute it and/or modify
   12  * it under the terms of the GNU General Public License Version 2 as
   13  * published by the Free Software Foundation.  You may not use, modify or
   14  * distribute this program under any other version of the GNU General
   15  * Public License.
   16  *
   17  * This program is distributed in the hope that it will be useful,
   18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   20  * GNU General Public License for more details.
   21  *
   22  * You should have received a copy of the GNU General Public License
   23  * along with this program; if not, write to the Free Software
   24  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
   25  *
   26  * Description:
   27  *
   28  * This file contains functions to select server configurations
   29  * and begin the FTPTelnet process.
   30  *
   31  * The Session Inspection Module interfaces with the Stream Inspection
   32  * Module and the User Interface Module to select the appropriate
   33  * FTPTelnet configuration and in the case of stateful inspection the
   34  * Session Inspection Module retrieves the user-data from the Stream
   35  * Module.  For stateless inspection, the Session Inspection Module uses
   36  * the same structure for use by each packet.
   37  *
   38  * The main responsibility of this module is to supply the appropriate
   39  * data structures and configurations for the rest of the FTPTelnet
   40  * process.  The module also determines what type of data is being
   41  * inspected, whether it is client, server, or neither.
   42  *
   43  * NOTES:
   44  * - 20.09.04:  Initial Development.  SAS
   45  *
   46  */
   47 #include <stdlib.h>
   48 #include <stdio.h>
   49 #include <string.h>
   50 
   51 #ifdef HAVE_CONFIG_H
   52 #include "config.h"
   53 #endif
   54 
   55 #include "ftpp_return_codes.h"
   56 #include "ftpp_ui_config.h"
   57 #include "ftpp_ui_client_lookup.h"
   58 #include "ftpp_ui_server_lookup.h"
   59 #include "ftpp_si.h"
   60 #include "spp_ftptelnet.h"
   61 #include "stream_api.h"
   62 #include "snort_ftptelnet.h"
   63 #include "sfPolicyUserData.h"
   64 #include "ssl_include.h"
   65 
   66 #ifndef WIN32
   67 # include <ctype.h>
   68 #endif
   69 
   70 extern tSfPolicyUserContextId ftp_telnet_config;
   71 
   72 static FTP_SESSION StaticSession;
   73 
   74 /*
   75  * Function: PortMatch(PROTO_CONF *Conf, unsigned short port)
   76  *
   77  * Purpose: Given a configuration and a port number, we decide if
   78  *          the port is in the port list.
   79  *
   80  * Arguments: PROTO_CONF    => pointer to the client or server configuration
   81  *            port          => the port number to check for
   82  *
   83  * Returns: int => 0 indicates the port is not a client/server port.
   84  *                 1 indicates the port is one of the client/server ports.
   85  *
   86  */
   87 static int PortMatch(PROTO_CONF *Conf, unsigned short port)
   88 {
   89     if(Conf->ports[port])
   90     {
   91         return 1;
   92     }
   93 
   94     return 0;
   95 }
   96 
   97 /*
   98  * Function: TelnetFreeSession(void *preproc_session)
   99  *
  100  * Purpose: This function frees the data that is associated with a session.
  101  *
  102  * Arguments: preproc_session   => pointer to the session to free
  103  *
  104  * Returns: None
  105  */
  106 static void TelnetFreeSession(void *preproc_session)
  107 {
  108     TELNET_SESSION *ssn = (TELNET_SESSION *)preproc_session;
  109     FTPTELNET_GLOBAL_CONF *pPolicyConfig = NULL;
  110 
  111     if (ssn == NULL)
  112         return;
  113 
  114     pPolicyConfig = (FTPTELNET_GLOBAL_CONF *)sfPolicyUserDataGet(ssn->global_conf, ssn->policy_id);
  115 
  116     if (pPolicyConfig != NULL)
  117     {
  118         pPolicyConfig->ref_count--;
  119         if ((pPolicyConfig->ref_count == 0) &&
  120             (ssn->global_conf != ftp_telnet_config))
  121         {
  122             sfPolicyUserDataClear (ssn->global_conf, ssn->policy_id);
  123             FTPTelnetFreeConfig(pPolicyConfig);
  124 
  125             if (sfPolicyUserPolicyGetActive(ssn->global_conf) == 0)
  126                 FTPTelnetFreeConfigs(ssn->global_conf);
  127         }
  128     }
  129 
  130     ftp_telnet_stats.telnet_sessions--;
  131     ftp_telnet_stats.heap_memory -= sizeof(TELNET_SESSION);
  132 
  133     free(ssn);
  134 }
  135 
  136 /*
  137  * Function: TelnetResetSession(TELNET_SESSION *Session)
  138  *
  139  * Purpose: This function resets all the variables that need to be
  140  *          initialized for a new Session.  I've tried to keep this to
  141  *          a minimum, so we don't have to worry about initializing big
  142  *          structures.
  143  *
  144  * Arguments: Session         => pointer to the session to reset
  145  *
  146  * Returns: int => return code indicating error or success
  147  *
  148  */
  149 static inline int TelnetResetSession(TELNET_SESSION *Session)
  150 {
  151     Session->ft_ssn.proto = FTPP_SI_PROTO_TELNET;
  152     Session->telnet_conf = NULL;
  153     Session->global_conf = NULL;
  154 
  155     Session->consec_ayt = 0;
  156     Session->encr_state = NO_STATE;
  157 
  158     Session->event_list.stack_count = 0;
  159 
  160     return FTPP_SUCCESS;
  161 }
  162 
  163 /*
  164  * Function: TelnetStatefulSessionInspection(Packet *p,
  165  *                              FTPTELNET_GLOBAL_CONF *GlobalConf,
  166  *                              TELNET_SESSION **TelnetSession,
  167  *                              FTPP_SI_INPUT *SiInput)
  168  *
  169  * Purpose: Initialize the session and server configurations for
  170  *          this packet/stream.  In this function, we set the Session
  171  *          pointer (which includes the correct server configuration).
  172  *          The actual processing to find which IP is the server and
  173  *          which is the client, is done in the InitServerConf() function.
  174  *
  175  * Arguments: p             => pointer to the packet/stream
  176  *            GlobalConf    => pointer to the global configuration
  177  *            Session       => double pointer to the Session structure
  178  *            SiInput       => pointer to the session information
  179  *
  180  * Returns: int => return code indicating error or success
  181  *
  182  */
  183 static int TelnetStatefulSessionInspection(SFSnortPacket *p,
  184         FTPTELNET_GLOBAL_CONF *GlobalConf,
  185         TELNET_SESSION **TelnetSession,
  186         FTPP_SI_INPUT *SiInput)
  187 {
  188     if (p->stream_session)
  189     {
  190         TELNET_SESSION *NewSession = (TELNET_SESSION *)calloc(1, sizeof(TELNET_SESSION));
  191 
  192         ftp_telnet_stats.telnet_sessions++;
  193         if (ftp_telnet_stats.telnet_sessions > ftp_telnet_stats.max_telnet_sessions)
  194             ftp_telnet_stats.max_telnet_sessions = ftp_telnet_stats.telnet_sessions;
  195 
  196         ftp_telnet_stats.heap_memory += sizeof(TELNET_SESSION); 
  197 
  198         tSfPolicyId policy_id = _dpd.getNapRuntimePolicy();
  199 
  200         if (NewSession == NULL)
  201         {
  202             DynamicPreprocessorFatalMessage("Failed to allocate memory for "
  203                                             "new Telnet session.\n");
  204         }
  205 
  206         TelnetResetSession(NewSession);
  207 
  208         NewSession->ft_ssn.proto = FTPP_SI_PROTO_TELNET;
  209         NewSession->telnet_conf = GlobalConf->telnet_config;
  210 
  211         NewSession->global_conf = ftp_telnet_config;
  212         NewSession->policy_id = policy_id;
  213         GlobalConf->ref_count++;
  214 
  215         SiInput->pproto = FTPP_SI_PROTO_TELNET;
  216 
  217         _dpd.sessionAPI->set_application_data(p->stream_session,
  218                 PP_FTPTELNET, NewSession, &TelnetFreeSession);
  219 
  220         *TelnetSession = NewSession;
  221         return FTPP_SUCCESS;
  222     }
  223 
  224     return FTPP_NONFATAL_ERR;
  225 }
  226 
  227 /*
  228  * Function: TelnetStatelessSessionInspection(Packet *p,
  229  *                              FTPTELNET_GLOBAL_CONF *GlobalConf,
  230  *                              TELNET_SESSION **TelnetSession,
  231  *                              FTPP_SI_INPUT *SiInput)
  232  *
  233  * Purpose: Initialize the session and server configurations for this
  234  *          packet/stream.  It is important to note in stateless mode that
  235  *          we assume no knowledge of the state of a connection, other
  236  *          than the knowledge that we can glean from an individual packet.
  237  *          So in essence, each packet is it's own session and there
  238  *          is no knowledge retained from one packet to another.  If you
  239  *          want to track a telnet session for real, use stateful mode.
  240  *
  241  *          In this function, we set the Session pointer (which includes
  242  *          the correct server configuration).  The actual processing to
  243  *          find which IP is the server and which is the client, is done in
  244  *          the InitServerConf() function.
  245  *
  246  * Arguments: p             => pointer to the packet/stream
  247  *            GlobalConf    => pointer to the global configuration
  248  *            Session       => double pointer to the Session structure
  249  *            SiInput       => pointer to the session information
  250  *
  251  * Returns: int => return code indicating error or success
  252  *
  253  */
  254 static int TelnetStatelessSessionInspection(SFSnortPacket *p,
  255         FTPTELNET_GLOBAL_CONF *GlobalConf,
  256         TELNET_SESSION **Session,
  257         FTPP_SI_INPUT *SiInput)
  258 {
  259     static TELNET_SESSION TelnetStaticSession;
  260 
  261     TelnetResetSession(&TelnetStaticSession);
  262 
  263     SiInput->pproto = FTPP_SI_PROTO_TELNET;
  264     TelnetStaticSession.telnet_conf = GlobalConf->telnet_config;
  265     TelnetStaticSession.global_conf = ftp_telnet_config;
  266 
  267     *Session = &TelnetStaticSession;
  268 
  269     return FTPP_SUCCESS;
  270 }
  271 
  272 
  273 /*
  274  * Function: TelnetSessionInspection(Packet *p,
  275  *                          FTPTELNET_GLOBAL_CONF *GlobalConf,
  276  *                          FTPP_SI_INPUT *SiInput,
  277  *                          int *piInspectMode)
  278  *
  279  * Purpose: The Session Inspection module selects the appropriate
  280  *          configuration for the session, and the type of inspection
  281  *          to be performed (client or server.)
  282  *
  283  *          When the Session Inspection module is in stateful mode, it
  284  *          checks to see if there is a TELNET_SESSION pointer already
  285  *          associated with the stream.  If there is, then it uses that
  286  *          session pointer, otherwise it calculates the server configuration
  287  *          using the FTP_SI_INPUT and returns a TELNET_SESSION pointer.  In
  288  *          stateful mode, this means that memory is allocated, but in
  289  *          stateless mode, the same session pointer is used for all packets
  290  *          to reduce the allocation overhead.
  291  *
  292  *          The inspection mode can be either client or server.
  293  *
  294  * Arguments: p             => pointer to the packet/stream
  295  *            GlobalConf    => pointer to the global configuration
  296  *            Session       => double pointer to the Session structure
  297  *            SiInput       => pointer to the session information
  298  *            piInspectMode => pointer for setting inspection mode
  299  *
  300  * Returns: int => return code indicating error or success
  301  *
  302  */
  303 int TelnetSessionInspection(SFSnortPacket *p, FTPTELNET_GLOBAL_CONF *GlobalConf,
  304         TELNET_SESSION **TelnetSession, FTPP_SI_INPUT *SiInput, int *piInspectMode)
  305 {
  306     int iRet;
  307     int iTelnetSip;
  308     int iTelnetDip;
  309 #ifdef TARGET_BASED
  310     int16_t app_id = SFTARGET_UNKNOWN_PROTOCOL;
  311 
  312     /* If possible, use Stream API to determine protocol. */
  313     if (_dpd.streamAPI)
  314     {
  315         app_id = _dpd.sessionAPI->get_application_protocol_id(p->stream_session);
  316     }
  317     if (app_id == SFTARGET_UNKNOWN_PROTOCOL)
  318     {
  319         return FTPP_INVALID_PROTO;
  320     }
  321     if (app_id == telnet_app_id)
  322     {
  323         if (SiInput->pdir == FTPP_SI_CLIENT_MODE ||
  324             SiInput->pdir == FTPP_SI_SERVER_MODE)
  325         {
  326             *piInspectMode = (int)SiInput->pdir;
  327         }
  328     }
  329     else if (app_id && app_id != telnet_app_id)
  330     {
  331         return FTPP_INVALID_PROTO;
  332     }
  333     else
  334     {
  335 #endif
  336         iTelnetSip = PortMatch((PROTO_CONF*)GlobalConf->telnet_config,
  337                                SiInput->sport);
  338         iTelnetDip = PortMatch((PROTO_CONF*)GlobalConf->telnet_config,
  339                                SiInput->dport);
  340 
  341         if (iTelnetSip)
  342         {
  343             *piInspectMode = FTPP_SI_SERVER_MODE;
  344         }
  345         else if (iTelnetDip)
  346         {
  347             *piInspectMode = FTPP_SI_CLIENT_MODE;
  348         }
  349         else
  350         {
  351             return FTPP_INVALID_PROTO;
  352         }
  353 #ifdef TARGET_BASED
  354     }
  355 #endif
  356 
  357     /*
  358      * We get the server configuration and the session structure differently
  359      * depending on what type of inspection we are doing.  In the case of
  360      * stateful processing, we may get the session structure from the Stream
  361      * Reassembly module (which includes the server configuration) or the
  362      * structure will be allocated and added to the stream pointer for the
  363      * rest of the session.
  364      *
  365      * In stateless mode, we just use a static variable that is contained in
  366      * the function here.
  367      */
  368     if(GlobalConf->inspection_type == FTPP_UI_CONFIG_STATEFUL)
  369     {
  370         iRet = TelnetStatefulSessionInspection(p, GlobalConf, TelnetSession, SiInput);
  371         if (iRet)
  372             return iRet;
  373     }
  374     else
  375     {
  376         /* Assume stateless processing otherwise */
  377         iRet = TelnetStatelessSessionInspection(p, GlobalConf, TelnetSession, SiInput);
  378         if (iRet)
  379             return iRet;
  380     }
  381 
  382     return FTPP_SUCCESS;
  383 }
  384 
  385 /*
  386  * Function: FTPGetPacketDir(Packet *p)
  387  *
  388  * Purpose: Attempts to determine the direction of an FTP packet by
  389  *          examining the first 3 bytes.  If all three are numeric,
  390  *          the packet is a server response packet.
  391  *
  392  * Arguments: p             => pointer to the Packet
  393  *
  394  * Returns: int => return code indicating the mode
  395  *
  396  */
  397 int FTPGetPacketDir(SFSnortPacket *p)
  398 {
  399     if (p->payload_size >= 3)
  400     {
  401         if (isdigit(p->payload[0]) &&
  402             isdigit(p->payload[1]) &&
  403             isdigit(p->payload[2]) )
  404         {
  405             return FTPP_SI_SERVER_MODE;
  406         }
  407         else
  408         {
  409             return FTPP_SI_CLIENT_MODE;
  410         }
  411     }
  412     return FTPP_SI_NO_MODE;
  413 }
  414 
  415 /*
  416  * Function: FTPInitConf(Packet *p, FTPTELNET_GLOBAL_CONF *GlobalConf,
  417  *                       FTP_CLIENT_PROTO_CONF **ClientConf,
  418  *                       FTP_SERVER_PROTO_CONF **ServerConf,
  419  *                       FTPP_SI_INPUT *SiInput, int *piInspectMode)
  420  *
  421  * Purpose: When a session is initialized, we must select the appropriate
  422  *          server configuration and select the type of inspection based
  423  *          on the source and destination ports.
  424  *
  425  * IMPORTANT NOTE:
  426  *   We should check to make sure that there are some unique configurations,
  427  *   otherwise we can just default to the global default and work some magic
  428  *   that way.
  429  *
  430  * Arguments: p                 => pointer to the Packet/Session
  431  *            GlobalConf        => pointer to the global configuration
  432  *            ClientConf        => pointer to the address of the client
  433  *                                 config so we can set it.
  434  *            ServerConf        => pointer to the address of the server
  435  *                                 config so we can set it.
  436  *            SiInput           => pointer to the packet info
  437  *            piInspectMode     => pointer so we can set the inspection mode
  438  *
  439  * Returns: int => return code indicating error or success
  440  *
  441  */
  442 static int FTPInitConf(SFSnortPacket *p, FTPTELNET_GLOBAL_CONF *GlobalConf,
  443                           FTP_CLIENT_PROTO_CONF **ClientConf,
  444                           FTP_SERVER_PROTO_CONF **ServerConf,
  445                           FTPP_SI_INPUT *SiInput, int *piInspectMode)
  446 {
  447     FTP_CLIENT_PROTO_CONF *ClientConfSip;
  448     FTP_CLIENT_PROTO_CONF *ClientConfDip;
  449     FTP_SERVER_PROTO_CONF *ServerConfSip;
  450     FTP_SERVER_PROTO_CONF *ServerConfDip;
  451     int iServerSip;
  452     int iServerDip;
  453     int iErr = 0;
  454     int iRet = FTPP_SUCCESS;
  455 #ifdef TARGET_BASED
  456     int16_t app_id = 0;
  457 #endif
  458     sfaddr_t sip;
  459     sfaddr_t dip;
  460 
  461     //structure copy
  462     sip = SiInput->sip;
  463     dip = SiInput->dip;
  464 
  465     /*
  466      * We find the client configurations for both the source and dest IPs.
  467      * There should be a check on the global configuration to see if there
  468      * is at least one unique client configuration.  If there isn't then we
  469      * assume the global client configuration.
  470      */
  471     ClientConfDip = ftpp_ui_client_lookup_find(GlobalConf->client_lookup,
  472             &dip,
  473             &iErr);
  474 
  475     if(!ClientConfDip)
  476     {
  477         ClientConfDip = GlobalConf->default_ftp_client;
  478     }
  479 
  480     ClientConfSip = ftpp_ui_client_lookup_find(GlobalConf->client_lookup,
  481             &sip,
  482             &iErr);
  483 
  484     if(!ClientConfSip)
  485     {
  486         ClientConfSip = GlobalConf->default_ftp_client;
  487     }
  488 
  489     /*
  490      * Now, we find the server configurations for both the source and dest IPs.
  491      * There should be a check on the global configuration to see if there
  492      * is at least one unique client configuration.  If there isn't then we
  493      * assume the global client configuration.
  494      */
  495     ServerConfDip = ftpp_ui_server_lookup_find(GlobalConf->server_lookup,
  496             &dip,
  497             &iErr);
  498 
  499     if(!ServerConfDip)
  500     {
  501         ServerConfDip = GlobalConf->default_ftp_server;
  502     }
  503 
  504     ServerConfSip = ftpp_ui_server_lookup_find(GlobalConf->server_lookup,
  505             &sip,
  506             &iErr);
  507 
  508     if(!ServerConfSip)
  509     {
  510         ServerConfSip = GlobalConf->default_ftp_server;
  511     }
  512 
  513     /*
  514      * We check the IP and the port to see if the FTP client is talking in
  515      * the session.  This should tell us whether it is client communication
  516      * or server configuration.  If both IPs and ports are servers, then there
  517      * is a sort of problem.  We don't know which side is the client and which
  518      * side is the server so we have to assume one.
  519      *
  520      * In stateful processing, we only do this stage on the startup of a
  521      * session, so we can still assume that the initial packet is the client
  522      * talking.
  523      */
  524     iServerDip = PortMatch((PROTO_CONF*)ServerConfDip, SiInput->dport);
  525     iServerSip = PortMatch((PROTO_CONF*)ServerConfSip, SiInput->sport);
  526 
  527     /*
  528      * We default to the no FTP traffic case
  529      */
  530     *piInspectMode = FTPP_SI_NO_MODE;
  531     *ClientConf = NULL;
  532     *ServerConf = NULL;
  533 
  534     /*
  535      * Depending on the type of packet direction we get from the
  536      * state machine, we evaluate client/server differently.
  537      */
  538     switch(SiInput->pdir)
  539     {
  540         case FTPP_SI_NO_MODE:
  541 
  542 #ifdef TARGET_BASED
  543             app_id = _dpd.sessionAPI->get_application_protocol_id(p->stream_session);
  544 
  545             if (app_id == ftp_app_id || app_id == 0)
  546             {
  547 #endif
  548 
  549             /*
  550              * We check for the case where both SIP and DIP
  551              * appear to be servers.  In this case, we assume server
  552              * and process that way.
  553              */
  554             if(iServerSip && iServerDip)
  555             {
  556                 /*
  557                  * We check for the case where both SIP and DIP
  558                  * appear to be servers.  In this case, we look at
  559                  * the first few bytes of the packet to try to
  560                  * determine direction -- 3 digits indicate server
  561                  * response.
  562                  */
  563 
  564                 /* look at the first few bytes of the packet.  We might
  565                  * be wrong if this is a reassembled packet and we catch
  566                  * a server response mid-stream.
  567                  */
  568                 *piInspectMode = FTPGetPacketDir(p);
  569                 if (*piInspectMode == FTPP_SI_SERVER_MODE)
  570                 {
  571                     /* Packet is from server --> src is Server */
  572                     *ClientConf = ClientConfDip;
  573                     *ServerConf = ServerConfSip;
  574                 }
  575                 else /* Assume client */
  576                 {
  577                     /* Packet is from client --> dest is Server */
  578                     *piInspectMode = FTPP_SI_CLIENT_MODE;
  579                     *ClientConf = ClientConfSip;
  580                     *ServerConf = ServerConfDip;
  581                 }
  582                 SiInput->pproto = FTPP_SI_PROTO_FTP;
  583             }
  584             else if(iServerDip)
  585             {
  586                 /* Packet is from client --> dest is Server */
  587                 *piInspectMode = FTPP_SI_CLIENT_MODE;
  588                 *ClientConf = ClientConfSip;
  589                 *ServerConf = ServerConfDip;
  590                 SiInput->pproto = FTPP_SI_PROTO_FTP;
  591             }
  592             else if(iServerSip)
  593             {
  594                 /* Packet is from server --> src is Server */
  595                 *piInspectMode = FTPP_SI_SERVER_MODE;
  596                 *ClientConf = ClientConfDip;
  597                 *ServerConf = ServerConfSip;
  598                 SiInput->pproto = FTPP_SI_PROTO_FTP;
  599             }
  600             break;
  601 
  602 #ifdef TARGET_BASED
  603             }
  604 #endif
  605 
  606         case FTPP_SI_CLIENT_MODE:
  607             /* Packet is from client --> dest is Server */
  608 #ifdef TARGET_BASED
  609             app_id = _dpd.sessionAPI->get_application_protocol_id(p->stream_session);
  610 
  611             if ((app_id == ftp_app_id) || (!app_id && iServerDip))
  612 #else
  613             if(iServerDip)
  614 #endif
  615             {
  616                 *piInspectMode = FTPP_SI_CLIENT_MODE;
  617                 *ClientConf = ClientConfSip;
  618                 *ServerConf = ServerConfDip;
  619                 SiInput->pproto = FTPP_SI_PROTO_FTP;
  620             }
  621             else
  622             {
  623                 *piInspectMode = FTPP_SI_NO_MODE;
  624                 iRet = FTPP_NONFATAL_ERR;
  625             }
  626             break;
  627 
  628         case FTPP_SI_SERVER_MODE:
  629             /* Packet is from server --> src is Server */
  630 #ifdef TARGET_BASED
  631             app_id = _dpd.sessionAPI->get_application_protocol_id(p->stream_session);
  632 
  633             if ((app_id == ftp_app_id) || (!app_id && iServerSip))
  634 #else
  635             if(iServerSip)
  636 #endif
  637             {
  638                 *piInspectMode = FTPP_SI_SERVER_MODE;
  639                 *ClientConf = ClientConfDip;
  640                 *ServerConf = ServerConfSip;
  641                 SiInput->pproto = FTPP_SI_PROTO_FTP;
  642             }
  643             else
  644             {
  645                 *piInspectMode = FTPP_SI_NO_MODE;
  646                 iRet = FTPP_NONFATAL_ERR;
  647             }
  648             break;
  649 
  650         default:
  651             *piInspectMode = FTPP_SI_NO_MODE;
  652             *ClientConf = NULL;
  653             *ServerConf = NULL;
  654             break;
  655     }
  656 
  657     return iRet;
  658 }
  659 
  660 /*
  661  * Function: FTPFreeSession(void *preproc_session)
  662  *
  663  * Purpose: This function frees the data that is associated with a session.
  664  *
  665  * Arguments: preproc_session   => pointer to the session to free
  666  *
  667  * Returns: None
  668  */
  669 static void FTPFreeSession(void *preproc_session)
  670 {
  671     FTP_SESSION *ssn = (FTP_SESSION *)preproc_session;
  672     FTPTELNET_GLOBAL_CONF *pPolicyConfig = NULL;
  673     ssl_callback_interface_t *ssl_cb = (ssl_callback_interface_t *)_dpd.getSSLCallback();
  674 
  675     if (ssn == NULL)
  676         return;
  677 
  678     pPolicyConfig = (FTPTELNET_GLOBAL_CONF *)sfPolicyUserDataGet(ssn->global_conf, ssn->policy_id);
  679 
  680     if (pPolicyConfig != NULL)
  681     {
  682         pPolicyConfig->ref_count--;
  683         if ((pPolicyConfig->ref_count == 0) &&
  684             (ssn->global_conf != ftp_telnet_config))
  685         {
  686 
  687             sfPolicyUserDataClear (ssn->global_conf, ssn->policy_id);
  688             FTPTelnetFreeConfig(pPolicyConfig);
  689 
  690             if (sfPolicyUserPolicyGetActive(ssn->global_conf) == 0)
  691                 FTPTelnetFreeConfigs(ssn->global_conf);
  692         }
  693     }
  694 
  695     if (ssn->filename)
  696     {
  697         ftp_telnet_stats.heap_memory -= (strlen(ssn->filename) + 1);
  698         free(ssn->filename);
  699     }
  700 
  701     if ( ssl_cb )
  702         ssl_cb->session_free(ssn->flow_id);
  703 
  704     ftp_telnet_stats.ftp_sessions--;
  705     ftp_telnet_stats.heap_memory -= sizeof(FTP_SESSION);
  706 #ifdef TARGET_BASED
  707     FTP_DATA_SESSION *datassn = ssn->datassn;
  708     if(datassn && (ssn == datassn->ftpssn))
  709         datassn->ftpssn = NULL;
  710     free(ssn);
  711 #endif
  712 }
  713 
  714 #ifdef TARGET_BASED
  715 /* Function: FTPDataSessionNew
  716  *
  717  * Create an ftp-data session from a packet
  718  */
  719 FTP_DATA_SESSION * FTPDataSessionNew(SFSnortPacket *p)
  720 {
  721     FTP_DATA_SESSION *ftpdata = calloc(1, sizeof *ftpdata);
  722 
  723     if (!ftpdata)
  724         return NULL;
  725 
  726     ftpdata->ft_ssn.proto = FTPP_SI_PROTO_FTP_DATA;
  727     ftpdata->flow_id = 0;
  728 
  729     /* Get the ftp-ctrl session key */
  730     ftpdata->ftp_key = _dpd.sessionAPI->get_session_key(p);
  731 
  732     if (!ftpdata->ftp_key)
  733     {
  734         free(ftpdata);
  735         ftpdata = NULL;
  736         return ftpdata;
  737     }
  738 
  739     ftp_telnet_stats.ftp_data_sessions++;
  740     if (ftp_telnet_stats.ftp_data_sessions > ftp_telnet_stats.max_ftp_data_sessions)
  741         ftp_telnet_stats.max_ftp_data_sessions = ftp_telnet_stats.ftp_data_sessions;
  742     
  743     ftp_telnet_stats.heap_memory += (sizeof (*ftpdata) + sizeof(StreamSessionKey));
  744 
  745     return ftpdata;
  746 }
  747 
  748 /*
  749  * Function: FTPDataSessionFree
  750  *
  751  * Free an ftp-data session
  752  */
  753 void FTPDataSessionFree(void *p_ssn)
  754 {
  755     FTP_DATA_SESSION *ssn = (FTP_DATA_SESSION *)p_ssn;
  756     ssl_callback_interface_t *ssl_cb = (ssl_callback_interface_t *)_dpd.getSSLCallback();
  757 
  758     if (!ssn)
  759         return;
  760 
  761     FTP_SESSION * ftpssn = ssn->ftpssn;
  762     if(ftpssn && (ssn == ftpssn->datassn))
  763         ftpssn->datassn = NULL;
  764 
  765     /* ftp-data key shouldn't exist without this but */
  766     if (ssn->ftp_key)
  767     {
  768         free(ssn->ftp_key);
  769     }
  770 
  771     if (ssn->filename)
  772     {
  773         ftp_telnet_stats.heap_memory -= (strlen(ssn->filename) + 1);
  774         free(ssn->filename);
  775     }
  776 
  777     if ( ssl_cb )
  778         ssl_cb->session_free(ssn->flow_id);
  779 
  780     ftp_telnet_stats.ftp_data_sessions--;
  781     ftp_telnet_stats.heap_memory -= sizeof(FTP_DATA_SESSION);
  782 
  783     free(ssn);
  784 }
  785 
  786 /* Function: FTPDataDirection
  787  *
  788  * Return true if packet is from the "sending" host
  789  * Return false if packet is from the "receiving" host
  790  */
  791 bool FTPDataDirection(SFSnortPacket *p, FTP_DATA_SESSION *ftpdata)
  792 {
  793     uint32_t direction;
  794     uint32_t pktdir = _dpd.sessionAPI->get_packet_direction(p);
  795 
  796     if (ftpdata->mode == FTPP_XFER_ACTIVE)
  797         direction = ftpdata->direction ?  FLAG_FROM_SERVER : FLAG_FROM_CLIENT;
  798     else
  799         direction = ftpdata->direction ?  FLAG_FROM_CLIENT : FLAG_FROM_SERVER;
  800 
  801     return (pktdir == direction);
  802 }
  803 
  804 #endif /* TARGET_BASED */
  805 
  806 /*
  807  * Function: FTPResetSession(FTP_SESSION *FtpSession, int first)
  808  *
  809  * Purpose: This function resets all the variables that need to be
  810  *          initialized for a new Session.  I've tried to keep this to
  811  *          a minimum, so we don't have to worry about initializing big
  812  *          structures.
  813  *
  814  * Arguments: FtpSession    => pointer to the session to reset
  815  *            first         => indicator whether this is a new conf
  816  *
  817  * Returns: int => return code indicating error or success
  818  *
  819  */
  820 static inline int FTPResetSession(FTP_SESSION *FtpSession)
  821 {
  822     FtpSession->ft_ssn.proto = FTPP_SI_PROTO_FTP;
  823 
  824     FtpSession->server.response.pipeline_req = 0;
  825     FtpSession->server.response.state = 0;
  826     FtpSession->client.request.pipeline_req = 0;
  827     FtpSession->client.state = 0;
  828 
  829     FtpSession->client_conf = NULL;
  830     FtpSession->server_conf = NULL;
  831     FtpSession->global_conf = NULL;
  832 
  833     FtpSession->encr_state = NO_STATE;
  834     FtpSession->encr_state_chello = false;
  835     FtpSession->flow_id = 0;
  836     IP_CLEAR(FtpSession->clientIP);
  837     FtpSession->clientPort = 0;
  838     IP_CLEAR(FtpSession->serverIP);
  839     FtpSession->serverPort = 0;
  840     FtpSession->data_chan_state = NO_STATE;
  841     FtpSession->data_chan_index = 0;
  842     FtpSession->data_xfer_index = 0;
  843     FtpSession->ftp_cmd_pipe_index = 1;
  844     FtpSession->rest_cmd_offset = 0;
  845 
  846     FtpSession->event_list.stack_count = 0;
  847 
  848     return FTPP_SUCCESS;
  849 }
  850 
  851 /*
  852  * Function: FTPStatefulSessionInspection(Packet *p,
  853  *                          FTPTELNET_GLOBAL_CONF *GlobalConf,
  854  *                          FTP_SESSION **FtpSession,
  855  *                          FTPP_SI_INPUT *SiInput, int *piInspectMode)
  856  *
  857  * Purpose: Initialize the session and server configurations for this
  858  *          packet/stream.  In this function, we set the Session pointer
  859  *          (which includes the correct server configuration).  The actual
  860  *          processing to find which IP is the server and which is the
  861  *          client, is done in the InitServerConf() function.
  862  *
  863  * Arguments: p                 => pointer to the Packet/Session
  864  *            GlobalConf        => pointer to the global configuration
  865  *            Session           => double pointer to the Session structure
  866  *            SiInput           => pointer to the session information
  867  *            piInspectMode     => pointer so the inspection mode can be set
  868  *
  869  * Returns: int => return code indicating error or success
  870  *
  871  */
  872 static int FTPStatefulSessionInspection(SFSnortPacket *p,
  873         FTPTELNET_GLOBAL_CONF *GlobalConf,
  874         FTP_SESSION **FtpSession,
  875         FTPP_SI_INPUT *SiInput, int *piInspectMode)
  876 {
  877     if (p->stream_session)
  878     {
  879         FTP_CLIENT_PROTO_CONF *ClientConf;
  880         FTP_SERVER_PROTO_CONF *ServerConf;
  881         int iRet;
  882 
  883         iRet = FTPInitConf(p, GlobalConf, &ClientConf, &ServerConf, SiInput, piInspectMode);
  884         if (iRet)
  885             return iRet;
  886 
  887         if (*piInspectMode)
  888         {
  889             FTP_SESSION *NewSession = (FTP_SESSION *)calloc(1, sizeof(FTP_SESSION));
  890 
  891             ftp_telnet_stats.ftp_sessions++;
  892             if (ftp_telnet_stats.ftp_sessions > ftp_telnet_stats.max_ftp_sessions)
  893                 ftp_telnet_stats.max_ftp_sessions = ftp_telnet_stats.ftp_sessions;
  894    
  895             ftp_telnet_stats.heap_memory += sizeof(FTP_SESSION);
  896 
  897             tSfPolicyId policy_id = _dpd.getNapRuntimePolicy();
  898 
  899             if (NewSession == NULL)
  900             {
  901                 DynamicPreprocessorFatalMessage("Failed to allocate memory for "
  902                                                 "new FTP session.\n");
  903             }
  904 
  905             FTPResetSession(NewSession);
  906 
  907             NewSession->ft_ssn.proto = FTPP_SI_PROTO_FTP;
  908             NewSession->client_conf = ClientConf;
  909             NewSession->server_conf = ServerConf;
  910 
  911             NewSession->global_conf = ftp_telnet_config;
  912             NewSession->policy_id = policy_id;
  913             GlobalConf->ref_count++;
  914 
  915             _dpd.sessionAPI->set_application_data
  916                 (p->stream_session, PP_FTPTELNET, NewSession, &FTPFreeSession);
  917 
  918             *FtpSession = NewSession;
  919             SiInput->pproto = FTPP_SI_PROTO_FTP;
  920             return FTPP_SUCCESS;
  921         }
  922     }
  923 
  924     return FTPP_INVALID_PROTO;
  925 }
  926 
  927 /*
  928  * Function: FTPStatelessSessionInspection(Packet *p,
  929  *                          FTPTELNET_GLOBAL_CONF *GlobalConf,
  930  *                          FTP_SESSION **FtpSession,
  931  *                          FTPP_SI_INPUT *SiInput, int *piInspectMode)
  932  *
  933  * Purpose: Initialize the session and server configurations for this
  934  *          packet/stream.  It is important to note in stateless mode that
  935  *          we assume no knowledge of the state of a connection, other than
  936  *          the knowledge that we can glean from an individual packet.  So
  937  *          in essence, each packet is it's own session and there is no
  938  *          knowledge retained from one packet to another.  If you want to
  939  *          track an FTP session for real, use stateful mode.
  940  *
  941  *          In this function, we set the Session pointer (which includes
  942  *          the correct server configuration).  The actual processing to find
  943  *          which IP is the server and which is the client, is done in the
  944  *          InitServerConf() function.
  945  *
  946  * Arguments: p                 => pointer to the Packet/Session
  947  *            GlobalConf        => pointer to the global configuration
  948  *            Session           => double pointer to the Session structure
  949  *            SiInput           => pointer to the session information
  950  *            piInspectMode     => pointer so the inspection mode can be set
  951  *
  952  * Returns: int => return code indicating error or success
  953  *
  954  */
  955 static int FTPStatelessSessionInspection(SFSnortPacket *p,
  956         FTPTELNET_GLOBAL_CONF *GlobalConf,
  957         FTP_SESSION **FtpSession,
  958         FTPP_SI_INPUT *SiInput, int *piInspectMode)
  959 {
  960     FTP_CLIENT_PROTO_CONF *ClientConf;
  961     FTP_SERVER_PROTO_CONF *ServerConf;
  962     int iRet;
  963 
  964     FTPResetSession(&StaticSession);
  965 
  966     iRet = FTPInitConf(p, GlobalConf, &ClientConf, &ServerConf, SiInput, piInspectMode);
  967     if (iRet)
  968         return iRet;
  969 
  970     StaticSession.ft_ssn.proto = FTPP_SI_PROTO_FTP;
  971     StaticSession.global_conf = ftp_telnet_config;
  972     StaticSession.client_conf = ClientConf;
  973     StaticSession.server_conf = ServerConf;
  974 
  975     SiInput->pproto = FTPP_SI_PROTO_FTP;
  976     *FtpSession = &StaticSession;
  977 
  978     return FTPP_SUCCESS;
  979 }
  980 
  981 
  982 /*
  983  * Function: FTPSessionInspection(Packet *p,
  984  *                          FTPTELNET_GLOBAL_CONF *GlobalConf,
  985  *                          FTPP_SI_INPUT *SiInput, int *piInspectMode)
  986  *
  987  * Purpose: The Session Inspection module selects the appropriate client
  988  *          configuration for the session, and the type of inspection to
  989  *          be performed (client or server.)
  990  *
  991  *          When the Session Inspection module is in stateful mode, it
  992  *          checks to see if there is a FTP_SESSION pointer already
  993  *          associated with the stream.  If there is, then it uses that
  994  *          session pointer, otherwise it calculates the server
  995  *          configuration using the FTP_SI_INPUT and returns a FTP_SESSION
  996  *          pointer.  In stateful mode, this means that memory is allocated,
  997  *          but in stateless mode, the same session pointer is used for all
  998  *          packets to reduce the allocation overhead.
  999  *
 1000  *          The inspection mode can be either client or server.
 1001  *
 1002  * Arguments: p                 => pointer to the Packet/Session
 1003  *            GlobalConf        => pointer to the global configuration
 1004  *            SiInput           => pointer to the session information
 1005  *            piInspectMode     => pointer so the inspection mode can be set
 1006  *
 1007  * Returns: int => return code indicating error or success
 1008  *
 1009  */
 1010 int FTPSessionInspection(SFSnortPacket *p, FTPTELNET_GLOBAL_CONF *GlobalConf,
 1011         FTP_SESSION **FtpSession, FTPP_SI_INPUT *SiInput, int *piInspectMode)
 1012 {
 1013     int iRet;
 1014 
 1015     /*
 1016      * We get the server configuration and the session structure differently
 1017      * depending on what type of inspection we are doing.  In the case of
 1018      * stateful processing, we may get the session structure from the Stream
 1019      * Reassembly module (which includes the server configuration) or the
 1020      * structure will be allocated and added to the stream pointer for the
 1021      * rest of the session.
 1022      *
 1023      * In stateless mode, we just use a static variable that is contained in
 1024      * the function here.
 1025      */
 1026     if(GlobalConf->inspection_type == FTPP_UI_CONFIG_STATEFUL)
 1027     {
 1028         iRet = FTPStatefulSessionInspection(p, GlobalConf, FtpSession, SiInput, piInspectMode);
 1029         if (iRet)
 1030             return iRet;
 1031     }
 1032     else
 1033     {
 1034         /* Assume stateless processing otherwise */
 1035         iRet = FTPStatelessSessionInspection(p, GlobalConf, FtpSession, SiInput, piInspectMode);
 1036         if (iRet)
 1037             return iRet;
 1038     }
 1039 
 1040     return FTPP_SUCCESS;
 1041 }
 1042 
 1043 /*
 1044  * Function: ftpp_si_determine_proto(Packet *p,
 1045  *                          FTPTELNET_GLOBAL_CONF *GlobalConf,
 1046  *                          FTPP_SI_INPUT *SiInput, int *piInspectMode)
 1047  *
 1048  * Purpose: The Protocol Determination module determines whether this is
 1049  *          an FTP or telnet request.  If this is an FTP request, it sets
 1050  *          the FTP Session data and inspection mode.
 1051  *
 1052  *          The inspection mode can be either client or server.
 1053  *
 1054  * Arguments: p                 => pointer to the Packet/Session
 1055  *            GlobalConf        => pointer to the global configuration
 1056  *            SiInput           => pointer to the session information
 1057  *            piInspectMode     => pointer so the inspection mode can be set
 1058  *
 1059  * Returns: int => return code indicating error or success
 1060  *
 1061  */
 1062 int ftpp_si_determine_proto(SFSnortPacket *p, FTPTELNET_GLOBAL_CONF *GlobalConf,
 1063         FTP_TELNET_SESSION **ft_ssn, FTPP_SI_INPUT *SiInput, int *piInspectMode)
 1064 {
 1065     /* Default to no FTP or Telnet case */
 1066     SiInput->pproto = FTPP_SI_PROTO_UNKNOWN;
 1067     *piInspectMode = FTPP_SI_NO_MODE;
 1068 
 1069     TelnetSessionInspection(p, GlobalConf, (TELNET_SESSION **)ft_ssn, SiInput, piInspectMode);
 1070     if (SiInput->pproto == FTPP_SI_PROTO_TELNET)
 1071         return FTPP_SUCCESS;
 1072 
 1073     FTPSessionInspection(p, GlobalConf, (FTP_SESSION **)ft_ssn, SiInput, piInspectMode);
 1074     if (SiInput->pproto == FTPP_SI_PROTO_FTP)
 1075         return FTPP_SUCCESS;
 1076 
 1077     return FTPP_INVALID_PROTO;
 1078 }