Coverage Report

Created: 2025-07-11 06:23

/src/libzmq/src/zap_client.cpp
Line
Count
Source (jump to first uncovered line)
1
/* SPDX-License-Identifier: MPL-2.0 */
2
3
#include "precompiled.hpp"
4
5
#include "zap_client.hpp"
6
#include "msg.hpp"
7
#include "session_base.hpp"
8
9
namespace zmq
10
{
11
const char zap_version[] = "1.0";
12
const size_t zap_version_len = sizeof (zap_version) - 1;
13
14
const char id[] = "1";
15
const size_t id_len = sizeof (id) - 1;
16
17
zap_client_t::zap_client_t (session_base_t *const session_,
18
                            const std::string &peer_address_,
19
                            const options_t &options_) :
20
0
    mechanism_base_t (session_, options_), peer_address (peer_address_)
21
0
{
22
0
}
23
24
void zap_client_t::send_zap_request (const char *mechanism_,
25
                                     size_t mechanism_length_,
26
                                     const uint8_t *credentials_,
27
                                     size_t credentials_size_)
28
0
{
29
0
    send_zap_request (mechanism_, mechanism_length_, &credentials_,
30
0
                      &credentials_size_, 1);
31
0
}
32
33
void zap_client_t::send_zap_request (const char *mechanism_,
34
                                     size_t mechanism_length_,
35
                                     const uint8_t **credentials_,
36
                                     size_t *credentials_sizes_,
37
                                     size_t credentials_count_)
38
0
{
39
    // write_zap_msg cannot fail. It could only fail if the HWM was exceeded,
40
    // but on the ZAP socket, the HWM is disabled.
41
42
0
    int rc;
43
0
    msg_t msg;
44
45
    //  Address delimiter frame
46
0
    rc = msg.init ();
47
0
    errno_assert (rc == 0);
48
0
    msg.set_flags (msg_t::more);
49
0
    rc = session->write_zap_msg (&msg);
50
0
    errno_assert (rc == 0);
51
52
    //  Version frame
53
0
    rc = msg.init_size (zap_version_len);
54
0
    errno_assert (rc == 0);
55
0
    memcpy (msg.data (), zap_version, zap_version_len);
56
0
    msg.set_flags (msg_t::more);
57
0
    rc = session->write_zap_msg (&msg);
58
0
    errno_assert (rc == 0);
59
60
    //  Request ID frame
61
0
    rc = msg.init_size (id_len);
62
0
    errno_assert (rc == 0);
63
0
    memcpy (msg.data (), id, id_len);
64
0
    msg.set_flags (msg_t::more);
65
0
    rc = session->write_zap_msg (&msg);
66
0
    errno_assert (rc == 0);
67
68
    //  Domain frame
69
0
    rc = msg.init_size (options.zap_domain.length ());
70
0
    errno_assert (rc == 0);
71
0
    memcpy (msg.data (), options.zap_domain.c_str (),
72
0
            options.zap_domain.length ());
73
0
    msg.set_flags (msg_t::more);
74
0
    rc = session->write_zap_msg (&msg);
75
0
    errno_assert (rc == 0);
76
77
    //  Address frame
78
0
    rc = msg.init_size (peer_address.length ());
79
0
    errno_assert (rc == 0);
80
0
    memcpy (msg.data (), peer_address.c_str (), peer_address.length ());
81
0
    msg.set_flags (msg_t::more);
82
0
    rc = session->write_zap_msg (&msg);
83
0
    errno_assert (rc == 0);
84
85
    //  Routing id frame
86
0
    rc = msg.init_size (options.routing_id_size);
87
0
    errno_assert (rc == 0);
88
0
    memcpy (msg.data (), options.routing_id, options.routing_id_size);
89
0
    msg.set_flags (msg_t::more);
90
0
    rc = session->write_zap_msg (&msg);
91
0
    errno_assert (rc == 0);
92
93
    //  Mechanism frame
94
0
    rc = msg.init_size (mechanism_length_);
95
0
    errno_assert (rc == 0);
96
0
    memcpy (msg.data (), mechanism_, mechanism_length_);
97
0
    if (credentials_count_)
98
0
        msg.set_flags (msg_t::more);
99
0
    rc = session->write_zap_msg (&msg);
100
0
    errno_assert (rc == 0);
101
102
    //  Credentials frames
103
0
    for (size_t i = 0; i < credentials_count_; ++i) {
104
0
        rc = msg.init_size (credentials_sizes_[i]);
105
0
        errno_assert (rc == 0);
106
0
        if (i < credentials_count_ - 1)
107
0
            msg.set_flags (msg_t::more);
108
0
        memcpy (msg.data (), credentials_[i], credentials_sizes_[i]);
109
0
        rc = session->write_zap_msg (&msg);
110
0
        errno_assert (rc == 0);
111
0
    }
112
0
}
113
114
int zap_client_t::receive_and_process_zap_reply ()
115
0
{
116
0
    int rc = 0;
117
0
    const size_t zap_reply_frame_count = 7;
118
0
    msg_t msg[zap_reply_frame_count];
119
120
    //  Initialize all reply frames
121
0
    for (size_t i = 0; i < zap_reply_frame_count; i++) {
122
0
        rc = msg[i].init ();
123
0
        errno_assert (rc == 0);
124
0
    }
125
126
0
    for (size_t i = 0; i < zap_reply_frame_count; i++) {
127
0
        rc = session->read_zap_msg (&msg[i]);
128
0
        if (rc == -1) {
129
0
            if (errno == EAGAIN) {
130
0
                return 1;
131
0
            }
132
0
            return close_and_return (msg, -1);
133
0
        }
134
0
        if ((msg[i].flags () & msg_t::more)
135
0
            == (i < zap_reply_frame_count - 1 ? 0 : msg_t::more)) {
136
0
            session->get_socket ()->event_handshake_failed_protocol (
137
0
              session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZAP_MALFORMED_REPLY);
138
0
            errno = EPROTO;
139
0
            return close_and_return (msg, -1);
140
0
        }
141
0
    }
142
143
    //  Address delimiter frame
144
0
    if (msg[0].size () > 0) {
145
        //  TODO can a ZAP handler produce such a message at all?
146
0
        session->get_socket ()->event_handshake_failed_protocol (
147
0
          session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZAP_UNSPECIFIED);
148
0
        errno = EPROTO;
149
0
        return close_and_return (msg, -1);
150
0
    }
151
152
    //  Version frame
153
0
    if (msg[1].size () != zap_version_len
154
0
        || memcmp (msg[1].data (), zap_version, zap_version_len)) {
155
0
        session->get_socket ()->event_handshake_failed_protocol (
156
0
          session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZAP_BAD_VERSION);
157
0
        errno = EPROTO;
158
0
        return close_and_return (msg, -1);
159
0
    }
160
161
    //  Request id frame
162
0
    if (msg[2].size () != id_len || memcmp (msg[2].data (), id, id_len)) {
163
0
        session->get_socket ()->event_handshake_failed_protocol (
164
0
          session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZAP_BAD_REQUEST_ID);
165
0
        errno = EPROTO;
166
0
        return close_and_return (msg, -1);
167
0
    }
168
169
    //  Status code frame, only 200, 300, 400 and 500 are valid status codes
170
0
    const char *status_code_data = static_cast<const char *> (msg[3].data ());
171
0
    if (msg[3].size () != 3 || status_code_data[0] < '2'
172
0
        || status_code_data[0] > '5' || status_code_data[1] != '0'
173
0
        || status_code_data[2] != '0') {
174
0
        session->get_socket ()->event_handshake_failed_protocol (
175
0
          session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZAP_INVALID_STATUS_CODE);
176
0
        errno = EPROTO;
177
0
        return close_and_return (msg, -1);
178
0
    }
179
180
    //  Save status code
181
0
    status_code.assign (static_cast<char *> (msg[3].data ()), 3);
182
183
    //  Save user id
184
0
    set_user_id (msg[5].data (), msg[5].size ());
185
186
    //  Process metadata frame
187
0
    rc = parse_metadata (static_cast<const unsigned char *> (msg[6].data ()),
188
0
                         msg[6].size (), true);
189
190
0
    if (rc != 0) {
191
0
        session->get_socket ()->event_handshake_failed_protocol (
192
0
          session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZAP_INVALID_METADATA);
193
0
        errno = EPROTO;
194
0
        return close_and_return (msg, -1);
195
0
    }
196
197
    //  Close all reply frames
198
0
    for (size_t i = 0; i < zap_reply_frame_count; i++) {
199
0
        const int rc2 = msg[i].close ();
200
0
        errno_assert (rc2 == 0);
201
0
    }
202
203
0
    handle_zap_status_code ();
204
205
0
    return 0;
206
0
}
207
208
void zap_client_t::handle_zap_status_code ()
209
0
{
210
    //  we can assume here that status_code is a valid ZAP status code,
211
    //  i.e. 200, 300, 400 or 500
212
0
    int status_code_numeric = 0;
213
0
    switch (status_code[0]) {
214
0
        case '2':
215
0
            return;
216
0
        case '3':
217
0
            status_code_numeric = 300;
218
0
            break;
219
0
        case '4':
220
0
            status_code_numeric = 400;
221
0
            break;
222
0
        case '5':
223
0
            status_code_numeric = 500;
224
0
            break;
225
0
    }
226
227
0
    session->get_socket ()->event_handshake_failed_auth (
228
0
      session->get_endpoint (), status_code_numeric);
229
0
}
230
231
zap_client_common_handshake_t::zap_client_common_handshake_t (
232
  session_base_t *const session_,
233
  const std::string &peer_address_,
234
  const options_t &options_,
235
  state_t zap_reply_ok_state_) :
236
0
    mechanism_base_t (session_, options_),
237
0
    zap_client_t (session_, peer_address_, options_),
238
0
    state (waiting_for_hello),
239
0
    _zap_reply_ok_state (zap_reply_ok_state_)
240
0
{
241
0
}
242
243
zmq::mechanism_t::status_t zap_client_common_handshake_t::status () const
244
0
{
245
0
    if (state == ready)
246
0
        return mechanism_t::ready;
247
0
    if (state == error_sent)
248
0
        return mechanism_t::error;
249
250
0
    return mechanism_t::handshaking;
251
0
}
252
253
int zap_client_common_handshake_t::zap_msg_available ()
254
0
{
255
0
    zmq_assert (state == waiting_for_zap_reply);
256
0
    return receive_and_process_zap_reply () == -1 ? -1 : 0;
257
0
}
258
259
void zap_client_common_handshake_t::handle_zap_status_code ()
260
0
{
261
0
    zap_client_t::handle_zap_status_code ();
262
263
    //  we can assume here that status_code is a valid ZAP status code,
264
    //  i.e. 200, 300, 400 or 500
265
0
    switch (status_code[0]) {
266
0
        case '2':
267
0
            state = _zap_reply_ok_state;
268
0
            break;
269
0
        case '3':
270
            //  a 300 error code (temporary failure)
271
            //  should NOT result in an ERROR message, but instead the
272
            //  client should be silently disconnected (see CURVEZMQ RFC)
273
            //  therefore, go immediately to state error_sent
274
0
            state = error_sent;
275
0
            break;
276
0
        default:
277
0
            state = sending_error;
278
0
    }
279
0
}
280
281
int zap_client_common_handshake_t::receive_and_process_zap_reply ()
282
0
{
283
0
    zmq_assert (state == waiting_for_zap_reply);
284
0
    return zap_client_t::receive_and_process_zap_reply ();
285
0
}
286
}