/src/suricata7/src/output-json-pgsql.c
Line | Count | Source |
1 | | /* Copyright (C) 2022-2024 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 | | /** |
19 | | * \file |
20 | | * |
21 | | * \author Juliana Fajardini <jufajardini@oisf.net> |
22 | | * |
23 | | * Implement JSON/eve logging for app-layer Pgsql. |
24 | | */ |
25 | | |
26 | | #include "suricata-common.h" |
27 | | #include "detect.h" |
28 | | #include "pkt-var.h" |
29 | | #include "conf.h" |
30 | | |
31 | | #include "threads.h" |
32 | | #include "threadvars.h" |
33 | | #include "tm-threads.h" |
34 | | |
35 | | #include "util-unittest.h" |
36 | | #include "util-buffer.h" |
37 | | #include "util-debug.h" |
38 | | #include "util-byte.h" |
39 | | |
40 | | #include "output.h" |
41 | | #include "output-json.h" |
42 | | |
43 | | #include "app-layer.h" |
44 | | #include "app-layer-parser.h" |
45 | | |
46 | | #include "output-json-pgsql.h" |
47 | | #include "rust.h" |
48 | | |
49 | 4 | #define PGSQL_LOG_PASSWORDS BIT_U32(0) |
50 | 0 | #define PGSQL_DEFAULTS (PGSQL_LOG_PASSWORDS) |
51 | | |
52 | | typedef struct OutputPgsqlCtx_ { |
53 | | uint32_t flags; |
54 | | OutputJsonCtx *eve_ctx; |
55 | | } OutputPgsqlCtx; |
56 | | |
57 | | typedef struct LogPgsqlLogThread_ { |
58 | | OutputPgsqlCtx *pgsqllog_ctx; |
59 | | OutputJsonThreadCtx *ctx; |
60 | | } LogPgsqlLogThread; |
61 | | |
62 | | bool JsonPgsqlAddMetadata(const Flow *f, uint64_t tx_id, JsonBuilder *jb) |
63 | 0 | { |
64 | 0 | void *state = FlowGetAppState(f); |
65 | 0 | if (state) { |
66 | 0 | void *tx = AppLayerParserGetTx(f->proto, ALPROTO_PGSQL, state, tx_id); |
67 | 0 | if (tx) { |
68 | 0 | return SCPgsqlLogger(tx, PGSQL_DEFAULTS, jb); |
69 | 0 | } |
70 | 0 | } |
71 | 0 | return false; |
72 | 0 | } |
73 | | |
74 | | static int JsonPgsqlLogger(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, void *state, |
75 | | void *txptr, uint64_t tx_id) |
76 | 353 | { |
77 | 353 | LogPgsqlLogThread *thread = thread_data; |
78 | 353 | SCLogDebug("Logging pgsql transaction %" PRIu64 ".", tx_id); |
79 | | |
80 | 353 | JsonBuilder *jb = |
81 | 353 | CreateEveHeader(p, LOG_DIR_FLOW, "pgsql", NULL, thread->pgsqllog_ctx->eve_ctx); |
82 | 353 | if (unlikely(jb == NULL)) { |
83 | 0 | return TM_ECODE_FAILED; |
84 | 0 | } |
85 | | |
86 | 353 | if (!SCPgsqlLogger(txptr, thread->pgsqllog_ctx->flags, jb)) { |
87 | 0 | goto error; |
88 | 0 | } |
89 | | |
90 | 353 | OutputJsonBuilderBuffer(jb, thread->ctx); |
91 | 353 | jb_free(jb); |
92 | | |
93 | 353 | return TM_ECODE_OK; |
94 | | |
95 | 0 | error: |
96 | 0 | jb_free(jb); |
97 | 0 | return TM_ECODE_FAILED; |
98 | 353 | } |
99 | | |
100 | | static void OutputPgsqlLogDeInitCtxSub(OutputCtx *output_ctx) |
101 | 0 | { |
102 | 0 | OutputPgsqlCtx *pgsqllog_ctx = (OutputPgsqlCtx *)output_ctx->data; |
103 | 0 | SCFree(pgsqllog_ctx); |
104 | 0 | SCFree(output_ctx); |
105 | 0 | } |
106 | | |
107 | | static void JsonPgsqlLogParseConfig(ConfNode *conf, OutputPgsqlCtx *pgsqllog_ctx) |
108 | 4 | { |
109 | 4 | pgsqllog_ctx->flags = ~0U; |
110 | | |
111 | 4 | const char *query = ConfNodeLookupChildValue(conf, "passwords"); |
112 | 4 | if (query != NULL) { |
113 | 0 | if (ConfValIsTrue(query)) { |
114 | 0 | pgsqllog_ctx->flags |= PGSQL_LOG_PASSWORDS; |
115 | 0 | } else { |
116 | 0 | pgsqllog_ctx->flags &= ~PGSQL_LOG_PASSWORDS; |
117 | 0 | } |
118 | 4 | } else { |
119 | 4 | pgsqllog_ctx->flags &= ~PGSQL_LOG_PASSWORDS; |
120 | 4 | } |
121 | 4 | } |
122 | | |
123 | | static OutputInitResult OutputPgsqlLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) |
124 | 4 | { |
125 | 4 | OutputInitResult result = { NULL, false }; |
126 | 4 | OutputJsonCtx *ojc = parent_ctx->data; |
127 | | |
128 | 4 | OutputPgsqlCtx *pgsql_ctx = SCMalloc(sizeof(OutputPgsqlCtx)); |
129 | 4 | if (unlikely(pgsql_ctx == NULL)) |
130 | 0 | return result; |
131 | | |
132 | 4 | OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); |
133 | 4 | if (unlikely(output_ctx == NULL)) { |
134 | 0 | SCFree(pgsql_ctx); |
135 | 0 | return result; |
136 | 0 | } |
137 | | |
138 | 4 | pgsql_ctx->eve_ctx = ojc; |
139 | | |
140 | 4 | output_ctx->data = pgsql_ctx; |
141 | 4 | output_ctx->DeInit = OutputPgsqlLogDeInitCtxSub; |
142 | | |
143 | 4 | JsonPgsqlLogParseConfig(conf, pgsql_ctx); |
144 | | |
145 | 4 | AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_PGSQL); |
146 | | |
147 | 4 | SCLogDebug("PostgreSQL log sub-module initialized."); |
148 | | |
149 | 4 | result.ctx = output_ctx; |
150 | 4 | result.ok = true; |
151 | 4 | return result; |
152 | 4 | } |
153 | | |
154 | | static TmEcode JsonPgsqlLogThreadInit(ThreadVars *t, const void *initdata, void **data) |
155 | 4 | { |
156 | 4 | LogPgsqlLogThread *thread = SCCalloc(1, sizeof(LogPgsqlLogThread)); |
157 | 4 | if (unlikely(thread == NULL)) { |
158 | 0 | return TM_ECODE_FAILED; |
159 | 0 | } |
160 | | |
161 | 4 | if (initdata == NULL) { |
162 | 0 | SCLogDebug("Error getting context for EveLogPgsql. \"initdata\" is NULL."); |
163 | 0 | goto error_exit; |
164 | 0 | } |
165 | | |
166 | 4 | thread->pgsqllog_ctx = ((OutputCtx *)initdata)->data; |
167 | 4 | thread->ctx = CreateEveThreadCtx(t, thread->pgsqllog_ctx->eve_ctx); |
168 | 4 | if (!thread->ctx) { |
169 | 0 | goto error_exit; |
170 | 0 | } |
171 | 4 | *data = (void *)thread; |
172 | | |
173 | 4 | return TM_ECODE_OK; |
174 | | |
175 | 0 | error_exit: |
176 | 0 | SCFree(thread); |
177 | 0 | return TM_ECODE_FAILED; |
178 | 4 | } |
179 | | |
180 | | static TmEcode JsonPgsqlLogThreadDeinit(ThreadVars *t, void *data) |
181 | 0 | { |
182 | 0 | LogPgsqlLogThread *thread = (LogPgsqlLogThread *)data; |
183 | 0 | if (thread == NULL) { |
184 | 0 | return TM_ECODE_OK; |
185 | 0 | } |
186 | 0 | FreeEveThreadCtx(thread->ctx); |
187 | 0 | SCFree(thread); |
188 | 0 | return TM_ECODE_OK; |
189 | 0 | } |
190 | | |
191 | | void JsonPgsqlLogRegister(void) |
192 | 74 | { |
193 | | /* PGSQL_START_REMOVE */ |
194 | 74 | if (ConfGetNode("app-layer.protocols.pgsql") == NULL) { |
195 | 3 | SCLogDebug("Disabling Pgsql eve-logger"); |
196 | 3 | return; |
197 | 3 | } |
198 | | /* PGSQL_END_REMOVE */ |
199 | | /* Register as an eve sub-module. */ |
200 | 71 | OutputRegisterTxSubModule(LOGGER_JSON_TX, "eve-log", "JsonPgsqlLog", "eve-log.pgsql", |
201 | 71 | OutputPgsqlLogInitSub, ALPROTO_PGSQL, JsonPgsqlLogger, JsonPgsqlLogThreadInit, |
202 | 71 | JsonPgsqlLogThreadDeinit, NULL); |
203 | | |
204 | 71 | SCLogDebug("PostgreSQL JSON logger registered."); |
205 | 71 | } |