"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