mirror of https://github.com/OISF/suricata
rust/ldap: implement logger
parent
93da339975
commit
910a5b226c
@ -0,0 +1,351 @@
|
||||
/* Copyright (C) 2024 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 Giuseppe Longo <giuseppe@glongo.it>
|
||||
|
||||
use crate::jsonbuilder::{JsonBuilder, JsonError};
|
||||
use crate::ldap::filters::*;
|
||||
use crate::ldap::ldap::LdapTransaction;
|
||||
use crate::ldap::types::*;
|
||||
|
||||
fn log_ldap(tx: &LdapTransaction, js: &mut JsonBuilder) -> Result<(), JsonError> {
|
||||
js.open_object("ldap")?;
|
||||
|
||||
if let Some(req) = &tx.request {
|
||||
let protocol_op_str = req.protocol_op.to_string();
|
||||
js.open_object("request")?;
|
||||
js.set_uint("message_id", req.message_id.0.into())?;
|
||||
js.set_string("operation", &protocol_op_str)?;
|
||||
|
||||
match &req.protocol_op {
|
||||
ProtocolOp::SearchRequest(msg) => log_search_request(msg, js)?,
|
||||
ProtocolOp::BindRequest(msg) => log_bind_request(msg, js)?,
|
||||
ProtocolOp::UnbindRequest => (),
|
||||
ProtocolOp::ModifyRequest(msg) => log_modify_request(msg, js)?,
|
||||
ProtocolOp::AddRequest(msg) => log_add_request(msg, js)?,
|
||||
ProtocolOp::DelRequest(msg) => log_del_request(msg, js)?,
|
||||
ProtocolOp::ModDnRequest(msg) => log_mod_dn_request(msg, js)?,
|
||||
ProtocolOp::CompareRequest(msg) => log_compare_request(msg, js)?,
|
||||
ProtocolOp::ExtendedRequest(msg) => log_extended_request(msg, js)?,
|
||||
_ => {}
|
||||
};
|
||||
|
||||
log_controls(&req.controls, js)?;
|
||||
|
||||
js.close()?;
|
||||
}
|
||||
|
||||
if !tx.responses.is_empty() {
|
||||
js.open_array("responses")?;
|
||||
|
||||
for response in &tx.responses {
|
||||
js.start_object()?;
|
||||
|
||||
let protocol_op_str = response.protocol_op.to_string();
|
||||
js.set_string("operation", &protocol_op_str)?;
|
||||
|
||||
if tx.request.is_none() {
|
||||
js.set_uint("message_id", response.message_id.0.into())?;
|
||||
}
|
||||
|
||||
match &response.protocol_op {
|
||||
ProtocolOp::SearchResultEntry(msg) => log_search_result_entry(msg, js)?,
|
||||
ProtocolOp::SearchResultDone(msg) => log_search_result_done(msg, js)?,
|
||||
ProtocolOp::BindResponse(msg) => log_bind_response(msg, js)?,
|
||||
ProtocolOp::ModifyResponse(msg) => log_modify_response(msg, js)?,
|
||||
ProtocolOp::AddResponse(msg) => log_add_response(msg, js)?,
|
||||
ProtocolOp::DelResponse(msg) => log_del_response(msg, js)?,
|
||||
ProtocolOp::ModDnResponse(msg) => log_mod_dn_response(msg, js)?,
|
||||
ProtocolOp::CompareResponse(msg) => log_compare_response(msg, js)?,
|
||||
ProtocolOp::ExtendedResponse(msg) => log_extended_response(msg, js)?,
|
||||
ProtocolOp::IntermediateResponse(msg) => log_intermediate_response(msg, js)?,
|
||||
_ => {}
|
||||
}
|
||||
log_controls(&response.controls, js)?;
|
||||
js.close()?;
|
||||
}
|
||||
js.close()?;
|
||||
}
|
||||
|
||||
js.close()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn log_search_request(msg: &SearchRequest, js: &mut JsonBuilder) -> Result<(), JsonError> {
|
||||
js.open_object("search_request")?;
|
||||
js.set_string("base_object", &msg.base_object.0)?;
|
||||
js.set_uint("scope", msg.scope.0.into())?;
|
||||
js.set_uint("deref_alias", msg.deref_aliases.0.into())?;
|
||||
js.set_uint("size_limit", msg.size_limit.into())?;
|
||||
js.set_uint("time_limit", msg.time_limit.into())?;
|
||||
js.set_bool("types_only", msg.types_only)?;
|
||||
if let Filter::Present(val) = &msg.filter {
|
||||
js.open_object("filter")?;
|
||||
js.set_string("type", "present")?;
|
||||
js.set_string("value", &val.0.to_string())?;
|
||||
js.close()?;
|
||||
}
|
||||
if !msg.attributes.is_empty() {
|
||||
js.open_array("attributes")?;
|
||||
for attr in &msg.attributes {
|
||||
js.append_string(&attr.0)?;
|
||||
}
|
||||
js.close()?;
|
||||
}
|
||||
|
||||
js.close()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn log_bind_request(msg: &BindRequest, js: &mut JsonBuilder) -> Result<(), JsonError> {
|
||||
js.open_object("bind_request")?;
|
||||
js.set_uint("version", msg.version.into())?;
|
||||
js.set_string("name", &msg.name.0)?;
|
||||
if let AuthenticationChoice::Sasl(sasl) = &msg.authentication {
|
||||
js.open_object("sasl")?;
|
||||
js.set_string("mechanism", &sasl.mechanism.0)?;
|
||||
if let Some(credentials) = &sasl.credentials {
|
||||
js.set_hex("credentials", credentials)?;
|
||||
}
|
||||
js.close()?;
|
||||
}
|
||||
js.close()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn log_modify_request(msg: &ModifyRequest, js: &mut JsonBuilder) -> Result<(), JsonError> {
|
||||
js.open_object("modify_request")?;
|
||||
js.set_string("object", &msg.object.0)?;
|
||||
if !msg.changes.is_empty() {
|
||||
js.open_array("changes")?;
|
||||
for change in &msg.changes {
|
||||
js.start_object()?;
|
||||
js.set_string("operation", &change.operation.to_string())?;
|
||||
js.open_object("modification")?;
|
||||
js.set_string("attribute_type", &change.modification.attr_type.0)?;
|
||||
if !change.modification.attr_vals.is_empty() {
|
||||
js.open_array("attribute_values")?;
|
||||
for attr in &change.modification.attr_vals {
|
||||
js.append_string_from_bytes(&attr.0[..])?;
|
||||
}
|
||||
js.close()?;
|
||||
}
|
||||
js.close()?;
|
||||
js.close()?;
|
||||
}
|
||||
js.close()?;
|
||||
}
|
||||
js.close()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn log_add_request(msg: &AddRequest, js: &mut JsonBuilder) -> Result<(), JsonError> {
|
||||
js.open_object("add_request")?;
|
||||
js.set_string("entry", &msg.entry.0)?;
|
||||
if !msg.attributes.is_empty() {
|
||||
js.open_array("attributes")?;
|
||||
for attr in &msg.attributes {
|
||||
js.start_object()?;
|
||||
js.set_string("name", &attr.attr_type.0)?;
|
||||
if !attr.attr_vals.is_empty() {
|
||||
js.open_array("values")?;
|
||||
for val in &attr.attr_vals {
|
||||
js.append_string_from_bytes(&val.0)?;
|
||||
}
|
||||
js.close()?;
|
||||
}
|
||||
js.close()?;
|
||||
}
|
||||
js.close()?;
|
||||
}
|
||||
js.close()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn log_del_request(msg: &LdapDN, js: &mut JsonBuilder) -> Result<(), JsonError> {
|
||||
js.open_object("del_request")?;
|
||||
js.set_string("dn", &msg.0)?;
|
||||
js.close()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn log_mod_dn_request(msg: &ModDnRequest, js: &mut JsonBuilder) -> Result<(), JsonError> {
|
||||
js.open_object("mod_dn_request")?;
|
||||
js.set_string("entry", &msg.entry.0)?;
|
||||
js.set_string("new_rdn", &msg.newrdn.0)?;
|
||||
js.set_bool("delete_old_rdn", msg.deleteoldrdn)?;
|
||||
if let Some(newsuperior) = &msg.newsuperior {
|
||||
js.set_string("new_superior", &newsuperior.0)?;
|
||||
}
|
||||
js.close()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn log_compare_request(msg: &CompareRequest, js: &mut JsonBuilder) -> Result<(), JsonError> {
|
||||
js.open_object("compare_request")?;
|
||||
js.set_string("entry", &msg.entry.0)?;
|
||||
js.open_object("attribute_value_assertion")?;
|
||||
js.set_string("description", &msg.ava.attribute_desc.0)?;
|
||||
js.set_string_from_bytes("value", &msg.ava.assertion_value[..])?;
|
||||
js.close()?;
|
||||
js.close()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn log_extended_request(msg: &ExtendedRequest, js: &mut JsonBuilder) -> Result<(), JsonError> {
|
||||
js.open_object("extended_request")?;
|
||||
js.set_string("name", &msg.request_name.0)?;
|
||||
if let Some(value) = &msg.request_value {
|
||||
js.set_string_from_bytes("value", &value[..])?;
|
||||
}
|
||||
js.close()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn log_search_result_entry(msg: &SearchResultEntry, js: &mut JsonBuilder) -> Result<(), JsonError> {
|
||||
js.open_object("search_result_entry")?;
|
||||
js.set_string("base_object", &msg.object_name.0)?;
|
||||
if !msg.attributes.is_empty() {
|
||||
js.open_array("attributes")?;
|
||||
for attr in &msg.attributes {
|
||||
js.start_object()?;
|
||||
js.set_string("type", &attr.attr_type.0)?;
|
||||
if !attr.attr_vals.is_empty() {
|
||||
js.open_array("values")?;
|
||||
for val in &attr.attr_vals {
|
||||
js.append_string_from_bytes(&val.0)?;
|
||||
}
|
||||
js.close()?;
|
||||
}
|
||||
js.close()?;
|
||||
}
|
||||
js.close()?;
|
||||
}
|
||||
js.close()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn log_search_result_done(msg: &LdapResult, js: &mut JsonBuilder) -> Result<(), JsonError> {
|
||||
js.open_object("search_result_done")?;
|
||||
log_ldap_result(msg, js)?;
|
||||
js.close()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn log_bind_response(msg: &BindResponse, js: &mut JsonBuilder) -> Result<(), JsonError> {
|
||||
js.open_object("bind_response")?;
|
||||
log_ldap_result(&msg.result, js)?;
|
||||
if let Some(creds) = &msg.server_sasl_creds {
|
||||
js.set_hex("server_sasl_creds", creds)?;
|
||||
};
|
||||
js.close()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn log_modify_response(msg: &ModifyResponse, js: &mut JsonBuilder) -> Result<(), JsonError> {
|
||||
js.open_object("modify_response")?;
|
||||
log_ldap_result(&msg.result, js)?;
|
||||
js.close()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn log_add_response(msg: &LdapResult, js: &mut JsonBuilder) -> Result<(), JsonError> {
|
||||
js.open_object("add_response")?;
|
||||
log_ldap_result(msg, js)?;
|
||||
js.close()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn log_del_response(msg: &LdapResult, js: &mut JsonBuilder) -> Result<(), JsonError> {
|
||||
js.open_object("del_response")?;
|
||||
log_ldap_result(msg, js)?;
|
||||
js.close()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn log_mod_dn_response(msg: &LdapResult, js: &mut JsonBuilder) -> Result<(), JsonError> {
|
||||
js.open_object("mod_dn_response")?;
|
||||
log_ldap_result(msg, js)?;
|
||||
js.close()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn log_compare_response(msg: &LdapResult, js: &mut JsonBuilder) -> Result<(), JsonError> {
|
||||
js.open_object("compare_response")?;
|
||||
log_ldap_result(msg, js)?;
|
||||
js.close()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn log_extended_response(msg: &ExtendedResponse, js: &mut JsonBuilder) -> Result<(), JsonError> {
|
||||
js.open_object("extended_response")?;
|
||||
log_ldap_result(&msg.result, js)?;
|
||||
if let Some(name) = &msg.response_name {
|
||||
js.set_string("name", &name.0)?;
|
||||
}
|
||||
if let Some(value) = &msg.response_value {
|
||||
js.set_string_from_bytes("value", &value[..])?;
|
||||
}
|
||||
js.close()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn log_intermediate_response(
|
||||
msg: &IntermediateResponse, js: &mut JsonBuilder,
|
||||
) -> Result<(), JsonError> {
|
||||
js.open_object("intermediate_response")?;
|
||||
if let Some(name) = &msg.response_name {
|
||||
js.set_string("name", &name.0)?;
|
||||
}
|
||||
if let Some(value) = &msg.response_value {
|
||||
js.set_string_from_bytes("value", &value[..])?;
|
||||
}
|
||||
js.close()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn log_ldap_result(msg: &LdapResult, js: &mut JsonBuilder) -> Result<(), JsonError> {
|
||||
js.set_string("result_code", &msg.result_code.to_string())?;
|
||||
js.set_string("matched_dn", &msg.matched_dn.0)?;
|
||||
js.set_string("message", &msg.diagnostic_message.0)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn log_controls(controls: &Option<Vec<Control>>, js: &mut JsonBuilder) -> Result<(), JsonError> {
|
||||
if let Some(ctls) = controls {
|
||||
js.open_array("controls")?;
|
||||
for ctl in ctls {
|
||||
js.start_object()?;
|
||||
js.set_string("control_type", &ctl.control_type.0)?;
|
||||
js.set_bool("criticality", ctl.criticality)?;
|
||||
if let Some(ctl_val) = &ctl.control_value {
|
||||
js.set_hex("control_value", ctl_val)?;
|
||||
};
|
||||
js.close()?;
|
||||
}
|
||||
js.close()?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn rs_ldap_logger_log(
|
||||
tx: *mut std::os::raw::c_void, js: &mut JsonBuilder,
|
||||
) -> bool {
|
||||
let tx = cast_pointer!(tx, LdapTransaction);
|
||||
log_ldap(tx, js).is_ok()
|
||||
}
|
Loading…
Reference in New Issue