From 41376da03c72550e8972f4b870856c2b7cf7dc20 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Wed, 14 Jun 2017 12:41:49 +0200 Subject: [PATCH] nfs: log more rpc --- rust/src/nfs/log.rs | 24 +++++++--- rust/src/nfs/nfs3.rs | 47 +++++++++++--------- rust/src/nfs/rpc_records.rs | 2 +- rust/src/nfs/types.rs | 88 +++++++++++++++++++++++++++++++++++++ src/output-json-nfs3.c | 7 ++- 5 files changed, 138 insertions(+), 30 deletions(-) diff --git a/rust/src/nfs/log.rs b/rust/src/nfs/log.rs index fd8335e8c3..28e5a9249f 100644 --- a/rust/src/nfs/log.rs +++ b/rust/src/nfs/log.rs @@ -80,7 +80,6 @@ fn nfs3_file_object(tx: &NFS3Transaction) -> Json fn nfs3_common_header(tx: &NFS3Transaction) -> Json { let js = Json::object(); - js.set_integer("xid", tx.xid as u64); js.set_string("procedure", &nfs3_procedure_string(tx.procedure)); let file_name = String::from_utf8_lossy(&tx.file_name); js.set_string("filename", &file_name); @@ -103,12 +102,7 @@ pub extern "C" fn rs_nfs3_log_json_response(tx: &mut NFS3Transaction) -> *mut Js let js = nfs3_common_header(tx); js.set_string("type", "response"); - js.set_string("status", &nfs3_status_string(tx.response_status)); - - if tx.has_creds { - let creds_js = nfs3_creds_object(tx); - js.set("creds", creds_js); - } + js.set_string("status", &nfs3_status_string(tx.nfs_response_status)); if tx.procedure == NFSPROC3_READ { let read_js = nfs3_file_object(tx); @@ -123,3 +117,19 @@ pub extern "C" fn rs_nfs3_log_json_response(tx: &mut NFS3Transaction) -> *mut Js return js.unwrap(); } + + +#[no_mangle] +pub extern "C" fn rs_rpc_log_json_response(tx: &mut NFS3Transaction) -> *mut JsonT +{ + let js = Json::object(); + js.set_integer("xid", tx.xid as u64); + js.set_string("status", &rpc_status_string(tx.rpc_response_status)); + js.set_string("auth_type", &rpc_auth_type_string(tx.auth_type)); + if tx.auth_type == RPCAUTH_UNIX { + let creds_js = nfs3_creds_object(tx); + js.set("creds", creds_js); + } + + return js.unwrap(); +} diff --git a/rust/src/nfs/nfs3.rs b/rust/src/nfs/nfs3.rs index edfc719d49..de5be914b6 100644 --- a/rust/src/nfs/nfs3.rs +++ b/rust/src/nfs/nfs3.rs @@ -132,13 +132,14 @@ pub struct NFS3Transaction { /// this is the 'from' or original name. pub file_name: Vec, + pub auth_type: u32, pub request_machine_name: Vec, pub request_uid: u32, pub request_gid: u32, - pub response_status: u32, + pub rpc_response_status: u32, + pub nfs_response_status: u32, - pub has_creds: bool, pub is_first: bool, pub is_last: bool, @@ -174,8 +175,9 @@ impl NFS3Transaction { request_machine_name:Vec::new(), request_uid:0, request_gid:0, - response_status:0, - has_creds: false, + rpc_response_status:0, + nfs_response_status:0, + auth_type: 0, is_first: false, is_last: false, request_done: false, @@ -399,12 +401,13 @@ impl NFS3State { } // TODO maybe not enough users to justify a func - fn mark_response_tx_done(&mut self, xid: u32, status: u32) + fn mark_response_tx_done(&mut self, xid: u32, rpc_status: u32, nfs_status: u32) { match self.get_tx_by_xid(xid) { Some(mut mytx) => { mytx.response_done = true; - mytx.response_status = status; + mytx.rpc_response_status = rpc_status; + mytx.nfs_response_status = nfs_status; SCLogDebug!("process_reply_record: tx ID {} XID {} REQUEST {} RESPONSE {}", mytx.id, mytx.xid, mytx.request_done, mytx.response_done); @@ -577,12 +580,12 @@ impl NFS3State { tx.type_data = Some(NFS3TransactionTypeData::RENAME(aux_file_name)); } + tx.auth_type = r.creds_flavor; match &r.creds_unix { &Some(ref u) => { tx.request_machine_name = u.machine_name_buf.to_vec(); tx.request_uid = u.uid; tx.request_gid = u.gid; - tx.has_creds = true; }, _ => { }, } @@ -639,12 +642,12 @@ impl NFS3State { tx.type_data = Some(NFS3TransactionTypeData::RENAME(aux_file_name)); } + tx.auth_type = r.creds_flavor; match &r.creds_unix { &Some(ref u) => { tx.request_machine_name = u.machine_name_buf.to_vec(); tx.request_uid = u.uid; tx.request_gid = u.gid; - tx.has_creds = true; }, _ => { }, } @@ -781,7 +784,7 @@ impl NFS3State { } fn process_reply_record_v3<'b>(&mut self, r: &RpcReplyPacket<'b>, xidmap: &mut NFS3RequestXidMap) -> u32 { - let status; + let nfs_status; if xidmap.procedure == NFSPROC3_LOOKUP { match parse_nfs3_response_lookup(r.prog_data) { @@ -789,7 +792,7 @@ impl NFS3State { SCLogDebug!("LOOKUP: {:?}", lookup); SCLogDebug!("RESPONSE LOOKUP file_name {:?}", xidmap.file_name); - status = lookup.status; + nfs_status = lookup.status; SCLogDebug!("LOOKUP handle {:?}", lookup.handle); self.namemap.insert(lookup.handle.value.to_vec(), xidmap.file_name.to_vec()); @@ -803,7 +806,7 @@ impl NFS3State { SCLogDebug!("nfs3_create_record: {:?}", nfs3_create_record); SCLogDebug!("RESPONSE CREATE file_name {:?}", xidmap.file_name); - status = nfs3_create_record.status; + nfs_status = nfs3_create_record.status; match nfs3_create_record.handle { Some(h) => { @@ -821,7 +824,7 @@ impl NFS3State { match parse_nfs3_reply_read(r.prog_data) { IResult::Done(_, ref reply) => { self.process_read_record(r, reply, Some(&xidmap)); - status = reply.status; + nfs_status = reply.status; }, IResult::Incomplete(_) => { panic!("Incomplete!"); }, IResult::Error(e) => { panic!("Parsing failed: {:?}",e); }, @@ -831,7 +834,7 @@ impl NFS3State { IResult::Done(_, ref reply) => { //SCLogDebug!("READDIRPLUS reply {:?}", reply); - status = reply.status; + nfs_status = reply.status; // cut off final eof field let d = &reply.data[..reply.data.len()-4 as usize]; @@ -874,27 +877,27 @@ impl NFS3State { } _ => 0 as u32 }; - status = stat; + nfs_status = stat; } SCLogDebug!("REPLY {} to procedure {} blob size {}", r.hdr.xid, xidmap.procedure, r.prog_data.len()); if xidmap.procedure != NFSPROC3_READ { - self.mark_response_tx_done(r.hdr.xid, status); + self.mark_response_tx_done(r.hdr.xid, r.reply_state, nfs_status); } 0 } fn process_reply_record_v2<'b>(&mut self, r: &RpcReplyPacket<'b>, xidmap: &NFS3RequestXidMap) -> u32 { - let status; + let nfs_status; if xidmap.procedure == NFSPROC3_READ { match parse_nfs2_reply_read(r.prog_data) { IResult::Done(_, ref reply) => { SCLogDebug!("NFSv2 READ reply record"); self.process_read_record(r, reply, Some(&xidmap)); - status = reply.status; + nfs_status = reply.status; }, IResult::Incomplete(_) => { panic!("Incomplete!"); }, IResult::Error(e) => { panic!("Parsing failed: {:?}",e); }, @@ -906,12 +909,12 @@ impl NFS3State { } _ => 0 as u32 }; - status = stat; + nfs_status = stat; } SCLogDebug!("REPLY {} to procedure {} blob size {}", r.hdr.xid, xidmap.procedure, r.prog_data.len()); - self.mark_response_tx_done(r.hdr.xid, status); + self.mark_response_tx_done(r.hdr.xid, r.reply_state, nfs_status); 0 } @@ -1102,7 +1105,8 @@ impl NFS3State { reply.count, fill_bytes as u8, reply.eof, &r.hdr.xid); if is_last { tdf.file_last_xid = r.hdr.xid; - tx.response_status = reply.status; + tx.rpc_response_status = r.reply_state; + tx.nfs_response_status = reply.status; tx.is_last = true; tx.response_done = true; } @@ -1124,7 +1128,8 @@ impl NFS3State { tx.is_first = true; if is_last { tdf.file_last_xid = r.hdr.xid; - tx.response_status = reply.status; + tx.rpc_response_status = r.reply_state; + tx.nfs_response_status = reply.status; tx.is_last = true; tx.response_done = true; } diff --git a/rust/src/nfs/rpc_records.rs b/rust/src/nfs/rpc_records.rs index 361d5c0de0..d1958f6a48 100644 --- a/rust/src/nfs/rpc_records.rs +++ b/rust/src/nfs/rpc_records.rs @@ -17,7 +17,7 @@ //! Nom parsers for RPC & NFSv3 -use nom::{be_u32, be_u64, rest}; +use nom::{be_u32, rest}; #[derive(Debug,PartialEq)] pub struct RpcRequestCredsUnix<'a> { diff --git a/rust/src/nfs/types.rs b/rust/src/nfs/types.rs index 9e8c00ec58..b0a0f88db9 100644 --- a/rust/src/nfs/types.rs +++ b/rust/src/nfs/types.rs @@ -136,3 +136,91 @@ pub fn nfs3_status_string(status: u32) -> String { }, }.to_string() } + +pub const RPCMSG_ACCEPTED: u32 = 0; +pub const RPCMSG_DENIED: u32 = 1; + +pub fn rpc_status_string(status: u32) -> String { + match status { + RPCMSG_ACCEPTED => "ACCEPTED", + RPCMSG_DENIED => "DENIED", + _ => { + return (status).to_string(); + }, + }.to_string() +} + +/* http://www.iana.org/assignments/rpc-authentication-numbers/rpc-authentication-numbers.xhtml */ +/* RFC 1057 Section 7.2 */ +/* RFC 2203 Section 3 */ + +pub const RPCAUTH_NULL: u32 = 0; +pub const RPCAUTH_UNIX: u32 = 1; +pub const RPCAUTH_SHORT: u32 = 2; +pub const RPCAUTH_DH: u32 = 3; +pub const RPCAUTH_KERB: u32 = 4; +pub const RPCAUTH_RSA: u32 = 5; +pub const RPCAUTH_GSS: u32 = 6; + +pub fn rpc_auth_type_string(auth_type: u32) -> String { + match auth_type { + RPCAUTH_NULL => "NULL", + RPCAUTH_UNIX => "UNIX", + RPCAUTH_SHORT => "SHORT", + RPCAUTH_DH => "DH", + RPCAUTH_KERB => "KERB", + RPCAUTH_RSA => "RSA", + RPCAUTH_GSS => "GSS", + _ => { + return (auth_type).to_string(); + }, + }.to_string() +} + +/* http://www.iana.org/assignments/rpc-authentication-numbers/rpc-authentication-numbers.xhtml */ +pub const RPCAUTH_OK: u32 = 0; // success/failed at remote end [RFC5531] +pub const RPCAUTH_BADCRED: u32 = 1; // bad credential (seal broken) [RFC5531] +pub const RPCAUTH_REJECTEDCRED: u32 = 2; // client must begin new session [RFC5531] +pub const RPCAUTH_BADVERF: u32 = 3; // bad verifier (seal broken) [RFC5531] +pub const RPCAUTH_REJECTEDVERF: u32 = 4; // verifier expired or replayed [RFC5531] +pub const RPCAUTH_TOOWEAK: u32 = 5; // rejected for security reasons/failed locally [RFC5531] +pub const RPCAUTH_INVALIDRESP: u32 = 6; // bogus response verifier [RFC5531] +pub const RPCAUTH_FAILED: u32 = 7; // reason unknown/AUTH_KERB errors; deprecated. See [RFC2695] [RFC5531] +pub const RPCAUTH_KERB_GENERIC: u32 = 8; // kerberos generic error [RFC5531] +pub const RPCAUTH_TIMEEXPIRE: u32 = 9; // time of credential expired [RFC5531] +pub const RPCAUTH_TKT_FILE: u32 = 10; // problem with ticket file [RFC5531] +pub const RPCAUTH_DECODE: u32 = 11; // can't decode authenticator [RFC5531] +pub const RPCAUTH_NET_ADDR: u32 = 12; // wrong net address in ticket/RPCSEC_GSS GSS related errors [RFC5531] +pub const RPCSEC_GSS_CREDPROBLEM: u32 = 13; // no credentials for user [RFC5531] +pub const RPCSEC_GSS_CTXPROBLEM: u32 = 14; // problem with context [RFC5531] +pub const RPCSEC_GSS_INNER_CREDPROBLEM: u32 = 15; // No credentials for multi-principal assertion inner context user [RFC7861] +pub const RPCSEC_GSS_LABEL_PROBLEM: u32 = 16; // Problem with label assertion [RFC7861] +pub const RPCSEC_GSS_PRIVILEGE_PROBLEM: u32 = 17; // Problem with structured privilege assertion [RFC7861] +pub const RPCSEC_GSS_UNKNOWN_MESSAGE: u32 = 18; // Unknown structured privilege assertion [RFC7861] + +pub fn rpc_auth_status_string(auth_status: u32) -> String { + match auth_status { + RPCAUTH_OK => "OK", + RPCAUTH_BADCRED => "BADCRED", + RPCAUTH_REJECTEDCRED => "REJECTEDCRED", + RPCAUTH_BADVERF => "BADVERF", + RPCAUTH_REJECTEDVERF => "REJECTEDVERF", + RPCAUTH_TOOWEAK => "TOOWEAK", + RPCAUTH_INVALIDRESP => "NVALIDRESP", + RPCAUTH_FAILED => "FAILED", + RPCAUTH_KERB_GENERIC => "KERB_GENERIC", + RPCAUTH_TIMEEXPIRE => "TIMEEXPIRE", + RPCAUTH_TKT_FILE => "TKT_FILE", + RPCAUTH_DECODE => "DECODE", + RPCAUTH_NET_ADDR => "NET_ADDR", + RPCSEC_GSS_CREDPROBLEM => "GSS_CREDPROBLEM", + RPCSEC_GSS_CTXPROBLEM => "GSS_CTXPROBLEM", + RPCSEC_GSS_INNER_CREDPROBLEM => "GSS_INNER_CREDPROBLEM", + RPCSEC_GSS_LABEL_PROBLEM => "GSS_LABEL_PROBLEM", + RPCSEC_GSS_PRIVILEGE_PROBLEM => "GSS_PRIVILEGE_PROBLEM", + RPCSEC_GSS_UNKNOWN_MESSAGE => "GSS_UNKNOWN_MESSAGE", + _ => { + return (auth_status).to_string(); + }, + }.to_string() +} diff --git a/src/output-json-nfs3.c b/src/output-json-nfs3.c index c2d5d04ac5..52eb711687 100644 --- a/src/output-json-nfs3.c +++ b/src/output-json-nfs3.c @@ -84,11 +84,16 @@ static int JsonNFS3Logger(ThreadVars *tv, void *thread_data, return TM_ECODE_FAILED; } + json_t *rpcjs = rs_rpc_log_json_response(tx); + if (unlikely(rpcjs == NULL)) { + goto error; + } + json_object_set_new(js, "rpc", rpcjs); + nfs3js = rs_nfs3_log_json_response(tx); if (unlikely(nfs3js == NULL)) { goto error; } - json_object_set_new(js, "nfs3", nfs3js); MemBufferReset(thread->buffer); -- 2.47.2