/* Copyright (C) 2017 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ // written by Clément Galland extern crate libc; extern crate nom; use std::str; use std; use std::mem::transmute; use applayer::LoggerFlags; #[derive(Debug)] pub struct TFTPTransaction { pub opcode : u8, pub filename : String, pub mode : String, pub logged : LoggerFlags } pub struct TFTPState { pub transactions : Vec } impl TFTPTransaction { pub fn new(opcode : u8, filename : String, mode : String) -> TFTPTransaction { TFTPTransaction { opcode : opcode, filename : filename, mode : mode.to_lowercase(), logged : LoggerFlags::new(), } } pub fn is_mode_ok(&self) -> bool { match self.mode.as_str() { "netascii" | "mail" | "octet" => true, _ => false } } } #[no_mangle] pub extern "C" fn rs_tftp_state_alloc() -> *mut libc::c_void { let state = TFTPState { transactions : Vec::new() }; let boxed = Box::new(state); return unsafe{transmute(boxed)}; } #[no_mangle] pub extern "C" fn rs_tftp_state_free(state: *mut libc::c_void) { let _state : Box = unsafe{transmute(state)}; } #[no_mangle] pub extern "C" fn rs_tftp_state_tx_free(state: &mut TFTPState, tx_id: libc::uint32_t) { state.transactions.remove(tx_id as usize); } #[no_mangle] pub extern "C" fn rs_tftp_get_tx(state: &mut TFTPState, tx_id: libc::uint64_t) -> *mut libc::c_void { if state.transactions.len() <= tx_id as usize { return std::ptr::null_mut(); } return unsafe{transmute(&state.transactions[tx_id as usize])}; } #[no_mangle] pub extern "C" fn rs_tftp_get_tx_logged(_state: &mut TFTPState, tx: &mut TFTPTransaction, logger: libc::uint32_t) -> i8 { if tx.logged.is_logged(logger) { 1 } else { 0 } } #[no_mangle] pub extern "C" fn rs_tftp_set_tx_logged(_state: &mut TFTPState, tx: &mut TFTPTransaction, logger: libc::uint32_t) { tx.logged.set_logged(logger); } #[no_mangle] pub extern "C" fn rs_tftp_has_event(state: &mut TFTPState) -> i64 { return state.transactions.len() as i64; } #[no_mangle] pub extern "C" fn rs_tftp_get_tx_cnt(state: &mut TFTPState) -> u64 { return state.transactions.len() as u64; } named!(getstr<&str>, map_res!( take_while!(call!(|c| c != 0)), str::from_utf8 ) ); named!(pub tftp_request, do_parse!( tag!([0]) >> opcode: take!(1) >> filename: getstr >> tag!([0]) >> mode : getstr >> ( TFTPTransaction::new(opcode[0], String::from(filename), String::from(mode)) ) ) ); #[no_mangle] pub extern "C" fn rs_tftp_request(state: &mut TFTPState, input: *const libc::uint8_t, len: libc::uint32_t) -> i64 { let buf = unsafe{std::slice::from_raw_parts(input, len as usize)}; return match tftp_request(buf) { nom::IResult::Done(_, rqst) => { state.transactions.push(rqst); 1 }, _ => 0 } }