"Fossies" - the Fresh Open Source Software Archive

Member "snort-2.9.17/src/dynamic-preprocessors/appid/service_plugins/service_rexec.c" (16 Oct 2020, 10955 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_rexec.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 REXEC_PORT  512
   35 #define REXEC_MAX_PORT_PACKET 6
   36 
   37 typedef enum
   38 {
   39     REXEC_STATE_PORT,
   40     REXEC_STATE_SERVER_CONNECT,
   41     REXEC_STATE_USERNAME,
   42     REXEC_STATE_PASSWORD,
   43     REXEC_STATE_COMMAND,
   44     REXEC_STATE_REPLY,
   45     REXEC_STATE_DONE,
   46     REXEC_STATE_BAIL,
   47     REXEC_STATE_STDERR_CONNECT_SYN,
   48     REXEC_STATE_STDERR_CONNECT_SYN_ACK,
   49     REXEC_STATE_STDERR_WAIT,
   50     REXEC_STATE_STDERR_DONE
   51 } REXECState;
   52 
   53 
   54 typedef struct _SERVICE_REXEC_DATA
   55 {
   56     REXECState state;
   57     struct _SERVICE_REXEC_DATA *parent;
   58     struct _SERVICE_REXEC_DATA *child;
   59 } ServiceREXECData;
   60 
   61 static int rexec_init(const InitServiceAPI * const init_api);
   62 static int rexec_validate(ServiceValidationArgs* args);
   63 
   64 static tRNAServiceElement svc_element =
   65 {
   66     .next = NULL,
   67     .validate = &rexec_validate,
   68     .detectorType = DETECTOR_TYPE_DECODER,
   69     .name = "rexec",
   70     .ref_count = 1,
   71     .current_ref_count = 1,
   72 };
   73 
   74 static RNAServiceValidationPort pp[] =
   75 {
   76     {&rexec_validate, REXEC_PORT, IPPROTO_TCP},
   77     {NULL, 0, 0}
   78 };
   79 
   80 tRNAServiceValidationModule rexec_service_mod =
   81 {
   82     "REXEC",
   83     &rexec_init,
   84     pp
   85 };
   86 
   87 static tAppRegistryEntry appIdRegistry[] = {{APP_ID_EXEC, APPINFO_FLAG_SERVICE_ADDITIONAL}};
   88 
   89 static int16_t app_id = 0;
   90 
   91 static int rexec_init(const InitServiceAPI * const init_api)
   92 {
   93     unsigned i;
   94 #ifdef TARGET_BASED
   95     app_id = init_api->dpd->addProtocolReference("rexec");
   96 
   97     for (i=0; i < sizeof(appIdRegistry)/sizeof(*appIdRegistry); i++)
   98     {
   99         _dpd.debugMsg(DEBUG_LOG,"registering appId: %d\n",appIdRegistry[i].appId);
  100         init_api->RegisterAppId(&rexec_validate, appIdRegistry[i].appId, appIdRegistry[i].additionalInfo, init_api->pAppidConfig);
  101     }
  102 #endif
  103 
  104     return 0;
  105 }
  106 
  107 static void rexec_free_state(void *data)
  108 {
  109     ServiceREXECData *rd = (ServiceREXECData *)data;
  110 
  111     if (rd)
  112     {
  113         if (rd->parent)
  114         {
  115             rd->parent->child = NULL;
  116             rd->parent->parent = NULL;
  117         }
  118         if (rd->child)
  119         {
  120             rd->child->parent = NULL;
  121             rd->child->child = NULL;
  122         }
  123         free(rd);
  124     }
  125 }
  126 
  127 /* Both the control & data sessions need to go to success else we bail.
  128    Let the control/data session know that we're bailing */
  129 static void rexec_bail(ServiceREXECData *rd, tAppIdData *flowp)
  130 {
  131     clearAppIdFlag(flowp, APPID_SESSION_REXEC_STDERR);
  132 
  133     if (!rd) return;
  134 
  135     rd->state = REXEC_STATE_BAIL;
  136     if (rd->child) rd->child->state = REXEC_STATE_BAIL;
  137     if (rd->parent) rd->parent->state = REXEC_STATE_BAIL;
  138 }
  139 
  140 static int rexec_validate(ServiceValidationArgs* args)
  141 {
  142     ServiceREXECData *rd;
  143     ServiceREXECData *tmp_rd;
  144     int i;
  145     uint32_t port;
  146     tAppIdData *pf;
  147     tAppIdData *flowp = args->flowp;
  148     const uint8_t *data = args->data;
  149     SFSnortPacket *pkt = args->pkt; 
  150     const int dir = args->dir;
  151     uint16_t size = args->size;
  152     bool app_id_debug_session_flag = args->app_id_debug_session_flag;
  153     char* app_id_debug_session = args->app_id_debug_session;
  154 
  155     rd = rexec_service_mod.api->data_get(flowp, rexec_service_mod.flow_data_index);
  156     if (!rd)
  157     {
  158         if (!size)
  159             goto inprocess;
  160         rd = calloc(1, sizeof(*rd));
  161         if (!rd)
  162             return SERVICE_ENOMEM;
  163         if (rexec_service_mod.api->data_add(flowp, rd, rexec_service_mod.flow_data_index, &rexec_free_state))
  164         {
  165             free(rd);
  166             return SERVICE_ENOMEM;
  167         }
  168         rd->state = REXEC_STATE_PORT;
  169     }
  170 
  171     if (app_id_debug_session_flag)
  172         _dpd.logMsg("AppIdDbg %s rexec state %d\n", app_id_debug_session, rd->state);
  173 
  174     switch (rd->state)
  175     {
  176     case REXEC_STATE_PORT:
  177         if (dir != APP_ID_FROM_INITIATOR) goto bail;
  178         if (size > REXEC_MAX_PORT_PACKET) goto bail;
  179         if (data[size-1]) goto bail;
  180         port = 0;
  181         for (i=0; i<size-1; i++)
  182         {
  183             if (!isdigit(data[i])) goto bail;
  184             port *= 10;
  185             port += data[i] - '0';
  186         }
  187         if (port > 65535) goto bail;
  188         if (port)
  189         {
  190             sfaddr_t *sip;
  191             sfaddr_t *dip;
  192 
  193             dip = GET_DST_IP(pkt);
  194             sip = GET_SRC_IP(pkt);
  195             pf = rexec_service_mod.api->flow_new(flowp, pkt, dip, 0, sip, (uint16_t)port, IPPROTO_TCP, app_id,
  196                                                  APPID_EARLY_SESSION_FLAG_FW_RULE);
  197             if (pf)
  198             {
  199                 tmp_rd = calloc(1, sizeof(ServiceREXECData));
  200                 if (tmp_rd == NULL)
  201                     return SERVICE_ENOMEM;
  202                 tmp_rd->state = REXEC_STATE_STDERR_CONNECT_SYN;
  203                 tmp_rd->parent = rd;
  204 
  205                 if (rexec_service_mod.api->data_add(pf, tmp_rd, rexec_service_mod.flow_data_index, &rexec_free_state))
  206                 {
  207                     pf->rnaServiceState = RNA_STATE_FINISHED;
  208                     free(tmp_rd);
  209                     return SERVICE_ENOMEM;
  210                 }
  211                 if (rexec_service_mod.api->data_add_id(pf, (uint16_t)port, &svc_element))
  212                 {
  213                     pf->rnaServiceState = RNA_STATE_FINISHED;
  214                     tmp_rd->state = REXEC_STATE_DONE;
  215                     tmp_rd->parent = NULL;
  216                     return SERVICE_ENULL;
  217                 }
  218                 pf->rnaServiceState = RNA_STATE_STATEFUL;
  219                 pf->scan_flags |= SCAN_HOST_PORT_FLAG;
  220                 PopulateExpectedFlow(flowp, pf,
  221                                      APPID_SESSION_CONTINUE |
  222                                      APPID_SESSION_REXEC_STDERR |
  223                                      APPID_SESSION_NO_TPI |
  224                                      APPID_SESSION_NOT_A_SERVICE |
  225                                      APPID_SESSION_PORT_SERVICE_DONE,
  226                                      APP_ID_FROM_RESPONDER);
  227                 pf->rnaServiceState = RNA_STATE_STATEFUL;
  228                 rd->child = tmp_rd;
  229                 rd->state = REXEC_STATE_SERVER_CONNECT;
  230                 setAppIdFlag(flowp, APPID_SESSION_CONTINUE);
  231                 goto success;
  232             }
  233             else
  234                 rd->state = REXEC_STATE_USERNAME;
  235         }
  236         else rd->state = REXEC_STATE_USERNAME;
  237         break;
  238     case REXEC_STATE_SERVER_CONNECT:
  239         if (!size) break;
  240         /* The only valid way out of this state is for the child flow to change it. */
  241         goto fail;
  242     case REXEC_STATE_USERNAME:
  243         if (!size) break;
  244         if (dir != APP_ID_FROM_INITIATOR) goto bail;
  245         for (i=0; i<size && data[i]; i++)
  246             if (!isprint(data[i]) || isspace(data[i])) goto bail;
  247         rd->state = REXEC_STATE_PASSWORD;
  248         if (i >= size) goto bail;
  249         i++;
  250         data += i;
  251         size -= i;
  252         /* Fall through */
  253     case REXEC_STATE_PASSWORD:
  254         if (!size) break;
  255         if (dir != APP_ID_FROM_INITIATOR) goto bail;
  256         for (i=0; i<size && data[i]; i++)
  257             if (!isprint(data[i])) goto bail;
  258         rd->state = REXEC_STATE_COMMAND;
  259         if (i >= size) goto bail;
  260         i++;
  261         data += i;
  262         size -= i;
  263         /* Fall through */
  264     case REXEC_STATE_COMMAND:
  265         if (!size) break;
  266         if (dir != APP_ID_FROM_INITIATOR) goto bail;
  267         for (i=0; i<size && data[i]; i++)
  268             if (!isprint(data[i])) goto bail;
  269         rd->state = REXEC_STATE_COMMAND;
  270         if (i >= size) goto bail;
  271         i++;
  272         data += i;
  273         size -= i;
  274         if (!size)
  275         {
  276             rd->state = REXEC_STATE_REPLY;
  277             break;
  278         }
  279         if (data[size-1]) goto bail;
  280         /* stdin */
  281         for (i=0; i<size && data[i]; i++)
  282         {
  283             if (!isprint(data[i])) goto bail;
  284         }
  285         i++;
  286         if (i != size) goto bail;
  287         rd->state = REXEC_STATE_REPLY;
  288         break;
  289     case REXEC_STATE_REPLY:
  290         if (!size) goto inprocess;
  291         if (dir != APP_ID_FROM_RESPONDER) goto fail;
  292         if (size != 1) goto fail;
  293         if (rd->child)
  294         {
  295             if(rd->child->state == REXEC_STATE_STDERR_WAIT)
  296                 rd->child->state = REXEC_STATE_STDERR_DONE;
  297             else
  298                 goto fail;
  299         }
  300         clearAppIdFlag(flowp, APPID_SESSION_CONTINUE);
  301         goto success;
  302     case REXEC_STATE_STDERR_CONNECT_SYN:
  303         rd->state = REXEC_STATE_STDERR_CONNECT_SYN_ACK;
  304         break;
  305     case REXEC_STATE_STDERR_CONNECT_SYN_ACK:
  306         if (rd->parent && rd->parent->state == REXEC_STATE_SERVER_CONNECT)
  307         {
  308             rd->parent->state = REXEC_STATE_USERNAME;
  309             rd->state = REXEC_STATE_STDERR_WAIT;
  310             break;
  311         }
  312         goto bail;
  313     case REXEC_STATE_STDERR_WAIT:
  314         /* The only valid way out of this state is for the parent flow to change it. */
  315         if (!size) break;
  316         goto bail;
  317     case REXEC_STATE_STDERR_DONE:
  318         clearAppIdFlag(flowp, APPID_SESSION_REXEC_STDERR | APPID_SESSION_CONTINUE);
  319         goto success;
  320     case REXEC_STATE_BAIL:
  321     default:
  322         goto bail;
  323     }
  324 
  325 inprocess:
  326     rexec_service_mod.api->service_inprocess(flowp, pkt, dir, &svc_element, NULL);
  327     return SERVICE_INPROCESS;
  328 
  329 success:
  330     rexec_service_mod.api->add_service(flowp, pkt, dir, &svc_element,
  331                                        APP_ID_EXEC, NULL, NULL, NULL, NULL);
  332     return SERVICE_SUCCESS;
  333 
  334 bail:
  335     rexec_bail(rd, flowp);
  336     rexec_service_mod.api->incompatible_data(flowp, pkt, dir, &svc_element,
  337                                              rexec_service_mod.flow_data_index,
  338                                              args->pConfig, NULL);
  339     return SERVICE_NOT_COMPATIBLE;
  340 
  341 fail:
  342     rexec_bail(rd, flowp);
  343     rexec_service_mod.api->fail_service(flowp, pkt, dir, &svc_element,
  344                                         rexec_service_mod.flow_data_index,
  345                                         args->pConfig, NULL);
  346     return SERVICE_NOMATCH;
  347 }
  348