Coverage Report

Created: 2026-10-10 07:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libssh/include/libssh/session.h
Line
Count
Source
1
/*
2
 * This file is part of the SSH Library
3
 *
4
 * Copyright (c) 2009 by Aris Adamantiadis
5
 *
6
 * This library is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU Lesser General Public
8
 * License as published by the Free Software Foundation; either
9
 * version 2.1 of the License, or (at your option) any later version.
10
 *
11
 * This library is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
 * Lesser General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Lesser General Public
17
 * License along with this library; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
 */
20
21
#ifndef SESSION_H_
22
#define SESSION_H_
23
#include <stdbool.h>
24
25
#include "libssh/priv.h"
26
#include "libssh/callbacks.h"
27
#include "libssh/kex.h"
28
#include "libssh/packet.h"
29
#include "libssh/pcap.h"
30
#include "libssh/auth.h"
31
#include "libssh/channels.h"
32
#include "libssh/poll.h"
33
#include "libssh/config.h"
34
#include "libssh/misc.h"
35
36
/* These are the different states a SSH session can be into its life */
37
enum ssh_session_state_e {
38
  SSH_SESSION_STATE_NONE=0,
39
  SSH_SESSION_STATE_CONNECTING,
40
  SSH_SESSION_STATE_SOCKET_CONNECTED,
41
  SSH_SESSION_STATE_BANNER_RECEIVED,
42
  SSH_SESSION_STATE_INITIAL_KEX,
43
  SSH_SESSION_STATE_KEXINIT_RECEIVED,
44
  SSH_SESSION_STATE_DH,
45
  SSH_SESSION_STATE_AUTHENTICATING,
46
  SSH_SESSION_STATE_AUTHENTICATED,
47
  SSH_SESSION_STATE_ERROR,
48
  SSH_SESSION_STATE_DISCONNECTED
49
};
50
51
enum ssh_dh_state_e {
52
  DH_STATE_INIT=0,
53
  DH_STATE_GROUP_SENT,
54
  DH_STATE_REQUEST_SENT,
55
  DH_STATE_INIT_SENT,
56
  DH_STATE_NEWKEYS_SENT,
57
  DH_STATE_FINISHED
58
};
59
60
enum ssh_pending_call_e {
61
    SSH_PENDING_CALL_NONE = 0,
62
    SSH_PENDING_CALL_CONNECT,
63
    SSH_PENDING_CALL_AUTH_NONE,
64
    SSH_PENDING_CALL_AUTH_PASSWORD,
65
    SSH_PENDING_CALL_AUTH_OFFER_PUBKEY,
66
    SSH_PENDING_CALL_AUTH_PUBKEY,
67
    SSH_PENDING_CALL_AUTH_AGENT,
68
    SSH_PENDING_CALL_AUTH_KBDINT_INIT,
69
    SSH_PENDING_CALL_AUTH_KBDINT_SEND,
70
    SSH_PENDING_CALL_AUTH_GSSAPI_MIC,
71
    SSH_PENDING_CALL_AUTH_GSSAPI_KEYEX,
72
};
73
74
/* libssh calls may block an undefined amount of time */
75
24.1k
#define SSH_SESSION_FLAG_BLOCKING 0x0001
76
77
/* Client successfully authenticated */
78
645k
#define SSH_SESSION_FLAG_AUTHENTICATED 0x0002
79
80
/* Do not accept new session channels (no-more-sessions@openssh.com) */
81
1.80k
#define SSH_SESSION_FLAG_NO_MORE_SESSIONS 0x0004
82
83
/* The KEXINIT message can be sent first by either of the parties so this flag
84
 * indicates that the message was already sent to make sure it is sent and avoid
85
 * sending it twice during key exchange to simplify the state machine. */
86
17.8k
#define SSH_SESSION_FLAG_KEXINIT_SENT 0x0008
87
88
/* The current SSH2 session implements the "strict KEX" feature and should behave
89
 * differently on SSH2_MSG_NEWKEYS. */
90
15.3k
#define SSH_SESSION_FLAG_KEX_STRICT 0x0010
91
/* Unexpected packets have been sent while the session was still unencrypted */
92
157k
#define SSH_SESSION_FLAG_KEX_TAINTED 0x0020
93
/* The scp on server can not handle quoted paths. Skip the mitigation for
94
 * CVE-2019-14889 when using scp */
95
2
#define SSH_SESSION_FLAG_SCP_QUOTING_BROKEN 0x0040
96
97
/* codes to use with ssh_handle_packets*() */
98
/* Infinite timeout */
99
7.72k
#define SSH_TIMEOUT_INFINITE -1
100
/* Use the timeout defined by user if any. Mostly used with new connections */
101
33.4k
#define SSH_TIMEOUT_USER -2
102
/* Use the default timeout, depending on ssh_is_blocking() */
103
0
#define SSH_TIMEOUT_DEFAULT -3
104
/* Don't block at all */
105
7.72k
#define SSH_TIMEOUT_NONBLOCKING 0
106
107
/* options flags */
108
/* Authentication with *** allowed */
109
8.20k
#define SSH_OPT_FLAG_PASSWORD_AUTH 0x1
110
8.20k
#define SSH_OPT_FLAG_PUBKEY_AUTH 0x2
111
8.20k
#define SSH_OPT_FLAG_KBDINT_AUTH 0x4
112
8.20k
#define SSH_OPT_FLAG_GSSAPI_AUTH 0x8
113
114
/* Escape expansion of different variables */
115
0
#define SSH_OPT_EXP_FLAG_KNOWNHOSTS 0x1
116
0
#define SSH_OPT_EXP_FLAG_GLOBAL_KNOWNHOSTS 0x2
117
0
#define SSH_OPT_EXP_FLAG_PROXYCOMMAND 0x4
118
0
#define SSH_OPT_EXP_FLAG_IDENTITY 0x8
119
0
#define SSH_OPT_EXP_FLAG_CONTROL_PATH 0x10
120
0
#define SSH_OPT_EXP_FLAG_USERNAME 0x20
121
122
/* extensions flags */
123
/* negotiation enabled */
124
15.2k
#define SSH_EXT_NEGOTIATION     0x01
125
/* server-sig-algs extension */
126
2.54k
#define SSH_EXT_SIG_RSA_SHA256  0x02
127
1.82k
#define SSH_EXT_SIG_RSA_SHA512  0x04
128
/* Host-bound public key authentication extension */
129
18
#define SSH_EXT_PUBLICKEY_HOSTBOUND 0x08
130
/* ping@openssh.com extension */
131
52
#define SSH_EXT_PING 0x10
132
133
/* members that are common to ssh_session and ssh_bind */
134
struct ssh_common_struct {
135
    struct error_struct error;
136
    ssh_callbacks callbacks; /* Callbacks to user functions */
137
    int log_verbosity; /* verbosity of the log functions */
138
};
139
140
struct ssh_session_struct {
141
    struct ssh_common_struct common;
142
    struct ssh_socket_struct *socket;
143
    char *serverbanner;
144
    char *clientbanner;
145
    int protoversion;
146
    int server;
147
    int client;
148
    int openssh;
149
    uint32_t send_seq;
150
    uint32_t recv_seq;
151
    struct ssh_timestamp last_rekey_time;
152
    bool proxy_root;
153
    uint32_t pending_pings;
154
    int connected;
155
    /* !=0 when the user got a session handle */
156
    int alive;
157
    /* two previous are deprecated */
158
    /* int auth_service_asked; */
159
160
    /* session flags (SSH_SESSION_FLAG_*) */
161
    int flags;
162
163
    /* Extensions negotiated using RFC 8308 */
164
    uint32_t extensions;
165
166
    ssh_string banner; /* that's the issue banner from the server */
167
    char *peer_discon_msg; /* disconnect message from the remote host */
168
    char *disconnect_message; /* disconnect message to be set */
169
    ssh_buffer in_buffer;
170
    PACKET in_packet;
171
    ssh_buffer out_buffer;
172
    struct ssh_list *out_queue; /* This list is used for delaying packets
173
                                   when rekeying is required */
174
175
    /* the states are used by the nonblocking stuff to remember */
176
    /* where it was before being interrupted */
177
    enum ssh_pending_call_e pending_call_state;
178
    enum ssh_session_state_e session_state;
179
    enum ssh_packet_state_e packet_state;
180
    enum ssh_dh_state_e dh_handshake_state;
181
    enum ssh_channel_request_state_e global_req_state;
182
    struct ssh_agent_state_struct *agent_state;
183
184
    struct {
185
        struct ssh_auth_auto_state_struct *auto_state;
186
        enum ssh_auth_service_state_e service_state;
187
        enum ssh_auth_state_e state;
188
        uint32_t supported_methods;
189
        uint32_t current_method;
190
    } auth;
191
192
    /* Sending this flag before key exchange to save one round trip during the
193
     * key exchange. This might make sense on high-latency connections.
194
     * So far internal only for testing. Usable only on the client side --
195
     * there is no key exchange method that would start with server message */
196
    bool send_first_kex_follows;
197
    /*
198
     * RFC 4253, 7.1: if the first_kex_packet_follows flag was set in
199
     * the received SSH_MSG_KEXINIT, but the guess was wrong, this
200
     * field will be set such that the following guessed packet will
201
     * be ignored on the receiving side.  Once that packet has been received and
202
     * ignored, this field is cleared.
203
     * On the sending side, this is set after we got peer KEXINIT message and we
204
     * need to resend the initial message of the negotiated KEX algorithm.
205
     */
206
    bool first_kex_follows_guess_wrong;
207
208
    ssh_string gssapi_key_exchange_mic;
209
210
    ssh_buffer in_hashbuf;
211
    ssh_buffer out_hashbuf;
212
    struct ssh_crypto_struct *current_crypto;
213
    /* next_crypto is going to be used after a SSH2_MSG_NEWKEYS */
214
    struct ssh_crypto_struct *next_crypto;
215
216
    struct ssh_list *channels; /* linked list of channels */
217
    uint32_t maxchannel;
218
    ssh_agent agent; /* ssh agent */
219
220
    /* keyboard interactive data */
221
    struct ssh_kbdint_struct *kbdint;
222
    struct ssh_gssapi_struct *gssapi;
223
224
    /* server host keys */
225
    struct {
226
        ssh_key rsa_key;
227
        ssh_key ecdsa_key;
228
        ssh_key ed25519_key;
229
        /* The type of host key wanted by client */
230
        enum ssh_keytypes_e hostkey;
231
        enum ssh_digest_e hostkey_digest;
232
    } srv;
233
234
    /* auths accepted by server */
235
    struct ssh_list *ssh_message_list; /* list of delayed SSH messages */
236
    int (*ssh_message_callback)(struct ssh_session_struct *session,
237
                                ssh_message msg, void *userdata);
238
    void *ssh_message_callback_data;
239
    ssh_server_callbacks server_callbacks;
240
    void (*ssh_connection_callback)( struct ssh_session_struct *session);
241
    struct ssh_packet_callbacks_struct default_packet_callbacks;
242
    struct ssh_list *packet_callbacks;
243
    struct ssh_socket_callbacks_struct socket_callbacks;
244
    ssh_poll_ctx default_poll_ctx;
245
    /* options */
246
#ifdef WITH_PCAP
247
    ssh_pcap_context pcap_ctx; /* pcap debugging context */
248
#endif
249
    struct {
250
        struct ssh_list *identity;
251
        struct ssh_list *identity_non_exp;
252
        struct ssh_iterator *identity_it;
253
        struct ssh_list *certificate;
254
        struct ssh_list *certificate_non_exp;
255
        struct ssh_list *proxy_jumps;
256
        struct ssh_list *proxy_jumps_user_cb;
257
        char *proxy_jumps_str;
258
        char *username;
259
        char *host;
260
        char *bindaddr; /* bind the client to an ip addr */
261
        char *homedir;
262
        char *sshdir;
263
        char *knownhosts;
264
        char *global_knownhosts;
265
        char *wanted_methods[SSH_KEX_METHODS];
266
        char *pubkey_accepted_types;
267
        char *ProxyCommand;
268
        char *agent_socket;
269
        unsigned long timeout; /* seconds */
270
        unsigned long timeout_usec;
271
        uint16_t port;
272
        socket_t fd;
273
        int StrictHostKeyChecking;
274
        char compressionlevel;
275
        char *gss_server_identity;
276
        char *gss_client_identity;
277
        bool gssapi_key_exchange;
278
        char *gssapi_key_exchange_algs;
279
        int gss_delegate_creds;
280
        int flags;
281
        int exp_flags;
282
        int nodelay;
283
        bool config_processed;
284
        uint8_t options_seen[SOC_MAX];
285
        uint64_t rekey_data;
286
        uint32_t rekey_time;
287
        int rsa_min_size;
288
        bool identities_only;
289
        int control_master;
290
        char *control_path;
291
        int address_family;
292
        int server_alive_interval;
293
        int server_alive_count_max;
294
        bool batch_mode;
295
        char *preferred_authentications;
296
        int number_of_password_prompts;
297
        int request_tty;
298
        int escape_char;
299
        struct ssh_list *local_forward;
300
        struct ssh_iterator *local_forward_it;
301
        struct ssh_list *remote_forward;
302
        struct ssh_iterator *remote_forward_it;
303
        struct ssh_list *send_env;
304
        struct ssh_iterator *send_env_it;
305
        char *originalhost;        /* user-supplied host for config matching */
306
        char *config_hostname; /* normalized HostName pattern, applied later */
307
        bool config_hostname_only; /* config hostname path: update host only,
308
                                      not originalhost */
309
        char *tag;                 /* configuration tag for Match tagged */
310
        int pubkey_auth;
311
        bool exit_on_forward_failure;
312
        bool forward_agent;
313
        char *forward_agent_sock_path;
314
        bool gateway_ports;
315
    } opts;
316
317
    /* server options */
318
    struct {
319
        char *custombanner;
320
        char *moduli_file;
321
    } server_opts;
322
323
    /* counters */
324
    ssh_counter socket_counter;
325
    ssh_counter raw_counter;
326
327
    /* PKI context structure containing various parameters to configure PKI
328
     * operations */
329
    struct ssh_pki_ctx_struct *pki_context;
330
};
331
332
/**
333
 * @internal
334
 *
335
 * @brief Apply the reduced-authentication behavior for an unsafe host key
336
 * continuation.
337
 *
338
 * When `StrictHostKeyChecking` is `off` and host key verification reports a
339
 * changed or other key, OpenSSH allows the connection to continue only
340
 * "subject to some restrictions"; see `ssh_config(5)` for
341
 * `StrictHostKeyChecking` and `check_host_key()` in OpenSSH's `sshconnect.c`
342
 * under the `continue_unsafe` label.  For libssh's supported client-side auth
343
 * methods, this means disabling password and keyboard-interactive
344
 * authentication for the rest of the session.
345
 */
346
static inline void ssh_known_hosts_continue_unsafe(ssh_session session)
347
0
{
348
0
    SSH_LOG(SSH_LOG_WARN,
349
0
            "Continuing despite an unsafe host key with "
350
0
            "StrictHostKeyChecking=off; password and keyboard-interactive "
351
0
            "authentication have been disabled for this session");
352
0
    session->opts.flags &=
353
0
        ~(SSH_OPT_FLAG_PASSWORD_AUTH | SSH_OPT_FLAG_KBDINT_AUTH);
354
0
}
Unexecuted instantiation: callbacks.c:ssh_known_hosts_continue_unsafe
Unexecuted instantiation: channels.c:ssh_known_hosts_continue_unsafe
Unexecuted instantiation: client.c:ssh_known_hosts_continue_unsafe
Unexecuted instantiation: curve25519.c:ssh_known_hosts_continue_unsafe
Unexecuted instantiation: sntrup761.c:ssh_known_hosts_continue_unsafe
Unexecuted instantiation: dh.c:ssh_known_hosts_continue_unsafe
Unexecuted instantiation: error.c:ssh_known_hosts_continue_unsafe
Unexecuted instantiation: hybrid_mlkem.c:ssh_known_hosts_continue_unsafe
Unexecuted instantiation: kex.c:ssh_known_hosts_continue_unsafe
Unexecuted instantiation: knownhosts.c:ssh_known_hosts_continue_unsafe
Unexecuted instantiation: log.c:ssh_known_hosts_continue_unsafe
Unexecuted instantiation: messages.c:ssh_known_hosts_continue_unsafe
Unexecuted instantiation: misc.c:ssh_known_hosts_continue_unsafe
Unexecuted instantiation: mlkem.c:ssh_known_hosts_continue_unsafe
Unexecuted instantiation: options.c:ssh_known_hosts_continue_unsafe
Unexecuted instantiation: packet.c:ssh_known_hosts_continue_unsafe
Unexecuted instantiation: packet_cb.c:ssh_known_hosts_continue_unsafe
Unexecuted instantiation: packet_crypt.c:ssh_known_hosts_continue_unsafe
Unexecuted instantiation: pcap.c:ssh_known_hosts_continue_unsafe
Unexecuted instantiation: pki.c:ssh_known_hosts_continue_unsafe
Unexecuted instantiation: poll.c:ssh_known_hosts_continue_unsafe
Unexecuted instantiation: session.c:ssh_known_hosts_continue_unsafe
Unexecuted instantiation: socket.c:ssh_known_hosts_continue_unsafe
Unexecuted instantiation: wrapper.c:ssh_known_hosts_continue_unsafe
Unexecuted instantiation: pki_crypto.c:ssh_known_hosts_continue_unsafe
Unexecuted instantiation: ecdh_crypto.c:ssh_known_hosts_continue_unsafe
Unexecuted instantiation: curve25519_crypto.c:ssh_known_hosts_continue_unsafe
Unexecuted instantiation: libcrypto.c:ssh_known_hosts_continue_unsafe
Unexecuted instantiation: dh_crypto.c:ssh_known_hosts_continue_unsafe
Unexecuted instantiation: server.c:ssh_known_hosts_continue_unsafe
Unexecuted instantiation: bind.c:ssh_known_hosts_continue_unsafe
Unexecuted instantiation: bind_config.c:ssh_known_hosts_continue_unsafe
Unexecuted instantiation: dh-gex.c:ssh_known_hosts_continue_unsafe
Unexecuted instantiation: mlkem_native.c:ssh_known_hosts_continue_unsafe
Unexecuted instantiation: agent.c:ssh_known_hosts_continue_unsafe
Unexecuted instantiation: auth.c:ssh_known_hosts_continue_unsafe
Unexecuted instantiation: config.c:ssh_known_hosts_continue_unsafe
Unexecuted instantiation: connect.c:ssh_known_hosts_continue_unsafe
Unexecuted instantiation: connector.c:ssh_known_hosts_continue_unsafe
Unexecuted instantiation: ecdh.c:ssh_known_hosts_continue_unsafe
Unexecuted instantiation: gzip.c:ssh_known_hosts_continue_unsafe
Unexecuted instantiation: kdf.c:ssh_known_hosts_continue_unsafe
355
356
/** @internal
357
 * @brief a termination function evaluates the status of an object
358
 * @param user[in] object to evaluate
359
 * @returns 1 if the polling routine should terminate, 0 instead
360
 */
361
typedef int (*ssh_termination_function)(void *user);
362
int ssh_handle_packets(ssh_session session, int timeout);
363
int ssh_handle_packets_termination(ssh_session session,
364
                                   int timeout,
365
                                   ssh_termination_function fct,
366
                                   void *user);
367
void ssh_socket_exception_callback(int code, int errno_code, void *user);
368
369
#endif /* SESSION_H_ */