Coverage Report

Created: 2024-09-06 06:25

/src/dovecot/src/lib-smtp/smtp-server-cmd-helo.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
2
3
#include "lib.h"
4
#include "str.h"
5
#include "array.h"
6
#include "smtp-syntax.h"
7
8
#include "smtp-server-private.h"
9
10
/* EHLO, HELO commands */
11
12
static void
13
cmd_helo_completed(struct smtp_server_cmd_ctx *cmd,
14
       struct smtp_server_cmd_helo *data)
15
7.24k
{
16
7.24k
  struct smtp_server_connection *conn = cmd->conn;
17
7.24k
  struct smtp_server_command *command = cmd->cmd;
18
19
7.24k
  i_assert(smtp_server_command_is_replied(command));
20
7.24k
  if (!smtp_server_command_replied_success(command)) {
21
    /* Failure */
22
0
    return;
23
0
  }
24
25
7.24k
  if (conn->pending_helo == &data->helo)
26
7.24k
    conn->pending_helo = NULL;
27
28
  /* Success */
29
7.24k
  smtp_server_connection_reset_state(conn);
30
31
7.24k
  i_free(conn->helo_domain);
32
7.24k
  conn->helo_domain = i_strdup(data->helo.domain);
33
7.24k
  conn->helo.domain = conn->helo_domain;
34
7.24k
  conn->helo.domain_valid = data->helo.domain_valid;
35
7.24k
  conn->helo.old_smtp = data->helo.old_smtp;
36
7.24k
}
37
38
static void
39
cmd_helo_next(struct smtp_server_cmd_ctx *cmd,
40
        struct smtp_server_cmd_helo *data)
41
7.24k
{
42
7.24k
  struct smtp_server_connection *conn = cmd->conn;
43
44
7.24k
  if (null_strcmp(conn->helo.domain, data->helo.domain) != 0 ||
45
7.24k
      conn->helo.old_smtp != data->helo.old_smtp)
46
1.37k
    data->changed = TRUE; /* Definitive assessment */
47
7.24k
}
48
49
static void
50
smtp_server_cmd_helo_run(struct smtp_server_cmd_ctx *cmd, const char *params,
51
       bool old_smtp)
52
7.90k
{
53
7.90k
  struct smtp_server_connection *conn = cmd->conn;
54
7.90k
  const struct smtp_server_callbacks *callbacks = conn->callbacks;
55
7.90k
  struct smtp_server_cmd_helo *helo_data;
56
7.90k
  struct smtp_server_command *command = cmd->cmd;
57
7.90k
  bool first = (conn->pending_helo == NULL && conn->helo.domain == NULL);
58
7.90k
  const char *domain = NULL;
59
7.90k
  int ret;
60
61
  /* Parse domain argument */
62
63
7.90k
  if (*params == '\0') {
64
659
    smtp_server_reply(cmd, 501, "", "Missing hostname");
65
659
    return;
66
659
  }
67
7.24k
  ret = smtp_helo_domain_parse(params, !old_smtp, &domain);
68
69
7.24k
  smtp_server_command_pipeline_block(cmd);
70
7.24k
  if (conn->state.state == SMTP_SERVER_STATE_GREETING) {
71
1.32k
    smtp_server_connection_set_state(conn, SMTP_SERVER_STATE_HELO,
72
1.32k
             NULL);
73
1.32k
  }
74
75
7.24k
  helo_data = p_new(cmd->pool, struct smtp_server_cmd_helo, 1);
76
7.24k
  helo_data->helo.domain = p_strdup(cmd->pool, domain);
77
7.24k
  helo_data->helo.domain_valid = ( ret >= 0 );
78
7.24k
  helo_data->helo.old_smtp = old_smtp;
79
7.24k
  helo_data->first = first;
80
7.24k
  command->data = helo_data;
81
82
7.24k
  if (null_strcmp(conn->helo.domain, domain) != 0 ||
83
7.24k
      conn->helo.old_smtp != old_smtp)
84
1.37k
    helo_data->changed = TRUE; /* Preliminary assessment */
85
86
7.24k
  if (conn->pending_helo == NULL)
87
7.24k
    conn->pending_helo = &helo_data->helo;
88
89
7.24k
  smtp_server_command_add_hook(
90
7.24k
    command, SMTP_SERVER_COMMAND_HOOK_NEXT,
91
7.24k
    cmd_helo_next, helo_data);
92
7.24k
  smtp_server_command_add_hook(
93
7.24k
    command, SMTP_SERVER_COMMAND_HOOK_COMPLETED,
94
7.24k
    cmd_helo_completed, helo_data);
95
96
7.24k
  smtp_server_command_ref(command);
97
7.24k
  if (callbacks != NULL && callbacks->conn_cmd_helo != NULL) {
98
    /* Specific implementation of EHLO command */
99
0
    ret = callbacks->conn_cmd_helo(conn->context, cmd, helo_data);
100
0
    if (ret <= 0) {
101
0
      i_assert(ret == 0 ||
102
0
         smtp_server_command_is_replied(command));
103
      /* Command is waiting for external event or it failed */
104
0
      smtp_server_command_unref(&command);
105
0
      return;
106
0
    }
107
0
  }
108
109
7.24k
  if (!smtp_server_command_is_replied(command)) {
110
    /* Submit default EHLO reply if none is provided */
111
7.24k
    smtp_server_cmd_ehlo_reply_default(cmd);
112
7.24k
  }
113
7.24k
  smtp_server_command_unref(&command);
114
7.24k
}
115
116
void smtp_server_cmd_ehlo(struct smtp_server_cmd_ctx *cmd, const char *params)
117
6.88k
{
118
  /* ehlo = "EHLO" SP ( Domain / address-literal ) CRLF */
119
120
6.88k
  smtp_server_cmd_helo_run(cmd, params, FALSE);
121
6.88k
}
122
123
void smtp_server_cmd_helo(struct smtp_server_cmd_ctx *cmd, const char *params)
124
1.02k
{
125
  /* helo = "HELO" SP Domain CRLF */
126
127
1.02k
  smtp_server_cmd_helo_run(cmd, params, TRUE);
128
1.02k
}
129
130
struct smtp_server_reply *
131
smtp_server_cmd_ehlo_reply_create(struct smtp_server_cmd_ctx *cmd)
132
7.24k
{
133
7.24k
  static struct {
134
7.24k
    const char *name;
135
7.24k
    void (*add)(struct smtp_server_reply *reply);
136
7.24k
  } standard_caps[] = {
137
    /* Sorted alphabetically */
138
7.24k
    { "8BITMIME", smtp_server_reply_ehlo_add_8bitmime },
139
7.24k
    { "BINARYMIME", smtp_server_reply_ehlo_add_binarymime },
140
7.24k
    { "CHUNKING", smtp_server_reply_ehlo_add_chunking },
141
7.24k
    { "DSN", smtp_server_reply_ehlo_add_dsn },
142
7.24k
    { "ENHANCEDSTATUSCODES",
143
7.24k
      smtp_server_reply_ehlo_add_enhancedstatuscodes },
144
7.24k
    { "PIPELINING", smtp_server_reply_ehlo_add_pipelining },
145
7.24k
    { "SIZE", smtp_server_reply_ehlo_add_size },
146
#ifdef EXPERIMENTAL_MAIL_UTF8
147
    { "SMTPUTF8", smtp_server_reply_ehlo_add_smtputf8 },
148
#endif
149
7.24k
    { "STARTTLS", smtp_server_reply_ehlo_add_starttls },
150
7.24k
    { "VRFY", smtp_server_reply_ehlo_add_vrfy },
151
7.24k
    { "XCLIENT", smtp_server_reply_ehlo_add_xclient }
152
7.24k
  };
153
7.24k
  const unsigned int standard_caps_count = N_ELEMENTS(standard_caps);
154
7.24k
  struct smtp_server_connection *conn = cmd->conn;
155
7.24k
  struct smtp_server_command *command = cmd->cmd;
156
7.24k
  struct smtp_server_cmd_helo *helo_data = command->data;
157
7.24k
  const struct smtp_capability_extra *extra_caps = NULL;
158
7.24k
  unsigned int extra_caps_count, i, j;
159
7.24k
  struct smtp_server_reply *reply;
160
161
7.24k
  reply = smtp_server_reply_create_ehlo(cmd->cmd);
162
163
7.24k
  if (helo_data->helo.old_smtp) {
164
792
    i_assert(cmd->cmd->reg->func == smtp_server_cmd_helo);
165
792
    return reply;
166
792
  }
167
7.24k
  i_assert(cmd->cmd->reg->func == smtp_server_cmd_ehlo);
168
169
6.45k
  extra_caps_count = 0;
170
6.45k
  if (array_is_created(&conn->extra_capabilities)) {
171
0
    extra_caps = array_get(&conn->extra_capabilities,
172
0
               &extra_caps_count);
173
0
  }
174
175
6.45k
  i = j = 0;
176
71.0k
  while (i < standard_caps_count || j < extra_caps_count) {
177
64.5k
    if (i < standard_caps_count &&
178
64.5k
        (j >= extra_caps_count ||
179
64.5k
         strcasecmp(standard_caps[i].name,
180
64.5k
        extra_caps[j].name) < 0)) {
181
64.5k
      standard_caps[i].add(reply);
182
64.5k
      i++;
183
64.5k
    } else {
184
0
      smtp_server_reply_ehlo_add_params(
185
0
        reply, extra_caps[j].name,
186
0
        extra_caps[j].params);
187
0
      j++;
188
0
    }
189
64.5k
  }
190
6.45k
  return reply;
191
6.45k
}
192
193
void smtp_server_cmd_ehlo_reply_default(struct smtp_server_cmd_ctx *cmd)
194
7.24k
{
195
7.24k
  struct smtp_server_reply *reply;
196
197
7.24k
  reply = smtp_server_cmd_ehlo_reply_create(cmd);
198
7.24k
  smtp_server_reply_submit(reply);
199
7.24k
}