"Fossies" - the Fresh Open Source Software Archive 
Member "snort-2.9.17/src/dynamic-preprocessors/appid/service_plugins/service_rpc.c" (16 Oct 2020, 32086 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_rpc.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 #include <netdb.h>
29
30 #include "appIdApi.h"
31 #include "appInfoTable.h"
32 #include "flow.h"
33 #include "service_api.h"
34
35 #if defined(FREEBSD) || defined(OPENBSD)
36 #include "rpc/rpc.h"
37 #endif
38
39 /*#define RNA_DEBUG_RPC 1 */
40
41 typedef enum
42 {
43 RPC_STATE_CALL,
44 RPC_STATE_REPLY,
45 RPC_STATE_DONE
46 } RPCState;
47
48 typedef enum
49 {
50 RPC_TCP_STATE_FRAG,
51 RPC_TCP_STATE_HEADER,
52 RPC_TCP_STATE_CRED,
53 RPC_TCP_STATE_CRED_DATA,
54 RPC_TCP_STATE_VERIFY,
55 RPC_TCP_STATE_VERIFY_DATA,
56 RPC_TCP_STATE_REPLY_HEADER,
57 RPC_TCP_STATE_PARTIAL,
58 RPC_TCP_STATE_DONE
59 } RPCTCPState;
60
61 typedef enum
62 {
63 RPC_REPLY_BEGIN,
64 RPC_REPLY_MULTI,
65 RPC_REPLY_MID
66 } RPCReplyState;
67
68 #define min(x,y) ((x)<(y) ? (x):(y))
69
70 #define RPC_TYPE_CALL 0
71 #define RPC_TYPE_REPLY 1
72
73 #define RPC_PROGRAM_PORTMAP 100000
74 #define RPC_PORTMAP_GETPORT 3
75
76 #define RPC_REPLY_ACCEPTED 0
77 #define RPC_REPLY_DENIED 1
78
79 #define RPC_MAX_ACCEPTED 4
80 #define RPC_MAX_DENIED 5
81
82 #define RPC_TCP_FRAG_MASK 0x80000000
83
84 /* sizeof(ServiceRPCCall)+sizeof(_SERVICE_RPC_PORTMAP)==56 */
85 #define RPC_MAX_TCP_PACKET_SIZE 56
86
87 #pragma pack(1)
88
89 typedef struct _SERVICE_RPC_FRAG
90 {
91 uint32_t length;
92 } ServiceRPCFragment;
93
94 typedef struct _SERVICE_RPC_AUTH
95 {
96 uint32_t flavor;
97 uint32_t length;
98 } ServiceRPCAuth;
99
100 typedef struct _SERVICE_RPC_PORTMAP
101 {
102 uint32_t program;
103 uint32_t version;
104 uint32_t proto;
105 uint32_t port;
106 } ServiceRPCPortmap;
107
108 typedef struct _SERVICE_RPC_PORTMAP_REPLY
109 {
110 uint32_t port;
111 } ServiceRPCPortmapReply;
112
113 typedef struct _SERVICE_RPC_HEADER
114 {
115 uint32_t xid;
116 uint32_t type;
117 } ServiceRPC;
118
119 typedef struct _SERVICE_RPC_CALL_HEADER
120 {
121 ServiceRPC header;
122 uint32_t version;
123 uint32_t program;
124 uint32_t program_version;
125 uint32_t procedure;
126 ServiceRPCAuth cred;
127 ServiceRPCAuth verify;
128 } ServiceRPCCall;
129
130 typedef struct _SERVICE_RPC_REPLY_HEADER
131 {
132 ServiceRPC header;
133 uint32_t reply_state;
134 ServiceRPCAuth verify;
135 uint32_t state;
136 } ServiceRPCReply;
137
138 #pragma pack()
139
140 typedef struct _SERVICE_RPC_DATA
141 {
142 RPCState state;
143 RPCTCPState tcpstate[APP_ID_APPID_SESSION_DIRECTION_MAX];
144 RPCTCPState tcpfragstate[APP_ID_APPID_SESSION_DIRECTION_MAX];
145 uint32_t program;
146 uint32_t procedure;
147 uint32_t xid;
148 uint32_t proto;
149 uint32_t tcpsize[APP_ID_APPID_SESSION_DIRECTION_MAX];
150 uint32_t tcpfragpos[APP_ID_APPID_SESSION_DIRECTION_MAX];
151 uint32_t tcpauthsize[APP_ID_APPID_SESSION_DIRECTION_MAX];
152 uint32_t tcppos[APP_ID_APPID_SESSION_DIRECTION_MAX];
153 uint8_t tcpdata[APP_ID_APPID_SESSION_DIRECTION_MAX][RPC_MAX_TCP_PACKET_SIZE];
154 int once;
155 } ServiceRPCData;
156
157 static int rpc_init(const InitServiceAPI * const init_api);
158 static int rpc_validate(ServiceValidationArgs* args);
159 static int rpc_tcp_validate(ServiceValidationArgs* args);
160 static void rpc_clean(const CleanServiceAPI * const clean_api);
161
162 static tRNAServiceElement svc_element =
163 {
164 .next = NULL,
165 .validate = &rpc_validate,
166 .detectorType = DETECTOR_TYPE_DECODER,
167 .name = "rpc",
168 .ref_count = 1,
169 .current_ref_count = 1,
170 };
171 static tRNAServiceElement tcp_svc_element =
172 {
173 .next = NULL,
174 .validate = &rpc_tcp_validate,
175 .detectorType = DETECTOR_TYPE_DECODER,
176 .name = "tcp rpc",
177 .ref_count = 1,
178 .current_ref_count = 1,
179 };
180
181 #define RPC_PORT_PORTMAPPER 111
182 #define RPC_PORT_NFS 2049
183 #define RPC_PORT_MOUNTD 4046
184 #define RPC_PORT_NLOCKMGR 4045
185
186 static RNAServiceValidationPort pp[] =
187 {
188 {&rpc_validate, RPC_PORT_PORTMAPPER, IPPROTO_UDP},
189 {&rpc_validate, RPC_PORT_PORTMAPPER, IPPROTO_UDP, 1},
190 {&rpc_tcp_validate, RPC_PORT_PORTMAPPER, IPPROTO_TCP},
191 {&rpc_validate, RPC_PORT_NFS, IPPROTO_UDP},
192 {&rpc_validate, RPC_PORT_NFS, IPPROTO_UDP, 1},
193 {&rpc_tcp_validate, RPC_PORT_NFS, IPPROTO_TCP},
194 {&rpc_validate, RPC_PORT_MOUNTD, IPPROTO_UDP},
195 {&rpc_validate, RPC_PORT_MOUNTD, IPPROTO_UDP, 1},
196 {&rpc_tcp_validate, RPC_PORT_MOUNTD, IPPROTO_TCP},
197 {&rpc_validate, RPC_PORT_NLOCKMGR, IPPROTO_UDP},
198 {&rpc_validate, RPC_PORT_NLOCKMGR, IPPROTO_UDP, 1},
199 {&rpc_tcp_validate, RPC_PORT_NLOCKMGR, IPPROTO_TCP},
200 {NULL, 0, 0}
201 };
202
203 tRNAServiceValidationModule rpc_service_mod =
204 {
205 "RPC",
206 &rpc_init,
207 pp,
208 .clean = rpc_clean
209 };
210
211 typedef struct _RPC_PROGRAM
212 {
213 struct _RPC_PROGRAM *next;
214 uint32_t program;
215 char *name;
216 } RPCProgram;
217
218 static RPCProgram *rpc_programs = NULL;
219
220 static uint8_t rpc_reply_accepted_pattern[8] = {0,0,0,1,0,0,0,0};
221 static uint8_t rpc_reply_denied_pattern[8] = {0,0,0,1,0,0,0,1};
222
223 static tAppRegistryEntry appIdRegistry[] =
224 {
225 {APP_ID_SUN_RPC, APPINFO_FLAG_SERVICE_ADDITIONAL | APPINFO_FLAG_SERVICE_UDP_REVERSED}
226 };
227
228 static int16_t app_id = 0;
229
230 static int rpc_init(const InitServiceAPI * const init_api)
231 {
232 struct rpcent *rpc;
233 RPCProgram *prog;
234
235 #ifdef TARGET_BASED
236 app_id = init_api->dpd->addProtocolReference("sunrpc");
237 #endif
238
239 if (!rpc_programs)
240 {
241 while ((rpc = getrpcent()))
242 {
243 if (rpc->r_name)
244 {
245 prog = calloc(1, sizeof(RPCProgram));
246 if (prog)
247 {
248 prog->program = rpc->r_number;
249 prog->next = rpc_programs;
250 rpc_programs = prog;
251 prog->name = strdup(rpc->r_name);
252 if (!prog->name)
253 _dpd.errMsg("failed to allocate rpc program name");
254 }
255 }
256 }
257 endrpcent();
258 }
259
260 init_api->RegisterPattern(&rpc_tcp_validate, IPPROTO_TCP, rpc_reply_accepted_pattern,
261 sizeof(rpc_reply_accepted_pattern), 8, "rpc", init_api->pAppidConfig);
262 init_api->RegisterPattern(&rpc_tcp_validate, IPPROTO_TCP, rpc_reply_denied_pattern,
263 sizeof(rpc_reply_denied_pattern), 8, "rpc", init_api->pAppidConfig);
264 init_api->RegisterPattern(&rpc_validate, IPPROTO_UDP, rpc_reply_accepted_pattern,
265 sizeof(rpc_reply_accepted_pattern), 4, "rpc", init_api->pAppidConfig);
266 init_api->RegisterPattern(&rpc_validate, IPPROTO_UDP, rpc_reply_denied_pattern,
267 sizeof(rpc_reply_denied_pattern), 4, "rpc", init_api->pAppidConfig);
268
269 unsigned i;
270 for (i=0; i < sizeof(appIdRegistry)/sizeof(*appIdRegistry); i++)
271 {
272 _dpd.debugMsg(DEBUG_LOG,"registering appId: %d\n",appIdRegistry[i].appId);
273 init_api->RegisterAppId(&rpc_validate, appIdRegistry[i].appId, appIdRegistry[i].additionalInfo, init_api->pAppidConfig);
274 }
275
276 return 0;
277 }
278
279 static const RPCProgram *FindRPCProgram(uint32_t program)
280 {
281 RPCProgram *rpc;
282
283 for (rpc=rpc_programs; rpc; rpc=rpc->next)
284 {
285 if (program == rpc->program) break;
286 }
287 return rpc;
288 }
289
290 static int validate_packet(const uint8_t *data, uint16_t size, int dir,
291 tAppIdData *flowp, SFSnortPacket *pkt, ServiceRPCData *rd,
292 const char * *pname, uint32_t *program)
293 {
294 const ServiceRPCCall *call;
295 const ServiceRPCReply *reply;
296 const ServiceRPC *rpc;
297 const ServiceRPCPortmap *pm;
298 const ServiceRPCAuth *a;
299 const ServiceRPCPortmapReply *pmr;
300 uint32_t tmp;
301 uint32_t val;
302 const uint8_t *end;
303 tAppIdData *pf;
304 const RPCProgram *rprog;
305
306 if (!size) return SERVICE_INPROCESS;
307
308 end = data + size;
309
310 if (flowp->proto == IPPROTO_UDP)
311 {
312 if (!rd->once)
313 {
314 rd->once = 1;
315 if (size < sizeof(ServiceRPC)) return SERVICE_NOMATCH;
316 rpc = (ServiceRPC *)data;
317 if (ntohl(rpc->type) == RPC_TYPE_REPLY)
318 {
319 setAppIdFlag(flowp, APPID_SESSION_UDP_REVERSED);
320 rd->state = RPC_STATE_REPLY;
321 dir = APP_ID_FROM_RESPONDER;
322 }
323 }
324 else if (getAppIdFlag(flowp, APPID_SESSION_UDP_REVERSED))
325 {
326 dir = (dir == APP_ID_FROM_RESPONDER) ? APP_ID_FROM_INITIATOR:APP_ID_FROM_RESPONDER;
327 }
328 }
329
330 switch (rd->state)
331 {
332 case RPC_STATE_CALL:
333 if (dir != APP_ID_FROM_INITIATOR) return SERVICE_INPROCESS;
334 rd->state = RPC_STATE_DONE;
335 if (size < sizeof(ServiceRPCCall)) return SERVICE_NOT_COMPATIBLE;
336 call = (ServiceRPCCall *)data;
337 if (ntohl(call->header.type) != RPC_TYPE_CALL) return SERVICE_NOT_COMPATIBLE;
338 if (ntohl(call->version) != 2) return SERVICE_NOT_COMPATIBLE;
339 rd->program = ntohl(call->program);
340 rd->procedure = ntohl(call->procedure);
341 tmp = ntohl(call->cred.length);
342 if (sizeof(ServiceRPCCall)+tmp > size) return SERVICE_NOT_COMPATIBLE;
343 data += (sizeof(ServiceRPCCall) - sizeof(ServiceRPCAuth)) + tmp;
344 a = (ServiceRPCAuth *)data;
345 tmp = ntohl(a->length);
346 if (tmp+sizeof(ServiceRPCAuth) > (unsigned)(end-data)) return SERVICE_NOT_COMPATIBLE;
347 data += sizeof(ServiceRPCAuth) + tmp;
348 if (rd->program >= 0x60000000) return SERVICE_NOT_COMPATIBLE;
349 switch (rd->program)
350 {
351 case RPC_PROGRAM_PORTMAP:
352 switch (rd->procedure)
353 {
354 case RPC_PORTMAP_GETPORT:
355 if (end-data < (int)sizeof(ServiceRPCPortmap)) return SERVICE_NOT_COMPATIBLE;
356 pm = (ServiceRPCPortmap *)data;
357 rd->proto = pm->proto;
358 break;
359 default:
360 break;
361 }
362 break;
363 default:
364 break;
365 }
366 rd->xid = call->header.xid;
367 rd->state = RPC_STATE_REPLY;
368 break;
369 case RPC_STATE_REPLY:
370 if (dir != APP_ID_FROM_RESPONDER) return SERVICE_INPROCESS;
371 rd->state = RPC_STATE_DONE;
372 if (size < sizeof(ServiceRPCReply)) return SERVICE_NOMATCH;
373 reply = (ServiceRPCReply *)data;
374 if (ntohl(reply->header.type) != RPC_TYPE_REPLY) return SERVICE_NOMATCH;
375 if (rd->xid != reply->header.xid && rd->xid != 0xFFFFFFFF) return SERVICE_NOMATCH;
376 tmp = ntohl(reply->verify.length);
377 if (sizeof(ServiceRPCReply)+tmp > size)
378 return SERVICE_NOMATCH;
379 data += sizeof(ServiceRPCReply) + tmp;
380 tmp = ntohl(reply->reply_state);
381 val = ntohl(reply->state);
382 if (tmp == RPC_REPLY_ACCEPTED)
383 {
384 if (val > RPC_MAX_ACCEPTED) return SERVICE_NOMATCH;
385 if (rd->xid == 0xFFFFFFFF && reply->header.xid != 0xFFFFFFFF)
386 {
387 rd->state = RPC_STATE_CALL;
388 return SERVICE_INPROCESS;
389 }
390 *program = rd->program;
391 switch (rd->program)
392 {
393 case RPC_PROGRAM_PORTMAP:
394 switch (rd->procedure)
395 {
396 case RPC_PORTMAP_GETPORT:
397 if (end-data < (int)sizeof(ServiceRPCPortmapReply))
398 return SERVICE_NOMATCH;
399 pmr = (ServiceRPCPortmapReply *)data;
400 if (pmr->port)
401 {
402 sfaddr_t *sip;
403 sfaddr_t *dip;
404
405 dip = GET_DST_IP(pkt);
406 sip = GET_SRC_IP(pkt);
407 tmp = ntohl(pmr->port);
408 #ifdef TARGET_BASED
409 pf = rpc_service_mod.api->flow_new(flowp, pkt, dip, 0, sip, (uint16_t)tmp, (uint8_t)ntohl(rd->proto), app_id, 0);
410 if (pf)
411 {
412 rpc_service_mod.api->data_add_id(pf, (uint16_t)tmp,
413 flowp->proto==IPPROTO_TCP ? &tcp_svc_element:&svc_element);
414 pf->rnaServiceState = RNA_STATE_STATEFUL;
415 setAppIdFlag(pf,
416 getAppIdFlag(flowp,
417 APPID_SESSION_RESPONDER_MONITORED |
418 APPID_SESSION_INITIATOR_MONITORED |
419 APPID_SESSION_SPECIAL_MONITORED |
420 APPID_SESSION_RESPONDER_CHECKED |
421 APPID_SESSION_INITIATOR_CHECKED |
422 APPID_SESSION_DISCOVER_APP |
423 APPID_SESSION_DISCOVER_USER));
424 }
425 #endif
426 }
427 break;
428 default:
429 break;
430 }
431 *pname = "portmap";
432 break;
433 default:
434 rprog = FindRPCProgram(rd->program);
435 if (rprog && rprog->name) *pname = rprog->name;
436 break;
437 }
438 }
439 else if (tmp == RPC_REPLY_DENIED)
440 {
441 if (val > RPC_MAX_DENIED) return SERVICE_NOMATCH;
442 }
443 else return SERVICE_NOMATCH;
444 rd->state = RPC_STATE_CALL;
445 return SERVICE_SUCCESS;
446 default:
447 return SERVICE_NOMATCH;
448 }
449 return SERVICE_INPROCESS;
450 }
451
452 static int rpc_validate(ServiceValidationArgs* args)
453 {
454 static char subname[64];
455 ServiceRPCData *rd;
456 RNAServiceSubtype sub;
457 RNAServiceSubtype *subtype;
458 uint32_t program = 0;
459 const char *pname = NULL;
460 int rval;
461 tAppIdData *flowp = args->flowp;
462 const uint8_t *data = args->data;
463 SFSnortPacket *pkt = args->pkt;
464 const int dir = args->dir;
465 uint16_t size = args->size;
466
467 if (!size)
468 {
469 rval = SERVICE_INPROCESS;
470 goto done;
471 }
472
473 rd = rpc_service_mod.api->data_get(flowp, rpc_service_mod.flow_data_index);
474 if (!rd)
475 {
476 rd = calloc(1, sizeof(*rd));
477 if (!rd)
478 return SERVICE_ENOMEM;
479 if (rpc_service_mod.api->data_add(flowp, rd, rpc_service_mod.flow_data_index, &free))
480 {
481 free(rd);
482 return SERVICE_ENOMEM;
483 }
484 rd->state = (dir == APP_ID_FROM_INITIATOR) ? RPC_STATE_CALL:RPC_STATE_REPLY;
485 rd->xid = 0xFFFFFFFF;
486 }
487
488 #ifdef RNA_DEBUG_RPC
489 fprintf(SF_DEBUG_FILE, "Begin %u -> %u %u %d state %d\n", pkt->src_port, pkt->dst_port, flowp->proto, dir, rd->state);
490 #endif
491
492 rval = validate_packet(data, size, dir, flowp, pkt, rd, &pname, &program);
493
494 #ifdef RNA_DEBUG_RPC
495 fprintf(SF_DEBUG_FILE, "End %u -> %u %u %d state %d rval %d\n", pkt->src_port, pkt->dst_port, flowp->proto, dir, rd->state, rval);
496 #endif
497
498 done:
499 switch (rval)
500 {
501 case SERVICE_INPROCESS:
502 if (!getAppIdFlag(flowp, APPID_SESSION_SERVICE_DETECTED))
503 {
504 rpc_service_mod.api->service_inprocess(flowp, pkt, dir, &svc_element, NULL);
505 }
506 return SERVICE_INPROCESS;
507
508 case SERVICE_SUCCESS:
509 if (!getAppIdFlag(flowp, APPID_SESSION_SERVICE_DETECTED))
510 {
511 if (pname && *pname)
512 {
513 memset(&sub, 0, sizeof(sub));
514 sub.service = pname;
515 subtype = ⊂
516 }
517 else if (program)
518 {
519 snprintf(subname, sizeof(subname), "(%u)", program);
520 memset(&sub, 0, sizeof(sub));
521 sub.service = subname;
522 subtype = ⊂
523 }
524 else subtype = NULL;
525 rpc_service_mod.api->add_service(flowp, pkt, dir, &svc_element,
526 APP_ID_SUN_RPC, NULL, NULL, subtype, NULL);
527 }
528 setAppIdFlag(flowp, APPID_SESSION_CONTINUE);
529 return SERVICE_SUCCESS;
530
531 case SERVICE_NOT_COMPATIBLE:
532 if (!getAppIdFlag(flowp, APPID_SESSION_SERVICE_DETECTED))
533 {
534 rpc_service_mod.api->incompatible_data(flowp, pkt, dir, &svc_element,
535 rpc_service_mod.flow_data_index,
536 args->pConfig, NULL);
537 }
538 clearAppIdFlag(flowp, APPID_SESSION_CONTINUE);
539 return SERVICE_NOT_COMPATIBLE;
540
541 case SERVICE_NOMATCH:
542 if (!getAppIdFlag(flowp, APPID_SESSION_SERVICE_DETECTED))
543 {
544 rpc_service_mod.api->fail_service(flowp, pkt, dir, &svc_element,
545 rpc_service_mod.flow_data_index,
546 args->pConfig, NULL);
547 }
548 clearAppIdFlag(flowp, APPID_SESSION_CONTINUE);
549 return SERVICE_NOMATCH;
550 default:
551 return rval;
552 }
553 }
554
555 static int rpc_tcp_validate(ServiceValidationArgs* args)
556 {
557 ServiceRPCData *rd;
558 const ServiceRPCFragment *frag;
559 uint32_t length;
560 uint32_t fragsize;
561 int ret;
562 int retval = -1;
563 ServiceRPCCall *call;
564 ServiceRPCReply *reply;
565
566 static char subname[64];
567 RNAServiceSubtype sub;
568 RNAServiceSubtype *subtype;
569 uint32_t program = 0;
570 const char *pname = NULL;
571
572 tAppIdData *flowp = args->flowp;
573 const uint8_t *data = args->data;
574 SFSnortPacket *pkt = args->pkt;
575 const int dir = args->dir;
576 uint16_t size = args->size;
577
578 if (!size)
579 goto inprocess;
580
581 rd = rpc_service_mod.api->data_get(flowp, rpc_service_mod.flow_data_index);
582 if (!rd)
583 {
584 rd = calloc(1, sizeof(*rd));
585 if (!rd)
586 return SERVICE_ENOMEM;
587 if (rpc_service_mod.api->data_add(flowp, rd, rpc_service_mod.flow_data_index, &free))
588 {
589 free(rd);
590 return SERVICE_ENOMEM;
591 }
592 rd->state = RPC_STATE_CALL;
593 for (ret=0; ret<APP_ID_APPID_SESSION_DIRECTION_MAX; ret++)
594 {
595 rd->tcpstate[ret] = RPC_TCP_STATE_FRAG;
596 rd->tcpfragstate[ret] = RPC_TCP_STATE_HEADER;
597 }
598 }
599
600 while (size)
601 {
602 fragsize = min(size, (rd->tcpsize[dir] & ~RPC_TCP_FRAG_MASK) -
603 rd->tcpfragpos[dir]);
604
605 switch (rd->tcpstate[dir])
606 {
607 case RPC_TCP_STATE_FRAG:
608 if (size < sizeof(ServiceRPCFragment)) goto bail;
609 frag = (ServiceRPCFragment *)data;
610 data += sizeof(ServiceRPCFragment);
611 size -= sizeof(ServiceRPCFragment);
612
613 rd->tcpsize[dir] = ntohl(frag->length);
614 rd->tcpfragpos[dir] = 0;
615 rd->tcpstate[dir] = rd->tcpfragstate[dir];
616 break;
617 case RPC_TCP_STATE_HEADER:
618 if (dir == APP_ID_FROM_INITIATOR)
619 {
620 length = min(fragsize, offsetof(ServiceRPCCall, cred) -
621 rd->tcppos[dir]);
622 memcpy(&rd->tcpdata[dir][rd->tcppos[dir]], data, length);
623 rd->tcppos[dir] += length;
624 rd->tcpfragpos[dir] += length;
625 data += length;
626 size -= length;
627 if (rd->tcppos[dir] >= offsetof(ServiceRPCCall, cred))
628 {
629 call = (ServiceRPCCall *)rd->tcpdata[dir];
630 if (ntohl(call->header.type) != RPC_TYPE_CALL) goto bail;
631 if (ntohl(call->version) != 2) goto bail;
632 rd->tcpstate[dir] = RPC_TCP_STATE_CRED;
633 rd->tcppos[dir] = 0;
634 }
635 }
636 else
637 {
638 length = min(fragsize, offsetof(ServiceRPCReply, verify) -
639 rd->tcppos[dir]);
640 memcpy(&rd->tcpdata[dir][rd->tcppos[dir]], data, length);
641 rd->tcppos[dir] += length;
642 rd->tcpfragpos[dir] += length;
643 data += length;
644 size -= length;
645 if (rd->tcppos[dir] >= offsetof(ServiceRPCReply, verify))
646 {
647 reply = (ServiceRPCReply *)rd->tcpdata[dir];
648 if (ntohl(reply->header.type) != RPC_TYPE_REPLY) goto fail;
649 rd->tcpstate[dir] = RPC_TCP_STATE_VERIFY;
650 rd->tcppos[dir] = 0;
651 }
652 }
653 break;
654 case RPC_TCP_STATE_CRED:
655 if (dir != APP_ID_FROM_INITIATOR)
656 goto bail;
657 length = min(fragsize, sizeof(ServiceRPCAuth) - rd->tcppos[dir]);
658 memcpy(&rd->tcpdata[dir][offsetof(ServiceRPCCall, cred)+rd->tcppos[dir]],
659 data, length);
660 rd->tcppos[dir] += length;
661 rd->tcpfragpos[dir] += length;
662 data += length;
663 size -= length;
664 if (rd->tcppos[dir] >= sizeof(ServiceRPCAuth))
665 {
666 call = (ServiceRPCCall *)rd->tcpdata[dir];
667 length = ntohl(call->cred.length);
668 if (length > (rd->tcpsize[dir] & ~RPC_TCP_FRAG_MASK) ||
669 rd->tcpfragpos[dir]+length > (rd->tcpsize[dir] & ~RPC_TCP_FRAG_MASK))
670 goto bail;
671 rd->tcpauthsize[dir] = length;
672 rd->tcpstate[dir] = RPC_TCP_STATE_CRED_DATA;
673 rd->tcppos[dir] = 0;
674 }
675 break;
676 case RPC_TCP_STATE_CRED_DATA:
677 if (dir != APP_ID_FROM_INITIATOR)
678 goto bail;
679 length = min(fragsize, rd->tcpauthsize[dir] - rd->tcppos[dir]);
680 rd->tcppos[dir] += length;
681 rd->tcpfragpos[dir] += length;
682 data += length;
683 size -= length;
684 if (rd->tcppos[dir] >= rd->tcpauthsize[dir])
685 {
686 call = (ServiceRPCCall *)rd->tcpdata[dir];
687 call->cred.flavor = 0;
688 call->cred.length = 0;
689 rd->tcpstate[dir] = RPC_TCP_STATE_VERIFY;
690 rd->tcppos[dir] = 0;
691 }
692 break;
693 case RPC_TCP_STATE_VERIFY:
694 length = min(fragsize, sizeof(ServiceRPCAuth) - rd->tcppos[dir]);
695 if (dir == APP_ID_FROM_INITIATOR)
696 memcpy(&rd->tcpdata[dir][offsetof(ServiceRPCCall, verify)+rd->tcppos[dir]],
697 data, length);
698 else
699 memcpy(&rd->tcpdata[dir][offsetof(ServiceRPCReply, verify)+rd->tcppos[dir]],
700 data, length);
701 rd->tcppos[dir] += length;
702 rd->tcpfragpos[dir] += length;
703 data += length;
704 size -= length;
705 fragsize -= length;
706 if (rd->tcppos[dir] >= sizeof(ServiceRPCAuth))
707 {
708 if (dir == APP_ID_FROM_INITIATOR)
709 {
710 call = (ServiceRPCCall *)rd->tcpdata[dir];
711 length = ntohl(call->verify.length);
712 }
713 else
714 {
715 reply = (ServiceRPCReply *)rd->tcpdata[dir];
716 length = ntohl(reply->verify.length);
717 }
718 if (length > (rd->tcpsize[dir] & ~RPC_TCP_FRAG_MASK) ||
719 rd->tcpfragpos[dir]+length > (rd->tcpsize[dir] & ~RPC_TCP_FRAG_MASK))
720 goto bail;
721 rd->tcpauthsize[dir] = length;
722 rd->tcpstate[dir] = RPC_TCP_STATE_VERIFY_DATA;
723 rd->tcppos[dir] = 0;
724 }
725 else
726 {
727 break;
728 }
729 case RPC_TCP_STATE_VERIFY_DATA:
730 length = min(fragsize, rd->tcpauthsize[dir] - rd->tcppos[dir]);
731 rd->tcppos[dir] += length;
732 rd->tcpfragpos[dir] += length;
733 data += length;
734 size -= length;
735 if (rd->tcppos[dir] >= rd->tcpauthsize[dir])
736 {
737 if (dir == APP_ID_FROM_INITIATOR)
738 {
739 call = (ServiceRPCCall *)rd->tcpdata[dir];
740 call->verify.flavor = 0;
741 call->verify.length = 0;
742 rd->tcpstate[dir] = RPC_TCP_STATE_PARTIAL;
743 rd->tcppos[dir] = sizeof(ServiceRPCCall);
744 if (rd->tcpfragpos[dir] >= (rd->tcpsize[dir] & ~RPC_TCP_FRAG_MASK))
745 {
746 if (rd->tcpsize[dir] & RPC_TCP_FRAG_MASK)
747 {
748
749 #ifdef RNA_DEBUG_RPC
750 fprintf(SF_DEBUG_FILE, "V Begin %u -> %u %u %d state %d\n", pkt->src_port, pkt->dst_port, flowp->proto, dir, rd->state);
751 #endif
752
753 ret = validate_packet(rd->tcpdata[dir], rd->tcppos[dir], dir, flowp, pkt,
754 rd, &pname, &program);
755
756 #ifdef RNA_DEBUG_RPC
757 fprintf(SF_DEBUG_FILE, "V End %u -> %u %u %d state %d rval %d\n", pkt->src_port, pkt->dst_port, flowp->proto, dir, rd->state, ret);
758 #endif
759
760 if (retval == -1) retval = ret;
761 rd->tcpfragstate[dir] = RPC_TCP_STATE_HEADER;
762 rd->tcppos[dir] = 0;
763 }
764 else rd->tcpfragstate[dir] = rd->tcpstate[dir];
765 rd->tcpstate[dir] = RPC_TCP_STATE_FRAG;
766 }
767 }
768 else
769 {
770 reply = (ServiceRPCReply *)rd->tcpdata[dir];
771 reply->verify.flavor = 0;
772 reply->verify.length = 0;
773 rd->tcpstate[dir] = RPC_TCP_STATE_REPLY_HEADER;
774 if (rd->tcpfragpos[dir]+sizeof(uint32_t) > (rd->tcpsize[dir] & ~RPC_TCP_FRAG_MASK))
775 goto bail;
776 rd->tcppos[dir] = 0;
777 }
778 }
779 break;
780 case RPC_TCP_STATE_REPLY_HEADER:
781 if (dir != APP_ID_FROM_RESPONDER) goto bail;
782 length = min(fragsize, sizeof(uint32_t) - rd->tcppos[dir]);
783 memcpy(&rd->tcpdata[dir][offsetof(ServiceRPCReply, state)+rd->tcppos[dir]],
784 data, length);
785 rd->tcppos[dir] += length;
786 rd->tcpfragpos[dir] += length;
787 data += length;
788 size -= length;
789
790 if (rd->tcppos[dir] >= sizeof(uint32_t))
791 {
792 rd->tcpstate[dir] = RPC_TCP_STATE_PARTIAL;
793 rd->tcppos[dir] = sizeof(ServiceRPCReply);
794 }
795 if (rd->tcpfragpos[dir] >= (rd->tcpsize[dir] & ~RPC_TCP_FRAG_MASK))
796 {
797 fragsize = 0;
798 }
799 else
800 {
801 break;
802 }
803 case RPC_TCP_STATE_PARTIAL:
804 if (rd->tcppos[dir] < RPC_MAX_TCP_PACKET_SIZE && fragsize)
805 {
806 length = min(fragsize, RPC_MAX_TCP_PACKET_SIZE - rd->tcppos[dir]);
807 memcpy(&rd->tcpdata[dir][rd->tcppos[dir]], data, length);
808 rd->tcppos[dir] += length;
809 }
810 else
811 {
812 length = fragsize;
813 }
814 rd->tcpfragpos[dir] += length;
815 data += length;
816 size -= length;
817 if (rd->tcpfragpos[dir] >= (rd->tcpsize[dir] & ~RPC_TCP_FRAG_MASK))
818 {
819 if (rd->tcpsize[dir] & RPC_TCP_FRAG_MASK)
820 {
821
822 #ifdef RNA_DEBUG_RPC
823 fprintf(SF_DEBUG_FILE, "P Begin %u -> %u %u %d state %d\n", pkt->src_port, pkt->dst_port, flowp->proto, dir, rd->state);
824 #endif
825
826 ret = validate_packet(rd->tcpdata[dir], rd->tcppos[dir], dir, flowp, pkt,
827 rd, &pname, &program);
828
829 #ifdef RNA_DEBUG_RPC
830 fprintf(SF_DEBUG_FILE, "P End %u -> %u %u %d state %d rval %d\n", pkt->src_port, pkt->dst_port, flowp->proto, dir, rd->state, ret);
831 #endif
832
833 if (retval == -1) retval = ret;
834 rd->tcpfragstate[dir] = RPC_TCP_STATE_HEADER;
835 rd->tcppos[dir] = 0;
836 }
837 else rd->tcpfragstate[dir] = rd->tcpstate[dir];
838 rd->tcpstate[dir] = RPC_TCP_STATE_FRAG;
839 }
840 break;
841 default:
842 if (retval == -1) goto fail;
843 else
844 {
845 clearAppIdFlag(flowp, APPID_SESSION_CONTINUE);
846 goto done;
847 }
848 }
849 if (rd->tcpstate[dir] != RPC_TCP_STATE_FRAG &&
850 rd->tcpstate[dir] != RPC_TCP_STATE_PARTIAL &&
851 rd->tcpfragpos[dir] >= (rd->tcpsize[dir] & ~RPC_TCP_FRAG_MASK))
852 {
853 if (rd->tcpsize[dir] & RPC_TCP_FRAG_MASK) goto bail;
854 rd->tcpfragstate[dir] = rd->tcpstate[dir];
855 rd->tcpstate[dir] = RPC_TCP_STATE_FRAG;
856 }
857 }
858 if (retval == -1) retval = SERVICE_INPROCESS;
859
860 done:
861 switch (retval)
862 {
863 case SERVICE_INPROCESS:
864 inprocess:
865 if (!getAppIdFlag(flowp, APPID_SESSION_SERVICE_DETECTED))
866 {
867 rpc_service_mod.api->service_inprocess(flowp, pkt, dir, &tcp_svc_element, NULL);
868 }
869 return SERVICE_INPROCESS;
870
871 case SERVICE_SUCCESS:
872 if (!getAppIdFlag(flowp, APPID_SESSION_SERVICE_DETECTED))
873 {
874 if (pname && *pname)
875 {
876 memset(&sub, 0, sizeof(sub));
877 sub.service = pname;
878 subtype = ⊂
879 }
880 else if (program)
881 {
882 sprintf(subname, "(%u)", program);
883 memset(&sub, 0, sizeof(sub));
884 sub.service = subname;
885 subtype = ⊂
886 }
887 else subtype = NULL;
888 rpc_service_mod.api->add_service(flowp, pkt, dir, &tcp_svc_element,
889 APP_ID_SUN_RPC, NULL, NULL, subtype, NULL);
890 }
891 setAppIdFlag(flowp, APPID_SESSION_CONTINUE);
892 return SERVICE_SUCCESS;
893
894 case SERVICE_NOT_COMPATIBLE:
895 if (!getAppIdFlag(flowp, APPID_SESSION_SERVICE_DETECTED))
896 {
897 rpc_service_mod.api->incompatible_data(flowp, pkt, dir, &tcp_svc_element,
898 rpc_service_mod.flow_data_index,
899 args->pConfig, NULL);
900 }
901 clearAppIdFlag(flowp, APPID_SESSION_CONTINUE);
902 return SERVICE_NOT_COMPATIBLE;
903
904 case SERVICE_NOMATCH:
905 fail:
906 if (!getAppIdFlag(flowp, APPID_SESSION_SERVICE_DETECTED))
907 {
908 rpc_service_mod.api->fail_service(flowp, pkt, dir, &tcp_svc_element,
909 rpc_service_mod.flow_data_index,
910 args->pConfig, NULL);
911 }
912 clearAppIdFlag(flowp, APPID_SESSION_CONTINUE);
913 return SERVICE_NOMATCH;
914 default:
915 return retval;
916 }
917
918 bail:
919 clearAppIdFlag(flowp, APPID_SESSION_CONTINUE);
920 rd->tcpstate[APP_ID_FROM_INITIATOR] = RPC_TCP_STATE_DONE;
921 rd->tcpstate[APP_ID_FROM_RESPONDER] = RPC_TCP_STATE_DONE;
922 if (dir == APP_ID_FROM_INITIATOR)
923 {
924 if (retval == -1) retval = SERVICE_NOT_COMPATIBLE;
925 }
926 else
927 {
928 if (retval == -1) retval = SERVICE_NOMATCH;
929 }
930 goto done;
931 }
932
933 static void rpc_clean(const CleanServiceAPI * const clean_api)
934 {
935 RPCProgram *prog = NULL;
936
937 while(rpc_programs)
938 {
939 prog = rpc_programs;
940
941 rpc_programs = rpc_programs->next;
942
943 if(prog->name)
944 free(prog->name);
945
946 free(prog);
947 }
948 }