1 /*
2 ** Copyright (C) 2014-2021 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 "flow.h"
30 #include "service_api.h"
31
32 #define LPR_COUNT_THRESHOLD 5
33
34 typedef enum
35 {
36 LPR_STATE_COMMAND,
37 LPR_STATE_RECEIVE,
38 LPR_STATE_REPLY1,
39 LPR_STATE_REPLY,
40 LPR_STATE_IGNORE
41 } LPRState;
42
43 typedef enum
44 {
45 LPR_CMD_PRINT = 1,
46 LPR_CMD_RECEIVE,
47 LPR_CMD_SHORT_STATE,
48 LPR_CMD_LONG_STATE,
49 LPR_CMD_REMOVE
50 } LPRCommand;
51
52 typedef enum
53 {
54 LPR_SUBCMD_ABORT = 1,
55 LPR_SUBCMD_CONTROL,
56 LPR_SUBCMD_DATA
57 } LPRSubCommand;
58
59 typedef struct _SERVICE_LPR_DATA
60 {
61 LPRState state;
62 unsigned no_data_count;
63 unsigned count;
64 } ServiceLPRData;
65
66 static int lpr_init(const InitServiceAPI * const init_api);
67 static int lpr_validate(ServiceValidationArgs* args);
68
69 static tRNAServiceElement svc_element =
70 {
71 .next = NULL,
72 .validate = &lpr_validate,
73 .detectorType = DETECTOR_TYPE_DECODER,
74 .name = "lpr",
75 .ref_count = 1,
76 .current_ref_count = 1,
77 };
78
79 static RNAServiceValidationPort pp[] =
80 {
81 {&lpr_validate, 515, IPPROTO_TCP},
82 {NULL, 0, 0}
83 };
84
85 tRNAServiceValidationModule lpr_service_mod =
86 {
87 "LPR",
88 &lpr_init,
89 pp
90 };
91
92 static tAppRegistryEntry appIdRegistry[] = {{APP_ID_PRINTSRV, 0}};
93
lpr_init(const InitServiceAPI * const init_api)94 static int lpr_init(const InitServiceAPI * const init_api)
95 {
96 unsigned i;
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(&lpr_validate, appIdRegistry[i].appId, appIdRegistry[i].additionalInfo, init_api->pAppidConfig);
101 }
102
103 return 0;
104 }
105
lpr_validate(ServiceValidationArgs * args)106 static int lpr_validate(ServiceValidationArgs* args)
107 {
108 ServiceLPRData *ld;
109 int i;
110 tAppIdData *flowp = args->flowp;
111 const uint8_t *data = args->data;
112 const int dir = args->dir;
113 uint16_t size = args->size;
114
115 if (!size) goto inprocess;
116
117 ld = lpr_service_mod.api->data_get(flowp, lpr_service_mod.flow_data_index);
118 if (!ld)
119 {
120 ld = calloc(1, sizeof(*ld));
121 if (!ld)
122 return SERVICE_ENOMEM;
123 if (lpr_service_mod.api->data_add(flowp, ld, lpr_service_mod.flow_data_index, &free))
124 {
125 free(ld);
126 return SERVICE_ENOMEM;
127 }
128 ld->state = LPR_STATE_COMMAND;
129 }
130
131 switch (ld->state)
132 {
133 case LPR_STATE_COMMAND:
134 if (dir != APP_ID_FROM_INITIATOR)
135 goto bail;
136 if (size < 3) goto bail;
137 switch (*data)
138 {
139 case LPR_CMD_RECEIVE:
140 if (data[size-1] != 0x0A) goto bail;
141 size--;
142 for (i=1; i<size; i++)
143 if (!isprint(data[i]) || isspace(data[i])) goto bail;
144 ld->state = LPR_STATE_REPLY;
145 break;
146 case LPR_CMD_PRINT:
147 ld->state = LPR_STATE_IGNORE;
148 break;
149 case LPR_CMD_SHORT_STATE:
150 ld->state = LPR_STATE_IGNORE;
151 break;
152 case LPR_CMD_LONG_STATE:
153 ld->state = LPR_STATE_IGNORE;
154 break;
155 case LPR_CMD_REMOVE:
156 ld->state = LPR_STATE_IGNORE;
157 break;
158 default:
159 goto bail;
160 }
161 break;
162 case LPR_STATE_RECEIVE:
163 if (dir != APP_ID_FROM_INITIATOR) goto inprocess;
164 if (size < 2) goto bail;
165 switch (*data)
166 {
167 case LPR_SUBCMD_ABORT:
168 if (size != 2) goto bail;
169 if (data[1] != 0x0A) goto bail;
170 ld->state = LPR_STATE_REPLY;
171 break;
172 case LPR_SUBCMD_CONTROL:
173 case LPR_SUBCMD_DATA:
174 if (size < 5) goto bail;
175 if (data[size-1] != 0x0A) goto bail;
176 if (!isdigit(data[1])) goto bail;
177 for (i=2; i<size; i++)
178 {
179 if (data[i] == 0x0A) goto bail;
180 else if (isspace(data[i])) break;
181 if (!isdigit(data[i])) goto bail;
182 }
183 i++;
184 if (i >= size) goto bail;
185 for (; i<size-1; i++)
186 if (!isprint(data[i]) || isspace(data[i])) goto bail;
187 ld->state = LPR_STATE_REPLY1;
188 break;
189 default:
190 goto bail;
191 }
192 break;
193 case LPR_STATE_REPLY1:
194 if (dir != APP_ID_FROM_RESPONDER) goto inprocess;
195 if (size != 1) goto fail;
196 ld->count++;
197 if (ld->count >= LPR_COUNT_THRESHOLD)
198 {
199 ld->state = LPR_STATE_IGNORE;
200 goto success;
201 }
202 ld->state = LPR_STATE_REPLY;
203 break;
204 case LPR_STATE_REPLY:
205 if (dir != APP_ID_FROM_RESPONDER) goto inprocess;
206 if (size != 1) goto fail;
207 ld->count++;
208 if (ld->count >= LPR_COUNT_THRESHOLD)
209 {
210 ld->state = LPR_STATE_IGNORE;
211 goto success;
212 }
213 ld->state = LPR_STATE_RECEIVE;
214 break;
215 case LPR_STATE_IGNORE:
216 break;
217 default:
218 goto bail;
219 }
220 inprocess:
221 lpr_service_mod.api->service_inprocess(flowp, args->pkt, dir, &svc_element, NULL);
222 return SERVICE_INPROCESS;
223
224 success:
225 lpr_service_mod.api->add_service(flowp, args->pkt, dir, &svc_element,
226 APP_ID_PRINTSRV, NULL, NULL, NULL, NULL);
227 return SERVICE_SUCCESS;
228
229 fail:
230 lpr_service_mod.api->fail_service(flowp, args->pkt, dir, &svc_element,
231 lpr_service_mod.flow_data_index, args->pConfig, NULL);
232 return SERVICE_NOMATCH;
233
234 bail:
235 lpr_service_mod.api->incompatible_data(flowp, args->pkt, dir, &svc_element,
236 lpr_service_mod.flow_data_index, args->pConfig, NULL);
237 return SERVICE_NOT_COMPATIBLE;
238 }
239
240