/src/suricata7/rust/src/krb/krb5.rs
Line | Count | Source |
1 | | /* Copyright (C) 2017-2021 Open Information Security Foundation |
2 | | * |
3 | | * You can copy, redistribute or modify this Program under the terms of |
4 | | * the GNU General Public License version 2 as published by the Free |
5 | | * Software Foundation. |
6 | | * |
7 | | * This program is distributed in the hope that it will be useful, |
8 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
9 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
10 | | * GNU General Public License for more details. |
11 | | * |
12 | | * You should have received a copy of the GNU General Public License |
13 | | * version 2 along with this program; if not, write to the Free Software |
14 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
15 | | * 02110-1301, USA. |
16 | | */ |
17 | | |
18 | | // written by Pierre Chifflier <chifflier@wzdftpd.net> |
19 | | |
20 | | use std; |
21 | | use std::ffi::CString; |
22 | | use nom7::{Err, IResult}; |
23 | | use nom7::number::streaming::be_u32; |
24 | | use der_parser::der::der_read_element_header; |
25 | | use der_parser::ber::Class; |
26 | | use kerberos_parser::krb5_parser; |
27 | | use kerberos_parser::krb5::{EncryptionType,ErrorCode,MessageType,PrincipalName,Realm}; |
28 | | use crate::applayer::{self, *}; |
29 | | use crate::core; |
30 | | use crate::core::{AppProto,Flow,ALPROTO_FAILED,ALPROTO_UNKNOWN,Direction}; |
31 | | |
32 | | #[derive(AppLayerEvent)] |
33 | | pub enum KRB5Event { |
34 | | MalformedData, |
35 | | WeakEncryption, |
36 | | } |
37 | | |
38 | | pub struct KRB5State { |
39 | | state_data: AppLayerStateData, |
40 | | |
41 | | pub req_id: u8, |
42 | | |
43 | | pub record_ts: usize, |
44 | | pub defrag_buf_ts: Vec<u8>, |
45 | | pub record_tc: usize, |
46 | | pub defrag_buf_tc: Vec<u8>, |
47 | | |
48 | | /// List of transactions for this session |
49 | | transactions: Vec<KRB5Transaction>, |
50 | | |
51 | | /// tx counter for assigning incrementing id's to tx's |
52 | | tx_id: u64, |
53 | | } |
54 | | |
55 | | impl State<KRB5Transaction> for KRB5State { |
56 | 493k | fn get_transaction_count(&self) -> usize { |
57 | 493k | self.transactions.len() |
58 | 493k | } |
59 | | |
60 | 43.9k | fn get_transaction_by_index(&self, index: usize) -> Option<&KRB5Transaction> { |
61 | 43.9k | self.transactions.get(index) |
62 | 43.9k | } |
63 | | } |
64 | | |
65 | | pub struct KRB5Transaction { |
66 | | /// The message type: AS-REQ, AS-REP, etc. |
67 | | pub msg_type: MessageType, |
68 | | |
69 | | /// The client PrincipalName, if present |
70 | | pub cname: Option<PrincipalName>, |
71 | | /// The server Realm, if present |
72 | | pub realm: Option<Realm>, |
73 | | /// The server PrincipalName, if present |
74 | | pub sname: Option<PrincipalName>, |
75 | | |
76 | | /// Encryption used (only in AS-REP and TGS-REP) |
77 | | pub etype: Option<EncryptionType>, |
78 | | |
79 | | /// Encryption used for ticket |
80 | | pub ticket_etype: Option<EncryptionType>, |
81 | | |
82 | | /// Error code, if request has failed |
83 | | pub error_code: Option<ErrorCode>, |
84 | | |
85 | | /// Message type of request. For using in responses. |
86 | | pub req_type: Option<MessageType>, |
87 | | |
88 | | /// The internal transaction id |
89 | | id: u64, |
90 | | |
91 | | tx_data: applayer::AppLayerTxData, |
92 | | } |
93 | | |
94 | | impl Transaction for KRB5Transaction { |
95 | 86.9k | fn id(&self) -> u64 { |
96 | 86.9k | self.id |
97 | 86.9k | } |
98 | | } |
99 | | |
100 | | impl Default for KRB5State { |
101 | 0 | fn default() -> Self { |
102 | 0 | Self::new() |
103 | 0 | } |
104 | | } |
105 | | |
106 | | impl KRB5State { |
107 | 15.5k | pub fn new() -> KRB5State { |
108 | 15.5k | Self { |
109 | 15.5k | state_data: AppLayerStateData::new(), |
110 | 15.5k | req_id: 0, |
111 | 15.5k | record_ts: 0, |
112 | 15.5k | defrag_buf_ts: Vec::new(), |
113 | 15.5k | record_tc: 0, |
114 | 15.5k | defrag_buf_tc: Vec::new(), |
115 | 15.5k | transactions: Vec::new(), |
116 | 15.5k | tx_id: 0, |
117 | 15.5k | } |
118 | 15.5k | } |
119 | | |
120 | | /// Parse a Kerberos request message |
121 | | /// |
122 | | /// Returns 0 in case of success, or -1 on error |
123 | 383k | fn parse(&mut self, i: &[u8], direction: Direction) -> i32 { |
124 | 383k | match der_read_element_header(i) { |
125 | 382k | Ok((_rem,hdr)) => { |
126 | | // Kerberos messages start with an APPLICATION header |
127 | 382k | if hdr.class() != Class::Application { return 0; } |
128 | 284k | match hdr.tag().0 { |
129 | | 10 => { |
130 | 79.4k | let req = krb5_parser::parse_as_req(i); |
131 | 79.4k | if let Ok((_,kdc_req)) = req { |
132 | 33.6k | let mut tx = self.new_tx(direction); |
133 | 33.6k | tx.msg_type = MessageType::KRB_AS_REQ; |
134 | 33.6k | tx.cname = kdc_req.req_body.cname; |
135 | 33.6k | tx.realm = Some(kdc_req.req_body.realm); |
136 | 33.6k | tx.sname = kdc_req.req_body.sname; |
137 | 33.6k | tx.etype = None; |
138 | 33.6k | self.transactions.push(tx); |
139 | 45.8k | }; |
140 | 79.4k | self.req_id = 10; |
141 | | }, |
142 | | 11 => { |
143 | 25.1k | let res = krb5_parser::parse_as_rep(i); |
144 | 25.1k | if let Ok((_,kdc_rep)) = res { |
145 | 12 | let mut tx = self.new_tx(direction); |
146 | 12 | tx.msg_type = MessageType::KRB_AS_REP; |
147 | 12 | if self.req_id > 0 { |
148 | 11 | // set request type only if previous message |
149 | 11 | // was a request |
150 | 11 | tx.req_type = Some(MessageType(self.req_id.into())); |
151 | 11 | } |
152 | 12 | tx.cname = Some(kdc_rep.cname); |
153 | 12 | tx.realm = Some(kdc_rep.crealm); |
154 | 12 | tx.sname = Some(kdc_rep.ticket.sname); |
155 | 12 | tx.ticket_etype = Some(kdc_rep.ticket.enc_part.etype); |
156 | 12 | tx.etype = Some(kdc_rep.enc_part.etype); |
157 | 12 | self.transactions.push(tx); |
158 | 12 | if test_weak_encryption(kdc_rep.enc_part.etype) { |
159 | 8 | self.set_event(KRB5Event::WeakEncryption); |
160 | 8 | } |
161 | 25.1k | }; |
162 | 25.1k | self.req_id = 0; |
163 | | }, |
164 | | 12 => { |
165 | 80.6k | let req = krb5_parser::parse_tgs_req(i); |
166 | 80.6k | if let Ok((_,kdc_req)) = req { |
167 | 4.76k | let mut tx = self.new_tx(direction); |
168 | 4.76k | tx.msg_type = MessageType::KRB_TGS_REQ; |
169 | 4.76k | tx.cname = kdc_req.req_body.cname; |
170 | 4.76k | tx.realm = Some(kdc_req.req_body.realm); |
171 | 4.76k | tx.sname = kdc_req.req_body.sname; |
172 | 4.76k | tx.etype = None; |
173 | 4.76k | self.transactions.push(tx); |
174 | 75.8k | }; |
175 | 80.6k | self.req_id = 12; |
176 | | }, |
177 | | 13 => { |
178 | 30.9k | let res = krb5_parser::parse_tgs_rep(i); |
179 | 30.9k | if let Ok((_,kdc_rep)) = res { |
180 | 4 | let mut tx = self.new_tx(direction); |
181 | 4 | tx.msg_type = MessageType::KRB_TGS_REP; |
182 | 4 | if self.req_id > 0 { |
183 | 3 | // set request type only if previous message |
184 | 3 | // was a request |
185 | 3 | tx.req_type = Some(MessageType(self.req_id.into())); |
186 | 3 | } |
187 | 4 | tx.cname = Some(kdc_rep.cname); |
188 | 4 | tx.realm = Some(kdc_rep.crealm); |
189 | 4 | tx.ticket_etype = Some(kdc_rep.ticket.enc_part.etype); |
190 | 4 | tx.sname = Some(kdc_rep.ticket.sname); |
191 | 4 | tx.etype = Some(kdc_rep.enc_part.etype); |
192 | 4 | self.transactions.push(tx); |
193 | 4 | if test_weak_encryption(kdc_rep.enc_part.etype) { |
194 | 1 | self.set_event(KRB5Event::WeakEncryption); |
195 | 3 | } |
196 | 30.9k | }; |
197 | 30.9k | self.req_id = 0; |
198 | | }, |
199 | 812 | 14 => { |
200 | 812 | self.req_id = 14; |
201 | 812 | }, |
202 | 1.20k | 15 => { |
203 | 1.20k | self.req_id = 0; |
204 | 1.20k | }, |
205 | | 30 => { |
206 | 59.9k | let res = krb5_parser::parse_krb_error(i); |
207 | 59.9k | if let Ok((_,error)) = res { |
208 | 4.00k | let mut tx = self.new_tx(direction); |
209 | 4.00k | if self.req_id > 0 { |
210 | 555 | // set request type only if previous message |
211 | 555 | // was a request |
212 | 555 | tx.req_type = Some(MessageType(self.req_id.into())); |
213 | 3.44k | } |
214 | 4.00k | tx.msg_type = MessageType::KRB_ERROR; |
215 | 4.00k | tx.cname = error.cname; |
216 | 4.00k | tx.realm = error.crealm; |
217 | 4.00k | tx.sname = Some(error.sname); |
218 | 4.00k | tx.error_code = Some(error.error_code); |
219 | 4.00k | self.transactions.push(tx); |
220 | 55.9k | }; |
221 | 59.9k | self.req_id = 0; |
222 | | }, |
223 | 6.46k | _ => { SCLogDebug!("unknown/unsupported tag {}", hdr.tag()); }, |
224 | | } |
225 | 284k | 0 |
226 | | }, |
227 | | Err(Err::Incomplete(_)) => { |
228 | | SCLogDebug!("Insufficient data while parsing KRB5 data"); |
229 | 205 | self.set_event(KRB5Event::MalformedData); |
230 | 205 | -1 |
231 | | }, |
232 | | Err(_) => { |
233 | | SCLogDebug!("Error while parsing KRB5 data"); |
234 | 179 | self.set_event(KRB5Event::MalformedData); |
235 | 179 | -1 |
236 | | }, |
237 | | } |
238 | 383k | } |
239 | | |
240 | 15.5k | pub fn free(&mut self) { |
241 | | // All transactions are freed when the `transactions` object is freed. |
242 | | // But let's be explicit |
243 | 15.5k | self.transactions.clear(); |
244 | 15.5k | } |
245 | | |
246 | 42.4k | fn new_tx(&mut self, direction: Direction) -> KRB5Transaction { |
247 | 42.4k | self.tx_id += 1; |
248 | 42.4k | KRB5Transaction::new(direction, self.tx_id) |
249 | 42.4k | } |
250 | | |
251 | 96 | fn get_tx_by_id(&mut self, tx_id: u64) -> Option<&KRB5Transaction> { |
252 | 96 | self.transactions.iter().find(|&tx| tx.id == tx_id + 1) |
253 | 96 | } |
254 | | |
255 | 40.7k | fn free_tx(&mut self, tx_id: u64) { |
256 | 40.7k | let tx = self.transactions.iter().position(|tx| tx.id == tx_id + 1); |
257 | 40.7k | debug_assert!(tx.is_some()); |
258 | 40.7k | if let Some(idx) = tx { |
259 | 40.7k | let _ = self.transactions.remove(idx); |
260 | 40.7k | } |
261 | 40.7k | } |
262 | | |
263 | | /// Set an event. The event is set on the most recent transaction. |
264 | 393 | fn set_event(&mut self, event: KRB5Event) { |
265 | 393 | if let Some(tx) = self.transactions.last_mut() { |
266 | 9 | tx.tx_data.set_event(event as u8); |
267 | 384 | } |
268 | 393 | } |
269 | | } |
270 | | |
271 | | impl KRB5Transaction { |
272 | 42.4k | pub fn new(direction: Direction, id: u64) -> KRB5Transaction { |
273 | 42.4k | let krbtx = KRB5Transaction{ |
274 | 42.4k | msg_type: MessageType(0), |
275 | 42.4k | cname: None, |
276 | 42.4k | realm: None, |
277 | 42.4k | sname: None, |
278 | 42.4k | etype: None, |
279 | 42.4k | ticket_etype: None, |
280 | 42.4k | error_code: None, |
281 | 42.4k | req_type: None, |
282 | 42.4k | id, |
283 | 42.4k | tx_data: applayer::AppLayerTxData::for_direction(direction), |
284 | 42.4k | }; |
285 | 42.4k | return krbtx; |
286 | 42.4k | } |
287 | | } |
288 | | |
289 | | /// Return true if Kerberos `EncryptionType` is weak |
290 | 49 | pub fn test_weak_encryption(alg:EncryptionType) -> bool { |
291 | 49 | match alg { |
292 | | EncryptionType::AES128_CTS_HMAC_SHA1_96 | |
293 | | EncryptionType::AES256_CTS_HMAC_SHA1_96 | |
294 | | EncryptionType::AES128_CTS_HMAC_SHA256_128 | |
295 | | EncryptionType::AES256_CTS_HMAC_SHA384_192 | |
296 | | EncryptionType::CAMELLIA128_CTS_CMAC | |
297 | 28 | EncryptionType::CAMELLIA256_CTS_CMAC => false, |
298 | 21 | _ => true, // all other ciphers are weak or deprecated |
299 | | } |
300 | 49 | } |
301 | | |
302 | | |
303 | | |
304 | | |
305 | | |
306 | | /// Returns *mut KRB5State |
307 | | #[no_mangle] |
308 | 15.5k | pub extern "C" fn rs_krb5_state_new(_orig_state: *mut std::os::raw::c_void, _orig_proto: AppProto) -> *mut std::os::raw::c_void { |
309 | 15.5k | let state = KRB5State::new(); |
310 | 15.5k | let boxed = Box::new(state); |
311 | 15.5k | return Box::into_raw(boxed) as *mut _; |
312 | 15.5k | } |
313 | | |
314 | | /// Params: |
315 | | /// - state: *mut KRB5State as void pointer |
316 | | #[no_mangle] |
317 | 15.5k | pub extern "C" fn rs_krb5_state_free(state: *mut std::os::raw::c_void) { |
318 | 15.5k | let mut state: Box<KRB5State> = unsafe{Box::from_raw(state as _)}; |
319 | 15.5k | state.free(); |
320 | 15.5k | } |
321 | | |
322 | | #[no_mangle] |
323 | 96 | pub unsafe extern "C" fn rs_krb5_state_get_tx(state: *mut std::os::raw::c_void, |
324 | 96 | tx_id: u64) |
325 | 96 | -> *mut std::os::raw::c_void |
326 | | { |
327 | 96 | let state = cast_pointer!(state,KRB5State); |
328 | 96 | match state.get_tx_by_id(tx_id) { |
329 | 94 | Some(tx) => tx as *const _ as *mut _, |
330 | 2 | None => std::ptr::null_mut(), |
331 | | } |
332 | 96 | } |
333 | | |
334 | | #[no_mangle] |
335 | 1.49M | pub unsafe extern "C" fn rs_krb5_state_get_tx_count(state: *mut std::os::raw::c_void) |
336 | 1.49M | -> u64 |
337 | | { |
338 | 1.49M | let state = cast_pointer!(state,KRB5State); |
339 | 1.49M | state.tx_id |
340 | 1.49M | } |
341 | | |
342 | | #[no_mangle] |
343 | 40.7k | pub unsafe extern "C" fn rs_krb5_state_tx_free(state: *mut std::os::raw::c_void, |
344 | 40.7k | tx_id: u64) |
345 | | { |
346 | 40.7k | let state = cast_pointer!(state,KRB5State); |
347 | 40.7k | state.free_tx(tx_id); |
348 | 40.7k | } |
349 | | |
350 | | #[no_mangle] |
351 | 84.4k | pub extern "C" fn rs_krb5_tx_get_alstate_progress(_tx: *mut std::os::raw::c_void, |
352 | 84.4k | _direction: u8) |
353 | 84.4k | -> std::os::raw::c_int |
354 | | { |
355 | 84.4k | 1 |
356 | 84.4k | } |
357 | | |
358 | | static mut ALPROTO_KRB5 : AppProto = ALPROTO_UNKNOWN; |
359 | | |
360 | | #[no_mangle] |
361 | 6.38k | pub unsafe extern "C" fn rs_krb5_probing_parser(_flow: *const Flow, |
362 | 6.38k | _direction: u8, |
363 | 6.38k | input:*const u8, input_len: u32, |
364 | 6.38k | _rdir: *mut u8) -> AppProto |
365 | | { |
366 | 6.38k | if input.is_null() { |
367 | 0 | return ALPROTO_UNKNOWN; |
368 | 6.38k | } |
369 | 6.38k | let slice = build_slice!(input,input_len as usize); |
370 | 6.38k | let alproto = ALPROTO_KRB5; |
371 | 6.38k | if slice.len() <= 10 { return ALPROTO_FAILED; } |
372 | 6.38k | match der_read_element_header(slice) { |
373 | 5.98k | Ok((rem, ref hdr)) => { |
374 | | // Kerberos messages start with an APPLICATION header |
375 | 5.98k | if hdr.class() != Class::Application { return ALPROTO_FAILED; } |
376 | | // Tag number should be <= 30 |
377 | 5.93k | if hdr.tag().0 > 30 { return ALPROTO_FAILED; } |
378 | | // Kerberos messages contain sequences |
379 | 5.90k | if rem.is_empty() || rem[0] != 0x30 { return ALPROTO_FAILED; } |
380 | | // Check kerberos version |
381 | 5.85k | if let Ok((rem,_hdr)) = der_read_element_header(rem) { |
382 | 5.73k | if rem.len() > 5 { |
383 | | #[allow(clippy::single_match)] |
384 | 5.51k | match (rem[2],rem[3],rem[4]) { |
385 | | // Encoding of DER integer 5 (version) |
386 | 5.47k | (2,1,5) => { return alproto; }, |
387 | 44 | _ => (), |
388 | | } |
389 | 221 | } |
390 | 116 | } |
391 | 381 | return ALPROTO_FAILED; |
392 | | }, |
393 | | Err(Err::Incomplete(_)) => { |
394 | 353 | return ALPROTO_UNKNOWN; |
395 | | }, |
396 | | Err(_) => { |
397 | 45 | return ALPROTO_FAILED; |
398 | | }, |
399 | | } |
400 | 6.38k | } |
401 | | |
402 | | #[no_mangle] |
403 | 8.84k | pub unsafe extern "C" fn rs_krb5_probing_parser_tcp(_flow: *const Flow, |
404 | 8.84k | direction: u8, |
405 | 8.84k | input:*const u8, input_len: u32, |
406 | 8.84k | rdir: *mut u8) -> AppProto |
407 | | { |
408 | 8.84k | if input.is_null() { |
409 | 1.41k | return ALPROTO_UNKNOWN; |
410 | 7.42k | } |
411 | 7.42k | let slice = build_slice!(input,input_len as usize); |
412 | 7.42k | if slice.len() <= 14 { return ALPROTO_FAILED; } |
413 | 6.39k | match be_u32(slice) as IResult<&[u8],u32> { |
414 | 6.39k | Ok((rem, record_mark)) => { |
415 | | // protocol implementations forbid very large requests |
416 | 6.39k | if record_mark > 16384 { return ALPROTO_FAILED; } |
417 | 6.32k | return rs_krb5_probing_parser(_flow, direction, |
418 | 6.32k | rem.as_ptr(), rem.len() as u32, rdir); |
419 | | }, |
420 | | Err(Err::Incomplete(_)) => { |
421 | 0 | return ALPROTO_UNKNOWN; |
422 | | }, |
423 | | Err(_) => { |
424 | 0 | return ALPROTO_FAILED; |
425 | | }, |
426 | | } |
427 | 8.84k | } |
428 | | |
429 | | #[no_mangle] |
430 | 160k | pub unsafe extern "C" fn rs_krb5_parse_request(_flow: *const core::Flow, |
431 | 160k | state: *mut std::os::raw::c_void, |
432 | 160k | _pstate: *mut std::os::raw::c_void, |
433 | 160k | stream_slice: StreamSlice, |
434 | 160k | _data: *const std::os::raw::c_void, |
435 | 160k | ) -> AppLayerResult { |
436 | 160k | let buf = stream_slice.as_slice(); |
437 | 160k | let state = cast_pointer!(state,KRB5State); |
438 | 160k | if state.parse(buf, Direction::ToServer) < 0 { |
439 | 194 | return AppLayerResult::err(); |
440 | 160k | } |
441 | 160k | AppLayerResult::ok() |
442 | 160k | } |
443 | | |
444 | | #[no_mangle] |
445 | 151k | pub unsafe extern "C" fn rs_krb5_parse_response(_flow: *const core::Flow, |
446 | 151k | state: *mut std::os::raw::c_void, |
447 | 151k | _pstate: *mut std::os::raw::c_void, |
448 | 151k | stream_slice: StreamSlice, |
449 | 151k | _data: *const std::os::raw::c_void, |
450 | 151k | ) -> AppLayerResult { |
451 | 151k | let buf = stream_slice.as_slice(); |
452 | 151k | let state = cast_pointer!(state,KRB5State); |
453 | 151k | if state.parse(buf, Direction::ToClient) < 0 { |
454 | 112 | return AppLayerResult::err(); |
455 | 150k | } |
456 | 150k | AppLayerResult::ok() |
457 | 151k | } |
458 | | |
459 | | #[no_mangle] |
460 | 76.6k | pub unsafe extern "C" fn rs_krb5_parse_request_tcp(_flow: *const core::Flow, |
461 | 76.6k | state: *mut std::os::raw::c_void, |
462 | 76.6k | _pstate: *mut std::os::raw::c_void, |
463 | 76.6k | stream_slice: StreamSlice, |
464 | 76.6k | _data: *const std::os::raw::c_void, |
465 | 76.6k | ) -> AppLayerResult { |
466 | 76.6k | let state = cast_pointer!(state,KRB5State); |
467 | 76.6k | let buf = stream_slice.as_slice(); |
468 | | |
469 | | let mut v : Vec<u8>; |
470 | 76.6k | let tcp_buffer = match state.record_ts { |
471 | 48.3k | 0 => buf, |
472 | | _ => { |
473 | | // sanity check to avoid memory exhaustion |
474 | 28.3k | if state.defrag_buf_ts.len() + buf.len() > 100000 { |
475 | | SCLogDebug!("rs_krb5_parse_request_tcp: TCP buffer exploded {} {}", |
476 | | state.defrag_buf_ts.len(), buf.len()); |
477 | 6 | return AppLayerResult::err(); |
478 | 28.3k | } |
479 | 28.3k | v = state.defrag_buf_ts.split_off(0); |
480 | 28.3k | v.extend_from_slice(buf); |
481 | 28.3k | v.as_slice() |
482 | | } |
483 | | }; |
484 | 76.6k | let mut cur_i = tcp_buffer; |
485 | 131k | while !cur_i.is_empty() { |
486 | 131k | if state.record_ts == 0 { |
487 | 102k | match be_u32(cur_i) as IResult<&[u8],u32> { |
488 | 56.0k | Ok((rem,record)) => { |
489 | 56.0k | state.record_ts = record as usize; |
490 | 56.0k | cur_i = rem; |
491 | 56.0k | }, |
492 | | Err(Err::Incomplete(_)) => { |
493 | 46.8k | state.defrag_buf_ts.extend_from_slice(cur_i); |
494 | 46.8k | return AppLayerResult::ok(); |
495 | | } |
496 | | _ => { |
497 | | SCLogDebug!("rs_krb5_parse_request_tcp: reading record mark failed!"); |
498 | 0 | return AppLayerResult::err(); |
499 | | } |
500 | | } |
501 | 28.3k | } |
502 | 84.3k | if cur_i.len() >= state.record_ts { |
503 | 54.5k | if state.parse(cur_i, Direction::ToServer) < 0 { |
504 | 51 | return AppLayerResult::err(); |
505 | 54.4k | } |
506 | 54.4k | state.record_ts = 0; |
507 | 54.4k | cur_i = &cur_i[state.record_ts..]; |
508 | | } else { |
509 | | // more fragments required |
510 | 29.8k | state.defrag_buf_ts.extend_from_slice(cur_i); |
511 | 29.8k | return AppLayerResult::ok(); |
512 | | } |
513 | | } |
514 | 0 | AppLayerResult::ok() |
515 | 76.6k | } |
516 | | |
517 | | #[no_mangle] |
518 | 113k | pub unsafe extern "C" fn rs_krb5_parse_response_tcp(_flow: *const core::Flow, |
519 | 113k | state: *mut std::os::raw::c_void, |
520 | 113k | _pstate: *mut std::os::raw::c_void, |
521 | 113k | stream_slice: StreamSlice, |
522 | 113k | _data: *const std::os::raw::c_void, |
523 | 113k | ) -> AppLayerResult { |
524 | 113k | let state = cast_pointer!(state,KRB5State); |
525 | 113k | let buf = stream_slice.as_slice(); |
526 | | |
527 | | let mut v : Vec<u8>; |
528 | 113k | let tcp_buffer = match state.record_tc { |
529 | 94.5k | 0 => buf, |
530 | | _ => { |
531 | | // sanity check to avoid memory exhaustion |
532 | 19.3k | if state.defrag_buf_tc.len() + buf.len() > 100000 { |
533 | | SCLogDebug!("rs_krb5_parse_response_tcp: TCP buffer exploded {} {}", |
534 | | state.defrag_buf_tc.len(), buf.len()); |
535 | 8 | return AppLayerResult::err(); |
536 | 19.3k | } |
537 | 19.3k | v = state.defrag_buf_tc.split_off(0); |
538 | 19.3k | v.extend_from_slice(buf); |
539 | 19.3k | v.as_slice() |
540 | | } |
541 | | }; |
542 | 113k | let mut cur_i = tcp_buffer; |
543 | 130k | while !cur_i.is_empty() { |
544 | 130k | if state.record_tc == 0 { |
545 | 111k | match be_u32(cur_i) as IResult<&[u8],_> { |
546 | 17.2k | Ok((rem,record)) => { |
547 | 17.2k | state.record_tc = record as usize; |
548 | 17.2k | cur_i = rem; |
549 | 17.2k | }, |
550 | | Err(Err::Incomplete(_)) => { |
551 | 94.0k | state.defrag_buf_tc.extend_from_slice(cur_i); |
552 | 94.0k | return AppLayerResult::ok(); |
553 | | } |
554 | | _ => { |
555 | | SCLogDebug!("reading record mark failed!"); |
556 | 0 | return AppLayerResult::ok(); |
557 | | } |
558 | | } |
559 | 19.3k | } |
560 | 36.6k | if cur_i.len() >= state.record_tc { |
561 | 16.7k | if state.parse(cur_i, Direction::ToClient) < 0 { |
562 | 27 | return AppLayerResult::err(); |
563 | 16.7k | } |
564 | 16.7k | state.record_tc = 0; |
565 | 16.7k | cur_i = &cur_i[state.record_tc..]; |
566 | | } else { |
567 | | // more fragments required |
568 | 19.8k | state.defrag_buf_tc.extend_from_slice(cur_i); |
569 | 19.8k | return AppLayerResult::ok(); |
570 | | } |
571 | | } |
572 | 0 | AppLayerResult::ok() |
573 | 113k | } |
574 | | |
575 | | export_tx_data_get!(rs_krb5_get_tx_data, KRB5Transaction); |
576 | | export_state_data_get!(rs_krb5_get_state_data, KRB5State); |
577 | | |
578 | | const PARSER_NAME : &[u8] = b"krb5\0"; |
579 | | |
580 | | #[no_mangle] |
581 | 34 | pub unsafe extern "C" fn rs_register_krb5_parser() { |
582 | 34 | let default_port = CString::new("88").unwrap(); |
583 | 34 | let mut parser = RustParser { |
584 | 34 | name : PARSER_NAME.as_ptr() as *const std::os::raw::c_char, |
585 | 34 | default_port : default_port.as_ptr(), |
586 | 34 | ipproto : core::IPPROTO_UDP, |
587 | 34 | probe_ts : Some(rs_krb5_probing_parser), |
588 | 34 | probe_tc : Some(rs_krb5_probing_parser), |
589 | 34 | min_depth : 0, |
590 | 34 | max_depth : 16, |
591 | 34 | state_new : rs_krb5_state_new, |
592 | 34 | state_free : rs_krb5_state_free, |
593 | 34 | tx_free : rs_krb5_state_tx_free, |
594 | 34 | parse_ts : rs_krb5_parse_request, |
595 | 34 | parse_tc : rs_krb5_parse_response, |
596 | 34 | get_tx_count : rs_krb5_state_get_tx_count, |
597 | 34 | get_tx : rs_krb5_state_get_tx, |
598 | 34 | tx_comp_st_ts : 1, |
599 | 34 | tx_comp_st_tc : 1, |
600 | 34 | tx_get_progress : rs_krb5_tx_get_alstate_progress, |
601 | 34 | get_eventinfo : Some(KRB5Event::get_event_info), |
602 | 34 | get_eventinfo_byid : Some(KRB5Event::get_event_info_by_id), |
603 | 34 | localstorage_new : None, |
604 | 34 | localstorage_free : None, |
605 | 34 | get_tx_files : None, |
606 | 34 | get_tx_iterator : Some(applayer::state_get_tx_iterator::<KRB5State, KRB5Transaction>), |
607 | 34 | get_tx_data : rs_krb5_get_tx_data, |
608 | 34 | get_state_data : rs_krb5_get_state_data, |
609 | 34 | apply_tx_config : None, |
610 | 34 | flags : 0, |
611 | 34 | truncate : None, |
612 | 34 | get_frame_id_by_name: None, |
613 | 34 | get_frame_name_by_id: None, |
614 | 34 | }; |
615 | | // register UDP parser |
616 | 34 | let ip_proto_str = CString::new("udp").unwrap(); |
617 | 34 | if AppLayerProtoDetectConfProtoDetectionEnabled(ip_proto_str.as_ptr(), parser.name) != 0 { |
618 | 34 | let alproto = AppLayerRegisterProtocolDetection(&parser, 1); |
619 | | // store the allocated ID for the probe function |
620 | 34 | ALPROTO_KRB5 = alproto; |
621 | 34 | if AppLayerParserConfParserEnabled(ip_proto_str.as_ptr(), parser.name) != 0 { |
622 | 34 | let _ = AppLayerRegisterParser(&parser, alproto); |
623 | 34 | } |
624 | 0 | } else { |
625 | 0 | SCLogDebug!("Protocol detector and parser disabled for KRB5/UDP."); |
626 | 0 | } |
627 | | // register TCP parser |
628 | 34 | parser.ipproto = core::IPPROTO_TCP; |
629 | 34 | parser.probe_ts = Some(rs_krb5_probing_parser_tcp); |
630 | 34 | parser.probe_tc = Some(rs_krb5_probing_parser_tcp); |
631 | 34 | parser.parse_ts = rs_krb5_parse_request_tcp; |
632 | 34 | parser.parse_tc = rs_krb5_parse_response_tcp; |
633 | 34 | let ip_proto_str = CString::new("tcp").unwrap(); |
634 | 34 | if AppLayerProtoDetectConfProtoDetectionEnabled(ip_proto_str.as_ptr(), parser.name) != 0 { |
635 | 34 | let alproto = AppLayerRegisterProtocolDetection(&parser, 1); |
636 | | // store the allocated ID for the probe function |
637 | 34 | ALPROTO_KRB5 = alproto; |
638 | 34 | if AppLayerParserConfParserEnabled(ip_proto_str.as_ptr(), parser.name) != 0 { |
639 | 34 | let _ = AppLayerRegisterParser(&parser, alproto); |
640 | 34 | } |
641 | 0 | } else { |
642 | 0 | SCLogDebug!("Protocol detector and parser disabled for KRB5/TCP."); |
643 | 0 | } |
644 | 34 | } |