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