Coverage Report

Created: 2026-11-12 06:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata8/src/detect-ftp-command-data.c
Line
Count
Source
1
/* Copyright (C) 2025-2026 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
 *
20
 * \author Jeff Lucovsky <jlucovsky@oisf.net>
21
 *
22
 * Implements the ftp.command_data sticky buffer
23
 *
24
 */
25
26
#include "suricata-common.h"
27
#include "detect.h"
28
29
#include "detect-parse.h"
30
#include "detect-engine.h"
31
#include "detect-engine-buffer.h"
32
#include "detect-engine-mpm.h"
33
#include "detect-engine-prefilter.h"
34
#include "detect-engine-helper.h"
35
#include "detect-content.h"
36
37
#include "flow.h"
38
39
#include "util-debug.h"
40
41
#include "app-layer.h"
42
#include "app-layer-ftp.h"
43
44
#include "detect-ftp-command-data.h"
45
46
12
#define KEYWORD_NAME "ftp.command_data"
47
12
#define KEYWORD_DOC  "ftp-keywords.html#ftp-command_data"
48
12
#define BUFFER_NAME  "ftp.command_data"
49
12
#define BUFFER_DESC  "ftp command_data"
50
51
static int g_ftp_cmd_data_buffer_id = 0;
52
53
static int DetectFtpCommandDataSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str)
54
140
{
55
140
    if (SCDetectBufferSetActiveList(de_ctx, s, g_ftp_cmd_data_buffer_id) < 0)
56
2
        return -1;
57
58
138
    if (SCDetectSignatureSetAppProto(s, ALPROTO_FTP) < 0)
59
2
        return -1;
60
61
136
    return 0;
62
138
}
63
64
static bool DetectFTPCommandDataGetData(
65
        const void *txv, const uint8_t _flow_flags, const uint8_t **buffer, uint32_t *buffer_len)
66
0
{
67
0
    FTPTransaction *tx = (FTPTransaction *)txv;
68
69
0
    if (tx->command_descriptor.command_code == FTP_COMMAND_UNKNOWN)
70
0
        return false;
71
72
0
    const char *b;
73
0
    uint8_t b_len;
74
0
    if (SCGetFtpCommandInfo(tx->command_descriptor.command_index, &b, NULL, &b_len)) {
75
        /* Compare rather than subtract: request_length is unsigned, so an
76
         * empty request would wrap and yield a bogus length. */
77
0
        if (tx->request != NULL && tx->request_length > (uint32_t)b_len + 1) {
78
            // command data starts here: advance past command + 1 space
79
0
            *buffer = tx->request + b_len + 1;
80
0
            *buffer_len = tx->request_length - b_len - 1;
81
0
            SCLogDebug("command data: \"%s\" [bytes %d]", *buffer, *buffer_len);
82
0
            return true;
83
0
        }
84
0
    }
85
86
0
    *buffer = NULL;
87
0
    *buffer_len = 0;
88
0
    return false;
89
0
}
90
91
void DetectFtpCommandDataRegister(void)
92
12
{
93
    /* ftp.command sticky buffer */
94
12
    sigmatch_table[DETECT_FTP_COMMAND_DATA].name = KEYWORD_NAME;
95
12
    sigmatch_table[DETECT_FTP_COMMAND_DATA].desc =
96
12
            "sticky buffer to match on the FTP command data buffer";
97
12
    sigmatch_table[DETECT_FTP_COMMAND_DATA].url = "/rules/" KEYWORD_DOC;
98
12
    sigmatch_table[DETECT_FTP_COMMAND_DATA].Setup = DetectFtpCommandDataSetup;
99
12
    sigmatch_table[DETECT_FTP_COMMAND_DATA].flags |= SIGMATCH_NOOPT | SIGMATCH_SUPPORT_FIREWALL;
100
101
12
    g_ftp_cmd_data_buffer_id = SCDetectHelperBufferProgressMpmRegister(BUFFER_NAME, BUFFER_DESC,
102
12
            ALPROTO_FTP, STREAM_TOSERVER, DetectFTPCommandDataGetData, FTP_STATE_FINISHED);
103
104
12
    SCLogDebug("registering " BUFFER_NAME " rule option");
105
12
}