• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OISF / suricata / 22550902417

01 Mar 2026 07:32PM UTC coverage: 68.401% (-5.3%) from 73.687%
22550902417

Pull #14922

github

web-flow
github-actions: bump actions/upload-artifact from 6.0.0 to 7.0.0

Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 6.0.0 to 7.0.0.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: 7.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Pull Request #14922: github-actions: bump actions/upload-artifact from 6.0.0 to 7.0.0

218243 of 319063 relevant lines covered (68.4%)

3284926.58 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/rust/src/pgsql/logger.rs
1
/* Copyright (C) 2022 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
// Author: Juliana Fajardini <jufajardini@gmail.com>
19

20
//! PostgreSQL parser json logger
21

22
use crate::jsonbuilder::{JsonBuilder, JsonError};
23
use crate::pgsql::parser::*;
24
use crate::pgsql::pgsql::*;
25
use std;
26

27
pub const PGSQL_LOG_PASSWORDS: u32 = BIT_U32!(0);
28

29
fn log_pgsql(tx: &PgsqlTransaction, flags: u32, js: &mut JsonBuilder) -> Result<(), JsonError> {
×
30
    js.open_object("pgsql")?;
×
31
    js.set_uint("tx_id", tx.tx_id)?;
×
32
    if !tx.requests.is_empty() {
×
33
        // For now, even if 'requests' is an array, we don't need to log it as such, as
34
        // there should be no duplicated messages, and there should be no more than 2 requests per tx
35
        debug_validate_bug_on!(tx.requests.len() > 2);
36
        js.open_object("request")?;
×
37
        log_request(tx, flags, js)?;
×
38
        js.close()?;
×
39
    } else if tx.responses.is_empty() {
×
40
        SCLogDebug!("Suricata created an empty PGSQL transaction");
41
        // TODO Log anomaly event?
42
        // if there are no transactions, there's nothing more to be logged
43
        js.close()?;
×
44
        return Ok(());
×
45
    }
×
46

47
    if !tx.responses.is_empty() {
×
48
        SCLogDebug!("Responses length: {}", tx.responses.len());
49
        js.set_object("response", &log_response_object(tx)?)?;
×
50
    }
×
51
    js.close()?;
×
52

53
    Ok(())
×
54
}
×
55

56
fn log_request(tx: &PgsqlTransaction, flags: u32, js: &mut JsonBuilder) -> Result<(), JsonError> {
×
57
    // CopyFail, ConsolidatedCopyDataIn, CopyDone
×
58
    let mut duplicated_messages: [u8; 3] = [0, 0, 0];
×
59
    for req in &tx.requests {
×
60
        SCLogDebug!("Suricata requests length: {}", tx.requests.len());
61
        match req {
×
62
            PgsqlFEMessage::StartupMessage(StartupPacket {
63
                length: _,
64
                proto_major,
×
65
                proto_minor,
×
66
                params,
×
67
            }) => {
×
68
                let proto = format!("{}.{}", proto_major, proto_minor);
×
69
                js.set_string("protocol_version", &proto)?;
×
70
                js.set_object("startup_parameters", &log_startup_parameters(params)?)?;
×
71
            }
72
            PgsqlFEMessage::SSLRequest(_) => {
73
                js.set_string("message", "SSL Request")?;
×
74
            }
75
            PgsqlFEMessage::SASLInitialResponse(SASLInitialResponsePacket {
76
                identifier: _,
77
                length: _,
78
                auth_mechanism,
×
79
                param_length: _,
×
80
                sasl_param,
×
81
            }) => {
×
82
                js.set_string("sasl_authentication_mechanism", auth_mechanism.to_str())?;
×
83
                js.set_string_from_bytes("sasl_param", sasl_param)?;
×
84
            }
85
            PgsqlFEMessage::PasswordMessage(RegularPacket {
86
                identifier: _,
87
                length: _,
88
                payload,
×
89
            }) => {
×
90
                if flags & PGSQL_LOG_PASSWORDS != 0 {
×
91
                    js.set_string_from_bytes(req.to_str(), payload)?;
×
92
                } else {
93
                    js.set_bool("password_redacted", true)?;
×
94
                }
95
            }
96
            PgsqlFEMessage::SASLResponse(RegularPacket {
97
                identifier: _,
98
                length: _,
99
                payload,
×
100
            }) => {
×
101
                js.set_string_from_bytes("sasl_response", payload)?;
×
102
            }
103
            PgsqlFEMessage::SimpleQuery(RegularPacket {
104
                identifier: _,
105
                length: _,
106
                payload,
×
107
            }) => {
×
108
                js.set_string_from_bytes(req.to_str(), payload)?;
×
109
            }
110
            PgsqlFEMessage::CopyFail(RegularPacket {
111
                identifier: _,
112
                length: _,
113
                payload,
×
114
            }) => {
×
115
                js.set_string_from_bytes(req.to_str(), payload)?;
×
116
                duplicated_messages[0] += 1;
×
117
                debug_validate_bug_on!(duplicated_messages[0] > 1);
118
            }
119
            PgsqlFEMessage::CancelRequest(CancelRequestMessage { pid, backend_key }) => {
×
120
                js.set_string("message", "cancel_request")?;
×
121
                js.set_uint("process_id", *pid)?;
×
122
                js.set_uint("secret_key", *backend_key)?;
×
123
            }
124
            PgsqlFEMessage::ConsolidatedCopyDataIn(ConsolidatedDataRowPacket {
125
                identifier: _,
126
                row_cnt,
×
127
                data_size,
×
128
            }) => {
×
129
                js.open_object(req.to_str())?;
×
130
                js.set_uint("msg_count", *row_cnt)?;
×
131
                js.set_uint("data_size", *data_size)?;
×
132
                js.close()?;
×
133
                duplicated_messages[1] += 1;
×
134
                debug_validate_bug_on!(duplicated_messages[1] > 1);
135
            }
136
            PgsqlFEMessage::CopyDone(_) => {
137
                js.set_string("message", req.to_str())?;
×
138
                duplicated_messages[2] += 1;
×
139
                debug_validate_bug_on!(duplicated_messages[2] > 1);
140
            }
141
            PgsqlFEMessage::Terminate(_) => {
142
                js.set_string("message", req.to_str())?;
×
143
            }
144
            PgsqlFEMessage::UnknownMessageType(RegularPacket {
145
                identifier: _,
146
                length: _,
147
                payload: _,
148
            }) => {
×
149
                // We don't want to log these, for now. Cf redmine: #6576
×
150
            }
×
151
        }
152
    }
153
    Ok(())
×
154
}
×
155

156
fn log_response_object(tx: &PgsqlTransaction) -> Result<JsonBuilder, JsonError> {
×
157
    let mut jb = JsonBuilder::try_new_object()?;
×
158
    let mut array_open = false;
×
159
    for response in &tx.responses {
×
160
        if let PgsqlBEMessage::ParameterStatus(msg) = response {
×
161
            if !array_open {
×
162
                jb.open_array("parameter_status")?;
×
163
                array_open = true;
×
164
            }
×
165
            jb.append_object(&log_pgsql_param(&msg.param)?)?;
×
166
        } else {
167
            if array_open {
×
168
                jb.close()?;
×
169
                array_open = false;
×
170
            }
×
171
            log_response(response, &mut jb)?;
×
172
        }
173
    }
174
    jb.close()?;
×
175
    Ok(jb)
×
176
}
×
177

178
fn log_response(res: &PgsqlBEMessage, jb: &mut JsonBuilder) -> Result<(), JsonError> {
×
179
    match res {
×
180
        PgsqlBEMessage::SSLResponse(message) => {
×
181
            if let SSLResponseMessage::SSLAccepted = message {
×
182
                jb.set_bool("ssl_accepted", true)?;
×
183
            } else {
184
                jb.set_bool("ssl_accepted", false)?;
×
185
            }
186
        }
187
        PgsqlBEMessage::NoticeResponse(ErrorNoticeMessage {
188
            identifier: _,
189
            length: _,
190
            message_body,
×
191
        })
192
        | PgsqlBEMessage::ErrorResponse(ErrorNoticeMessage {
193
            identifier: _,
194
            length: _,
195
            message_body,
×
196
        }) => {
197
            log_error_notice_field_types(message_body, jb)?;
×
198
        }
199
        PgsqlBEMessage::AuthenticationMD5Password(AuthenticationMessage {
200
            identifier: _,
201
            length: _,
202
            auth_type: _,
203
            payload,
×
204
        })
205
        | PgsqlBEMessage::AuthenticationSSPI(AuthenticationMessage {
206
            identifier: _,
207
            length: _,
208
            auth_type: _,
209
            payload,
×
210
        })
211
        | PgsqlBEMessage::AuthenticationSASLFinal(AuthenticationMessage {
212
            identifier: _,
213
            length: _,
214
            auth_type: _,
215
            payload,
×
216
        })
217
        | PgsqlBEMessage::CommandComplete(RegularPacket {
218
            identifier: _,
219
            length: _,
220
            payload,
×
221
        }) => {
222
            jb.set_string_from_bytes(res.to_str(), payload)?;
×
223
        }
224
        PgsqlBEMessage::UnknownMessageType(RegularPacket {
225
            identifier: _,
226
            length: _,
227
            payload: _,
228
        }) => {
×
229
            // We don't want to log these, for now. Cf redmine: #6576
×
230
        }
×
231
        PgsqlBEMessage::AuthenticationOk(_)
232
        | PgsqlBEMessage::AuthenticationCleartextPassword(_)
233
        | PgsqlBEMessage::AuthenticationSASL(_)
234
        | PgsqlBEMessage::AuthenticationSASLContinue(_)
235
        | PgsqlBEMessage::CopyDone(_) => {
236
            jb.set_string("message", res.to_str())?;
×
237
        }
238
        PgsqlBEMessage::ParameterStatus(ParameterStatusMessage {
239
            identifier: _,
240
            length: _,
241
            param: _,
242
        }) => {
×
243
            // We take care of these elsewhere
×
244
        }
×
245
        PgsqlBEMessage::CopyOutResponse(CopyResponse {
246
            identifier: _,
247
            length: _,
248
            column_cnt,
×
249
        })
250
        | PgsqlBEMessage::CopyInResponse(CopyResponse {
251
            identifier: _,
252
            length: _,
253
            column_cnt,
×
254
        }) => {
255
            jb.open_object(res.to_str())?;
×
256
            jb.set_uint("columns", *column_cnt)?;
×
257
            jb.close()?;
×
258
        }
259
        PgsqlBEMessage::BackendKeyData(BackendKeyDataMessage {
260
            identifier: _,
261
            length: _,
262
            backend_pid,
×
263
            secret_key,
×
264
        }) => {
×
265
            jb.set_uint("process_id", *backend_pid)?;
×
266
            jb.set_uint("secret_key", *secret_key)?;
×
267
        }
268
        PgsqlBEMessage::ReadyForQuery(ReadyForQueryMessage {
269
            identifier: _,
270
            length: _,
271
            transaction_status: _,
272
        }) => {
×
273
            // We don't want to log this one
×
274
        }
×
275
        PgsqlBEMessage::ConsolidatedCopyDataOut(ConsolidatedDataRowPacket {
276
            identifier: _,
277
            row_cnt,
×
278
            data_size,
×
279
        }) => {
×
280
            jb.open_object(res.to_str())?;
×
281
            jb.set_uint("row_count", *row_cnt)?;
×
282
            jb.set_uint("data_size", *data_size)?;
×
283
            jb.close()?;
×
284
        }
285
        PgsqlBEMessage::RowDescription(RowDescriptionMessage {
286
            identifier: _,
287
            length: _,
288
            field_count,
×
289
            fields: _,
×
290
        }) => {
×
291
            jb.set_uint("field_count", *field_count)?;
×
292
        }
293
        PgsqlBEMessage::ConsolidatedDataRow(ConsolidatedDataRowPacket {
294
            identifier: _,
295
            row_cnt,
×
296
            data_size,
×
297
        }) => {
×
298
            jb.set_uint("data_rows", *row_cnt)?;
×
299
            jb.set_uint("data_size", *data_size)?;
×
300
        }
301
        PgsqlBEMessage::NotificationResponse(NotificationResponse {
302
            identifier: _,
303
            length: _,
304
            pid,
×
305
            channel_name,
×
306
            payload,
×
307
        }) => {
×
308
            jb.set_uint("pid", *pid)?;
×
309
            jb.set_string_from_bytes("channel_name", channel_name)?;
×
310
            jb.set_string_from_bytes("payload", payload)?;
×
311
        }
312
    }
313
    Ok(())
×
314
}
×
315

316
fn log_error_notice_field_types(
×
317
    error_fields: &Vec<PgsqlErrorNoticeMessageField>, jb: &mut JsonBuilder,
×
318
) -> Result<(), JsonError> {
×
319
    for field in error_fields {
×
320
        jb.set_string_from_bytes(field.field_type.to_str(), &field.field_value)?;
×
321
    }
322
    Ok(())
×
323
}
×
324

325
fn log_startup_parameters(params: &PgsqlStartupParameters) -> Result<JsonBuilder, JsonError> {
×
326
    let mut jb = JsonBuilder::try_new_object()?;
×
327
    // User is a mandatory field in a pgsql message
328
    jb.set_string_from_bytes("user", &params.user.value)?;
×
329
    if let Some(parameters) = &params.optional_params {
×
330
        jb.open_array("optional_parameters")?;
×
331
        for parameter in parameters {
×
332
            jb.append_object(&log_pgsql_param(parameter)?)?;
×
333
        }
334
        jb.close()?;
×
335
    }
×
336

337
    jb.close()?;
×
338
    Ok(jb)
×
339
}
×
340

341
fn log_pgsql_param(param: &PgsqlParameter) -> Result<JsonBuilder, JsonError> {
×
342
    let mut jb = JsonBuilder::try_new_object()?;
×
343
    jb.set_string_from_bytes(param.name.to_str(), &param.value)?;
×
344
    jb.close()?;
×
345
    Ok(jb)
×
346
}
×
347

348
#[no_mangle]
349
pub unsafe extern "C" fn SCPgsqlLogger(
×
350
    tx: *mut std::os::raw::c_void, flags: u32, js: &mut JsonBuilder,
×
351
) -> bool {
×
352
    let tx_pgsql = cast_pointer!(tx, PgsqlTransaction);
×
353
    SCLogDebug!(
×
354
        "----------- PGSQL rs_pgsql_logger call. Tx id is {:?}",
×
355
        tx_pgsql.tx_id
×
356
    );
×
357
    log_pgsql(tx_pgsql, flags, js).is_ok()
×
358
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc