"Fossies" - the Fresh Open Source Software Archive

Member "snort-2.9.17/src/dynamic-preprocessors/appid/service_plugins/service_tftp.c" (16 Oct 2020, 11054 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 "service_tftp.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 ** Copyright (C) 2014-2020 Cisco and/or its affiliates. All rights reserved.
    3 ** Copyright (C) 2005-2013 Sourcefire, Inc.
    4 **
    5 ** This program is free software; you can redistribute it and/or modify
    6 ** it under the terms of the GNU General Public License Version 2 as
    7 ** published by the Free Software Foundation.  You may not use, modify or
    8 ** distribute this program under any other version of the GNU General
    9 ** Public License.
   10 **
   11 ** This program is distributed in the hope that it will be useful,
   12 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
   13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   14 ** GNU General Public License for more details.
   15 **
   16 ** You should have received a copy of the GNU General Public License
   17 ** along with this program; if not, write to the Free Software
   18 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
   19 */
   20 
   21 
   22 #include <ctype.h>
   23 #include <string.h>
   24 #include <stdlib.h>
   25 #include <stddef.h>
   26 #include <sys/types.h>
   27 #include <netinet/in.h>
   28 
   29 #include "appIdApi.h"
   30 #include "appInfoTable.h"
   31 #include "flow.h"
   32 #include "service_api.h"
   33 
   34 #define TFTP_PORT   69
   35 
   36 #define TFTP_COUNT_THRESHOLD 1
   37 #define TFTP_MAX_PACKET_SIZE 512
   38 
   39 typedef enum
   40 {
   41     TFTP_STATE_CONNECTION,
   42     TFTP_STATE_TRANSFER,
   43     TFTP_STATE_ACK,
   44     TFTP_STATE_DATA,
   45     TFTP_STATE_ERROR
   46 } TFTPState;
   47 
   48 typedef struct _SERVICE_TFTP_DATA
   49 {
   50     TFTPState state;
   51     unsigned count;
   52     int last;
   53     uint16_t block;
   54 } ServiceTFTPData;
   55 
   56 #pragma pack(1)
   57 
   58 typedef struct _SERVICE_TFTP_HEADER
   59 {
   60     uint16_t opcode;
   61     union
   62     {
   63         uint16_t block;
   64         uint16_t errorcode;
   65     } d;
   66 } ServiceTFTPHeader;
   67 
   68 #pragma pack()
   69 
   70 static int tftp_init(const InitServiceAPI * const api);
   71 static int tftp_validate(ServiceValidationArgs* args);
   72 
   73 static tRNAServiceElement svc_element =
   74 {
   75     .next = NULL,
   76     .validate = &tftp_validate,
   77     .detectorType = DETECTOR_TYPE_DECODER,
   78     .name = "tftp",
   79     .ref_count = 1,
   80     .current_ref_count = 1,
   81 };
   82 
   83 static RNAServiceValidationPort pp[] =
   84 {
   85     {&tftp_validate, 69, IPPROTO_UDP},
   86     {NULL, 0, 0}
   87 };
   88 
   89 tRNAServiceValidationModule tftp_service_mod =
   90 {
   91     "TFTP",
   92     &tftp_init,
   93     pp
   94 };
   95 
   96 static tAppRegistryEntry appIdRegistry[] = {{APP_ID_TFTP, APPINFO_FLAG_SERVICE_ADDITIONAL}};
   97 
   98 static int16_t app_id;
   99 
  100 static int tftp_init(const InitServiceAPI * const init_api)
  101 {
  102     unsigned i;
  103 #ifdef TARGET_BASED
  104     app_id = init_api->dpd->addProtocolReference("tftp");
  105 
  106     for (i=0; i < sizeof(appIdRegistry)/sizeof(*appIdRegistry); i++)
  107     {
  108         _dpd.debugMsg(DEBUG_LOG,"registering appId: %d\n",appIdRegistry[i].appId);
  109         init_api->RegisterAppId(&tftp_validate, appIdRegistry[i].appId, appIdRegistry[i].additionalInfo, init_api->pAppidConfig);
  110     }
  111 #endif
  112 
  113     return 0;
  114 }
  115 
  116 static int tftp_verify_header(const uint8_t *data, uint16_t size,
  117                               uint16_t *block)
  118 {
  119     const ServiceTFTPHeader *hdr;
  120 
  121     if (size < sizeof(ServiceTFTPHeader)) return -1;
  122     hdr = (ServiceTFTPHeader *)data;
  123     switch (ntohs(hdr->opcode))
  124     {
  125     case 3:
  126         if (size > sizeof(ServiceTFTPHeader) + TFTP_MAX_PACKET_SIZE)
  127             return -1;
  128         *block = ntohs(hdr->d.block);
  129         return TFTP_STATE_DATA;
  130     case 4:
  131         if (size != sizeof(ServiceTFTPHeader)) return -1;
  132         *block = ntohs(hdr->d.block);
  133         return TFTP_STATE_ACK;
  134     case 5:
  135         if (ntohs(hdr->d.errorcode) > 7) return -1;
  136         if (size <= sizeof(ServiceTFTPHeader)) return -1;
  137         if (data[size-1] != 0) return -1;
  138         return TFTP_STATE_ERROR;
  139     default:
  140         return -1;
  141     }
  142 }
  143 
  144 static int tftp_validate(ServiceValidationArgs* args)
  145 {
  146     ServiceTFTPData *td;
  147     ServiceTFTPData *tmp_td;
  148     int mode;
  149     uint16_t block = 0;
  150     uint16_t tmp;
  151     tAppIdData *pf;
  152     sfaddr_t *sip;
  153     sfaddr_t *dip;
  154     tAppIdData *flowp = args->flowp;
  155     const uint8_t *data = args->data;
  156     SFSnortPacket *pkt = args->pkt;
  157     const int dir = args->dir;
  158     uint16_t size = args->size;
  159     char* app_id_debug_session = args->app_id_debug_session;
  160 
  161     if (!size)
  162         goto inprocess;
  163 
  164     td = tftp_service_mod.api->data_get(flowp, tftp_service_mod.flow_data_index);
  165     if (!td)
  166     {
  167         td = calloc(1, sizeof(*td));
  168         if (!td)
  169             return SERVICE_ENOMEM;
  170         if (tftp_service_mod.api->data_add(flowp, td, tftp_service_mod.flow_data_index, &free))
  171         {
  172             free(td);
  173             return SERVICE_ENOMEM;
  174         }
  175         td->state = TFTP_STATE_CONNECTION;
  176     }
  177     if (args->app_id_debug_session_flag)
  178         _dpd.logMsg("AppIdDbg %s tftp state %d\n", app_id_debug_session, td->state);
  179 
  180     if (td->state == TFTP_STATE_CONNECTION && dir == APP_ID_FROM_RESPONDER)
  181         goto fail;
  182     if ((td->state == TFTP_STATE_TRANSFER || td->state == TFTP_STATE_DATA) &&
  183         dir == APP_ID_FROM_INITIATOR)
  184     {
  185         goto inprocess;
  186     }
  187     switch (td->state)
  188     {
  189     case TFTP_STATE_CONNECTION:
  190         if (size < 6) goto bail;
  191         tmp = ntohs(*((uint16_t *)data));
  192         if (tmp != 0x0001 && tmp != 0x0002) goto bail;
  193         data += sizeof(uint16_t);
  194         size -= sizeof(uint16_t);
  195         if (!(*data)) goto bail;
  196         for (; *data && size; data++, size--)
  197         {
  198             if (!isprint(*data)) goto bail;
  199         }
  200         if (!size) goto bail;
  201         size--;
  202         data++;
  203         if (!size || !(*data)) goto bail;
  204         if (data[size-1]) goto bail;
  205         if (strcasecmp((char *)data, "netascii") && strcasecmp((char *)data, "octet"))
  206             goto bail;
  207 
  208         tmp_td = calloc(1, sizeof(ServiceTFTPData));
  209         if (tmp_td == NULL) return SERVICE_ENOMEM;
  210         tmp_td->state = TFTP_STATE_TRANSFER;
  211 
  212         dip = GET_DST_IP(pkt);
  213         sip = GET_SRC_IP(pkt);
  214         pf = tftp_service_mod.api->flow_new(flowp, pkt, dip, 0, sip, pkt->src_port, flowp->proto, app_id, APPID_EARLY_SESSION_FLAG_FW_RULE);
  215         if (pf)
  216         {
  217             if (tftp_service_mod.api->data_add(pf, tmp_td, tftp_service_mod.flow_data_index, &free))
  218             {
  219                 free(tmp_td);
  220                 return SERVICE_ENOMEM;
  221             }
  222             if (tftp_service_mod.api->data_add_id(pf, pkt->dst_port, &svc_element))
  223             {
  224                 setAppIdFlag(pf, APPID_SESSION_SERVICE_DETECTED);
  225                 clearAppIdFlag(pf, APPID_SESSION_CONTINUE);
  226                 tmp_td->state = TFTP_STATE_ERROR;
  227                 return SERVICE_ENOMEM;
  228             }
  229             PopulateExpectedFlow(flowp, pf, APPID_SESSION_EXPECTED_EVALUATE, APP_ID_FROM_RESPONDER);
  230             sfaddr_copy_to_raw(&pf->common.initiator_ip, sip);
  231             pf->rnaServiceState = RNA_STATE_STATEFUL;
  232             pf->scan_flags |= SCAN_HOST_PORT_FLAG;
  233         }
  234         else
  235         {
  236             free(tmp_td);
  237             goto inprocess;   /* Assume that the flow already exists
  238                                  as in a retransmit situation */
  239         }
  240         break;
  241     case TFTP_STATE_TRANSFER:
  242         if ((mode=tftp_verify_header(data, size, &block)) < 0)
  243         {
  244             if (args->app_id_debug_session_flag)
  245                 _dpd.logMsg("AppIdDbg %s tftp failed to verify\n", app_id_debug_session);
  246             goto fail;
  247         }
  248         if (args->app_id_debug_session_flag)
  249             _dpd.logMsg("AppIdDbg %s tftp mode %d and block %u\n", app_id_debug_session,
  250                         mode, (unsigned)block);
  251         if (mode == TFTP_STATE_ACK)
  252         {
  253             if (block != 0)
  254             {
  255                 td->state = TFTP_STATE_ERROR;
  256                 goto fail;
  257             }
  258             td->last = 0;
  259             td->block = 0;
  260             td->state = TFTP_STATE_ACK;
  261         }
  262         else if (mode == TFTP_STATE_DATA)
  263         {
  264             if (block != 1)
  265             {
  266                 td->state = TFTP_STATE_ERROR;
  267                 goto fail;
  268             }
  269             td->block = 1;
  270             td->state = TFTP_STATE_DATA;
  271         }
  272         else if (mode == TFTP_STATE_ERROR) break;
  273         else
  274         {
  275             td->state = TFTP_STATE_ERROR;
  276             goto fail;
  277         }
  278         break;
  279     case TFTP_STATE_ACK:
  280         if ((mode=tftp_verify_header(data, size, &block)) < 0)
  281         {
  282             if (dir == APP_ID_FROM_RESPONDER) goto fail;
  283             else
  284             {
  285                 if (args->app_id_debug_session_flag)
  286                     _dpd.logMsg("AppIdDbg %s tftp failed to verify\n", app_id_debug_session);
  287                 goto bail;
  288             }
  289         }
  290         if (args->app_id_debug_session_flag)
  291             _dpd.logMsg("AppIdDbg %s tftp mode %d\n", app_id_debug_session, mode);
  292         if (mode == TFTP_STATE_ERROR)
  293         {
  294             td->state = TFTP_STATE_TRANSFER;
  295             break;
  296         }
  297         if (dir == APP_ID_FROM_INITIATOR && mode != TFTP_STATE_DATA)
  298         {
  299             if (args->app_id_debug_session_flag)
  300                 _dpd.logMsg("AppIdDbg %s tftp bad mode\n", app_id_debug_session);
  301             goto bail;
  302         }
  303         if (dir == APP_ID_FROM_RESPONDER && mode != TFTP_STATE_ACK)
  304             goto fail;
  305         if (dir == APP_ID_FROM_INITIATOR)
  306         {
  307             if (size < sizeof(ServiceTFTPHeader) + TFTP_MAX_PACKET_SIZE)
  308                 td->last = 1;
  309             break;
  310         }
  311         if (block == (uint16_t)(td->block + 1))
  312             td->block++;
  313         else if (block != td->block)
  314             goto fail;
  315         td->count++;
  316         if (td->count >= TFTP_COUNT_THRESHOLD)
  317             goto success;
  318         if (td->last)
  319             td->state = TFTP_STATE_TRANSFER;
  320         break;
  321     case TFTP_STATE_DATA:
  322         if ((mode=tftp_verify_header(data, size, &block)) < 0)
  323             goto fail;
  324         if (mode == TFTP_STATE_ERROR) td->state = TFTP_STATE_TRANSFER;
  325         else if (mode != TFTP_STATE_DATA) goto fail;
  326         if (block == (uint16_t)(td->block + 1))
  327             td->block++;
  328         else if (block != td->block)
  329             goto fail;
  330         td->count++;
  331         if (td->count >= TFTP_COUNT_THRESHOLD)
  332             goto success;
  333         if (size < sizeof(ServiceTFTPHeader) + TFTP_MAX_PACKET_SIZE)
  334             td->state = TFTP_STATE_TRANSFER;
  335         break;
  336     case TFTP_STATE_ERROR:
  337     default:
  338         goto fail;
  339     }
  340 
  341 inprocess:
  342     tftp_service_mod.api->service_inprocess(flowp, pkt, dir, &svc_element, NULL);
  343     return SERVICE_INPROCESS;
  344 
  345 success:
  346     if (args->app_id_debug_session_flag)
  347         _dpd.logMsg("AppIdDbg %s tftp success\n", app_id_debug_session);
  348     tftp_service_mod.api->add_service(flowp, pkt, dir, &svc_element,
  349                                       APP_ID_TFTP, NULL, NULL, NULL, NULL);
  350     return SERVICE_SUCCESS;
  351 
  352 bail:
  353     tftp_service_mod.api->incompatible_data(flowp, pkt, dir, &svc_element,
  354                                             tftp_service_mod.flow_data_index, args->pConfig, NULL);
  355     return SERVICE_NOT_COMPATIBLE;
  356 
  357 fail:
  358     tftp_service_mod.api->fail_service(flowp, pkt, dir, &svc_element,
  359                                        tftp_service_mod.flow_data_index, args->pConfig, NULL);
  360     return SERVICE_NOMATCH;
  361 }
  362