"Fossies" - the Fresh Open Source Software Archive

Member "snort-2.9.17/src/dynamic-preprocessors/ftptelnet/pp_ftp.c" (16 Oct 2020, 72344 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 "pp_ftp.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 /* $Id$ */
    2 /*
    3  ** Copyright (C) 2014-2020 Cisco and/or its affiliates. All rights reserved.
    4  ** Copyright (C) 2004-2013 Sourcefire, Inc.
    5  **
    6  ** This program is free software; you can redistribute it and/or modify
    7  ** it under the terms of the GNU General Public License Version 2 as
    8  ** published by the Free Software Foundation.  You may not use, modify or
    9  ** distribute this program under any other version of the GNU General
   10  ** Public License.
   11  **
   12  ** This program is distributed in the hope that it will be useful,
   13  ** but WITHOUT ANY WARRANTY; without even the implied warranty of
   14  ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   15  ** GNU General Public License for more details.
   16  **
   17  ** You should have received a copy of the GNU General Public License
   18  ** along with this program; if not, write to the Free Software
   19  ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
   20  */
   21 
   22 /* pp_ftp.c
   23  *
   24  * Purpose:  FTP sessions contain commands and responses.  Certain
   25  *           commands are vectors of attack.  This module checks
   26  *           those FTP client commands and their parameter values, as
   27  *           well as the server responses per the configuration.
   28  *
   29  * Arguments:  None
   30  *
   31  * Effect:  Alerts may be raised
   32  *
   33  * Comments:
   34  *
   35  */
   36 
   37 /* your preprocessor header file goes here */
   38 
   39 #define _GNU_SOURCE
   40 
   41 #ifdef HAVE_CONFIG_H
   42 #include "config.h"
   43 #endif
   44 
   45 #ifdef HAVE_STRINGS_H
   46 #include <strings.h>
   47 #endif
   48 
   49 #include <string.h>
   50 #include <stdlib.h>
   51 #include <stdio.h>
   52 #include <sys/types.h>
   53 #ifndef WIN32
   54 #include <sys/socket.h>
   55 #include <netinet/in.h>
   56 #include <arpa/inet.h>
   57 #include <ctype.h>
   58 #else
   59 #include <windows.h>
   60 #endif
   61 
   62 #include <errno.h>
   63 #include "ftpp_eo_log.h"
   64 #include "pp_ftp.h"
   65 #include "pp_telnet.h"
   66 #include "ftpp_return_codes.h"
   67 #include "ftp_cmd_lookup.h"
   68 #include "ftp_bounce_lookup.h"
   69 #include "spp_ftptelnet.h"
   70 //#include "decode.h"
   71 #include "snort_debug.h"
   72 #include "stream_api.h"
   73 //#include "plugbase.h"
   74 
   75 #ifndef MAXHOSTNAMELEN /* Why doesn't Windows define this? */
   76 #define MAXHOSTNAMELEN 256
   77 #endif
   78 
   79 #include "ipv6_port.h"
   80 
   81 #ifdef TARGET_BASED
   82 extern int16_t ftp_data_app_id;
   83 extern unsigned s_ftpdata_eof_cb_id;
   84 #endif
   85 #ifdef DUMP_BUFFER
   86 #include "ftptelnet_buffer_dump.h"
   87 #endif
   88 
   89 #define DEFAULT_MEM_ALLOC 512
   90 
   91 /*
   92  * Function: getIP959(char **ip_start,
   93  *                 char *last_char,
   94  *                 char term_char,
   95  *                 uint32_t *ipRet,
   96  *                 uint16_t *portRet)
   97  *
   98  * Purpose: Returns a 32bit IP address and port from an RFC 959 FTP-style
   99  *          string -- ie, a,b,c,d,p1,p2.  Stops checking when term_char
  100  *          is seen.  Used to get address and port information from FTP
  101  *          PORT command and server response to PASV command.
  102  *
  103  * Arguments ip_start        => Pointer to pointer to the start of string.
  104  *                              Updated to end of IP address if successful.
  105  *           last_char       => End of string
  106  *           term_char       => Character delimiting the end of the address.
  107  *           ipRet           => Return pointer to 32bit address on success
  108  *           portRet         => Return pointer to 16bit port on success
  109  *
  110  * Returns: int => return code indicating error or success
  111  */
  112 static int getIP959(
  113     const char **ip_start, const char *last_char, char *term_char,
  114     sfaddr_t *ipRet, uint16_t *portRet
  115 )
  116 {
  117     uint32_t ip=0;
  118     uint16_t port=0;
  119     int octet=0;
  120     const char *this_param = *ip_start;
  121     do
  122     {
  123         int value = 0;
  124         do
  125         {
  126             if (!isdigit((int)(*this_param)))
  127             {
  128                 return FTPP_NON_DIGIT;
  129             }
  130             value = value * 10 + (*this_param - '0');
  131             this_param++;
  132         } while ((this_param < last_char) &&
  133                  (*this_param != ',') &&
  134                  (strchr(term_char, *this_param) == NULL));
  135         if (value > 0xFF)
  136         {
  137             return FTPP_INVALID_ARG;
  138         }
  139         if (octet  < 4)
  140         {
  141             ip = (ip << 8) + value;
  142         }
  143         else
  144         {
  145             port = (port << 8) + value;
  146         }
  147 
  148         if (strchr(term_char, *this_param) == NULL)
  149             this_param++;
  150         octet++;
  151     } while ((this_param < last_char) && (strchr(term_char, *this_param) == NULL));
  152 
  153     if (octet != 6)
  154     {
  155         return FTPP_MALFORMED_IP_PORT;
  156     }
  157 
  158     ip = htonl(ip);
  159     sfip_set_raw(ipRet, &ip, AF_INET);
  160     *portRet = port;
  161     *ip_start = this_param;
  162 
  163     return FTPP_SUCCESS;
  164 }
  165 
  166 /*
  167  * getIP1639() parses the LPRT command parameters which have this
  168  * format (ftyp == e_long_host_port):
  169  *
  170  *     LPRT af,hal,h1,h2,h3,h4...,pal,p1,p2...
  171  *     LPRT 4,4,132,235,1,2,2,24,131
  172  *     LPRT 6,16,16,128,0,...,0,8,128,0,32,12,65,123,2,20,162
  173  *
  174  * (The above examples correspond to the EPRT examples below.)
  175  *
  176  * af (address family) is the IP version.  h# and p# are in network
  177  * byte order (high byte first).
  178  *
  179  * This function is called for the LPSV response as well, which
  180  * has this format:
  181  *
  182  *    228 <human readable text> (af,hal,h1,h2,h3,h4...,pal,p1,p2...)
  183  */
  184 static int getIP1639 (
  185     const char **ip_start, const char *last_char, char *term_char,
  186     sfaddr_t* ipRet, uint16_t *portRet
  187 )
  188 {
  189     char bytes[21];  /* max of 1+5+3 and 1+17+3 */
  190     const char* tok = *ip_start;
  191     unsigned nBytes = 0;
  192     bytes[0] = 0;
  193 
  194     /* first we just try to get a sequence of csv bytes */
  195     while ( nBytes < sizeof(bytes) && tok < last_char )
  196     {
  197         char* endPtr = (char*)tok;
  198         unsigned long val = strtoul(tok, &endPtr, 10);
  199 
  200         if (
  201             val > 255 || endPtr == tok ||
  202             ( *endPtr && *endPtr != ',' && endPtr != last_char )
  203         ) {
  204             return FTPP_INVALID_ARG;
  205         }
  206         bytes[nBytes++] = (uint8_t)val;
  207         tok = (endPtr < last_char) ? endPtr + 1 : endPtr;
  208     }
  209     *ip_start = tok;
  210 
  211     /* now we check that the we have a valid sequence of */
  212     /* bytes and convert the address and port accordingly */
  213     switch ( bytes[0] )
  214     {
  215     case 4:
  216         if ( nBytes != 9 || bytes[1] != 4 || bytes[6] != 2 )
  217             return FTPP_INVALID_ARG;
  218         {
  219             uint32_t ip4_addr = 0;
  220             int n;
  221             for ( n = 0; n < 4; n++ )
  222                 ip4_addr = (ip4_addr << 8) | bytes[n+2];
  223             /* don't call sfip_set_raw() on raw bytes
  224                to avoid possible word alignment issues */
  225             ip4_addr = htonl(ip4_addr);
  226             sfip_set_raw(ipRet, (void*)&ip4_addr, AF_INET);
  227         }
  228         *portRet = (bytes[7] << 8) | bytes[8];
  229         break;
  230 
  231     case 6:
  232         if ( nBytes != 21 || bytes[1] != 16 || bytes[18] != 2 )
  233             return FTPP_INVALID_ARG;
  234 
  235         sfip_set_raw(ipRet, bytes+2, AF_INET6);
  236         *portRet = (bytes[19] << 8) | bytes[20];
  237         break;
  238     default:
  239         return FTPP_INVALID_ARG;
  240     }
  241     return FTPP_SUCCESS;
  242 }
  243 
  244 /*
  245  * getIP2428() parses the EPRT command parameters which have this
  246  * format (ftyp == e_extd_host_port):
  247  *
  248  *     EPRT |<family>|address|<tcp-port>|
  249  *     EPRT |1|132.235.1.2|6275|
  250  *     EPRT |2|1080::8:800:200C:417A|5282|
  251  *
  252  * Note that the address family is 1|2 (as in RFC 2428), not 4|6
  253  * (as in IP version), nor 2|10 (as in AF_INET[6]).
  254  *
  255  * This function is called for the EPSV response as well, which
  256  * has this format (ftyp == e_int):
  257  *
  258  *     229 <human readable text> (|||<tcp-port>|)
  259  *
  260  * The delimiter may be other than '|' if required to represent
  261  * the protocol address, but must be between 33-126 inclusive.
  262  * Other delimiters aren't required for IPv{4,6} but we allow
  263  * them for flexibility.
  264  *
  265  * It is assumed that *ip_start points to the first delimiter in
  266  * both cases.
  267  */
  268 
  269 /*
  270  * this copy is unfortunate but inet_pton() doesn't
  271  * like the delim and the src buf is const so ...
  272  */
  273 void CopyField (
  274     char* buf, const char* tok, int max, const char* end, char delim
  275 )
  276 {
  277     int len = end - tok + 1;
  278     char* s;
  279 
  280     if ( len >= max )
  281     {
  282         strncpy(buf, tok, max);
  283         buf[max-1] = '\0';
  284     }
  285     else
  286     {
  287         strncpy(buf, tok, len);
  288         buf[len] = '\0';
  289     }
  290     s = strchr(buf, delim);
  291 
  292     if ( s ) *s = '\0';
  293     else *buf = '\0';
  294 }
  295 
  296 static int getIP2428 (
  297     const char **ip_start, const char *last_char, char *term_char,
  298     sfaddr_t* ipRet, uint16_t *portRet, FTP_PARAM_TYPE ftyp
  299 )
  300 {
  301     const char* tok = *ip_start;
  302     char delim = *tok;
  303     int field = 1, fieldMask = 0;
  304     int family = AF_UNSPEC, port = 0;
  305     char buf[64];
  306 
  307     IP_CLEAR((*ipRet));
  308     *portRet = 0;
  309 
  310     /* check first delimiter */
  311     if ( delim < 33 || delim > 126 )
  312         return FTPP_INVALID_ARG;
  313 
  314     while ( tok && tok < last_char && field < 4 ) {
  315         int check = (*++tok != delim) ? field : 0;
  316 
  317         switch ( check ) {
  318             case 0:  /* empty */
  319                 break;
  320 
  321             case 1:  /* check family */
  322                 family = atoi(tok);
  323                 if ( family == 1 ) family = AF_INET;
  324                 else if ( family == 2 ) family = AF_INET6;
  325                 else return FTPP_INVALID_ARG;
  326                 fieldMask |= 1;
  327                 break;
  328 
  329             case 2:  /* check address */
  330                 CopyField(buf, tok, sizeof(buf), last_char, delim);
  331                 if ( sfaddr_pton(buf, ipRet) != SFIP_SUCCESS || ipRet->family != family )
  332                     return FTPP_INVALID_ARG;
  333 
  334                 fieldMask |= 2;
  335                 break;
  336 
  337             case 3:  /* check port */
  338                 port = atoi(tok);
  339                 if ( port < 0 || port > MAXPORTS-1 )
  340                     return FTPP_MALFORMED_IP_PORT;
  341                 *portRet = port;
  342                 fieldMask |= 4;
  343                 break;
  344         }
  345         /* advance to next field */
  346         tok = strchr(tok, delim);
  347         field++;
  348     }
  349 
  350     if (tok)
  351     {
  352         if ( *tok == delim ) tok++;
  353         *ip_start = tok;
  354     }
  355     else
  356     {
  357         *ip_start = last_char;
  358     }
  359 
  360     if ( ftyp == e_int && fieldMask == 4 )
  361         /* TBD: do we need to check for bounce if addr present? */
  362         return FTPP_SUCCESS;
  363 
  364     if ( ftyp == e_extd_host_port && fieldMask == 7 )
  365         return FTPP_SUCCESS;
  366 
  367     return FTPP_INVALID_ARG;
  368 }
  369 
  370 static int getFTPip(
  371     FTP_PARAM_TYPE ftyp, const char **ip_start, const char *last_char,
  372     char *term_char, sfaddr_t *ipRet, uint16_t *portRet
  373 )
  374 {
  375     if ( ftyp == e_host_port )
  376     {
  377         return getIP959(ip_start, last_char, term_char, ipRet, portRet);
  378     }
  379     if ( ftyp == e_long_host_port )
  380     {
  381         return getIP1639(ip_start, last_char, term_char, ipRet, portRet);
  382     }
  383     return getIP2428(ip_start, last_char, term_char, ipRet, portRet, ftyp);
  384 }
  385 
  386 
  387 /*
  388  * Function: validate_date_format(
  389  *                            FTP_DATE_FMT *ThisFmt,
  390  *                            char **this_param)
  391  *
  392  * Purpose: Recursively determines whether a date matches the
  393  *          a valid format.
  394  *
  395  * Arguments: ThisFmt        => Pointer to the current format
  396  *            this_param     => Pointer to start of the portion to validate.
  397  *                              Updated to end of valid section if valid.
  398  *
  399  * Returns: int => return code indicating error or success
  400  *
  401  */
  402 static int validate_date_format(FTP_DATE_FMT *ThisFmt, const char **this_param)
  403 {
  404     int valid_string = 0;
  405     int checked_something_else = 0;
  406     int checked_next = 0;
  407     int iRet = FTPP_ALERT;
  408     const char *curr_ch;
  409     if (!ThisFmt)
  410         return FTPP_INVALID_ARG;
  411 
  412     if (!this_param || !(*this_param))
  413         return FTPP_INVALID_ARG;
  414 
  415     curr_ch = *this_param;
  416     if (!ThisFmt->empty)
  417     {
  418         char *format_char = ThisFmt->format_string;
  419 
  420         do
  421         {
  422             switch (*format_char)
  423             {
  424             case 'n':
  425                 if (!isdigit((int)(*curr_ch)))
  426                 {
  427                     /* Return for non-digit */
  428                     return FTPP_INVALID_DATE;
  429                 }
  430                 curr_ch++;
  431                 format_char++;
  432                 break;
  433             case 'C':
  434                 if (!isalpha((int)(*curr_ch)))
  435                 {
  436                     /* Return for non-char */
  437                     return FTPP_INVALID_DATE;
  438                 }
  439                 curr_ch++;
  440                 format_char++;
  441                 break;
  442             default:
  443                 if (*curr_ch != *format_char)
  444                 {
  445                     /* Return for non-matching char */
  446                     return FTPP_INVALID_DATE;
  447                 }
  448                 curr_ch++;
  449                 format_char++;
  450                 break;
  451             }
  452             valid_string = 1;
  453         }
  454         while ((*format_char != '\0') && !isspace((int)(*curr_ch)));
  455 
  456         if ((*format_char != '\0') && isspace((int)(*curr_ch)))
  457         {
  458             /* Didn't have enough chars to complete this format */
  459             return FTPP_INVALID_DATE;
  460         }
  461     }
  462 
  463     if ((ThisFmt->optional) && !isspace((int)(*curr_ch)))
  464     {
  465         const char *tmp_ch = curr_ch;
  466         iRet = validate_date_format(ThisFmt->optional, &tmp_ch);
  467         if (iRet == FTPP_SUCCESS)
  468             curr_ch = tmp_ch;
  469     }
  470     if ((ThisFmt->next_a) && !isspace((int)(*curr_ch)))
  471     {
  472         const char *tmp_ch = curr_ch;
  473         checked_something_else = 1;
  474         iRet = validate_date_format(ThisFmt->next_a, &tmp_ch);
  475         if (iRet == FTPP_SUCCESS)
  476         {
  477             curr_ch = tmp_ch;
  478         }
  479         else if (ThisFmt->next_b)
  480         {
  481             iRet = validate_date_format(ThisFmt->next_b, &tmp_ch);
  482             if (iRet == FTPP_SUCCESS)
  483                 curr_ch = tmp_ch;
  484         }
  485         if (ThisFmt->next)
  486         {
  487             iRet = validate_date_format(ThisFmt->next, &tmp_ch);
  488             if (iRet == FTPP_SUCCESS)
  489             {
  490                 curr_ch = tmp_ch;
  491                 checked_next = 1;
  492             }
  493         }
  494         if (iRet == FTPP_SUCCESS)
  495         {
  496             *this_param = curr_ch;
  497             return iRet;
  498         }
  499     }
  500     if ((!checked_next) && (ThisFmt->next))
  501     {
  502         const char *tmp_ch = curr_ch;
  503         checked_something_else = 1;
  504         iRet = validate_date_format(ThisFmt->next, &tmp_ch);
  505         if (iRet == FTPP_SUCCESS)
  506         {
  507             curr_ch = tmp_ch;
  508             checked_next = 1;
  509         }
  510     }
  511 
  512     if ((isspace((int)(*curr_ch))) && ((!ThisFmt->next) || checked_next))
  513     {
  514         *this_param = curr_ch;
  515         return FTPP_SUCCESS;
  516     }
  517 
  518     if (valid_string)
  519     {
  520         int all_okay = 0;
  521         if (checked_something_else)
  522         {
  523             if (iRet == FTPP_SUCCESS)
  524                 all_okay = 1;
  525         }
  526         else
  527         {
  528             all_okay = 1;
  529         }
  530 
  531         if (all_okay)
  532         {
  533             *this_param = curr_ch;
  534             return FTPP_SUCCESS;
  535         }
  536     }
  537 
  538     return FTPP_INVALID_DATE;
  539 }
  540 
  541 /*
  542  * Function: validate_param(
  543  *                            Packet *p
  544  *                            char *param
  545  *                            char *end
  546  *                            FTP_PARAM_FMT *param_format,
  547  *                            FTP_SESSION *Session)
  548  *
  549  * Purpose: Validates the current parameter against the format
  550  *          specified.
  551  *
  552  * Arguments: p              => Pointer to the current packet
  553  *            params_begin   => Pointer to beginning of parameters
  554  *            params_end     => End of params buffer
  555  *            param_format   => Parameter format specifier for this command
  556  *            Session        => Pointer to the session info
  557  *
  558  * Returns: int => return code indicating error or success
  559  *
  560  */
  561 static int validate_param(SFSnortPacket *p,
  562                 const char *param,
  563                 const char *end,
  564                 FTP_PARAM_FMT *ThisFmt,
  565                 FTP_SESSION *Session)
  566 {
  567     int iRet;
  568     const char *this_param = param;
  569 
  570     if (param > end)
  571         return FTPP_ALERT;
  572 
  573     switch (ThisFmt->type)
  574     {
  575     case e_head:
  576         /* shouldn't get here, but just in case */
  577         /* this hack is because we do get here! */
  578         this_param--;
  579         break;
  580     case e_unrestricted:
  581         /* strings/filenames only occur as the last param,
  582          * so move to the end of the param buffer. */
  583         this_param = end;
  584         break;
  585     case e_strformat:
  586         /* Check for 2 % signs within the parameter for an FTP command
  587          * 2 % signs is the magic number per existing rules (24 Sep 2004)
  588          */
  589 #define MAX_PERCENT_SIGNS 2
  590         {
  591             int numPercents = 0;
  592             do
  593             {
  594                 if (*this_param == '%')
  595                 {
  596                     numPercents++;
  597                     if (numPercents >= MAX_PERCENT_SIGNS)
  598                     {
  599                         break;
  600                     }
  601                 }
  602                 this_param++;
  603             }
  604             while ((this_param < end) &&
  605                    (*this_param != '\n'));
  606 
  607             if (numPercents >= MAX_PERCENT_SIGNS)
  608             {
  609                 /* Alert on string format attack in parameter */
  610                 ftp_eo_event_log(Session, FTP_EO_PARAMETER_STR_FORMAT,
  611                     NULL, NULL);
  612                 return FTPP_ALERTED;
  613             }
  614         }
  615         break;
  616     case e_int:
  617         /* check that this_param is all digits up to next space */
  618         {
  619             do
  620             {
  621                 if (!isdigit((int)(*this_param)))
  622                 {
  623                     /* Alert on non-digit */
  624                     return FTPP_INVALID_PARAM;
  625                 }
  626                 this_param++;
  627             }
  628             while ((this_param < end) && (*this_param != ' ') );
  629         }
  630         break;
  631     case e_number:
  632         /* check that this_param is all digits up to next space
  633          * and value is between 1 & 255 */
  634         {
  635             int iValue = 0;
  636             do
  637             {
  638                 if (!isdigit((int)(*this_param)))
  639                 {
  640                     /* Alert on non-digit */
  641                     return FTPP_INVALID_PARAM;
  642                 }
  643                 iValue = iValue * 10 + (*this_param - '0');
  644                 this_param++;
  645             }
  646             while ((this_param < end) && (*this_param != ' ') );
  647 
  648             if ((iValue > 255) || (iValue == 0))
  649                 return FTPP_INVALID_PARAM;
  650         }
  651         break;
  652     case e_char:
  653         /* check that this_param is one of chars specified */
  654         {
  655             int bitNum = (*this_param & 0x1f);
  656             if (!isalpha((int)(*this_param)))
  657             {
  658                 /* Alert on non-char */
  659                 return FTPP_INVALID_PARAM;
  660             }
  661             else
  662             {
  663                 if (!(ThisFmt->format.chars_allowed & (1 << (bitNum-1))) )
  664                 {
  665                     /* Alert on unexpected char */
  666                     return FTPP_INVALID_PARAM;
  667                 }
  668             }
  669             this_param++; /* should be a space */
  670         }
  671         break;
  672     case e_date:
  673         /* check that this_param conforms to date specified */
  674         {
  675             const char *tmp_ch = this_param;
  676             iRet = validate_date_format(ThisFmt->format.date_fmt, &tmp_ch);
  677             if (iRet != FTPP_SUCCESS)
  678             {
  679                 /* Alert invalid date */
  680                 return FTPP_INVALID_PARAM;
  681             }
  682             if (!isspace((int)(*tmp_ch)))
  683             {
  684                 /* Alert invalid date -- didn't make it to end of parameter.
  685                 Overflow attempt? */
  686                 return FTPP_INVALID_PARAM;
  687             }
  688             this_param = tmp_ch;
  689         }
  690         break;
  691     case e_literal:
  692         /* check that this_param matches the literal specified */
  693         {
  694             const char* s = ThisFmt->format.literal;
  695             size_t n = strlen(s);
  696 
  697             if ( strncmp(this_param, s, n) )
  698             {
  699                 /* Alert on non-char */
  700                 return FTPP_INVALID_PARAM;
  701             }
  702             this_param += n;
  703         }
  704         break;
  705                             /* check that this_param is:  */
  706     case e_host_port:       /* PORT: h1,h2,h3,h4,p1,p2    */
  707     case e_long_host_port:  /* LPRT: af,hal,h1,h2,h3,h4...,pal,p1,p2... */
  708     case e_extd_host_port:  /* EPRT: |<af>|<addr>|<port>| */
  709         {
  710             sfaddr_t ipAddr;
  711             uint16_t port=0;
  712 
  713             int ret = getFTPip(
  714                 ThisFmt->type, &this_param, end, " \n", &ipAddr, &port
  715             );
  716             switch (ret)
  717             {
  718             case FTPP_NON_DIGIT:
  719                 /* Alert on non-digit */
  720                 return FTPP_INVALID_PARAM;
  721                 break;
  722             case FTPP_INVALID_ARG:
  723                 /* Alert on number > 255 */
  724                 return FTPP_INVALID_PARAM;
  725                 break;
  726             case FTPP_MALFORMED_IP_PORT:
  727                 /* Alert on malformed host-port */
  728                 return FTPP_INVALID_PARAM;
  729                 break;
  730             }
  731 
  732             if ( ThisFmt->type == e_extd_host_port && !sfaddr_is_set(&ipAddr) )
  733             {
  734                 // actually, we expect no addr in 229 responses, which is
  735                 // understood to be server address, so we set that here
  736                 ipAddr = *GET_SRC_IP(p);
  737             }
  738             if ((Session->client_conf->bounce.on) &&
  739                 (Session->client_conf->bounce.alert))
  740             {
  741                 if (!IP_EQUALITY(&ipAddr, GET_SRC_IP(p)))
  742                 {
  743                     int alert = 1;
  744 
  745                     FTP_BOUNCE_TO *BounceTo = ftp_bounce_lookup_find(
  746                         Session->client_conf->bounce_lookup, &ipAddr, &iRet);
  747                     if (BounceTo)
  748                     {
  749                         if (BounceTo->portlo)
  750                         {
  751                             if (BounceTo->porthi)
  752                             {
  753                                 if ((port >= BounceTo->portlo) &&
  754                                     (port <= BounceTo->porthi))
  755                                     alert = 0;
  756                             }
  757                             else
  758                             {
  759                                 if (port == BounceTo->portlo)
  760                                     alert = 0;
  761                             }
  762                         }
  763                     }
  764 
  765                     /* Alert on invalid IP address for PORT */
  766                     if (alert)
  767                     {
  768                         ftp_eo_event_log(Session, FTP_EO_BOUNCE, NULL, NULL);
  769                         /* Return here -- because we will likely want to
  770                          * inspect the data traffic over a bounced data
  771                          * connection */
  772                         return FTPP_PORT_ATTACK;
  773                     }
  774                 }
  775             }
  776 
  777             Session->clientIP = ipAddr;
  778             Session->clientPort = port;
  779             Session->data_chan_state |= DATA_CHAN_PORT_CMD_ISSUED;
  780             if (Session->data_chan_state & DATA_CHAN_PASV_CMD_ISSUED)
  781             {
  782                 /*
  783                  * If there was a PORT command previously in
  784                  * a series of pipelined requests, this
  785                  * cancels it.
  786                  */
  787                 Session->data_chan_state &= ~DATA_CHAN_PASV_CMD_ISSUED;
  788             }
  789 
  790             IP_CLEAR(Session->serverIP);
  791             Session->serverPort = 0;
  792         }
  793         break;
  794     }
  795 
  796     ThisFmt->next_param = this_param;
  797 
  798     return FTPP_SUCCESS;
  799 }
  800 
  801 /*
  802  * Function: check_ftp_param_validity(
  803  *                            Packet *p,
  804  *                            char *params_begin,
  805  *                            char *params_end,
  806  *                            FTP_PARAM_FMT *param_format,
  807  *                            FTP_SESSION *Session)
  808  *
  809  * Purpose: Recursively determines whether each of the parameters for
  810  *          an FTP command are valid.
  811  *
  812  * Arguments: p              => Pointer to the current packet
  813  *            params_begin   => Pointer to beginning of parameters
  814  *            params_end     => End of params buffer
  815  *            param_format   => Parameter format specifier for this command
  816  *            Session        => Pointer to the session info
  817  *
  818  * Returns: int => return code indicating error or success
  819  *
  820  */
  821 static int check_ftp_param_validity(SFSnortPacket *p,
  822                              const char *params_begin,
  823                              const char *params_end,
  824                              FTP_PARAM_FMT *param_format,
  825                              FTP_SESSION *Session)
  826 {
  827     int iRet = FTPP_ALERT;
  828     FTP_PARAM_FMT *ThisFmt = param_format;
  829     FTP_PARAM_FMT *NextFmt;
  830     const char *this_param = params_begin;
  831 
  832     if (!param_format)
  833         return FTPP_INVALID_ARG;
  834 
  835     if (!params_begin && !ThisFmt->next_param_fmt && ThisFmt->optional_fmt)
  836         return FTPP_SUCCESS;  /* no param is allowed in this case */
  837 
  838     if (!params_begin && (ThisFmt->next_param_fmt && ThisFmt->next_param_fmt->type == e_strformat))
  839         return FTPP_SUCCESS;  /* string format check of non existent param */
  840 
  841     if (!params_begin)
  842         return FTPP_INVALID_ARG;
  843 
  844     if ((!ThisFmt->next_param_fmt) && (params_begin >= params_end))
  845         return FTPP_SUCCESS;
  846 
  847     ThisFmt->next_param = params_begin;
  848 
  849     if (ThisFmt->optional_fmt)
  850     {
  851         /* Check against optional */
  852         iRet = validate_param(p, this_param, params_end,
  853                               ThisFmt->optional_fmt, Session);
  854         if (iRet == FTPP_SUCCESS)
  855         {
  856             const char *next_param;
  857             NextFmt = ThisFmt->optional_fmt;
  858             next_param = NextFmt->next_param+1;
  859             iRet = check_ftp_param_validity(p, next_param, params_end,
  860                                             NextFmt, Session);
  861             if (iRet == FTPP_SUCCESS)
  862             {
  863                 this_param = NextFmt->next_param+1;
  864             }
  865         }
  866     }
  867 
  868     if ((iRet != FTPP_SUCCESS) && (ThisFmt->choices))
  869     {
  870         /* Check against choices -- one of many */
  871         int i;
  872         int valid = 0;
  873         for (i=0;i<ThisFmt->numChoices && !valid;i++)
  874         {
  875             /* Try choice [i] */
  876             iRet = validate_param(p, this_param, params_end,
  877                               ThisFmt->choices[i], Session);
  878             if (iRet == FTPP_SUCCESS)
  879             {
  880                 const char *next_param;
  881                 NextFmt = ThisFmt->choices[i];
  882                 next_param = NextFmt->next_param+1;
  883                 iRet = check_ftp_param_validity(p, next_param, params_end,
  884                                                 NextFmt, Session);
  885                 if (iRet == FTPP_SUCCESS)
  886                 {
  887                     this_param = NextFmt->next_param+1;
  888                     valid = 1;
  889                     break;
  890                 }
  891             }
  892         }
  893     }
  894     else if ((iRet != FTPP_SUCCESS) && (ThisFmt->next_param_fmt))
  895     {
  896         /* Check against next param */
  897         iRet = validate_param(p, this_param, params_end,
  898                           ThisFmt->next_param_fmt, Session);
  899         if (iRet == FTPP_SUCCESS)
  900         {
  901             const char *next_param;
  902             NextFmt = ThisFmt->next_param_fmt;
  903             next_param = NextFmt->next_param+1;
  904             iRet = check_ftp_param_validity(p, next_param, params_end,
  905                                             NextFmt, Session);
  906             if (iRet == FTPP_SUCCESS)
  907             {
  908                 this_param = NextFmt->next_param+1;
  909             }
  910         }
  911     }
  912     else if ((iRet != FTPP_SUCCESS) && (!ThisFmt->next_param_fmt) &&
  913         this_param)
  914     {
  915         iRet = FTPP_SUCCESS;
  916     }
  917     if (iRet == FTPP_SUCCESS)
  918     {
  919         ThisFmt->next_param = this_param;
  920     }
  921     return iRet;
  922 }
  923 
  924 /*
  925  * Function: initialize_ftp(FTP_SESSION *Session, Packet *p, int iMode)
  926  *
  927  * Purpose: Initializes the state machine for checking an FTP packet.
  928  *          Does normalization checks.
  929  *
  930  * Arguments: Session        => Pointer to session info
  931  *            p              => pointer to the current packet struct
  932  *            iMode          => Mode indicating server or client checks
  933  *
  934  * Returns: int => return code indicating error or success
  935  *
  936  */
  937 int initialize_ftp(FTP_SESSION *Session, SFSnortPacket *p, int iMode)
  938 {
  939     int iRet;
  940     const unsigned char *read_ptr = p->payload;
  941     FTP_CLIENT_REQ *req;
  942     char ignoreTelnetErase = FTPP_APPLY_TNC_ERASE_CMDS;
  943     FTPTELNET_GLOBAL_CONF *global_conf = (FTPTELNET_GLOBAL_CONF *)sfPolicyUserDataGet(Session->global_conf, Session->policy_id);
  944 
  945     /* Normalize this packet ala telnet */
  946     if (((iMode == FTPP_SI_CLIENT_MODE) &&
  947          (Session->client_conf->ignore_telnet_erase_cmds.on == 1)) ||
  948         ((iMode == FTPP_SI_SERVER_MODE) &&
  949          (Session->server_conf->ignore_telnet_erase_cmds.on == 1)) )
  950         ignoreTelnetErase = FTPP_IGNORE_TNC_ERASE_CMDS;
  951 
  952     iRet = normalize_telnet(global_conf, NULL, p, iMode, ignoreTelnetErase);
  953 
  954     if (iRet != FTPP_SUCCESS && iRet != FTPP_NORMALIZED)
  955     {
  956         if (iRet == FTPP_ALERT)
  957         {
  958             if (global_conf->telnet_config->detect_anomalies)
  959             {
  960                 ftp_eo_event_log(Session, FTP_EO_EVASIVE_TELNET_CMD, NULL, NULL);
  961         }   }
  962         return iRet;
  963     }
  964 
  965     if (_dpd.Is_DetectFlag(SF_FLAG_ALT_DECODE))
  966     {
  967         /* Normalized data will always be in decode buffer */
  968         if ( ((Session->client_conf->telnet_cmds.alert) &&
  969               (iMode == FTPP_SI_CLIENT_MODE)) ||
  970              ((Session->server_conf->telnet_cmds.alert) &&
  971               (iMode == FTPP_SI_SERVER_MODE)) )
  972         {
  973             /* alert -- FTP channel with telnet commands */
  974             ftp_eo_event_log(Session, FTP_EO_TELNET_CMD, NULL, NULL);
  975             return FTPP_ALERT; /* Nothing else to do since we alerted */
  976         }
  977 
  978         read_ptr = _dpd.altBuffer->data;
  979     }
  980 
  981     if (iMode == FTPP_SI_CLIENT_MODE)
  982     {
  983         req = &Session->client.request;
  984 
  985 #ifdef DUMP_BUFFER
  986         dumpBuffer(FTP_REQUEST_CMD_LINE,req->cmd_line,req->cmd_line_size);
  987         dumpBuffer(FTP_REQUEST_CMD,req->cmd_begin,req->cmd_size);
  988         dumpBuffer(FTP_REQUEST_PARAM,req->param_begin,req->param_size);
  989 #endif
  990 
  991     }
  992     else if (iMode == FTPP_SI_SERVER_MODE)
  993     {
  994         FTP_SERVER_RSP *rsp = &Session->server.response;
  995         req = (FTP_CLIENT_REQ *)rsp;
  996 
  997 #ifdef DUMP_BUFFER
  998         dumpBuffer(FTP_RESPONSE_LINE,rsp->rsp_line,rsp->rsp_line_size);
  999         dumpBuffer(FTP_RESPONSE_DUMP,rsp->rsp_begin,rsp->rsp_size);
 1000         dumpBuffer(FTP_RESPONSE_MSG,rsp->msg_begin,rsp->msg_size);
 1001 #endif
 1002 
 1003     }
 1004     else
 1005         return FTPP_INVALID_ARG;
 1006 
 1007     /* Set the beginning of the pipeline to the start of the
 1008      * (normalized) buffer */
 1009     req->pipeline_req = (const char *)read_ptr;
 1010 
 1011     return FTPP_SUCCESS;
 1012 }
 1013 
 1014 static inline void prepareForEncryption(FTP_SESSION *Session, FTPTELNET_GLOBAL_CONF *global_conf, int new_encr_state)
 1015 {
 1016     Session->encr_state = new_encr_state;
 1017     Session->encr_state_chello = true;
 1018     if (global_conf->encrypted.alert)
 1019     {
 1020         /* Alert on encrypted channel */
 1021         ftp_eo_event_log(Session, FTP_EO_ENCRYPTED,
 1022             NULL, NULL);
 1023     }
 1024 }
 1025 
 1026 /*
 1027  * Function: do_stateful_checks(FTP_SESSION *Session, Packet *p,
 1028  *                            FTP_CLIENT_REQ *req, int rsp_code)
 1029  *
 1030  * Purpose: Handle stateful checks and state updates for FTP response
 1031  *          packets.
 1032  *
 1033  * Arguments: Session        => Pointer to session info
 1034  *            p              => Pointer to the current packet struct
 1035  *            req            => Pointer to current response from packet
 1036  *                              (this function may be called multiple
 1037  *                              times for pipelined requests).
 1038  *            rsp_code       => Integer response value for server response
 1039  *
 1040  * Returns: int => return code indicating error or success
 1041  *
 1042  */
 1043 static int do_stateful_checks(FTP_SESSION *Session, SFSnortPacket *p,
 1044                        FTP_CLIENT_REQ *req, int rsp_code)
 1045 {
 1046     int iRet = FTPP_SUCCESS;
 1047     FTPTELNET_GLOBAL_CONF *global_conf = (FTPTELNET_GLOBAL_CONF *)sfPolicyUserDataGet(Session->global_conf, Session->policy_id);
 1048 
 1049     //if (Session->server_conf->data_chan)
 1050     {
 1051         if (rsp_code == 226)
 1052         {
 1053             /* Just ignore this code -- end of transfer...
 1054              * If we saw all the other dat for this channel
 1055              * Session->data_chan_state should be NO_STATE. */
 1056         }
 1057         else if (Session->data_chan_state & DATA_CHAN_PASV_CMD_ISSUED)
 1058         {
 1059             if (Session->ftp_cmd_pipe_index == Session->data_chan_index)
 1060             {
 1061                 if (Session->data_xfer_index == 0)
 1062                     Session->ftp_cmd_pipe_index = 1;
 1063                 Session->data_chan_index = 0;
 1064 
 1065                 if ( rsp_code >= 227 && rsp_code <= 229 )
 1066                 {
 1067                     sfaddr_t ipAddr;
 1068                     uint16_t port=0;
 1069                     const char *ip_begin = req->param_begin;
 1070                     IP_CLEAR(ipAddr);
 1071                     Session->data_chan_state &= ~DATA_CHAN_PASV_CMD_ISSUED;
 1072                     Session->data_chan_state |= DATA_CHAN_PASV_CMD_ACCEPT;
 1073                     Session->data_chan_index = 0;
 1074                     /* Interpret response message to identify the
 1075                      * Server IP/Port.  Server response is inside
 1076                      * a pair of ()s.  Find the left (, and use same
 1077                      * means to find IP/Port as is done for the PORT
 1078                      * command. */
 1079                     if (req->param_size != 0)
 1080                     {
 1081                         while ((ip_begin < req->param_end) &&
 1082                                (*ip_begin != '('))
 1083                         {
 1084                             ip_begin++;
 1085                         }
 1086                     }
 1087 
 1088                     if (ip_begin < req->param_end)
 1089                     {
 1090                         FTP_PARAM_TYPE ftyp =
 1091                             /* e_int is used in lieu of adding a new value to the
 1092                              * enum because this case doesn't correspond to a
 1093                              * validation config option; it could effectively be
 1094                              * replaced with an additional bool arg to getFTPip() that
 1095                              * differentiated between commands and responses, but
 1096                              * this distinction is only required for EPSV rsps. */
 1097                             (rsp_code == 229) ? e_int :
 1098                                 (rsp_code == 228 ? e_long_host_port : e_host_port);
 1099 
 1100                         ip_begin++;
 1101                         iRet = getFTPip(
 1102                             ftyp, &ip_begin, req->param_end, ")", &ipAddr, &port
 1103                         );
 1104                         if (iRet == FTPP_SUCCESS)
 1105                         {
 1106                             if (!sfaddr_is_set(&ipAddr))
 1107                                 IP_COPY_VALUE(Session->serverIP, GET_SRC_IP(p));
 1108                             else
 1109                             {
 1110                                 Session->serverIP = ipAddr;
 1111                             }
 1112                             Session->serverPort = port;
 1113                             IP_COPY_VALUE(Session->clientIP, GET_DST_IP(p));
 1114                             Session->clientPort = 0;
 1115 #ifdef TARGET_BASED
 1116                             if ((_dpd.fileAPI->get_max_file_depth(_dpd.getCurrentSnortConfig(), false) > 0) || !(Session->server_conf->data_chan))
 1117                             {
 1118                                 FTP_DATA_SESSION *ftpdata = FTPDataSessionNew(p);
 1119 
 1120                                 if (ftpdata)
 1121                                 {
 1122                                     int result;
 1123                                     /* This is a passive data transfer */
 1124                                     ftpdata->mode = FTPP_XFER_PASSIVE;
 1125                                     ftpdata->data_chan = Session->server_conf->data_chan;
 1126                                     /* Store the FTP_SESSION in FTP_DATA_SESSION, needed when FTP_DATA_SESSION is freed.
 1127                                      * This is needed to handle pruning of FTP_DATA_SESSION */
 1128                                     ftpdata->ftpssn = Session;
 1129                                     /*If a FTP_DATA_SESSION already exists, the FTP_SESSION reference in that should be removed*/
 1130                                     if(Session->datassn)
 1131                                     {
 1132                                         FTP_DATA_SESSION * ssn = Session->datassn;
 1133                                         ssn->ftpssn = NULL;
 1134                                     }
 1135                                     Session->datassn = ftpdata;
 1136 
 1137                                     /* Call into Streams to mark data channel as ftp-data */
 1138                                     result = _dpd.streamAPI->set_application_protocol_id_expected_preassign_callback(
 1139                                         p, IP_ARG(Session->clientIP), Session->clientPort,
 1140                                         IP_ARG(Session->serverIP), Session->serverPort, GET_IPH_PROTO(p),
 1141                                         ftp_data_app_id, PP_FTPTELNET, (void *)ftpdata, &FTPDataSessionFree,
 1142                                         s_ftpdata_eof_cb_id, SE_EOF, &p->expectedSession);
 1143 
 1144                                     if (result < 0)
 1145                                         FTPDataSessionFree(ftpdata);
 1146                                 }
 1147                             }
 1148                             else if (Session->server_conf->data_chan)
 1149 #else
 1150                             if (Session->server_conf->data_chan)
 1151 #endif
 1152                             {
 1153                                 /* Call into Streams to mark data channel as something
 1154                                  * to ignore. */
 1155                                 _dpd.sessionAPI->ignore_session(p, IP_ARG(Session->clientIP), Session->clientPort,
 1156                                         IP_ARG(Session->serverIP), Session->serverPort, GET_IPH_PROTO(p),
 1157                                         PP_FTPTELNET, SSN_DIR_BOTH, 0 /* Not permanent */, &p->expectedSession );
 1158                             }
 1159                         }
 1160                     }
 1161                     else
 1162                     {
 1163                         iRet = FTPP_MALFORMED_FTP_RESPONSE;
 1164                     }
 1165                 }
 1166                 else
 1167                 {
 1168                     Session->data_chan_index = 0;
 1169                     Session->data_chan_state &= ~DATA_CHAN_PASV_CMD_ISSUED;
 1170                 }
 1171             }
 1172         }
 1173         else if (Session->data_chan_state & DATA_CHAN_PORT_CMD_ISSUED)
 1174         {
 1175             if (Session->ftp_cmd_pipe_index == Session->data_chan_index)
 1176             {
 1177                 if (Session->data_xfer_index == 0)
 1178                     Session->ftp_cmd_pipe_index = 1;
 1179                 Session->data_chan_index = 0;
 1180                 if (rsp_code == 200)
 1181                 {
 1182                     Session->data_chan_state &= ~DATA_CHAN_PORT_CMD_ISSUED;
 1183                     Session->data_chan_state |= DATA_CHAN_PORT_CMD_ACCEPT;
 1184                     Session->data_chan_index = 0;
 1185                     if (sfaddr_is_set(&Session->clientIP))
 1186                     {
 1187                         /* This means we're not in passive mode. */
 1188                         /* Server is listening/sending from its own IP,
 1189                          * FTP Port -1 */
 1190                         /* Client IP, Port specified via PORT command */
 1191                         IP_COPY_VALUE(Session->serverIP, GET_SRC_IP(p));
 1192 
 1193                         /* Can't necessarily guarantee this, especially
 1194                          * in the case of a proxy'd connection where the
 1195                          * data channel might not be on port 20 (or server
 1196                          * port-1).  Comment it out for now.
 1197                          */
 1198                         /*
 1199                         Session->serverPort = ntohs(p->tcph->th_sport) -1;
 1200                         */
 1201 #ifdef TARGET_BASED
 1202                         if ((_dpd.fileAPI->get_max_file_depth(_dpd.getCurrentSnortConfig(), false) > 0) || !(Session->server_conf->data_chan))
 1203                         {
 1204                             FTP_DATA_SESSION *ftpdata = FTPDataSessionNew(p);
 1205 
 1206                             if (ftpdata)
 1207                             {
 1208                                 int result;
 1209                                 /* This is a active data transfer */
 1210                                 ftpdata->mode = FTPP_XFER_ACTIVE;
 1211                                 ftpdata->data_chan = Session->server_conf->data_chan;
 1212                                 /* Store the FTP_SESSION in FTP_DATA_SESSION, needed when FTP_DATA_SESSION is freed.
 1213                                  * This is needed to handle pruning of FTP_DATA_SESSION */
 1214                                 ftpdata->ftpssn = Session;
 1215                                 /*If a FTP_DATA_SESSION already exists, the FTP_SESSION reference in that should be removed*/
 1216                                 if(Session->datassn)
 1217                                 {
 1218                                     FTP_DATA_SESSION * ssn = Session->datassn;
 1219                                     ssn->ftpssn = NULL;
 1220                                 }
 1221                                 Session->datassn = ftpdata;
 1222 
 1223                                 /* Call into Streams to mark data channel as ftp-data */
 1224                                 result = _dpd.streamAPI->set_application_protocol_id_expected_preassign_callback(
 1225                                     p, IP_ARG(Session->serverIP), Session->serverPort,
 1226                                     IP_ARG(Session->clientIP), Session->clientPort, GET_IPH_PROTO(p),
 1227                                     ftp_data_app_id, PP_FTPTELNET, (void *)ftpdata, &FTPDataSessionFree,
 1228                                     s_ftpdata_eof_cb_id, SE_EOF, &p->expectedSession);
 1229 
 1230                                 if (result < 0)
 1231                                     FTPDataSessionFree(ftpdata);
 1232                             }
 1233                         }
 1234                         else if (Session->server_conf->data_chan)
 1235 #else
 1236                         if (Session->server_conf->data_chan)
 1237 #endif
 1238                         {
 1239                             /* Call into Streams to mark data channel as something
 1240                              * to ignore. */
 1241                             _dpd.sessionAPI->ignore_session(p, IP_ARG(Session->serverIP), Session->serverPort,
 1242                                     IP_ARG(Session->clientIP), Session->clientPort, GET_IPH_PROTO(p),
 1243                                     PP_FTPTELNET, SSN_DIR_BOTH, 0 /* Not permanent */, &p->expectedSession );
 1244                         }
 1245                     }
 1246                 }
 1247                 else if (Session->ftp_cmd_pipe_index == Session->data_chan_index)
 1248                 {
 1249                     Session->data_chan_index = 0;
 1250                     Session->data_chan_state &= ~DATA_CHAN_PORT_CMD_ISSUED;
 1251                 }
 1252             }
 1253         }
 1254         else if (Session->data_chan_state & DATA_CHAN_REST_CMD_ISSUED)
 1255         {
 1256             if (Session->ftp_cmd_pipe_index == Session->data_xfer_index)
 1257             {
 1258                 if (Session->data_chan_index == 0)
 1259                     Session->ftp_cmd_pipe_index = 1;
 1260                 Session->data_xfer_index = 0;
 1261                 if (rsp_code == 350)
 1262                 {
 1263 #ifdef TARGET_BASED
 1264                     FTP_DATA_SESSION *ftpdata = Session->datassn;
 1265                     if(ftpdata)
 1266                         ftpdata->flags |= FTPDATA_FLG_REST;
 1267 #endif
 1268                 }
 1269                 else
 1270                     Session->rest_cmd_offset= 0;
 1271                 Session->data_chan_index = 0;
 1272                 Session->data_chan_state &= ~DATA_CHAN_REST_CMD_ISSUED;
 1273             }
 1274         }
 1275         else if (Session->data_chan_state & DATA_CHAN_XFER_CMD_ISSUED)
 1276         {
 1277             if (Session->ftp_cmd_pipe_index == Session->data_xfer_index)
 1278             {
 1279                 if (Session->data_chan_index == 0)
 1280                     Session->ftp_cmd_pipe_index = 1;
 1281                 Session->data_xfer_index = 0;
 1282                 if ((rsp_code == 150) || (rsp_code == 125))
 1283                 {
 1284                     Session->data_chan_state = DATA_CHAN_XFER_STARTED;
 1285                 }
 1286                 /* Clear the session info for next transfer -->
 1287                  * reset host/port */
 1288                 IP_CLEAR(Session->serverIP);
 1289                 IP_CLEAR(Session->clientIP);
 1290                 Session->serverPort = Session->clientPort = 0;
 1291                 Session->data_chan_state = NO_STATE;
 1292             }
 1293         }
 1294     } /* if (Session->server_conf->data_chan) */
 1295 
 1296     if (global_conf->encrypted.on && rsp_code == 234)
 1297     {
 1298         /* any of these states is now anticipatory of the client hello */
 1299         switch(Session->encr_state)
 1300         {
 1301         case AUTH_TLS_CMD_ISSUED:
 1302             prepareForEncryption(Session, global_conf, AUTH_TLS_ENCRYPTED);
 1303             DEBUG_WRAP(DebugMessage(DEBUG_FTPTELNET,
 1304                 "FTP stream is now TLS encrypted\n"););
 1305             break;
 1306         case AUTH_SSL_CMD_ISSUED:
 1307             prepareForEncryption(Session, global_conf, AUTH_SSL_ENCRYPTED);
 1308             DEBUG_WRAP(DebugMessage(DEBUG_FTPTELNET,
 1309                 "FTP stream is now SSL encrypted\n"););
 1310             break;
 1311         case AUTH_UNKNOWN_CMD_ISSUED:
 1312         default: // encr_state got confused, but we do have a 234
 1313             prepareForEncryption(Session, global_conf, AUTH_UNKNOWN_ENCRYPTED);
 1314             DEBUG_WRAP(DebugMessage(DEBUG_FTPTELNET,
 1315                 "FTP stream is now encrypted\n"););
 1316             break;
 1317         case AUTH_TLS_ENCRYPTED:
 1318         case AUTH_SSL_ENCRYPTED:
 1319         case AUTH_UNKNOWN_ENCRYPTED:
 1320             // already been through here
 1321             break;
 1322         }
 1323     } /* if (global_conf->encrypted.on && rsp_code == 234) */
 1324 
 1325     return iRet;
 1326 }
 1327 
 1328 /*
 1329  * Function: check_ftp(FTP_SESSION *Session, Packet *p, int iMode)
 1330  *
 1331  * Purpose: Handle some trivial validation checks of an FTP packet.  Namely,
 1332  *          check argument length and some protocol enforcement.
 1333  *
 1334  *          Wishful: This results in exposing the FTP command (and looking
 1335  *          at the results) to the rules layer.
 1336  *
 1337  * Arguments: Session        => Pointer to session info
 1338  *            p              => pointer to the current packet struct
 1339  *            iMode          => Mode indicating server or client checks
 1340  *
 1341  * Returns: int => return code indicating error or success
 1342  *
 1343  */
 1344 #define NUL 0x00
 1345 #define CR 0x0d
 1346 #define LF 0x0a
 1347 #define SP 0x20
 1348 #define DASH 0x2D
 1349 
 1350 #define FTP_CMD_OK 0
 1351 #define FTP_CMD_INV 1
 1352 #define FTP_RESPONSE_INV 1
 1353 #define FTP_RESPONSE 2
 1354 #define FTP_RESPONSE_2BCONT 2
 1355 #define FTP_RESPONSE_CONT   3
 1356 #define FTP_RESPONSE_ENDCONT 4
 1357 int check_ftp(FTP_SESSION  *ftpssn, SFSnortPacket *p, int iMode)
 1358 {
 1359     int iRet = FTPP_SUCCESS;
 1360     int encrypted = 0;
 1361     int space = 0;
 1362     long state = FTP_CMD_OK;
 1363     int rsp_code = 0;
 1364     FTPTELNET_GLOBAL_CONF *global_conf = (FTPTELNET_GLOBAL_CONF *)sfPolicyUserDataGet(ftpssn->global_conf, ftpssn->policy_id);
 1365     FTP_CLIENT_REQ *req;
 1366     FTP_CMD_CONF *CmdConf = NULL;
 1367 #ifdef TARGET_BASED
 1368     FTP_DATA_SESSION *datassn;
 1369 #endif
 1370 
 1371     const unsigned char *read_ptr;
 1372     const unsigned char *end = p->payload + p->payload_size;
 1373 
 1374     if (_dpd.Is_DetectFlag(SF_FLAG_ALT_DECODE))
 1375         end = _dpd.altBuffer->data + _dpd.altBuffer->len;
 1376 
 1377     if (iMode == FTPP_SI_CLIENT_MODE)
 1378     {
 1379         req = &ftpssn->client.request;
 1380         ftpssn->ftp_cmd_pipe_index = 1;
 1381     }
 1382     else if (iMode == FTPP_SI_SERVER_MODE)
 1383     {
 1384         FTP_SERVER_RSP *rsp = &ftpssn->server.response;
 1385         req = (FTP_CLIENT_REQ *)rsp;
 1386     }
 1387     else
 1388         return FTPP_INVALID_ARG;
 1389 
 1390     while (req->pipeline_req)
 1391     {
 1392         state = FTP_CMD_OK;
 1393 
 1394         /* Starts at the beginning of the buffer/line,
 1395          * so next up is a command */
 1396         read_ptr = (const unsigned char *)req->pipeline_req;
 1397 
 1398          /* but first we ignore leading white space */
 1399          while ( (read_ptr < end) &&
 1400              (iMode == FTPP_SI_CLIENT_MODE) && isspace(*read_ptr) )
 1401              read_ptr++;
 1402 
 1403         // ignore extra \r\n emitted by some clients
 1404         if ( read_ptr == end )
 1405             break;
 1406 
 1407         req->cmd_begin = (const char *)read_ptr;
 1408 
 1409         while ((read_ptr < end) &&
 1410                (*read_ptr != SP) &&
 1411                (*read_ptr != CR) &&
 1412                (*read_ptr != LF) && /* Check for LF when there wasn't a CR,
 1413                                      * protocol violation, but accepted by
 1414                                      * some servers. */
 1415                (*read_ptr != DASH))
 1416         {
 1417             /* If the first char is a digit this is a response
 1418              * in server mode. */
 1419             if (iMode == FTPP_SI_SERVER_MODE)
 1420             {
 1421                 if (isdigit(*read_ptr))
 1422                 {
 1423                     if (state != FTP_RESPONSE_INV)
 1424                     {
 1425                         state = FTP_RESPONSE;
 1426                     }
 1427                 }
 1428                 else if (!isascii(*read_ptr))
 1429                 {
 1430                     /* Non-ascii char here?  Bad response */
 1431                     state = FTP_RESPONSE_INV;
 1432                 }
 1433             }
 1434             /* Or, if this is not a char, this is garbage in client mode */
 1435             else if (!isalpha(*read_ptr) && (iMode == FTPP_SI_CLIENT_MODE))
 1436             {
 1437                 state = FTP_CMD_INV;
 1438             }
 1439 
 1440             read_ptr++;
 1441         }
 1442         req->cmd_end = (const char *)read_ptr;
 1443         req->cmd_size = req->cmd_end - req->cmd_begin;
 1444 
 1445         if (iMode == FTPP_SI_CLIENT_MODE)
 1446         {
 1447             if ( (req->cmd_size > ftpssn->server_conf->max_cmd_len)
 1448               || (req->cmd_size < MIN_CMD)
 1449               || (state == FTP_CMD_INV) )
 1450             {
 1451                 /* Uh, something is very wrong...
 1452                  * nonalpha char seen or cmd is bad length.
 1453                  * See if this might be encrypted, ie, non-alpha bytes. */
 1454                 const unsigned char *ptr = (const unsigned char *)req->cmd_begin;
 1455                 while (ptr < (const unsigned char *)req->cmd_end)
 1456                 {
 1457                     if (!isalpha((int)(*ptr)))
 1458                     {
 1459                         if (!isascii((int)(*ptr)) || !isprint((int)(*ptr)))
 1460                         {
 1461                             encrypted = 1;
 1462                         }
 1463                         break;
 1464                     }
 1465                     ptr++;
 1466                 }
 1467             }
 1468 
 1469             if (encrypted)
 1470             {
 1471                 /* If the session wasn't already marked as encrypted...
 1472                  * Don't want to double-alert if we've already
 1473                  * determined the session is encrypted and we're
 1474                  * checking encrypted sessions.
 1475                  */
 1476                 if (ftpssn->encr_state == 0)
 1477                 {
 1478                     ftpssn->encr_state = AUTH_UNKNOWN_ENCRYPTED;
 1479                     if (global_conf->encrypted.alert)
 1480                     {
 1481                         /* Alert on encrypted channel */
 1482                         ftp_eo_event_log(ftpssn, FTP_EO_ENCRYPTED,
 1483                             NULL, NULL);
 1484                     }
 1485                     if (!global_conf->check_encrypted_data)
 1486                     {
 1487                         /* Mark this session & packet as one to ignore */
 1488                         _dpd.sessionAPI->stop_inspection(p->stream_session, p,
 1489                                                 SSN_DIR_BOTH, -1, 0);
 1490                     }
 1491                     DEBUG_WRAP(DebugMessage(DEBUG_FTPTELNET,
 1492                         "FTP client stream is now encrypted\n"););
 1493                 }
 1494                 break;
 1495             }
 1496             else
 1497             {
 1498                 /*
 1499                  * Check the list of valid FTP commands as
 1500                  * supplied in ftpssn.
 1501                  */
 1502                 if ( req->cmd_size > ftpssn->server_conf->max_cmd_len )
 1503                 {
 1504                     /* Alert, cmd not found */
 1505                     ftp_eo_event_log(ftpssn, FTP_EO_INVALID_CMD, NULL, NULL);
 1506                     state = FTP_CMD_INV;
 1507                 }
 1508                 else
 1509                 {
 1510                     CmdConf = ftp_cmd_lookup_find(ftpssn->server_conf->cmd_lookup,
 1511                                               req->cmd_begin,
 1512                                               req->cmd_size,
 1513                                               &iRet);
 1514                     if ((iRet == FTPP_NOT_FOUND) || (CmdConf == NULL))
 1515                     {
 1516                         /* Alert, cmd not found */
 1517                         ftp_eo_event_log(ftpssn, FTP_EO_INVALID_CMD, NULL, NULL);
 1518                         state = FTP_CMD_INV;
 1519                     }
 1520                     else
 1521                     {
 1522                         /* In case we were encrypted, but aren't now */
 1523                         ftpssn->encr_state = 0;
 1524                     }
 1525                 }
 1526             }
 1527         }
 1528         else if (iMode == FTPP_SI_SERVER_MODE)
 1529         {
 1530             if (state == FTP_CMD_INV)
 1531                 state = FTP_RESPONSE_INV;
 1532 
 1533             if ( (req->cmd_size != 3) || (state == FTP_RESPONSE_INV) )
 1534             {
 1535                 /* Uh, something is very wrong...
 1536                  * nondigit char seen or resp code is not 3 chars.
 1537                  * See if this might be encrypted, ie, non-alpha bytes. */
 1538                 const char *ptr = req->cmd_begin;
 1539                 while (ptr < req->cmd_end)
 1540                 {
 1541                     if (!isdigit((int)(*ptr)))
 1542                     {
 1543                         if (!isascii((int)(*ptr)) || !isprint((int)(*ptr)))
 1544                         {
 1545                             encrypted = 1;
 1546                         }
 1547                         break;
 1548                     }
 1549                     ptr++;
 1550                 }
 1551             }
 1552 
 1553             if (encrypted)
 1554             {
 1555                 /* If the session wasn't already marked as encrypted...
 1556                  * Don't want to double-alert if we've already
 1557                  * determined the session is encrypted and we're
 1558                  * checking encrypted sessions.
 1559                  */
 1560                 if (ftpssn->encr_state == 0)
 1561                 {
 1562                     ftpssn->encr_state = AUTH_UNKNOWN_ENCRYPTED;
 1563                     if (global_conf->encrypted.alert)
 1564                     {
 1565                         /* Alert on encrypted channel */
 1566                         ftp_eo_event_log(ftpssn, FTP_EO_ENCRYPTED,
 1567                             NULL, NULL);
 1568                     }
 1569                     if (!global_conf->check_encrypted_data)
 1570                     {
 1571                         /* Mark this session & packet as one to ignore */
 1572                         _dpd.sessionAPI->stop_inspection(p->stream_session, p,
 1573                                                 SSN_DIR_BOTH, -1, 0);
 1574                     }
 1575                     DEBUG_WRAP(DebugMessage(DEBUG_FTPTELNET,
 1576                         "FTP server stream is now encrypted\n"););
 1577                 }
 1578                 break;
 1579             }
 1580             else
 1581             {
 1582                 /* In case we were encrypted, but aren't now */
 1583                 if ((ftpssn->encr_state == AUTH_TLS_ENCRYPTED) ||
 1584                     (ftpssn->encr_state == AUTH_SSL_ENCRYPTED) ||
 1585                     (ftpssn->encr_state == AUTH_UNKNOWN_ENCRYPTED))
 1586                 {
 1587                     ftpssn->encr_state = 0;
 1588                 }
 1589 
 1590                 /* Otherwise, might have an encryption command pending */
 1591             }
 1592 
 1593             if (read_ptr < end)
 1594             {
 1595                 if (*read_ptr != DASH)
 1596                 {
 1597                     const unsigned char *resp_begin = (const unsigned char *)req->cmd_begin;
 1598                     const unsigned char *resp_end = (const unsigned char *)req->cmd_end;
 1599                     if (resp_end - resp_begin >= 3)
 1600                     {
 1601                         if (isdigit(*(resp_begin)) &&
 1602                             isdigit(*(resp_begin+1)) &&
 1603                             isdigit(*(resp_begin+2)) )
 1604                         {
 1605                             rsp_code = ( (*(resp_begin) - '0') * 100 +
 1606                                          (*(resp_begin+1) - '0') * 10 +
 1607                                          (*(resp_begin+2) - '0') );
 1608                             if (rsp_code == ftpssn->server.response.state)
 1609                             {
 1610                                 /* End of continued response */
 1611                                 state = FTP_RESPONSE_ENDCONT;
 1612                                 ftpssn->server.response.state = 0;
 1613                             }
 1614                             else
 1615                             {
 1616                                 /* Single line response */
 1617                                 state = FTP_RESPONSE;
 1618                             }
 1619                         }
 1620                     }
 1621 
 1622                     if (ftpssn->server.response.state != 0)
 1623                     {
 1624                         req->cmd_begin = NULL;
 1625                         req->cmd_end = NULL;
 1626                         if (*read_ptr != SP)
 1627                             read_ptr--;
 1628                         state = FTP_RESPONSE_CONT;
 1629                     }
 1630                 }
 1631                 else if ((state == FTP_RESPONSE) && (*read_ptr == DASH))
 1632                 {
 1633                     const unsigned char *resp_begin = (const unsigned char *)req->cmd_begin;
 1634                     if (isdigit(*(resp_begin)) &&
 1635                         isdigit(*(resp_begin+1)) &&
 1636                         isdigit(*(resp_begin+2)) )
 1637                     {
 1638                         int resp_code = ( (*(resp_begin) - '0') * 100 +
 1639                                           (*(resp_begin+1) - '0') * 10 +
 1640                                           (*(resp_begin+2) - '0') );
 1641                         if (resp_code == ftpssn->server.response.state)
 1642                         {
 1643                             /* Continuation of previous response */
 1644                             state = FTP_RESPONSE_CONT;
 1645                         }
 1646                         else
 1647                         {
 1648                             /* Start of response, state stays as -2 */
 1649                             state = FTP_RESPONSE_2BCONT;
 1650                             ftpssn->server.response.state = resp_code;
 1651                             rsp_code = resp_code;
 1652                         }
 1653                     }
 1654                     else
 1655                     {
 1656                         DEBUG_WRAP(DebugMessage(DEBUG_FTPTELNET,
 1657                             "invalid FTP response code."););
 1658                         ftpssn->server.response.state = FTP_RESPONSE_INV;
 1659                     }
 1660                 }
 1661             }
 1662         }
 1663 
 1664         if (read_ptr < end)
 1665         {
 1666             if (*read_ptr == SP)
 1667             {
 1668                 space = 1;
 1669             }
 1670 
 1671             read_ptr++; /* Move past the space, dash, or CR */
 1672         }
 1673 
 1674         /* If there is anything left... */
 1675 
 1676         if (read_ptr < end)
 1677         {
 1678             /* Look for an LF --> implies no parameters/message */
 1679             if (*read_ptr == LF)
 1680             {
 1681                 read_ptr++;
 1682                 req->param_begin = NULL;
 1683                 req->param_end = NULL;
 1684             }
 1685             else if (!space && ftpssn->server.response.state == 0)
 1686             {
 1687                 DEBUG_WRAP(DebugMessage(DEBUG_FTPTELNET,
 1688                     "Missing LF from end of FTP command\n"););
 1689             }
 1690             else
 1691             {
 1692                 /* Now grab the command parameters/response message
 1693                  * read_ptr < end already checked */
 1694                 req->param_begin = (const char *)read_ptr;
 1695                 if ((read_ptr = memchr(read_ptr, CR, end - read_ptr)) == NULL)
 1696                     read_ptr = end;
 1697                 req->param_end = (const char *)read_ptr;
 1698                 read_ptr++;
 1699 
 1700                 if (read_ptr < end)
 1701                 {
 1702                     /* Cool, got the end of the parameters, move past
 1703                      * the LF, so we can process the next one in
 1704                      * the pipeline.
 1705                      */
 1706                     if (*read_ptr == LF)
 1707                     {
 1708                        read_ptr++;
 1709                     }
 1710                     else
 1711                     {
 1712                         DEBUG_WRAP(DebugMessage(DEBUG_FTPTELNET,
 1713                             "Missing LF from end of FTP command with params\n"););
 1714                     }
 1715                 }
 1716             }
 1717         }
 1718         else
 1719         {
 1720             /* Nothing left --> no parameters/message.  Not even an LF */
 1721             req->param_begin = NULL;
 1722             req->param_end = NULL;
 1723             DEBUG_WRAP(DebugMessage(DEBUG_FTPTELNET,
 1724                 "Missing LF from end of FTP command sans params\n"););
 1725         }
 1726 
 1727         /* Set the pointer for the next request/response
 1728          * in the pipeline. */
 1729         if (read_ptr < end)
 1730             req->pipeline_req = (const char *)read_ptr;
 1731         else
 1732             req->pipeline_req = NULL;
 1733 
 1734         req->param_size = req->param_end - req->param_begin;
 1735         switch (state)
 1736         {
 1737         case FTP_CMD_INV:
 1738             DEBUG_WRAP(DebugMessage(DEBUG_FTPTELNET,
 1739                 "Illegal FTP command found: %.*s\n",
 1740                 req->cmd_size, req->cmd_begin));
 1741             iRet = FTPP_ALERT;
 1742             break;
 1743         case FTP_RESPONSE: /* Response */
 1744             DEBUG_WRAP(DebugMessage(DEBUG_FTPTELNET,
 1745                 "FTP response: code: %.*s : M len %d : M %.*s\n",
 1746                 req->cmd_size, req->cmd_begin, req->param_size,
 1747                 req->param_size, req->param_begin));
 1748             if ((ftpssn->client_conf->max_resp_len > 0) &&
 1749                 (req->param_size > ftpssn->client_conf->max_resp_len))
 1750             {
 1751                 /* Alert on response message overflow */
 1752                 ftp_eo_event_log(ftpssn, FTP_EO_RESPONSE_LENGTH_OVERFLOW,
 1753                     NULL, NULL);
 1754                 iRet = FTPP_ALERT;
 1755             }
 1756 #ifdef TARGET_BASED
 1757              if (!(ftpssn->flags & FTP_FLG_MALWARE_ENABLED) &&
 1758                      _dpd.fileAPI->file_config_malware_check(p->stream_session, ftp_data_app_id))
 1759              {
 1760                  ftpssn->flags |= FTP_FLG_MALWARE_ENABLED;
 1761              }
 1762 #endif
 1763             if (global_conf->inspection_type ==
 1764                 FTPP_UI_CONFIG_STATEFUL)
 1765             {
 1766                 int newRet = do_stateful_checks(ftpssn, p, req, rsp_code);
 1767                 if (newRet != FTPP_SUCCESS)
 1768                     iRet = newRet;
 1769             }
 1770             break;
 1771         case FTP_RESPONSE_CONT: /* Response continued */
 1772             DEBUG_WRAP(DebugMessage(DEBUG_FTPTELNET,
 1773                 "FTP response: continuation of code: %d : M len %d : M %.*s\n",
 1774                 ftpssn->server.response.state, req->param_size,
 1775                 req->param_size, req->param_begin));
 1776             if ((ftpssn->client_conf->max_resp_len > 0) &&
 1777                 (req->param_size > ftpssn->client_conf->max_resp_len))
 1778             {
 1779                 /* Alert on response message overflow */
 1780                 ftp_eo_event_log(ftpssn, FTP_EO_RESPONSE_LENGTH_OVERFLOW,
 1781                     NULL, NULL);
 1782                 iRet = FTPP_ALERT;
 1783             }
 1784             break;
 1785         case FTP_RESPONSE_ENDCONT: /* Continued response end */
 1786             DEBUG_WRAP(DebugMessage(DEBUG_FTPTELNET,
 1787                 "FTP response: final continue of code: %.*s : M len %d : "
 1788                 "M %.*s\n", req->cmd_size, req->cmd_begin,
 1789                 req->param_size, req->param_size, req->param_begin));
 1790             if ((ftpssn->client_conf->max_resp_len > 0) &&
 1791                 (req->param_size > ftpssn->client_conf->max_resp_len))
 1792             {
 1793                 /* Alert on response message overflow */
 1794                 ftp_eo_event_log(ftpssn, FTP_EO_RESPONSE_LENGTH_OVERFLOW,
 1795                     NULL, NULL);
 1796                 iRet = FTPP_ALERT;
 1797             }
 1798             break;
 1799         default:
 1800             DEBUG_WRAP(DebugMessage(DEBUG_FTPTELNET, "FTP command: CMD: %.*s : "
 1801                 "P len %d : P %.*s\n", req->cmd_size, req->cmd_begin,
 1802                 req->param_size, req->param_size, req->param_begin));
 1803 
 1804             if (CmdConf)
 1805             {
 1806                 if ((req->param_size > CmdConf->max_param_len))
 1807                 {
 1808                     /* Alert on param length overrun */
 1809                     ftp_eo_event_log(ftpssn, FTP_EO_PARAMETER_LENGTH_OVERFLOW,
 1810                         NULL, NULL);
 1811                     DEBUG_WRAP(DebugMessage(DEBUG_FTPTELNET, "FTP command: %.*s"
 1812                         "parameter length overrun %d > %d \n",
 1813                         req->cmd_size, req->cmd_begin, req->param_size,
 1814                         CmdConf->max_param_len));
 1815                     iRet = FTPP_ALERT;
 1816                 }
 1817 
 1818                 if (CmdConf->data_chan_cmd)
 1819                 {
 1820                     ftpssn->data_chan_state |= DATA_CHAN_PASV_CMD_ISSUED;
 1821                     ftpssn->data_chan_index = ftpssn->ftp_cmd_pipe_index;
 1822                     if (ftpssn->data_chan_state & DATA_CHAN_PORT_CMD_ISSUED)
 1823                     {
 1824                         /*
 1825                          * If there was a PORT command previously in
 1826                          * a series of pipelined requests, this
 1827                          * cancels it.
 1828                          */
 1829                         ftpssn->data_chan_state &= ~DATA_CHAN_PORT_CMD_ISSUED;
 1830                     }
 1831                 }
 1832                 else if (CmdConf->data_rest_cmd)
 1833                 {
 1834                     if ((req->param_begin != NULL) && (req->param_size > 0))
 1835                     {
 1836                         char *return_ptr = 0;
 1837                         unsigned long offset = 0;
 1838 
 1839                         errno = 0;
 1840                         offset = strtoul(req->param_begin, &return_ptr, 10);
 1841 
 1842                         if ((errno == ERANGE || errno == EINVAL) || (offset > 0))
 1843                         {
 1844                             ftpssn->data_chan_state |= DATA_CHAN_REST_CMD_ISSUED;
 1845                             ftpssn->data_xfer_index = ftpssn->ftp_cmd_pipe_index;
 1846                             ftpssn->rest_cmd_offset = offset;
 1847                         }
 1848                     }
 1849                 }
 1850                 else if (CmdConf->data_xfer_cmd)
 1851                 {
 1852 #ifdef TARGET_BASED
 1853                     /* If we are not ignoring the data channel OR file processing is enabled */
 1854                     if (!ftpssn->server_conf->data_chan || (_dpd.fileAPI->get_max_file_depth(_dpd.getCurrentSnortConfig(), false) > -1))
 1855                     {
 1856                         /* The following  check cleans up filename  for failed data
 1857                          * transfers.  If  the  transfer had  been  successful  the
 1858                          * filename  pointer  would have  been  handed  off to  the
 1859                          * FTP_DATA_SESSION for tracking. */
 1860                         if (ftpssn->filename)
 1861                         {
 1862                             free(ftpssn->filename);
 1863                             ftpssn->filename = NULL;
 1864                             ftpssn->file_xfer_info = FTPP_FILE_IGNORE;
 1865                         }
 1866 
 1867                         // Get the file name and set direction of the get/put request.
 1868                         // Request could have been sent without parameters, i.e. filename,
 1869                         // so make sure something is there.
 1870                         if (((req->param_begin != NULL) && (req->param_size > 0))
 1871                                 && (CmdConf->file_get_cmd || CmdConf->file_put_cmd))
 1872                         {
 1873                             ftpssn->filename = (char *)malloc(req->param_size+1);
 1874                             ftp_telnet_stats.heap_memory += req->param_size+1;
 1875                             if (ftpssn->filename)
 1876                             {
 1877                                 memcpy(ftpssn->filename, req->param_begin, req->param_size);
 1878                                 ftpssn->filename[req->param_size] = '\0';
 1879                                 ftpssn->file_xfer_info = req->param_size;
 1880                                 if (ftpssn->flags & FTP_FLG_MALWARE_ENABLED)
 1881                                 {
 1882                                     IP_COPY_VALUE(ftpssn->control_clientIP, GET_SRC_IP(p));
 1883                                     IP_COPY_VALUE(ftpssn->control_serverIP, GET_DST_IP(p));
 1884                                     ftpssn->control_serverPort = ntohs(p->tcp_header->destination_port);
 1885                                     ftpssn->control_clientPort = ntohs(p->tcp_header->source_port);
 1886 #ifdef TARGET_BASED
 1887                                     datassn = (FTP_DATA_SESSION *)ftpssn->datassn;
 1888                                     if(datassn)
 1889                                     {
 1890                                         char *file_name = strrchr(ftpssn->filename, '/');
 1891                                         if(!file_name)
 1892                                             file_name = ftpssn->filename;
 1893                                         datassn->path_hash = _dpd.fileAPI->str_to_hash((uint8_t *)file_name, strlen(file_name));
 1894                                     }
 1895 #endif
 1896                                 }
 1897                             }
 1898                             else
 1899                             {
 1900                                 _dpd.errMsg("check_ftp: "
 1901                                         "Memory allocation failed for filename in ftpssn\n");
 1902                             }
 1903                             // 0 for Download, 1 for Upload
 1904                             ftpssn->data_xfer_dir = CmdConf->file_get_cmd ? false : true;
 1905                             FTP_DATA_SESSION *ftpdata = ftpssn->datassn;
 1906                             if(ftpdata)
 1907                                 ftpdata->direction = ftpssn->data_xfer_dir;
 1908                         }
 1909                         else
 1910                         {
 1911                             ftpssn->file_xfer_info = FTPP_FILE_IGNORE;
 1912                         }
 1913                     }
 1914 #endif
 1915                     ftpssn->data_chan_state |= DATA_CHAN_XFER_CMD_ISSUED;
 1916                     ftpssn->data_xfer_index = ftpssn->ftp_cmd_pipe_index;
 1917                 }
 1918                 else if (CmdConf->encr_cmd)
 1919                 {
 1920                     if (req->param_begin && (req->param_size > 0) &&
 1921                         ((req->param_begin[0] == 'T') || (req->param_begin[0] == 't')))
 1922                     {
 1923                         ftpssn->encr_state = AUTH_TLS_CMD_ISSUED;
 1924                     }
 1925                     else if (req->param_begin && (req->param_size > 0) &&
 1926                              ((req->param_begin[0] == 'S') || (req->param_begin[0] == 's')))
 1927                     {
 1928                         ftpssn->encr_state = AUTH_SSL_CMD_ISSUED;
 1929                     }
 1930                     else
 1931                     {
 1932                         ftpssn->encr_state = AUTH_UNKNOWN_CMD_ISSUED;
 1933                     }
 1934                 }
 1935                 if (CmdConf->check_validity)
 1936                 {
 1937                     iRet = check_ftp_param_validity(p, req->param_begin,
 1938                                     req->param_end, CmdConf->param_format,
 1939                                     ftpssn);
 1940                     /* If negative, haven't already alerted on violation */
 1941                     if (iRet < 0)
 1942                     {
 1943                         /* Set Alert on malformatted parameter */
 1944                         ftp_eo_event_log(ftpssn, FTP_EO_MALFORMED_PARAMETER,
 1945                             NULL, NULL);
 1946                         iRet = FTPP_ALERT;
 1947                         break;
 1948                     }
 1949                     else if (iRet > 0)
 1950                     {
 1951                         /* Already alerted -- ie, string format attack. */
 1952                         break;
 1953                     }
 1954                 }
 1955             }
 1956             break;
 1957         }
 1958 
 1959         if (iMode == FTPP_SI_CLIENT_MODE)
 1960             ftpssn->ftp_cmd_pipe_index++;
 1961         else if ((rsp_code != 226) && (rsp_code != 426))
 1962         {
 1963              /*
 1964               * In terms of counting responses, ignore
 1965               * 226 response saying transfer complete
 1966               * 426 response saying transfer aborted
 1967               * The 226 may or may not be sent by the server.
 1968               * Both are 2nd response to a transfer command.
 1969               */
 1970             ftpssn->ftp_cmd_pipe_index++;
 1971         }
 1972     }
 1973 
 1974     if (iMode == FTPP_SI_CLIENT_MODE)
 1975     {
 1976         ftpssn->ftp_cmd_pipe_index = 1;
 1977     }
 1978 
 1979     if (encrypted)
 1980         return FTPP_ALERT;
 1981 
 1982     return iRet;
 1983 }