Coverage Report

Created: 2026-09-28 07:39

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata8/src/output-file.c
Line
Count
Source
1
/* Copyright (C) 2007-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 Victor Julien <victor@inliniac.net>
22
 *
23
 * AppLayer File Logger Output registration functions
24
 */
25
26
#include "suricata-common.h"
27
#include "output.h"
28
#include "output-file.h"
29
#if 0
30
#include "app-layer.h"
31
#endif
32
#include "app-layer-parser.h" // FileApplyTxFlags
33
#include "detect-filemagic.h"
34
#include "util-file.h"
35
#include "util-magic.h"
36
#include "util-profiling.h"
37
#include "util-validate.h"
38
39
bool g_file_logger_enabled = false;
40
41
/* logger instance, a module + a output ctx,
42
 * it's perfectly valid that have multiple instances of the same
43
 * log module (e.g. http.log) with different output ctx'. */
44
typedef struct OutputFileLogger_ {
45
    SCFileLogger LogFunc;
46
    void *initdata;
47
    struct OutputFileLogger_ *next;
48
    const char *name;
49
    LoggerId logger_id;
50
    ThreadInitFunc ThreadInit;
51
    ThreadDeinitFunc ThreadDeinit;
52
} OutputFileLogger;
53
54
static OutputFileLogger *list = NULL;
55
56
int SCOutputRegisterFileLogger(LoggerId id, const char *name, SCFileLogger LogFunc, void *initdata,
57
        ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit)
58
4
{
59
4
    OutputFileLogger *op = SCCalloc(1, sizeof(*op));
60
4
    if (op == NULL)
61
0
        return -1;
62
63
4
    op->LogFunc = LogFunc;
64
4
    op->initdata = initdata;
65
4
    op->name = name;
66
4
    op->logger_id = id;
67
4
    op->ThreadInit = ThreadInit;
68
4
    op->ThreadDeinit = ThreadDeinit;
69
70
4
    if (list == NULL)
71
4
        list = op;
72
0
    else {
73
0
        OutputFileLogger *t = list;
74
0
        while (t->next)
75
0
            t = t->next;
76
0
        t->next = op;
77
0
    }
78
79
4
    SCLogDebug("OutputRegisterFileLogger happy");
80
81
4
    g_file_logger_enabled = true;
82
4
    return 0;
83
4
}
84
85
static void CloseFile(const Packet *p, Flow *f, AppLayerTxData *txd, File *file)
86
118k
{
87
118k
    DEBUG_VALIDATE_BUG_ON((file->flags & FILE_LOGGED) != 0);
88
118k
    DEBUG_VALIDATE_BUG_ON(f->alproto == ALPROTO_SMB && txd->files_logged != 0);
89
118k
    DEBUG_VALIDATE_BUG_ON(f->alproto == ALPROTO_FTPDATA && txd->files_logged != 0);
90
118k
    txd->files_logged++;
91
118k
    DEBUG_VALIDATE_BUG_ON(txd->files_logged > txd->files_opened);
92
118k
    file->flags |= FILE_LOGGED;
93
118k
    SCLogDebug("ff %p FILE_LOGGED", file);
94
118k
}
95
96
void OutputFileLogFfc(ThreadVars *tv, OutputFileLoggerThreadData *op_thread_data, Packet *p,
97
        FileContainer *ffc, void *txv, const uint64_t tx_id, AppLayerTxData *txd,
98
        const bool file_close, const bool file_trunc, uint8_t dir)
99
808k
{
100
808k
    if (ffc->head == NULL)
101
362k
        return;
102
103
445k
    SCLogDebug("ffc %p ffc->head %p file_close %d file_trunc %d dir %s", ffc,
104
445k
            ffc ? ffc->head : NULL, file_close, file_trunc, dir == STREAM_TOSERVER ? "ts" : "tc");
105
445k
    File *ff;
106
897k
    for (ff = ffc->head; ff != NULL; ff = ff->next) {
107
451k
        SCLogDebug("ff %p pre-FILE_LOGGED", ff);
108
451k
        if (ff->flags & FILE_LOGGED)
109
332
            continue;
110
111
451k
        FileApplyTxFlags(txd, dir, ff);
112
113
451k
        SCLogDebug("ff %p state %u post-FILE_LOGGED", ff, ff->state);
114
115
451k
        if (file_trunc && ff->state < FILE_STATE_CLOSED) {
116
0
            SCLogDebug("file_trunc %d ff->state %u => FILE_STATE_TRUNCATED", file_trunc, ff->state);
117
0
            ff->state = FILE_STATE_TRUNCATED;
118
0
        }
119
120
451k
        if (file_close && ff->state < FILE_STATE_CLOSED) {
121
0
            SCLogDebug("file_close %d ff->state %u => FILE_STATE_TRUNCATED", file_close, ff->state);
122
0
            ff->state = FILE_STATE_TRUNCATED;
123
0
        }
124
125
451k
        SCLogDebug("ff %p state %u", ff, ff->state);
126
127
451k
        if (ff->state > FILE_STATE_OPENED) {
128
118k
            SCLogDebug("FILE LOGGING");
129
118k
            bool file_logged = false;
130
#ifdef HAVE_MAGIC
131
            if (FileForceMagic() && ff->magic == NULL) {
132
                FilemagicThreadLookup(&op_thread_data->magic_ctx, ff);
133
            }
134
#endif
135
118k
            const OutputFileLogger *logger = list;
136
118k
            const OutputLoggerThreadStore *store = op_thread_data->store;
137
236k
            while (logger && store) {
138
118k
                DEBUG_VALIDATE_BUG_ON(logger->LogFunc == NULL);
139
140
118k
                SCLogDebug("logger %p", logger);
141
118k
                PACKET_PROFILING_LOGGER_START(p, logger->logger_id);
142
118k
                logger->LogFunc(tv, store->thread_data, (const Packet *)p, (const File *)ff, txv,
143
118k
                        tx_id, dir);
144
118k
                PACKET_PROFILING_LOGGER_END(p, logger->logger_id);
145
118k
                file_logged = true;
146
147
118k
                logger = logger->next;
148
118k
                store = store->next;
149
150
118k
                DEBUG_VALIDATE_BUG_ON(logger == NULL && store != NULL);
151
118k
                DEBUG_VALIDATE_BUG_ON(logger != NULL && store == NULL);
152
118k
            }
153
154
118k
            if (file_logged) {
155
118k
                CloseFile(p, p->flow, txd, ff);
156
118k
            }
157
118k
        }
158
451k
    }
159
445k
}
160
161
/** \brief thread init for the file logger
162
 *  This will run the thread init functions for the individual registered
163
 *  loggers */
164
TmEcode OutputFileLogThreadInit(ThreadVars *tv, OutputFileLoggerThreadData **data)
165
4
{
166
4
    OutputFileLoggerThreadData *td = SCCalloc(1, sizeof(*td));
167
4
    if (td == NULL)
168
0
        return TM_ECODE_FAILED;
169
4
    *data = td;
170
171
#ifdef HAVE_MAGIC
172
    td->magic_ctx = MagicInitContext();
173
    if (td->magic_ctx == NULL) {
174
        SCFree(td);
175
        return TM_ECODE_FAILED;
176
    }
177
#endif
178
179
4
    SCLogDebug("OutputFileLogThreadInit happy (*data %p)", *data);
180
181
4
    OutputFileLogger *logger = list;
182
8
    while (logger) {
183
4
        if (logger->ThreadInit) {
184
4
            void *retptr = NULL;
185
4
            if (logger->ThreadInit(tv, logger->initdata, &retptr) == TM_ECODE_OK) {
186
4
                OutputLoggerThreadStore *ts = SCCalloc(1, sizeof(*ts));
187
4
                /* todo */ BUG_ON(ts == NULL);
188
189
                /* store thread handle */
190
4
                ts->thread_data = retptr;
191
192
4
                if (td->store == NULL) {
193
4
                    td->store = ts;
194
4
                } else {
195
0
                    OutputLoggerThreadStore *tmp = td->store;
196
0
                    while (tmp->next != NULL)
197
0
                        tmp = tmp->next;
198
0
                    tmp->next = ts;
199
0
                }
200
201
4
                SCLogDebug("%s is now set up", logger->name);
202
4
            }
203
4
        }
204
205
4
        logger = logger->next;
206
4
    }
207
208
4
    return TM_ECODE_OK;
209
4
}
210
211
TmEcode OutputFileLogThreadDeinit(ThreadVars *tv, OutputFileLoggerThreadData *op_thread_data)
212
0
{
213
0
    OutputLoggerThreadStore *store = op_thread_data->store;
214
0
    OutputFileLogger *logger = list;
215
216
0
    while (logger && store) {
217
0
        if (logger->ThreadDeinit) {
218
0
            logger->ThreadDeinit(tv, store->thread_data);
219
0
        }
220
221
0
        OutputLoggerThreadStore *next_store = store->next;
222
0
        SCFree(store);
223
0
        store = next_store;
224
0
        logger = logger->next;
225
0
    }
226
227
#ifdef HAVE_MAGIC
228
    MagicDeinitContext(op_thread_data->magic_ctx);
229
#endif
230
231
0
    SCFree(op_thread_data);
232
0
    return TM_ECODE_OK;
233
0
}
234
235
void OutputFileLoggerRegister(void)
236
78
{
237
78
}
238
239
void OutputFileShutdown(void)
240
0
{
241
0
    OutputFileLogger *logger = list;
242
0
    while (logger) {
243
0
        OutputFileLogger *next_logger = logger->next;
244
0
        SCFree(logger);
245
0
        logger = next_logger;
246
0
    }
247
248
    list = NULL;
249
0
}